It’s been a real long while since I was here, but I’m back with good reason (and needing help), this latest issue of mine has left me frustrated, drained, and stumped.
I’m working on implementing my own custom hitbox system for a side project of mine, it’s currently in a very rough state, but it should theoretically work…which it does, but it has this not-so-small issue that I’ll talk about further down this post.
It’s implemented like this:
- Once the player left clicks, a function starts running and a event is fired, the server starts its own function related to the player’s left click.
- As both functions runs nearly in sync, the server opens a temporary connection that varies on the player’s ping, through another event. It automatically disconnects once its time is up.
- The player handles the hitbox on the client, getting all enemies that were caught in it and sending it to the server to that same event.
- If the server receives the information in time, then it does a sanity check (not implemented) to see which enemies are vaild, and whatever the connected function was (usually damaging them).
Alternatively if the server does not receive the information in time, then it does the hitbox itself and handles whatever the connected function was supposed to do (usually damaging them again).
In short, this lets the player handle the hitboxes, but the server usurps that from them whenever they get too laggy.
Some additional notes:
- All events are under ReplicatedStorage, as it’s shared between all players.
- No new events are created.
With my base of my hitbox system completed, I wanted to try see if the temporary connection works…it does, but for whatever god forsaken reason, the it the previous “fire” gets sent instead of the current one. After some testing and experimenting, turns out it the previous “fire” is queued and gets sent to the server instead whenever it reconnects to the event, causing issues. I genuinely have no idea how to work around this.
Relevant client code snippet:
function class:M1Button()
parentClass.M1Button(self)
self.Animations.Attack:Play(0.3333)
wait(0.5833)
delay(0.25, function()
HitEvent:FireServer(HitboxCreator:GetEnemiesInBox(self.Character.HumanoidRootPart.CFrame:ToWorldSpace(CFrame.new(Vector3.new(0, 0, -5))), Vector3.new(4,5,6), Params, 3, Color3.new(0,1,0)))
end)
wait(0.1167)
self.Animations.Attack:AdjustWeight(0, 0.1333)
end
Relevant server code snippet:
function class:M1Button()
wait(0.5833 - self.root.Ping/2)
local Success = false
local Connection = HitEvent.OnServerEvent:Connect(function(Player, CaughtEnemies)
if #CaughtEnemies == 0 then return end
for _, Enemy in CaughtEnemies do
--print("damage done from the cilent")
Enemy.Humanoid.Health -= 20
Enemy.Head.Color = Color3.new(0,1,0)
end
Success = true
end)
wait(self.root.Ping)
Connection:Disconnect()
if not Success then
local rootcframe : CFrame = self.Character.HumanoidRootPart.CFrame
local CaughtEnemies = HitboxCreator:GetEnemiesInBox(rootcframe:ToWorldSpace(CFrame.new(Vector3.new(0, 0, -5))), Vector3.new(4,5,6), Params, 3)
for _, Enemy in CaughtEnemies do
--print("damage done from the server")
Enemy.Humanoid.Health -= 20
Enemy.Head.Color = Color3.new(1,0,0)
end
end
end
It’s important that my way of implementing the system should (roughly) remain the same, as I feel like it’s the only way than I could create fair hitboxes (and also because I’m going to reuse it for important project of mine, so I can’t really change much how its implemented).
Or perhaps am I being too stubborn with wanting it remain roughly the same, and there’s a easier alternative solution to this?