Knockback difference between characters and npcs

Hello! I have a knockback system that uses ApplyImpulse() on HumanoidRootParts to apply the knockback. However, while knockback on npcs always remain the same and consistent, knockback on the player characters tend to vary and they usually take less knockback than the npcs. The impulse is applied on the npcs via a module used by the server, and the impulse is applied on the characters via a local script that is connected to the server through a remote event. I have set the same knockback power for both characters and npcs, and I have also use print() statements and both characters and npcs have the same mass.

Does the problem have something to do with ping? If not, then why is knockback taken by characters more inconsistent and less powerful than knockback taken by npcs?

Thanks for taking time to read :slight_smile:

Oh! If we look at Roblox Documentation, Roblox sets the NetworkOwnership of unanchored objects to the nearest player, because it follows a kind of distributed-physics system, where the physics computations are offloaded and divided between the server and clients.

So an example to say is that if you play your game, you can see you play as your own characterModel which is under the workspace. And when you walk around, it is quite responsive… But if we use SetNetworkOwnerShip method which works in a way as it is described here in the documentation. We can learn that if the ownership is set to nil so that it is only owned by the server at all times, then all the computations are done on the server-side and not any client for that model. So, if we playtest again after writing a server script that sets the NetworkOwnerShip of the player’s character to nil via a playerAdded event and characterAdded event, and if we walk around, it isn’t so responsive anymore because the whole movement and everything is done on the server and it is sent to you, whereas earlier the whole thing happened on client (your pc) side before your current state is told (sent) to the server so the server can replicate it to everyone else, in which, the NetworkOwnership is set to the player itself who’s controlling the character.

The latter is the ideal way because it clearly won’t be laggy, so roblox on default has it.

That’s exactly the reason why the knockback is a bit inconsistent on a real player if compared to an NPC (where the network ownership is set to the nearest player, in this case, you), because You don’t get the network ownership of real players as the network ownership is already set to themselves already and because of this it’s looking less responsive on your PC. I’m honestly not more knowledgeable than this, to explain the reason behind why the distance covered by the real player being knocked away is less than the NPC’s distance according to your post.

But to at least fix the inconsistencies, I have a suggestion for you. This might not be the best workaround for this; but you can temporarily set the NetworkOwnership of the humanoid root part of the player you are knocking, to the person who is currently using the knockback ability, and then set the NetworkOwnership back to what it was before.

An example of the flow of code that I described above, is this you see below:

-- Your knockback logic
-- Since this is just an example, I'm just showing you who the players would be directly with references like this at the moment:
local knockingPlayer = game.Players.Unimaginative_Games -- The player who is currently using the knockback ability.
local targetPlayer = game.Players.Bpandu -- The player who is being knocked back.
targetPlayer.Character.HumanoidRootPart:SetNetworkOwner(knockingPlayer)
-- // (Your knockback code runs here... like, targetPlayer.Character.HumanoidRootPart:ApplyImpulse() and etc.)
-- // After the whole knockback is over, you set back the ownership of targetPlayer back to themselves like this:
targetPlayer.Character.HumanoidRootPart:SetNetworkOwner(targetPlayer)

Now I think this would make it appear more responsive on the player’s computer who is using the knockback ability, in the same way as it is consistent for the NPCs.

But, during that time window when the knockingPlayer is given the NetworkOwnership of the targetPlayer, if they’re an exploiter they could move the targetPlayer anywhere, this is the downside to this approach, and there may be other issues to this too, but you may have an antiexploit that works for your own game-system to prevent those other issues…

You may even experiment with this further and confirm for yourself about what’s the best. I couldn’t recall if the SetNetworkOwner function works on assemblies (models) too if called on them directly like this:
targetPlayer.Character:SetNetworkOwnerShip(knockingPlayer)
and then, back to being normal like this:
targetPlayer.Character:SetNetworkOwnerShip(targetPlayer)

I don’t know if this would work, that’s why I wrote the example above with only considering the HumanoidRootPart’s network ownership, but don’t be afraid to experiment with different ways yourself! And I hope this was helpful, have a great day!

2 Likes