Client Freezes and Crashes When Missing 4th M1 (no errors, only happens sometimes)

  1. What do you want to achieve?
  • I want my combat system to work consistently without freezing when a player misses the 4th M1.
  1. What is the issue?
  • The freeze only happens sometimes, not always. Maybe like a 10 percent chance.
  • This happens both in Studio play testing and in a Roblox server.
  • It only happens when the attack misses if the hit connects, it works fine.
  • The crash occurs right as the animation is finishing.
  • The crash only affects the player who missed other players in the game are not affected.
  • There are no errors or warnings in the output when this happens the client just freezes immediately after the 4th M1 miss.

Here’s a clip of it happening (the footage is cropped, but nothing important is cropped):

  1. What solutions have you tried so far?
  • I checked my animation handling to make sure nothing unusual happens when the move ends.
  • I searched the Creator Hub and DevForum but couldn’t find a post about this specific case.
  • Rescripted my entire M1 system.

Here’s my scripts related to the m1:

On server when a miss occurs:

OnFinish = function(HitCount)
	if HitCount == 0 and combo == 4 then
		MoveModule.CreateBoolValue(char, "NoMovement", 0.75)
	end
end,

CreateBoolValue Function:

function MoveModule.CreateBoolValue(Character, Name, Duration)
	if not Character or not Character.Parent then return end
	ActiveBools[Character] = ActiveBools[Character] or {}

	if ActiveBools[Character][Name] then
		if ActiveBools[Character][Name].Parent then
			ActiveBools[Character][Name]:Destroy()
		end
		ActiveBools[Character][Name] = nil
	end

	local BoolValue = Instance.new("BoolValue")
	BoolValue.Name = Name
	BoolValue.Parent = Character

	ActiveBools[Character][Name] = BoolValue

	task.delay(Duration, function()
		if BoolValue and BoolValue.Parent then
			BoolValue:Destroy()
		end
		if ActiveBools[Character] and ActiveBools[Character][Name] == BoolValue then
			ActiveBools[Character][Name] = nil
		end
	end)

	return BoolValue
end

Client M1 script (Snippet):

function m1.Start(state)
	if fourthLock then return end
	local humanoid = getHumanoid()
	if not humanoid then return end

	if tick() - lasthit > 2 then combo = 1 end
	lasthit = tick()

	humanoid.JumpPower = 0
	humanoid.JumpHeight = 0
	humanoid:SetStateEnabled(Enum.HumanoidStateType.Jumping, false)
	cd = true

	if combo == 4 then
		local anim = state == "air" and getAnimation("Air", true) or 
			state == "falling" and getAnimation("Falling", true) or 
			getAnimation(tostring(combo))
		playAnimation(anim, 1.5 * m1.attackSpeed, state, true)
	else
		playAnimation(getAnimation(tostring(combo)), m1.M1Speed, state, false)
	end
end

NoMovement Handling (Client Sided) (Snippet):

local NoMovementCount = 0

local function handleNoMovementAdded()
	NoMovementCount = NoMovementCount + 1
	if NoMovementCount == 1 then
		if not humanoid then return end
		pcall(function()
			humanoid.WalkSpeed = 0
			humanoid.JumpPower = 0
		end)
		stopSprint()
		pcall(function()
			block.Stop()
		end)
	end
end

local function handleNoMovementRemoved()
	NoMovementCount = math.max(NoMovementCount - 1, 0)
	if NoMovementCount == 0 then
		if humanoid then
			humanoid.WalkSpeed = defaultWalkSpeed
			humanoid.JumpPower = defaultJumpPower
		end
		if wHeld then
			task.delay(0.15, startSprint)
		end
		if blockHolding and (not character:FindFirstChild("NoBlock")) and (not character:GetAttribute("Ragdolled")) then
			block.Start()
		end
	end
end

	character:.ChildAdded:Connect(function(child)
		if not character or not character.Parent then return end
		if child and child.Name == "Stun" then
			handleStunAdded()
		elseif child and child.Name == "NoMovement" then
			handleNoMovementAdded()
		end
	end)

	character:.ChildRemoved:Connect(function(child)
		if not character or not character.Parent then return end
		if child and child.Name == "Stun" then
			handleStunRemoved()
		elseif child and child.Name == "NoMovement" then
			handleNoMovementRemoved()
		end
	end)

	humanoid:GetPropertyChangedSignal("WalkSpeed"):Connect(function()
		if (isStunned() or NoMovementCount > 0) and humanoid.WalkSpeed ~= 0 then
			humanoid.WalkSpeed = 0
		end
	end)

	humanoid:GetPropertyChangedSignal("JumpPower"):Connect(function()
		if (isStunned() or NoMovementCount > 0) and humanoid.JumpPower ~= 0 then
			humanoid.JumpPower = 0
		end
	end)

If you need any other snippet, please let me know.

Any insight would be greatly appreciated.