local function B(B)if B.Magnitude==0 then return Vector3.zero end return B.Unit end local G=math.huge return function(R,p,r,c)debug.profilebegin("\065\120\105\115 \067\111\110\115\116\114\097\105\110\116")local j=c:Inverse()*p local y=j.X local W=j.Y local l=j.Z local a=R.XAxisLimits local Y=R.YAxisLimits local f=R.ZAxisLimits local H=R.AxisLocked[1]and 0 or 1 local q=R.AxisLocked[2]and 0 or 1 local N=R.AxisLocked[3]and 0 or 1 if a.Min==-G and(a.Max==G and(Y.Min==-G and(Y.Max==G and(f.Min==-G and f.Max==G))))then if H==1 and(q==1 and N==1)then debug.profileend()return p else return c*Vector3.new(y*H,W*q,l*N)end end local Z=a.Min+R.Radius local J=Z<=a.Max-R.Radius and a.Max-R.Radius or Z local S=Y.Min+R.Radius local T=S<=Y.Max-R.Radius and Y.Max-R.Radius or S local i=f.Min+R.Radius local g=i<=f.Max-R.Radius and f.Max-R.Radius or i y=y<Z and Z or y>J and J or y W=W<S and S or W>T and T or W l=l<i and i or l>g and g or l y*=H W*=q l*=N local u=c*Vector3.new(y,W,l)p=u local t=c.RightVector local O=c.UpVector local z=c.LookVector local k=B(p-r)if y~=j.X then local B=t:Dot(k)<0 and-t or t R:ClipVelocity(p,B)end if W~=j.Y then local B=O:Dot(k)<0 and-O or O R:ClipVelocity(p,B)end if l~=j.Z then local B=z:Dot(k)>0 and-z or z R:ClipVelocity(p,B)end debug.profileend()return p end
local function SafeUnit(v3)
	if v3.Magnitude == 0 then
		return Vector3.zero
	end

	return v3.Unit
end

local inf = math.huge

return function(self, Position, LastPosition, RootCFrame)
	debug.profilebegin("Axis Constraint")
	local RootOffset = RootCFrame:Inverse() * Position

	local X = RootOffset.X
	local Y = RootOffset.Y
	local Z = RootOffset.Z

	local XLimit = self.XAxisLimits
	local YLimit = self.YAxisLimits
	local ZLimit = self.ZAxisLimits

	local XLock = self.AxisLocked[1] and 0 or 1
	local YLock = self.AxisLocked[2] and 0 or 1
	local ZLock = self.AxisLocked[3] and 0 or 1

	-- Most bones probably wont have an axis limit, this allows us to skip all the other stuff
	if XLimit.Min == -inf and XLimit.Max == inf and YLimit.Min == -inf and YLimit.Max == inf and ZLimit.Min == -inf and ZLimit.Max == inf then
		if XLock == 1 and YLock == 1 and ZLock == 1 then
			debug.profileend()
			return Position
		else
			return RootCFrame * Vector3.new(X * XLock, Y * YLock, Z * ZLock)
		end
	end

	-- If our radius is > than the diff between min and max
	-- We do this because its faster than math.min() ¯\_(ツ)_/¯
	local XMin = XLimit.Min + self.Radius
	local XMax = XMin <= (XLimit.Max - self.Radius) and XLimit.Max - self.Radius or XMin

	local YMin = YLimit.Min + self.Radius
	local YMax = YMin <= (YLimit.Max - self.Radius) and YLimit.Max - self.Radius or YMin

	local ZMin = ZLimit.Min + self.Radius
	local ZMax = ZMin <= (ZLimit.Max - self.Radius) and ZLimit.Max - self.Radius or ZMin

	X = X < XMin and XMin or (X > XMax and XMax or X)
	Y = Y < YMin and YMin or (Y > YMax and YMax or Y)
	Z = Z < ZMin and ZMin or (Z > ZMax and ZMax or Z)

	X *= XLock
	Y *= YLock
	Z *= ZLock

	local WorldSpace = RootCFrame * Vector3.new(X, Y, Z)

	Position = WorldSpace

	local XAxis = RootCFrame.RightVector
	local YAxis = RootCFrame.UpVector
	local ZAxis = RootCFrame.LookVector

	local DifferenceDirection = SafeUnit(Position - LastPosition)

	-- Remove our velocity on the vectors we collided with, stops any weird jittering.
	if X ~= RootOffset.X then
		local Normal = XAxis:Dot(DifferenceDirection) < 0 and -XAxis or XAxis
		self:ClipVelocity(Position, Normal)
	end

	if Y ~= RootOffset.Y then
		local Normal = YAxis:Dot(DifferenceDirection) < 0 and -YAxis or YAxis
		self:ClipVelocity(Position, Normal)
	end

	if Z ~= RootOffset.Z then
		local Normal = ZAxis:Dot(DifferenceDirection) > 0 and -ZAxis or ZAxis
		self:ClipVelocity(Position, Normal)
	end
	debug.profileend()

	return Position
end
