Neck C0 not working on R6 but working fine on R15

Hello! I’m making a market system in a game which has a NPC that is supposed to look at you once you come within a certain amount of studs of him. Here is the current code for turning the head to face you:

local boothPerson = game.Workspace.Dummy
local NPCHRP = boothPerson.HumanoidRootPart
local neck = boothPerson.Head:WaitForChild("Neck")
local xOffSet = neck.C0.X
local yOffSet = neck.C0.Y
local zOffSet = neck.C0.Z

function main()
	local HRP = script.Parent:WaitForChild("HumanoidRootPart")
	local dist = (HRP.Position-NPCHRP.Position).Magnitude
	local dir = (HRP.Position-NPCHRP.Position).Unit
	local vecA = Vector2.new(NPCHRP.CFrame.LookVector.X, NPCHRP.CFrame.LookVector.Z)
	local vecB = Vector2.new(dir.X, dir.Z)
	local dotValue = vecA:Dot(vecB)
	local crossValue = vecA:Cross(vecB)
	local ht = NPCHRP.Position.Y - HRP.Position.Y
	local upAngle = math.atan(ht/dist)

	local angle = math.atan2(crossValue, dotValue)
	if angle > math.pi/3 then
		angle = math.pi/3
	elseif angle < -math.pi/3 then
		angle = -math.pi/3
	end
	neck.C0 = (CFrame.new(xOffSet, yOffSet, zOffSet)*CFrame.Angles(0,-angle,0)*CFrame.Angles(-upAngle, 0, 0))
end

RunService:BindToRenderStep("standHeadFollow", 1000, main)

The odd thing is this code works perfectly fine on an R15 dummy, but not on an R6 dummy, which is a problem because I wanted to make the NPC R6. Here’s two videos showing the difference:
(Sorry in advance that it’s low quality, this isn’t my regular setup so I don’t have OBS installed)



I’m not sure what causes the difference but thanks in advance if anyone can fix it!

This problem was never solved but if anyone is having this issue and wants a fix that’s relatively close to what I was trying to accomplish, here’s some code that makes the head look side to side where the player goes, but not up or down:

Code
function main()
	local HRP = script.Parent:WaitForChild("HumanoidRootPart")
	local dist = (HRP.Position-NPCHRP.Position).Magnitude
	local dir = (HRP.Position-NPCHRP.Position).Unit
	local vecA = Vector2.new(NPCHRP.CFrame.LookVector.X, NPCHRP.CFrame.LookVector.Z)
	local vecB = Vector2.new(dir.X, dir.Z)
	local dotValue = vecA:Dot(vecB)
	local crossValue = vecA:Cross(vecB)
	local ht = NPCHRP.Position.Y - HRP.Position.Y
	local upAngle = math.atan(ht/dist)

	local angle = math.atan2(crossValue, dotValue)
	if angle > math.pi/3 then
		angle = math.pi/3
	elseif angle < -math.pi/3 then
		angle = -math.pi/3
	end
	neck.C0 = (CFrame.new(xOffSet, yOffSet, zOffSet)*CFrame.Angles(0,-angle,0)*CFrame.Angles(-upAngle, 0, 0))
end

RunService:BindToRenderStep("standHeadFollow", 250, main)

The ‘Neck’ joint is inside the ‘Torso’ limb for R6 avatar rigs.

I know and I corrected it accordingly, I would just be getting an error if I didn’t.
The C0 is just behaving differently for R6 and I don’t know why.

That’s because the Neck motor on the R6 is specifically built differently.

I know this post is old and you’ve probably already solved your problem, but I recommend marking my post as the solution because this is the first post that appears when you search for the topic.

I don’t know exactly what’s the difference between both necks (R6 / R15) but some values are inverted, and I took your script and made some small changes and it worked well!

The first thing I did was change the neck’s origin variable, since in your code you completely excluded the values involving the neck’s original rotation (that’s why the head was in a totally buggy position, looking down inside the torso)

The second thing I did was to change the RunService event to RenderStepped, but if you have a big number of npcs that look at the player I recommend using Heartbeat because RenderStepped requires a lot of resources from the person’s device, which in high quantities can cause a lot of lag.

The third thing I did was the simplest, which was simply to put :WaitForChild on some instances since the script is Client Sided, which on some devices could cause an error because the instance hasn’t loaded yet.

Enough talking, here’s the result!

local boothPerson = workspace:WaitForChild("Dummy")
local NPCHRP = boothPerson:WaitForChild("HumanoidRootPart")
local neck = boothPerson:WaitForChild("Torso"):WaitForChild("Neck")
local NeckOrigin = neck.C0

local RunService = game:GetService("RunService")

RunService.RenderStepped:Connect(function()
	local HRP = script.Parent:WaitForChild("HumanoidRootPart")
	local dist = (HRP.Position-NPCHRP.Position).Magnitude
	local dir = (HRP.Position-NPCHRP.Position).Unit
	local vecA = Vector2.new(NPCHRP.CFrame.LookVector.X, NPCHRP.CFrame.LookVector.Z)
	local vecB = Vector2.new(dir.X, dir.Z)
	local dotValue = vecA:Dot(vecB)
	local crossValue = vecA:Cross(vecB)
	local ht = NPCHRP.Position.Y - HRP.Position.Y
	local upAngle = math.atan(ht/dist)

	local angle = math.atan2(crossValue, dotValue)
	if angle > math.pi/3 then
		angle = math.pi/3
	elseif angle < -math.pi/3 then
		angle = -math.pi/3
	end

	neck.C0 = NeckOrigin * CFrame.Angles(0, 0, -angle) * CFrame.Angles(upAngle, 0, 0)
end)