Trouble with client and server in a combat game

My question is what elements of a combat system should be done on the server and what should be done on the client?

I want hit boxes, hitstun, knockback, and other elements that would go in a fighting game. I just dont know how those are commonly implemented.

Hello I have made my own complex combat system so I’ll just tell you what I did. I handled almost everything server side including animations with a base Entity class. The dodge roll was handled client side but that’s because the roll logic uses run service. For hitboxes I used raycast hitbox v4. For knockback I used runservice (for players) and heartbeat (for NPCs). As I mentioned I used a base entity class that all players and enemy NPC’s use. This class has methods like Damage(), Block(), IsDodging() etc etc. Hope this helps.

2 Likes

Thank you that helped. So the base Entity class is something you made? Also what do you mean by using runservice for roll logic?

Yea so you can make classes in lua like this (in a module script):

local Entity = {}
Entity.__index = Entity

function Entity.new(name)
	local self = setmetatable({}, Entity)

	return self
end

return Entity

Im not sure how familiar you are with OOP or classes but it’s very useful for stuff like this.For the roll logic, I didn’t write the code but it uses RenderStepped to change your AssemblyLinearVelocity during the roll.

function OnRenderStepped()
	local DashSpeed = EaseQuarticIn(_DashSpeed, 0, math.min(tick() - LastDash, _DashDuration), _DashDuration) 

	local DashVelocity = LastMDirection * DashSpeed

	local Velocity = Root.AssemblyLinearVelocity

	Root.AssemblyLinearVelocity = DashSpeed > 0 and Vector3.new(DashVelocity.X, Velocity.Y, DashVelocity.Z) or Velocity
end

1 Like

In most of my games, I do something like this:

Client Input → Server Attack → Client Hitbox → Server Damage

Now for hitstun and interrurption, proxies are the best option. newproxy() generates an empty but unique value that can be used to see if something has changed. To demonstrate, here’s a stun function with and without proxies.

function BeStunned(Time)
	InStun = true
	task.wait(Time)
	InStun = false
--//If this function is run again before it has ended, it will un-stun the player twice, and earlier than intended.
end
StunProxy = newproxy()
function BeStunned(Time)
	LProxy = newproxy()
	StunProxy  = LProxy

	InStun = true
	task.wait(Time)

	if LProxy == StunProxy then --//If the function has not been run again, then we can continue.
		InStun = false
	end
end
1 Like

Thank you, i didnt know about proxies