I am writing a combat system and am having an issue with the melee weapon hitboxes (though this also applies to ranged weapons as well). There is a discrepancy between the server’s CFrame and the client’s CFrame. The green part is spawned locally using the client’s CFrame while the red one is spawned on the server through a RemoteEvent. I would’ve assumed that by the time the RemoteEvent reached the server, the server’s character CFrame would’ve matched up the location of where it was when the client clicked, however there is a bit of an offset.
The offset does not seem to vary with latency. Here are two videos with a higher player speed. The first is with 40ms latency (0 incoming replication lag) the second is with 850ms latency (0.4 incoming replication lag. The offset is just about the same in each.
So I am wondering what I could do to remedy this. The easiest solution would be to just send the client’s aim CFrame with the fire remote and use that with some magnitude checks, but that still seems pretty exploitable (can use it to place the aim CFrame through walls, etc). I was wondering if anyone has experience writing secure, fast paced combat system and would be able to offer some advice?
Here is the place file with two simple test scripts:
HitboxTesting.rbxl (21.8 KB)
The scripts are also pasted identical below
Client Code (in StarterCharacterScripts)
local UserInputService = game:GetService("UserInputService")
local HitboxRemote = ReplicatedStorage:WaitForChild("HitboxRemote")
local testPart = ReplicatedStorage:WaitForChild("TestPart")
local Parent = script.Parent
local Player = game.Players:GetPlayerFromCharacter(Parent);
local Character = Player.Character or Player.CharacterAdded:Wait()
UserInputService.InputBegan:Connect(function(input, gameProcessed) --spawn a "slash" on the client representing an attack hitbox
if input.UserInputType == Enum.UserInputType.MouseButton1 then
local frame = Character.HumanoidRootPart.CFrame
local part = testPart:Clone()
part.Parent = game.Workspace
part.Color = Color3.new(0, 1, 0)
part.CFrame = frame
HitboxRemote:FireServer()
wait(1)
part:Destroy()
end
end)
Server Code (in ServerScriptService)
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local HitboxRemote = Instance.new("RemoteEvent")
HitboxRemote.Name = "HitboxRemote"
HitboxRemote.Parent = ReplicatedStorage
local testPart = Instance.new("Part")
testPart.Anchored = true
testPart.CanCollide = false
testPart.Name = "TestPart"
testPart.Size = Vector3.new(1,1,5)
testPart.Parent = ReplicatedStorage
HitboxRemote.OnServerEvent:Connect(function(Player) --spawn a "slash" on the server representing an attack hitbox
local Character = Player.Character
local frame = Character.HumanoidRootPart.CFrame
local part = testPart:Clone()
part.Color = Color3.new(1, 0, 0)
part.Parent = game.Workspace
part.CFrame = frame
wait(1)
part:Destroy()
end)