Thanks for the immense effort, but my brain is a bit fried and I’m having trouble implementing your function into my build script
local e = true
local qr
local tb
local mou = game.Players.LocalPlayer:GetMouse()
local function raysurfaceface(e)
local dotY = e:Dot(Vector3.new(0,1,0))
local dotX = e:Dot(Vector3.new(1,0,0))
local dotZ = e:Dot(Vector3.new(0,0,1))
local surface
if (math.abs(dotY) >= 0.9) then
if (dotY < 0) then
surface = Enum.NormalId.Bottom
else
surface = Enum.NormalId.Top
end
elseif (math.abs(dotX) >= 0.9) then
if (dotX < 0) then
surface = Enum.NormalId.Left
else
surface = Enum.NormalId.Right
end
else
if (dotZ < 0) then
surface = Enum.NormalId.Front
else
surface = Enum.NormalId.Back
end
end
return surface
end
local function vec3Func(f, ...)
local x, y, z = {}, {}, {}
for i, v in next, {...} do
x[i], y[i], z[i] = v.x, v.y, v.z
end
return Vector3.new(f(unpack(x)), f(unpack(y)), f(unpack(z)))
end
local function getRotationBetween(u, v, axis)
local dot, uxv = u:Dot(v), u:Cross(v)
if (dot < -0.99999) then return CFrame.fromAxisAngle(axis, math.pi) end
return CFrame.new(0, 0, 0, uxv.x, uxv.y, uxv.z, 1 + dot)
end
local function getSurfaceCF(part, lnormal)
local pcf, size2 = part.CFrame, part.Size/2
local transition = getRotationBetween(Vector3.new(0,0,1), lnormal, Vector3.new(0,1,0))
local size = vec3Func(math.abs, transition:VectorToWorldSpace(part.Size))
return (pcf * transition) * CFrame.new(size/2 * Vector3.new(0, 0, 1)), size
end
local function boundingbox(size,cf)
local a = {
Vector3.new(0,0,0)+cf.RightVector.Unit*size.X/2+cf.UpVector.Unit*size.Y/2+cf.LookVector.Unit*size.Z/2,
Vector3.new(0,0,0)+cf.RightVector.Unit*size.X/2+cf.UpVector.Unit*size.Y/2-cf.LookVector.Unit*size.Z/2,
Vector3.new(0,0,0)+cf.RightVector.Unit*size.X/2-cf.UpVector.Unit*size.Y/2+cf.LookVector.Unit*size.Z/2,
Vector3.new(0,0,0)+cf.RightVector.Unit*size.X/2-cf.UpVector.Unit*size.Y/2-cf.LookVector.Unit*size.Z/2,
Vector3.new(0,0,0)-cf.RightVector.Unit*size.X/2+cf.UpVector.Unit*size.Y/2+cf.LookVector.Unit*size.Z/2,
Vector3.new(0,0,0)-cf.RightVector.Unit*size.X/2+cf.UpVector.Unit*size.Y/2-cf.LookVector.Unit*size.Z/2,
Vector3.new(0,0,0)-cf.RightVector.Unit*size.X/2-cf.UpVector.Unit*size.Y/2+cf.LookVector.Unit*size.Z/2,
Vector3.new(0,0,0)-cf.RightVector.Unit*size.X/2-cf.UpVector.Unit*size.Y/2-cf.LookVector.Unit*size.Z/2
}
local minlpx = 0
local minlpy = 0
local minlpz = 0
local maxlpx = 0
local maxlpy = 0
local maxlpz = 0
for i=1,#a do
if a[i].X<minlpx then
minlpx=a[i].X
end
end
for i=1,#a do
if a[i].Y<minlpy then
minlpy=a[i].Y
end
end
for i=1,#a do
if a[i].Z<minlpz then
minlpz=a[i].Z
end
end
for i=1,#a do
if a[i].X>maxlpx then
maxlpx=a[i].X
end
end
for i=1,#a do
if a[i].Y>maxlpy then
maxlpy=a[i].Y
end
end
for i=1,#a do
if a[i].Z>maxlpz then
maxlpz=a[i].Z
end
end
return Vector3.new(minlpx,minlpy,minlpz), Vector3.new(maxlpx,maxlpy,maxlpz)
end
local function getSurfaceSize(CRay)
local List = {"UpVector","LookVector","RightVector"}
local List2 = {}
local Sides = {{"X","Y","Z"},{"X","Z","Y"},{"Y","X","Z"}}
for count = 1,6,1 do
local modi = -1+(count%2)*2
List2[CRay.Instance.CFrame[List[math.ceil(count/2)]]*modi] = Sides[math.ceil(count/2)]
end
local Size = CRay.Instance.Size
local N = List2[CRay.Normal]
return Vector3.new(Size[N[1]],Size[N[2]],Size[N[3]])
end
local function GetWorldOrientedSurface(part, normalId)
local cf = part.CFrame
local n = Vector3.fromNormalId(normalId)
local nWorld = cf:VectorToWorldSpace(n)
-- pick arbitrary vector parallel to one of the edges
local x = cf.LookVector
if math.abs(x:Dot(nWorld)) > 0.9999 then
x = cf.RightVector -- for front/back face
end
-- calculate another vector orthongal to the first on the surface
local y = nWorld:Cross(x)
-- flip up if pointing down
x = math.sign(x.Y) * x
y = math.sign(y.Y) * y
-- choose which one is "more up" as the y axis
y = y.Y > x.Y and y or x
-- recalculate x axis based on that y axis vector
x = y:Cross(nWorld)
-- get position on surface
local partSizeNormalAxisOnly = part.Size * n -- e.g. (3, 4, 5) * (0, 1, 0) -> (0, 4, 0)
local partSizeInNormal = partSizeNormalAxisOnly.X + partSizeNormalAxisOnly.Y + partSizeNormalAxisOnly.Z -- e.g. (0, 4, 0) -> 4
local surfacePos = part.Position + nWorld * math.abs(partSizeInNormal) / 2
-- put together cframe matrix
local surfaceCFrame = CFrame.fromMatrix(surfacePos, x, y, nWorld)
-- get width of part in direction of x and y
local sizeInWorldSpace = part.CFrame:VectorToWorldSpace(part.Size)
local sizeInSurfaceSpace = surfaceCFrame:VectorToObjectSpace(sizeInWorldSpace)
-- correct for negatives
sizeInSurfaceSpace = Vector3.new(
math.abs(sizeInSurfaceSpace.X),
math.abs(sizeInSurfaceSpace.Y),
math.abs(sizeInSurfaceSpace.Z))
return surfaceCFrame
end
local tb = Instance.new("Part",workspace)
tb.Anchored=true
game:GetService("RunService").RenderStepped:Connect(function()
if e==true then
local rcp = RaycastParams.new()
rcp.FilterType=Enum.RaycastFilterType.Blacklist
rcp.FilterDescendantsInstances={game.Players.LocalPlayer.Character,tb}
local ray = workspace:Raycast(workspace.CurrentCamera.CFrame.Position,(mou.Hit.p-workspace.CurrentCamera.CFrame.Position).Unit*500,rcp)
if ray==nil then
tb.Parent=nil
else
local f1 = 0
local f2
print(ray.Normal.Unit)
if math.abs(ray.Normal.Unit.X)>f1 then
f1=math.abs(ray.Normal.Unit.X)
f2 = "x"
end
if math.abs(ray.Normal.Unit.Y)>f1 then
f1=math.abs(ray.Normal.Unit.Y)
f2 = "y"
end
if math.abs(ray.Normal.Unit.Z)>f1 then
f1=math.abs(ray.Normal.Unit.Z)
f2 = "z"
end
local r = 45
local jarsx,jarsy,jarsz
if f2=="y" then
jarsx,jarsy,jarsz = ((CFrame.lookAt(Vector3.new(0,0,0),ray.Normal.Unit,ray.Instance.CFrame:VectorToWorldSpace(Vector3.new(0,1,0)))*CFrame.fromOrientation(math.rad(-90),0,0))*CFrame.fromOrientation(0,math.rad(r),0)):ToOrientation()
else
jarsx,jarsy,jarsz = ((CFrame.lookAt(Vector3.new(0,0,0),ray.Normal.Unit,Vector3.new(0,1,0))*CFrame.fromOrientation(math.rad(-90),0,0))*CFrame.fromOrientation(0,math.rad(r),0)):ToOrientation()
end
tb.Parent=workspace
local i1 = Vector3.new(ray.Position.X,ray.Position.Y,ray.Position.Z)
--if raysurfaceface(ray.Instance.CFrame:VectorToObjectSpace(ray.Normal))==Enum.NormalId.Bottom then
-- i1=i1-(tb.PrimaryPart.CFrame.UpVector.Unit*(tb.PrimaryPart.Size.Y/2))
--elseif raysurfaceface(ray.Instance.CFrame:VectorToObjectSpace(ray.Normal))==Enum.NormalId.Top then
-- i1=i1+(tb.PrimaryPart.CFrame.UpVector.Unit*(tb.PrimaryPart.Size.Y/2))
--elseif raysurfaceface(ray.Instance.CFrame:VectorToObjectSpace(ray.Normal))==Enum.NormalId.Front then
-- i1=i1+(tb.PrimaryPart.CFrame.LookVector.Unit*(tb.PrimaryPart.Size.Z/2))
--elseif raysurfaceface(ray.Instance.CFrame:VectorToObjectSpace(ray.Normal))==Enum.NormalId.Back then
-- i1=i1-(tb.PrimaryPart.CFrame.LookVector.Unit*(tb.PrimaryPart.Size.Z/2))
--elseif raysurfaceface(ray.Instance.CFrame:VectorToObjectSpace(ray.Normal))==Enum.NormalId.Right then
-- i1=i1+(tb.PrimaryPart.CFrame.RightVector.Unit*(tb.PrimaryPart.Size.X/2))
--elseif raysurfaceface(ray.Instance.CFrame:VectorToObjectSpace(ray.Normal))==Enum.NormalId.Left then
-- i1=i1-(tb.PrimaryPart.CFrame.RightVector.Unit*(tb.PrimaryPart.Size.X/2))
--end
local intended = CFrame.new(i1)*CFrame.fromOrientation(jarsx,jarsy,jarsz)
local p1,p2 = boundingbox(tb.Size,CFrame.fromOrientation(jarsx,jarsy,jarsz))
local intended2
print(f2)
print(getSurfaceSize(ray))
local kars = GetWorldOrientedSurface(ray.Instance,raysurfaceface(ray.Normal))
if f2=="y" then
print(math.clamp(kars:pointToObjectSpace(intended.Position).X,-getSurfaceSize(ray).X/2+math.abs(p1.X-p2.X)/2,getSurfaceSize(ray).X/2-math.abs(p1.X-p2.X)/2))
print(kars:pointToObjectSpace(intended.Position).Y)
print(math.clamp(kars:pointToObjectSpace(intended.Position).Z,-getSurfaceSize(ray).Z/2+math.abs(p1.Z-p2.Z)/2,getSurfaceSize(ray).Z/2-math.abs(p1.Z-p2.Z)/2))
intended2 = CFrame.new(Vector3.new(math.clamp(kars:pointToObjectSpace(intended.Position).X,-getSurfaceSize(ray).X/2+math.abs(p1.X-p2.X)/2,getSurfaceSize(ray).X/2-math.abs(p1.X-p2.X)/2),kars:pointToObjectSpace(intended.Position).Y,math.clamp(kars:pointToObjectSpace(intended.Position).Z,-getSurfaceSize(ray).Z/2+math.abs(p1.Z-p2.Z)/2,getSurfaceSize(ray).Z/2-math.abs(p1.Z-p2.Z)/2)))
elseif f2=="x" then
intended2 = CFrame.new(Vector3.new(kars:pointToObjectSpace(intended.Position).X,math.clamp(kars:pointToObjectSpace(intended.Position).Y,-getSurfaceSize(ray).Z/2+math.abs(p1.Y-p2.Y)/2,getSurfaceSize(ray).Z/2-math.abs(p1.Y-p2.Y)/2),math.clamp(kars:pointToObjectSpace(intended.Position).Z,-getSurfaceSize(ray).Z/2+math.abs(p1.Z-p2.Z)/2,getSurfaceSize(ray).Z/2-math.abs(p1.Z-p2.Z)/2)))
elseif f2=="z" then
intended2 = CFrame.new(Vector3.new(math.clamp(kars:pointToObjectSpace(intended.Position).X,-getSurfaceSize(ray).X/2+math.abs(p1.X-p2.X)/2,getSurfaceSize(ray).X/2-math.abs(p1.X-p2.X)/2),math.clamp(kars:pointToObjectSpace(intended.Position).Y,-getSurfaceSize(ray).Z/2+math.abs(p1.Y-p2.Y)/2,getSurfaceSize(ray).Z/2-math.abs(p1.Y-p2.Y)/2),kars:pointToObjectSpace(intended.Position).Z))
end
intended2=CFrame.new(kars:pointToWorldSpace(intended2.Position))
intended2=CFrame.new(intended2.Position)*CFrame.fromOrientation(jarsx,jarsy,jarsz)
game:GetService("TweenService"):Create(tb,TweenInfo.new(.1/3,Enum.EasingStyle.Quad,Enum.EasingDirection.InOut),{CFrame=intended2}):Play()
end
end
end)
Place it in StarterGui