Morphed custom rig is turning smooth in shift lock / first person

When I am a regular character, the character turns normally (snapping without smoothing) when shift locking or first person locking.

When I turn into a morph into the custom rig, it starts smoothing out which is unintended behavior.

I want to remove this unintended smoothing in shift lock and first person on the custom rig.

Video:

Custom Rig:
rig-with-shift-lock-bug.rbxm (50.3 KB)

Place Where You Can Replicate Bug:
smooth-shift-lock-bug.rbxl (106.4 KB)

MorphHandler (server) script:

--!strict

local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local ServerScriptService = game:GetService("ServerScriptService")
local ServerStorage = game:GetService("ServerStorage")
local Workspace = game:GetService("Workspace")

local ServerConstants = require(ServerScriptService:WaitForChild("ServerConstants"))

local characterTemplates = ServerStorage:WaitForChild("Characters")

local function createDisableIsMorphingAttributeFunction(player: Player)
	return function()
		player:SetAttribute(ServerConstants.IS_MORPHING_ATTRIBUTE, false)
	end
end

local function handleChildDescendantInMorph(descendant: Instance, player: Player)
	if not descendant:IsA("BasePart") then
		return
	end

	descendant.Anchored = false
	descendant.CanTouch = false
	if not descendant.CanCollide then
		descendant.CanQuery = false
	end
	descendant.Massless = true
	if descendant:IsDescendantOf(Workspace) and not descendant.Anchored then
		descendant:SetNetworkOwner(player)
	end
end

local function morphPlayer(player: Player, characterTemplate: Model)
	player:SetAttribute(ServerConstants.IS_MORPHING_ATTRIBUTE, true)

	local disableIsMorphingAttribute = createDisableIsMorphingAttributeFunction(player)
	local character = player.Character
	if not character then
		disableIsMorphingAttribute()
		return
	end

	local currentPivot = character:GetPivot()

	local humanoid = character:FindFirstChildOfClass("Humanoid")
	if not humanoid then
		disableIsMorphingAttribute()
		return
	end

	local rootPart = humanoid.RootPart
	if not rootPart then
		disableIsMorphingAttribute()
		return
	end

	local newCharacter = characterTemplate:Clone()
	newCharacter.Name = player.Name
	local newCharacterHumanoid = newCharacter:FindFirstChildOfClass("Humanoid")
	if not newCharacterHumanoid then
		newCharacter:Destroy()
		disableIsMorphingAttribute()
		return
	end
	local newCharacterRootPart = newCharacterHumanoid.RootPart
	if not newCharacterRootPart then
		newCharacter:Destroy()
		disableIsMorphingAttribute()
		return
	end

	newCharacter:SetAttribute(ServerConstants.CURRENT_MORPH_ATTRIBUTE, characterTemplate.Name)

	newCharacter.Parent = Workspace

	player.Character = newCharacter

	task.delay(ServerConstants.DISABLE_IS_MORPHING_DELAY, disableIsMorphingAttribute)

	newCharacterRootPart.Anchored = false
	newCharacter:PivotTo(currentPivot)
	for _, descendant in newCharacter:GetDescendants() do
		handleChildDescendantInMorph(descendant, player)
	end
end

local function onMorphPartPlayerHeartbeat(morphPart: BasePart, player: Player)
	local character = player.Character
	if not character then
		return
	end

	local currentMorph = character:GetAttribute(ServerConstants.CURRENT_MORPH_ATTRIBUTE)
	if player:GetAttribute(ServerConstants.IS_MORPHING_ATTRIBUTE) or currentMorph then
		return
	end

	local humanoid = character:FindFirstChildOfClass("Humanoid")
	if not humanoid then
		return
	end

	local rootPart = humanoid.RootPart
	if not rootPart then
		return
	end

	local rootPartYPlanePosition = Vector2.new(rootPart.Position.X, rootPart.Position.Z)
	local morphPartYPlanePosition = Vector2.new(morphPart.Position.X, morphPart.Position.Z)
	local distance = (rootPartYPlanePosition - morphPartYPlanePosition).Magnitude
	if distance > ServerConstants.MORPH_PART_RADIUS then
		return
	end

	local characterTemplate = characterTemplates:FindFirstChild(morphPart.Name)
	if not characterTemplate then
		return
	end

	morphPlayer(player, characterTemplate)
end

local function onMorphPartHeartbeat(morphPart: BasePart)
	for _, player in Players:GetPlayers() do
		onMorphPartPlayerHeartbeat(morphPart, player)
	end
end

local function onHeartbeat()
	local morphPartsModel = Workspace:FindFirstChild("MorphParts")
	if not morphPartsModel then
		return
	end

	local morphParts: { BasePart } = morphPartsModel:GetChildren()
	for _, morphPart in morphParts do
		onMorphPartHeartbeat(morphPart)
	end
end

local function initialize()
	RunService.Heartbeat:Connect(onHeartbeat)
end

initialize()

Set the accessories/baseparts of the custom rig to have Massless enabled

  • That’s already done in the rig (template model) and the script (character after morphing), every BasePart set to Massless = true
  • The rig only has a 2 BasePart which is the HumanoidRootPart and Torso
local function handleChildDescendantInMorph(descendant: Instance, player: Player)
	if not descendant:IsA("BasePart") then
		return
	end

	descendant.Anchored = false
	descendant.CanTouch = false
	if not descendant.CanCollide then
		descendant.CanQuery = false
	end
	descendant.Massless = true
	if descendant:IsDescendantOf(Workspace) and not descendant.Anchored then
		descendant:SetNetworkOwner(player)
	end
end

If massless didn’t help you can try setting custom physical properties

What do you mean about setting custom physical properties? What exactly should I do with them, which properties and what values?

image

That didn’t fix the problem as the shift lock smoothing still persists. On top of that, that also created problems for the movement.

Do you have any ideas for a possible solution?

you need to make a HumanoidRootPart
Becouse humanoid doesnt understand where to put HipHeight likely
Also bro wtf heppened to this mesh?


Why its boundingbox so huge? :sob: :pray: