Animation cancelling a specific limb

I have an issue where a humanoid that is playing an animation will create jank with forced headmovement.

The following animation is played:

When i run a server script that rotates the head towards the players face, the animation will override the headmovement before being corrected

The following script is run in

loop = RunService.Stepped:Connect(function() ... end)
local function GetVectors(cf1)
	local sx, sy, sz, m00, m01, m02, m10, m11, m12, m20, m21, m22 = cf1:GetComponents()

	local X = math.atan2(-m12, m22)
	local Y = math.asin(m02)
	local Z = math.atan2(-m01, m00)

	return Vector3.new(math.round(X*roundVal)/roundVal, math.round(Y*roundVal)/roundVal, math.round(Z*roundVal)/roundVal)
end

local function LookTo(lookatItem)

	local goalCF			

	local success, response = pcall(function()
		goalCF = CFrame.lookAt(head.Position, lookatItem.Position, torso.CFrame.UpVector)
	end)
	if not success then	
		goalCF = CFrame.lookAt(head.Position, lookatItem:GetBoundingBox().Position, torso.CFrame.UpVector)
	end

	local relativeToPart1 = Neck.C0*Neck.C1:Inverse()*Neck.Part1.CFrame:Inverse()*goalCF*Neck.C1

	relativeToPart1 -= relativeToPart1.Position
	
	local X, Y, Z = relativeToPart1:ToEulerAnglesXYZ()
	X, Y, Z = math.deg(X), math.deg(Y), math.deg(Z)
	
	--print(X)

	local maxXAngle = 130
	local minXAngle = -120
	
	--X = math.clamp(X, minXAngle, maxXAngle)
	
	if X < maxXAngle and X >= 0 then
		X = maxXAngle
	elseif X > minXAngle and X < 0 then
		X = minXAngle
	
	end
	--print(X)

	--print(relativeToPart1)
	--print(CFrame.Angles(X,Y,Z))

	local goalC0CFrame = relativeToPart1+Neck.C0.Position--New orientation but keep old C0 joint position
	goalC0CFrame = CFrame.Angles(math.rad(X),math.rad(Y),math.rad(Z))+Neck.C0.Position
	
	local vec, vec2 = GetVectors(goalC0CFrame), GetVectors(Neck.C0)

	if vec ~= vec2 then
		tween = TweenService:Create(Neck, tweeninfo, {C0 = goalC0CFrame}):Play()
	end
end

Ive tried running the lookTo loop on a local script using renderstepped, but it became worse. Heartbeat didnt help either.

I tried renaming body parts to different names to cancel the animation while running the loop, but the animation wouldnt revert if ex. player goes out of range.

What i also tried to do is create a module that removes specific limbs from animations, which could work but is SUPER DEMANDING if using moonanimator.

Is there any way i can stop animating a specific limb on command while not lagging the game or ruining the NPC indefinently?

why does it have to be on a server in first place?
Make it locally using .Transform
Also it could be that you need step that goes after .Stepped in runservice like PostSimulation etc

It’s in the server because it’s in the same script used for detecting other things to look at. Such as other players guns and such.

If i do the loop on the server and then call in a local script to turn the head it’s even more of a lag.

I tried figuring out which step animations are played in as to do it after, but couldn’t find anything. I tried post tender and a few different steps and couldn’t get it to work. I’ll try post simulation again.

That problem of implementation then.
Is it really worth “gatekeeping” it and secrofising network perfomance and look of game?

network performance? A 10 second moon animation has like 4000 keyframes due to smoothing. It literally freezes the game (with the script i have). Either that or i in advance split animations before they loaded in, which is too many too keep track of

yes network perfomance.
You are updating value that has to be sent to client every time which is a wrong way to make games…
Client should do it locally without involvement of server.

I tried to update the value locally, still freezes the game. What the module does is go through every keyframe and remove its CFrame, if i add task.wait() to the for loop the animation will take a sec to load. It could work but im hoping for a better soltution :slight_smile:

I tried post simulation and i know why it wont work. The animation will move the head before post simulation, and then it gets adjusted by the script. Pre animation wont work either for the same reason

maybe just try IKConrolls instead?
As far as i understood you want character’s head to face player and for that you better make client side touch event to resume connection that runs every frame and disconnect it when leaves the zone

No not quite. I want to have a function that disconnects a given limb from an animation. Ideally not even a function just a regular command

I have made one, but it freezes the client based on the amount of keyframes

The loop is cancelled on player death. Would you like the entire script?

No
I just feel like you are doing something wrong that causes it.
You want it to look at player you can use IKControl instead.
Also wdym “command”?
You are overthinking too much and making it even harder and less optimized.

I am for sure overthinking, which is why i would like a simple solution. By command i mean something like “Head.Animatable = false” (which i know doesnt exist)

The script works with everything else, just not when animated

if you want to cancel animation at a limb just update its Transform property to CFrame.idenity each PostSimulation

I couldnt get this to work but figured out the problem. Got a module to manually remove the limb from the animation without causing lag

It stores the removed frames if you want to restore it later

local removedlimbs = {
	--["Animation"] = {["Limb"] = {keyframes}}
}
local keyframeService : KeyframeSequenceProvider = game:GetService('KeyframeSequenceProvider')

module.RemoveLimbFromAnimation = function(NPC, Animation, Limb)
	local Sequence = keyframeService:GetKeyframeSequenceAsync(Animation.AnimationId)
	
	if not removedlimbs[Animation] then
		removedlimbs[Animation] = {}
	end
	
	if not removedlimbs[Animation][Limb] then
		for _, frame : Keyframe in pairs(Sequence:GetKeyframes()) do
			
			local Khrp = frame.HumanoidRootPart
			local children = Khrp:GetChildren()

			local limb = Khrp:FindFirstChild(Limb, true)
			if limb then
				if removedlimbs[Animation][Limb] then
					table.insert(removedlimbs[Animation][Limb], limb:Clone())
				else
					removedlimbs[Animation][Limb] = {limb:Clone()}
				end
				
				limb:Destroy()
			end
		end
		print(removedlimbs)
	end
	
	local asset = keyframeService:RegisterKeyframeSequence(Sequence)
	return asset
end