Custom Enemies and Hit Detection

Sorry, English isn’t my first language, so please feel free to ask for clarification. I have a game where I rely on creating custom enemies which are moved with cframe server-side. They are indicated by only a brick:

And the client builds the rest of the enemy on their side

And basically on the server, I would send a remote event to the clients indicating which enemy on the map is doing animations depending on what state they are in (running, idle, jumping, etc) and works well enough. Though, I have a problem with this kind of system. Since the client’s are handling the created enemy’s animations, I am unable to use KeyframeReached on an attack animation on the server-side to indicate when a keyframe should “damage” the player.

My question is, would it be safe to handle enemy hit detection to the player done on the client? I feel it is very unsafe so I have come to you guys for suggestions on what I should do with the system I have. I have read somewhere that a game like Dark Souls uses some sort of hybrid-client side hit detections too even in online modes but that made it very vulnerable to exploits. I have tried manually timing on the server-side but it felt desync’d and not satisfying and ultimately harder for the player to react since the animation shown on screen was different than when the damage was dealt.

3 Likes

Wait for KeyframeReached on the client, then fire a remote event and tell the server that the player should take damage.

Thanks, I was thinking of doing that originally. However, I know absolutely nothing about exploiters in games and all my knowledge for filtering was from hours upon hours of reading on how to do it but I never read anything that tells what an exploiter can do. Sorry if it sounds stupid, but if I did it like that, will an exploiter be able to somehow negate that remote event (if that makes sense) to make him/herself somehow god mode because the remote event never fired?

As long as you don’t name it something super obvious, like DamageEvent, then no. Unless they manage to delete the whole entire script, they can’t negate the event either. All they should be able to do is fire the event to damage themself.

3 Likes

Thank you for the help. I will try it

No problem, happy to help.

The posts above assume that exploiters fail to bypass the most basic of obfuscation, which is a bit of a naive assumption.

Exploiters don’t care about the names of remotes. Obfuscating names of remotes is just security through obscurity, which isn’t real security. They will just see which remotes are being fired when, and then they’ll be able to determine the remote that’s giving them damage, regardless of name. They could then hook into the remote (they already do this) to see what is being passed / change the contents / make the remote event drop entirely.

My advice would be that you should do damage checking fully server-side if possible.

4 Likes

Hold on - there is an alternative. I’ve just been working on something very similar yesterday, and I found there’s a function of AnimationTracks called :GetTimeOfKeyframe(). You can use this to determine how long to wait before detecting when the enemy attacks and most importantly, you can do it all server-side. I was going to do the method described to you before, but if you want better security I’d recommend trying this, unless you see something wrong with it.

For myself, I don’t have the players detect hitting. I just have a hitbox on the server side and the detect all parts within it when the animation should “hit” there. This creates pretty much the same effect, but it’s more secure because we aren’t relying on the players to tell the server if they should get damaged or not.

12 Likes

For some reason, when I try to use that function, I get

And if I disable and then re-enable it the script, it finds it? I am using the line below to test.

script.AnimationController:LoadAnimation(Anim):GetTimeOfKeyframe(Keyframe)

This is in a script located inside ServerScriptService.

It’s quite annoying - there’s a time you need to wait for it to load before you can actually use it. Do wait(1) and it should work, but there’s probably an easier way to see if it’s loaded.

3 Likes

I see. Thank you too for your help, works well.

Misread previous post, please ignore this - I did post another answer, though.

Hate to revive a dead post, but I don’t know if this is the best practice now. Players have full network ownership of their characters anyway, and it’d make more sense to check for targets hit on the client instead of the server, for instant feedback (no lag because of ping). The same sanity checks can be done on the server, but overall it’s probably a good idea to utilise what the client already has available.

I’ve seen a lot of games that do all of this on the server and it often feels just a little bit off, sometimes can be pretty clunky if the client relies on server feedback a lot. Just thought I’d add to this with new experience!

2 Likes

I assume that OP has moved on from this method and instead opted to start a hitbox cast along with sending the animation to be played, wrt raycast hitbox resource.

Personally I’m still interested in this whole concept of handling NPCs on the client while representing them as a single part on the server because that is a very good optimisation but difficult in my experience to manage. I’m not quite able to get a grip on the thread nor the replies and what they suggest.

One thing I do know is that the whole wait thing is definitely not the best practice. In an ideal environment you want anything to do with animations to rely on the AnimationTrack API with out any uses of wait. I’m not too sure how you’d interface GetTimeOfKeyframe via the server when the client is playing the animations, either.

4 Likes

It’s great to hear your new experiences no matter how old, so I thank you for putting out an update.

Coincidentally enough, I am still looking for better ways to deal damage to the players with this same format. Your suggestion with :GetTimeOfKeyframe served its purpose for the time but it became very restrictive (and only really worked with one attack move) and like you said, there is always a little delay because it required loading the animation. I wouldn’t mind reviving this topic for the sake of innovating some new methods.

When you say network ownership of their characters, do you mean networking owning the players or the enemies? I do hit detection on both client and server, so clients can see the feedback while the server can have its own thing going on.

1 Like

Oops. I misread the post, got caught up in correcting myself lol
The update I posted is only relevant for players attacking enemies/other players. It isn’t really relevant for enemies damaging players. Network ownership shouldn’t matter here, since enemies should only be owned by the server anyway.

But true, waiting on the server is probably not a great idea in that regard, but I’ve thought that a new potential solution could be trying to determine the damage taken on the client when the animation keyframe hits, and then have the server send the real data over in case the values are any different (in which case the client can update the visuals such as health bar or anything else).

This means you’d tell the client to play the animation, and you’d wait on the server for that timing in the animation, at which point you’d send data again to the client, telling them all of the new values or how much damage was taken, all of that.

Also, wouldn’t you only have to load the animation once when the game loads anyway, and save the timing of it somewhere?

3 Likes