Combat system verification system goes out of sync

Hello all,
I’ve done a verification system for my basic combat system but sometimes it goes out of sync, which I don’t know why happens.
SERVER SCRIPT →

local playerRandoms = {}

PlayerManager.PlayerAdded:Connect(function(player)
	local seed = math.random() * 3264
	playerRandoms[player] = Random.new(seed)
	print(playerRandoms[player], player)
	SeedRemoteEvent:FireClient(player, seed, itemsWithoutSpaces)
end)

local total = 0
for i, data in animations do total += data.Chance end

local function SelectAnimation(player)
	local value = playerRandoms[player]:NextInteger(1, total)

	for i, data in animations do
		value -= data.Chance
		if value > 0 then continue end
		return animations[i]
	end
end

local function SelectDamage(player, animation)
	return playerRandoms[player]:NextInteger(animation.Damage.Min, animation.Damage.Max)
end

PlayerAttackRemoteEvent.OnServerEvent:Connect(function(player, anim, playerHit)
	local animation = SelectAnimation(player)
	local animationDamage = SelectDamage(player, animation)
	local tool = player.Character:FindFirstChildWhichIsA("Tool")
	local toolDamage = itemsWithoutSpaces[tool.Name].Damage

	if animation.Chance == anim.Chance then --Safety check
		local damage = toolDamage + animationDamage
		if damage > 0 then
			playerHit.Character.Humanoid:TakeDamage(damage)
		end
	end
end)

AnimationStoppedRemoteEvent.OnServerEvent:Connect(function(player)
	SelectAnimation(player)
	playerRandoms[player]:NextNumber()
end)

LOCALSCRIPT →

local canAttack = true
	tool.Activated:Connect(function()
		if tool:GetAttribute("Type") == "Sword" or tool:GetAttribute("Type") == "Axe" then
			if canAttack and LocalPlayer.PlayerGui.Inventory.InventoryFrame.Items.Visible == false then
				local anim = SelectAnimation()
				local animation = animator:LoadAnimation(anim.Animation)
				
				tool.Main.Trail.Enabled = true
				animation:Play()
				
				if tool:FindFirstChildWhichIsA("Sound") == nil then
					local sound = game.ReplicatedStorage.SoundEffects.WeaponSound:Clone()
					sound.Parent = tool
				end
				
				tool:FindFirstChildWhichIsA("Sound"):Play()
				
				canAttack = false

				local players = {}

				local connection = tool.Main.Touched:Connect(function(hit)
					local player = Players:GetPlayerFromCharacter(hit.Parent)

					if player and players[player] == nil then
						players[player] = true

						local animationDamage = SelectDamage(anim)
						local toolDamage = items[tool.Name].Damage
						
						local damage = animationDamage + toolDamage
						local healthDamage = damage

						if healthDamage then
							local toolDamageText = ToolDamageText:Clone()
							toolDamageText.Text = healthDamage
							toolDamageText.TextColor3 = Color3.fromRGB(170, 0, 0)
							toolDamageText.Position = UDim2.new((0.3 + math.random() * (0.7 - 0.3)), 0, (0.3 + math.random() * (0.7 - 0.3)), 0)
							toolDamageText.Parent = LocalPlayer.PlayerGui.UI
							
							toolDamageText:TweenSize(UDim2.new(0, 75, 0, 75), Enum.EasingDirection.InOut, Enum.EasingStyle.Linear, 1, true, function()
								local transparencyTween = TweenService:Create(toolDamageText, toolDamageTextTweenInfo, { TextTransparency = 1 })
								transparencyTween:Play()
								transparencyTween.Completed:Connect(function()
									toolDamageText:Destroy()
								end)
							end)
						end

						PlayerAttackRemoteEvent:FireServer(anim, player)
					end
				end)

				animation.Stopped:Connect(function()
					tool.Main.Trail.Enabled = false
					connection:Disconnect()
					localRandom:NextNumber()
					AnimationStoppedRemoteEvent:FireServer()
					
					wait(1)
					
					canAttack = true
				end)
			end
		end
	end)

The way it works is that the server sends a certain seed to a client so they both can get the same NextInteger() values for it. This works very well until the player misses hitting somebody (eg. just hits the air), after that it will no longer be synced and many will not go thru the safety check which is commented in the server script. Help is appreciated, if you have any questions, please leave them below

1 Like

I wouldn’t really recommend rolling code as a form of security. It’s primary use is preventing relay attacks in wireless key entry systems. So the only thing it’s preventing is third parties from picking up the signals the key fob produces and creating a mimic key.

For your application, this security check isn’t very effective because the client is the key fob and the server is the car, they both know how to produce the codes. And the only solution so your issue is the server doesn’t match the client, you assume the server is behind the client due to missing some codes and attempts the next X number of codes.

The server would be behind when The client would change The localscript because i specifically added a wait so this wouldn’t happen. I just can’t see where it gets out of sync