I have a combat system in Roblox inspired by TSB, However I’m struggling with network ownership issues, particularly when combining knockback with ragdoll. Here’s the problem:
Knockback (short pushes with each punch using linear velocity) and ragdoll require transferring the enemy’s network ownership to the attacking player to work correctly.
For Ragdolling, I apply the network ownership of the enemy’s torso to the attacking player right before the final punch. This works fine because the ownership naturally returns to normal when the enemy gets up most likely because of humanoid state.
However, for knockback on regular punches, I face a dilemma:
If I apply network ownership before each punch and unapply it after, The ragdoll stops working because the ragdoll is initiated after the last punch in a combo.
If I don’t unapply network ownership, The enemy’s character would not function properly because of network ownership…
I need a way to temporarily apply network ownership for each knockback and also the ragdoll and then unapply it after.
In essence, I’m looking for a method to apply network ownership before each knockback (including ragdoll initiation), execute the knockback/ragdoll effects and then unapply the network ownership immediately after - all while ensuring that these operations don’t interfere with each other.
(local script combat client):
local function executePunchSequence(isPunchHold)
if currentPunchPosition >= 5 then
currentPunchPosition = 1
return
end
-- Set up animation and markers
currentTrack = punchAnimationTracks[currentPunchPosition]
local markerConnections = {}
currentTrack:Play() -- this is just the punch animation
-- Set up hitbox
task.spawn(function()
hitboxSet()
hitboxDeploy()
end)
-- Handle hit detection
task.spawn(function()
hitDetection(function(hitPlayers)
for enemyCharacter, _ in hitPlayers do -- for every player hit
if not enemyCharacter then continue end
hitPlayer = true
-- Handle blocking
if handleBlocking(enemyCharacter) then
return -- Stop further logic if enemy blocking
else
-- Handle ragdoll
task.spawn(function()
if currentPunchPosition and currentPunchPosition >= 4 then
if not enemyCharacter then return end
isLastHit = true
print("changing humanoidstate into ragdoll")
ragdoll(enemyCharacter, enemyHumanoid)
end
end)
-- Set up animation markers
if enemyTorso and differenceDirection then
table.insert(markerConnections, currentTrack:GetMarkerReachedSignal("prepunch"):Connect(function() -- this doesn't matter
print("prepunch is reached")
hitKnockback(torso, differenceDirection, true) -- push for player
end))
table.insert(markerConnections, currentTrack:GetMarkerReachedSignal("punch"):Connect(function()
print("punch is reached")
-- Check blocking again at the moment of impact
applyNetworkRemote:InvokeServer(enemyPlayer, enemyTorso)
hitKnockback(enemyTorso, differenceDirection, false, isLastHit) -- pushes the enemy and isLastHit checks if LastHit is true, if it is, isLastHit becomes true and sends to the function for a strong knockback.
--unapplyNetworkRemote:InvokeServer(enemyPlayer, enemyTorso) -- here is the unapply network ownership i have no idea how to use
end))
end
end
end
end)
end)
currentTrack.Stopped:Wait()-- dont mind all this, just for performance
for _, connection in ipairs(markerConnections) do
connection:Disconnect()
end
currentPunchPosition += 1
hitPlayer = false
end
Video:
In the video you can see that when the player punches the enemy once without ragdolling the enemy’s network ownership for the player stays without getting removed, But when the ragdoll happens, The network ownership returns.
Note: I use the client for the knockback and ragdoll for performance benefits.
i just set the enemy’s torso network ownership to the player and then to himself using remote functions:
local function applyNetwork(player, enemyPlayer, enemyTorso)
local character = player.Character
local torso = character:FindFirstChild("Torso")
if enemyTorso and torso then
enemyTorso:SetNetworkOwner(player)
end
return
end
applyNetworkRemote.OnServerInvoke = applyNetwork -- connect the remote with function
local function revertNetwork(player, enemyPlayer, enemyTorso)
if enemyTorso and enemyPlayer then
enemyTorso:SetNetworkOwner(enemyPlayer)
end
return
end
unapplyNetworkRemote.OnServerInvoke = revertNetwork -- connect the remote with function
When the enemy ragdolls and then gets up it naturally returns the network ownership, the problem is that i need to set the enemy’s network ownership to the player before the knockback and remove it after, the last hit(ragdoll) also requires to set the network ownership but i don’t know why the network ownership is removed before the ragdoll happens
Why not just add an if statement to check if they’re ragdolled then?
On another note: You shouldn’t be dealing knockback from a client script because of how unsafe it is (unless I am misinterpreting the script?) and also having remotes that set the character’s network ownership, because of how any exploiter could just use it to pretty much break the game.
I’d suggest having some sort of server middleman script that does that for the client instead of giving it the total power to ‘possess’ other players.
Normally, if you want smooth knockback, you’d send a client event to the player who is being knocked back to inflict the knockback on themselves rather.
EDIT: Dealing knockback on the client isn’t thaaaat much of a bad idea, but you should still consider having a serverscript register the hits and then apply the network ownership rather than the client doing it by themselves.
What i want exactly is to check if the hit is not the last hit which ragdolls and unapply/unset the network ownership for after each hit, But the problem is that if i unapply it immediately or delay it the enemy returns to where he was from when the network ownership was applied.
i have 2 questions regarding the stuff you talked about earlier:
Can’t a hacker exploit the remote event sent to the middle man script itself?
A local script runs on each client, So what do you mean by sending a client event to the enemy client to execute knockback or ragdoll on himself?
i will say, in TSB network ownership isn’t given on punches, and i don’t believe in ragdoll either. you can tell this because you can punch a person as they dash, and the knockback doesn’t happen until after they finish their dash (which the dash is client sided). then they get stunned a few seconds after which allows for them to annoying escape combos. the reason i don’t believe networkownership is changed on ragdoll is because a lot of the mechanics rely on raycasting to determine the player’s condition (ragdolled in air, landed, knockedback, etc).
networkownership only really changes on grabbing moves as you still can maneuver your character even when another player is welded to you.
I understand that TSB doesn’t rely on network ownership, But in this case the knockback and ragdoll I’m using don’t work without it on the client, And I’m still trying to figure it out.
How does TSB handle this? Is there a way to handle knockback and ragdoll on the client without network ownership?
ragdolls kind of have to be on the client partly as humanoidstates will be set, and setting humanoidstates have to be done on the client.
im not certain what type of body movers they use for knockback. most likely linearvelocity or bodyvelocity as it locks you into that velocity whilst its active.
for ragdoll, i assume they have a value on the client or they fire an event that tells the client to set their humanoidstate to ragdoll while creating joints for the ragdoll rig on the server.
I’m doing exactly this, but the knockback and ragdoll don’t work without transferring the enemy’s network ownership to the player attacking and then transferring it back to him after, the problem is when I transfer it back it just returns the player to where he was before transferring the network ownership.
there are a couple of issues with the method you’re describing to me
if you give ownership to another player for a short time then return it, it may be that the player controlling the other player cannot replicate the position fast enough for the other player to see it. this is why they return to their original position when you return networkownership
constantly swapping networkownership for every punch will cause overlap if multiple people are m1’ing a person causing extremely bad physics calculations on the attacked player
if you constantly swap networkownership there may be an issue regaining ownership of your character causing very delayed inputs.
i get what you’re attempting to do but i do not think it is a very efficient way to go about making a knockback system, roblox has many bodymovers and velocity functions at your disposal to make a knockback system without issues.
neither of them should require a networkownership change. there will always be a delay in velocity to act upon a character because of the replication system.
Transfer network ownership temporarily for the knockback and ragdoll.
Use server-side logic to apply and remove network ownership safely without conflicting with the ragdoll process (which naturally returns the ownership once the player gets up).
Manage timing such that ownership is only briefly transferred for the necessary physics operations and is immediately removed after the effect is applied.
Client Script:
-- Client-side combat system (part of your punch logic)
local function executePunchSequence(isPunchHold)
if currentPunchPosition >= 5 then
currentPunchPosition = 1
return
end
-- Set up animation and markers
currentTrack = punchAnimationTracks[currentPunchPosition]
local markerConnections = {}
currentTrack:Play() -- this is just the punch animation
-- Set up hitbox
task.spawn(function()
hitboxSet()
hitboxDeploy()
end)
-- Handle hit detection
task.spawn(function()
hitDetection(function(hitPlayers)
for enemyCharacter, _ in hitPlayers do -- for every player hit
if not enemyCharacter then continue end
hitPlayer = true
-- Handle blocking
if handleBlocking(enemyCharacter) then
return -- Stop further logic if enemy blocking
else
-- Handle ragdoll (for the last hit)
task.spawn(function()
if currentPunchPosition and currentPunchPosition >= 4 then
if not enemyCharacter then return end
isLastHit = true
print("changing humanoidstate into ragdoll")
ragdoll(enemyCharacter, enemyHumanoid)
end
end)
-- Set up animation markers
if enemyTorso and differenceDirection then
table.insert(markerConnections, currentTrack:GetMarkerReachedSignal("prepunch"):Connect(function()
print("prepunch is reached")
hitKnockback(torso, differenceDirection, true) -- Push the player
end))
table.insert(markerConnections, currentTrack:GetMarkerReachedSignal("punch"):Connect(function()
print("punch is reached")
-- Apply network ownership before knockback
applyNetworkRemote:InvokeServer(enemyPlayer, enemyTorso)
-- Execute knockback and check if it's the last hit
hitKnockback(enemyTorso, differenceDirection, false, isLastHit)
-- Wait for the knockback duration, then unapply network ownership
task.wait(0.2) -- Adjust timing to match the knockback effect duration
unapplyNetworkRemote:InvokeServer(enemyPlayer, enemyTorso)
end))
end
end
end
end)
end)
currentTrack.Stopped:Wait() -- Wait until the punch animation ends
for _, connection in ipairs(markerConnections) do
connection:Disconnect()
end
currentPunchPosition += 1
hitPlayer = false
end
Server Script:
-- Apply network ownership to the attacking player
local function applyNetwork(player, enemyPlayer, enemyTorso)
local character = player.Character
local torso = character:FindFirstChild("Torso")
if enemyTorso and torso then
enemyTorso:SetNetworkOwner(player)
end
return
end
applyNetworkRemote.OnServerInvoke = applyNetwork -- Connect the remote to the function
-- Revert network ownership to the enemy player
local function revertNetwork(player, enemyPlayer, enemyTorso)
if enemyTorso and enemyPlayer then
enemyTorso:SetNetworkOwner(enemyPlayer)
end
return
end
unapplyNetworkRemote.OnServerInvoke = revertNetwork -- Connect the remote to the function