Client Desync via Remote Events

This is a support category for asking questions about how to get something done on the Roblox websites or how to do something on Roblox applications such as Roblox Studio.

You can write your topic however you want, but you need to answer these questions:

  1. What I want to achieve; creating a reliable fast weapon system with less desync

  2. What is the issue? At the moment, for the purpose of having smooth hit detection, raycasting and part creation, what I do is create the essentials on the client like how things were before fe, then for all other players I fire a server remote event that just fires the same event on the client which copies what was done on the main client. It definitely works perfectly for a smooth experience but sometimes the clients can desync where a knife would hit the player but on the other players screen it missed.

  3. So far I haven’t found a good solution that doesn’t make the weapon very slow, however I did manage to make it a bit more accurate from client to client by running these things along side eachother.

Here is the client remote event listener from the knife module that is required to everyones client upon entering the server. The parameters starting with “p” are just to have one available to pass vector3s

RemoteEvents.KnifeWeaponFunction.OnClientEvent:Connect(function(p1, p2, p3, p4, p5, p6, p7, p8)
	if p3 ~= game.Players.LocalPlayer.Character then
		if p2 == "CreateNormal" then
			local KnifeTracker = p4
			local Knife = p3.Knife.Handle:Clone()
			Knife.CanCollide = false
			Knife.Anchored = true
			Knife.CFrame = p3.Knife.Handle.CFrame
			Knife.Name = "tKnife"..KnifeTracker
			Knife.Parent = workspace
			local ThrowLoop = Instance.new("Sound")
			ThrowLoop.Name = "ThrowLoop"
			ThrowLoop.Looped = true
			ThrowLoop.Volume = 0.3
			ThrowLoop.SoundId = "http://www.roblox.com/asset?id="..Sounds.ThrowLoop[1]
			ThrowLoop.Parent = Knife
			ThrowLoop:Play()
		elseif p2 == "AirSwoosh" then
			local KnifeTracker = p7
			local Knife = workspace:WaitForChild("tKnife"..KnifeTracker)
			local Pos, KCP, Distance = p4, p5, p6
			for i = 1, Distance, 6 do
				Knife.CFrame = CFrame.new(Pos, KCP) * CFrame.new(0,0,i-Distance) * CFrame.fromEulerAnglesXYZ(math.rad(i*15),math.rad(180),math.rad(360))
				wait()
			end
		elseif p2 == "Stop" then
			local KnifeTracker = p6
			local Knife = workspace:WaitForChild("tKnife"..KnifeTracker)
			local P, K = p4, p5
			Knife.CFrame = CFrame.new(P, K) * CFrame.new(0,0,0) * CFrame.fromEulerAnglesXYZ(math.rad(90),math.rad(180),math.rad(360))
		elseif p2 == "WallHit" then
			local KnifeTracker = p4
			local Knife = workspace:WaitForChild("tKnife"..KnifeTracker)
			local KnifeContents = Knife:GetChildren()
			for k = 1, #KnifeContents do
				if KnifeContents[k]:IsA("Sound") then
					KnifeContents[k]:Destroy()
				end
			end
			local Wallhit = Instance.new("Sound")
			Wallhit.Parent = Knife
			Wallhit.Volume = 0.5
			Wallhit.SoundId = "rbxassetid://"..Sounds.WallHit[math.random(1, 2)]
			Wallhit:Play()
			Wallhit.Changed:Connect(function()
				if Wallhit.IsPlaying == false then
					Wallhit:Destroy()
				end
			end)
			delay(10, function()
				Knife:Destroy()
				Knife = nil
			end)
		elseif p2 == "DestroyKnife" then
			local KnifeTracker = p4
			local Knife = workspace:WaitForChild("tKnife"..KnifeTracker)
			Knife:Destroy()
		elseif p2 == "CreateLaser" then
			local KnifeTracker = p4
			local Knife = p3.Knife.Handle:Clone()
			Knife.CanCollide = false
			Knife.Anchored = true
			Knife.CFrame = p3.Knife.Handle.CFrame
			Knife.Name = "tKnife"..KnifeTracker
			Knife.Parent = workspace
		elseif p2 == "CreateLaserBeam" then
			local KnifeTracker = p4
			local Knife = workspace:WaitForChild("tKnife"..KnifeTracker)
			local Pos, KCP, Distance = p5, Knife.CFrame.p , p7
			local LaserPart = Instance.new("Part")
			LaserPart.Name = "Laser"..KnifeTracker
			LaserPart.CanQuery = false
			LaserPart.Anchored = true
			LaserPart.CanCollide = false
			LaserPart.Material = "Neon"
			LaserPart.Color = Color3.new(1, 0, 0)
			LaserPart.TopSurface = Enum.SurfaceType.Smooth
			LaserPart.BottomSurface = Enum.SurfaceType.Smooth
			LaserPart.Size = Vector3.new(0.2, 0.2, Distance)
			LaserPart.CFrame = CFrame.new(Pos, KCP) * CFrame.new(0, 0, (-Distance/2) + 2)
			LaserPart.Parent = workspace
		elseif p2 == "AnimateLaser" then
			local KnifeTracker = p4
			local Knife = workspace:WaitForChild("tKnife"..KnifeTracker)
			local LaserPart = workspace:WaitForChild("Laser"..KnifeTracker)
			local Distance, Pos, KCP = p5, p6, Knife.CFrame.p
			for i = 10000, Distance do
				Knife.CFrame = CFrame.new(Pos, KCP) * CFrame.new(0,0,i-Distance) * CFrame.fromEulerAnglesXYZ(math.rad(90),math.rad(180),math.rad(360))
			end
			Knife.CFrame = CFrame.new(Pos, KCP) * CFrame.new(0,0,0) * CFrame.fromEulerAnglesXYZ(math.rad(90),math.rad(180),math.rad(360))
			local TweenProperies = {
				Size = Vector3.new(0.02, 0.02, Distance);
				Transparency = 0.5
			}
			local FadeLaser = game.TweenService:Create(LaserPart, TweenInfo.new(0.1, Enum.EasingStyle.Linear, Enum.EasingDirection.In), TweenProperies)
			FadeLaser:Play()
			delay(0.11, function()
				LaserPart:Destroy()
			end)
		elseif p2 == "SecondaryWallHit" then
			local KnifeTracker = p4
			local Knife = workspace:WaitForChild("tKnife"..KnifeTracker)
			local Wallhit = Instance.new("Sound")
			Wallhit.Parent = Knife
			Wallhit.Volume = 0.5
			Wallhit.SoundId = "rbxassetid://"..Sounds.WallHit[math.random(1, 2)]
			Wallhit:Play()
			Wallhit.Changed:Connect(function()
				if Wallhit.IsPlaying == false then
					Wallhit:Destroy()
				end
			end)
			delay(10, function()
				Knife:Destroy()
				Knife = nil
			end)
		end
	end
end)

Here is the server listener

Events.KnifeWeaponFunction.OnServerEvent:Connect(function(p, p1, p2, p3, p4, p5, p6, p7, p8)
	local Char = p.Character
	Events.KnifeWeaponFunction:FireAllClients("N/A", p2, Char, p4, p5, p6, p7, p8)
end)

Here’s is the function where the knife gets thrown, I am aware I’m using depreciated methods of taycasting, that’s just what I’m used to and it still works, I’ll upgrade soon!

local function ThrowKnife(MousePos)
	Throwing = true
	Events.KnifeSound:FireServer(Sounds.Throw, Char.Torso, 0.5)
	KnifeTracker = KnifeTracker + 1
	if KnifePower == "Normal" or KnifePower == "Explosive Knife" or KnifePower == "Electric Knife"  then
		local Touched = false
		spawn(function()
			Events.KnifeWeaponFunction:FireServer("N/A", "CreateNormal", "N/A", KnifeTracker)
		end)
		local Knife = Tool.Handle:Clone()
		Knife.CanCollide = false
		Knife.Anchored = true
		Knife.CFrame = Char.Knife.Handle.CFrame
		Knife.Name = "tKnife"..KnifeTracker
		Knife.Parent = workspace
		local ThrowLoop = Instance.new("Sound")
		ThrowLoop.Name = "ThrowLoop"
		ThrowLoop.Looped = true
		ThrowLoop.Volume = 0.3
		ThrowLoop.SoundId = "http://www.roblox.com/asset?id="..Sounds.ThrowLoop[1]
		ThrowLoop.Parent = Knife
		ThrowLoop:Play()
		local NewRay = Ray.new(Knife.CFrame.p, (MousePos - Knife.CFrame.p).unit * 1000)
		local Hit, Pos = game.Workspace:FindPartOnRayWithIgnoreList(NewRay, GenerateIgnoreList(Knife, Char))
		local Distance = (Pos - Knife.CFrame.p).magnitude
		spawn(function()
			local P, K, D = Pos, Knife.CFrame.p, Distance
			Events.KnifeWeaponFunction:FireServer("N/A", "AirSwoosh", "N/A", P, K, D, KnifeTracker)
		end)
		for i = 1, Distance, 6 do
			DetectHuman(Knife, Char)
			Knife.CFrame = CFrame.new(Pos, Knife.CFrame.p) * CFrame.new(0,0,i-Distance) * CFrame.fromEulerAnglesXYZ(math.rad(i*15),math.rad(180),math.rad(360))
			wait()
		end
		spawn(function()
			local P, K = Pos, Knife.CFrame.p
			Events.KnifeWeaponFunction:FireServer("N/A", "Stop", "N/A", P, K, KnifeTracker)
		end)
		Knife.CFrame = CFrame.new(Pos, Knife.CFrame.p) * CFrame.new(0,0,0) * CFrame.fromEulerAnglesXYZ(math.rad(90),math.rad(180),math.rad(360))
		local KnifeContents = Knife:GetChildren()
		for k = 1, #KnifeContents do
			if KnifeContents[k]:IsA("Sound") then
				KnifeContents[k]:Destroy()
			end
		end
		if Hit then
			if game.Players:GetPlayerFromCharacter(Hit.Parent) == nil and game.Players:GetPlayerFromCharacter(Hit.Parent.Parent) == nil then
				Knife.Anchored = true
				spawn(function()
					Events.KnifeWeaponFunction:FireServer("N/A", "WallHit", "N/A", KnifeTracker)
				end)
				local Wallhit = Instance.new("Sound")
				Wallhit.Parent = Knife
				Wallhit.Volume = 0.5
				Wallhit.SoundId = "rbxassetid://"..Sounds.WallHit[math.random(1, 2)]
				Wallhit:Play()
				Wallhit.Changed:Connect(function()
					if Wallhit.IsPlaying == false then
						Wallhit:Destroy()
					end
				end)
				delay(10, function()
					Knife:Destroy()
				end)
			else
				local char1, char2 = game.Players:GetPlayerFromCharacter(Hit.Parent), game.Players:GetPlayerFromCharacter(Hit.Parent.Parent)
				if char1 ~= nil or char2 ~= nil and char1 ~= Char and char2 ~= Char then
					local GetChar = nil
					if Hit.Parent:FindFirstChild("Humanoid") and not Hit.Parent.Parent:FindFirstChild("Humanoid") then
						GetChar = Hit.Parent
					elseif Hit.Parent.Parent:FindFirstChild("Humanoid") and Hit.Parent:IsA("Accessory") and not Hit.Parent:FindFirstChild("Humanoid") then
						GetChar = Hit.Parent.Parent
					end
					if GetChar ~= nil then
						local GetTorso = GetChar:FindFirstChild("Torso")
						local GetHuman = GetChar:FindFirstChild("Humanoid")
						if GetTorso and GetHuman then
							if Char then
								Events.KnifeSound:FireServer(Sounds.ThrowHit, GetTorso, 0.5)
								if game.ReplicatedStorage.Content.GameInProgress.Value == true then
									if game.ReplicatedStorage.Content.GameMode.Value == "Wicked Murderer" then
										Events.KnifeDamage:FireServer(GetHuman, 100)
									elseif game.ReplicatedStorage.Content.GameMode.Value == "Freeze Tag"  then
										if GetChar:FindFirstChild("Role") and GetChar.Role.Value == "Bystander" then
											Events.FreezePlayerKnife:FireServer(GetChar)
										end
									else
										-- any other gamemode not specified
										Events.KnifeDamage:FireServer(GetHuman, 100)
									end
								elseif game.ReplicatedStorage.Content.GameInProgress.Value == false then
									Events.KnifeDamage:FireServer(GetHuman, 100)
									-- when a game is not occuring
								end
							end
							spawn(function()
								Events.KnifeWeaponFunction:FireServer("N/A", "DestroyKnife", "N/A", KnifeTracker)
							end)
							Knife:Destroy()
						end
					end
				end
			end
		end
	elseif KnifePower == "Laser Knife" then
		local Touched = false
		spawn(function()
			Events.KnifeWeaponFunction:FireServer("N/A", "CreateLaser", "N/A", KnifeTracker)
		end)
		local Knife = Tool.Handle:Clone()
		Knife.CanCollide = false
		Knife.Anchored = true
		Knife.CFrame = Tool.Handle.CFrame
		Knife.Name = "tKnife"..KnifeTracker
		Knife.Parent = workspace
		local NewRay = Ray.new(Knife.CFrame.p, (MousePos - Knife.CFrame.p).unit * 1000)
		local Hit, Pos = game.Workspace:FindPartOnRay(NewRay, Char, false, true)
		local Distance = (Pos - Knife.CFrame.p).magnitude
		if game.Players.LocalPlayer.Character == Char then
			Events.KnifeSound:FireServer(Sounds.Laser, Char.Torso, 0.5)
			Events.KnifeSound:FireServer(Sounds.LaserSoundEffects, Char.Torso, 0.3)
		end
		spawn(function()
			local P, K, D = Pos, Knife.CFrame.p, Distance
			Events.KnifeWeaponFunction:FireServer("N/A", "CreateLaserBeam", "N/A", KnifeTracker, P, K, D)
		end)
		local LaserPart = Instance.new("Part")
		LaserPart.Name = "Laser"..KnifeTracker
		LaserPart.CanQuery = false
		LaserPart.Anchored = true
		LaserPart.CanCollide = false
		LaserPart.Material = "Neon"
		LaserPart.Color = Color3.new(1, 0, 0)
		LaserPart.TopSurface = Enum.SurfaceType.Smooth
		LaserPart.BottomSurface = Enum.SurfaceType.Smooth
		LaserPart.Size = Vector3.new(0.2, 0.2, Distance)
		LaserPart.CFrame = CFrame.new(Pos, Knife.CFrame.p) * CFrame.new(0, 0, (-Distance/2) + 2)
		LaserPart.Parent = workspace
		spawn(function()
			local D, P, K = Distance, Pos, Knife.CFrame.p
			Events.KnifeWeaponFunction:FireServer("N/A", "AnimateLaser", "N/A", KnifeTracker, D, P, K)
		end)
		for i = 10000, Distance do
			Knife.CFrame = CFrame.new(Pos, Knife.CFrame.p) * CFrame.new(0,0,i-Distance) * CFrame.fromEulerAnglesXYZ(math.rad(90),math.rad(180),math.rad(360))
		end
		Knife.CFrame = CFrame.new(Pos, Knife.CFrame.p) * CFrame.new(0,0,0) * CFrame.fromEulerAnglesXYZ(math.rad(90),math.rad(180),math.rad(360))
		local TweenProperies = {
			Size = Vector3.new(0.02, 0.02, Distance);
			Transparency = 0.5
		}
		local FadeLaser = game.TweenService:Create(LaserPart, TweenInfo.new(0.1, Enum.EasingStyle.Linear, Enum.EasingDirection.In), TweenProperies)
		FadeLaser:Play()
		delay(0.11, function()
			LaserPart:Destroy()
		end)
		if Hit then
			if game.Players:GetPlayerFromCharacter(Hit.Parent) ~= nil or game.Players:GetPlayerFromCharacter(Hit.Parent.Parent) ~= nil then
				local CChar = nil 
				if Hit.Parent:FindFirstChild("Humanoid") and not Hit.Parent.Parent:FindFirstChild("Humanoid") then
					CChar = Hit.Parent
				elseif Hit.Parent:IsA("Accessory") and Hit.Parent.Parent:FindFirstChild("Humanoid") then
					CChar = Hit.Parent.Parent
				end
				if CChar ~= nil and CChar ~= Char then
					local GetTorso = CChar:FindFirstChild("Torso")
					local GetHuman = CChar:FindFirstChild("Humanoid")
					if GetTorso and GetHuman then
						Events.KnifeSound:FireServer(Sounds.ThrowHit, GetTorso, 0.5)
						if game.ReplicatedStorage.Content.GameInProgress.Value == true then
							if game.ReplicatedStorage.Content.GameMode.Value == "Wicked Murderer" then
								Events.KnifeDamage:FireServer(GetHuman, 100)
							elseif game.ReplicatedStorage.Content.GameMode.Value == "Freeze Tag"  then
								if CChar:FindFirstChild("Role") and CChar.Role.Value == "Bystander" then
									Events.FreezePlayerKnife:FireServer(CChar)
								end
							else
								-- any other gamemode not specified
								Events.KnifeDamage:FireServer(GetHuman, 100)
							end
						elseif game.ReplicatedStorage.Content.GameInProgress.Value == false then
							Events.KnifeDamage:FireServer(GetHuman, 100)
							-- when a game is not occuring
						end
						spawn(function()
							Events.KnifeWeaponFunction:FireServer("N/A", "DestroyKnife", "N/A", KnifeTracker)
						end)
						Knife:Destroy()
					end
				end
			else
				spawn(function()
					Events.KnifeWeaponFunction:FireServer("N/A", "SecondaryWallHit", "N/A", KnifeTracker)
				end)
				Knife.Anchored = true
				local Wallhit = Instance.new("Sound")
				Wallhit.Parent = Knife
				Wallhit.Volume = 0.5
				Wallhit.SoundId = "rbxassetid://"..Sounds.WallHit[math.random(1, 2)]
				Wallhit:Play()
				Wallhit.Changed:Connect(function()
					if Wallhit.IsPlaying == false then
						Wallhit:Destroy()
					end
				end)
				delay(10, function()
					Knife:Destroy()
				end)
			end
		end
	end	
	Throwing = false
end