Weird behaviour when giving victim's client network ownership to attacker's client

Hi there,
The Roblox developer forum is my final resort to get this issue hopefully fixed. I have been heavily struggling with a way to have an attacker grab a victim and jump up in the sky with this person, then smash it down. Everything in this sequence is done properly; except handling desyncs.

I have tried everything, from having the server manage the ownerships of both attacker and victim and rendering any velocities on the server, having the client manage all velocities and grab and hold renderstepped cframes…

My current combat system is as follows;

  1. Attacker initiates attack
  2. Server validates cooldown
  3. Server plays attack
  4. A timing table that is triggered with animation KeyFrames is activated (on the server)
  5. The rest should be self explanatory. Any constraints will be applied on the clients.

https://gyazo.com/6acc9317789fc4286815e088fda9d18d
Here is a great showcase of what is happening.
Note that the network ownership of the victim is properly given to the attacker as you can see in the video

Below is some code which is ran on the attacker’s client and fired from the server.

CombatPackets.lockVictim.listen(function(data)
	local victim: Model = if data.target_flag == 0 then players:FindFirstChild(data.target).Character else workspace:FindFirstChild(data.target)
	if not victim then return end
	
	local hrp: Part = victim.HumanoidRootPart
	local lock_to: Part = localPlayer.Character:FindFirstChild(data.origin, true)
	
	local c = runservice.RenderStepped:Connect(function(dt)
		hrp.CFrame = lock_to.CFrame * data.offset
	end)
    -- some code here to manage closing the renderstepped connection. Dont worry about it.
end)

Below is some modularized code that is ran as part of the timing table;

Constraints.setOwnershipOfChar(victim_character, attacker)
ByteNetClientWrapper.lockVictim(
	attacker,
	victim_character.Name,
	0,
	CFrame.new(0, 0, -2.5) * CFrame.Angles(math.rad(90), 0, 0),
	"Left Arm"
)
ByteNetClientWrapper.spawnVelocity(
	attacker,
	"Knockback",
	Vector3.new(0, 1, 0),
	50,
	.5
	
)

This is a bit of a complex topic. Thank you in advanced for taking the time to read this and potentially come up with a solution for this problem.

TLDR

I am trying to find a way to be able to work with rapid linear velocities without this crazy desync. I would like to have explained WHY this desync even occurs when the attacker has network ownership over the victim the whole time!

Hm, quite the interesting problem.
Have you tried rendering a “fake” victim in this scenario? If you create a fake character, and basically weld it / somehow link it to the attacker’s character, and then make the real victim’s character invisible and disable their inputs, you could probably pull this effect off.

Roblox assigns clients full network ownership of their characters, and you as a developer cannot really influence that (unless you make a custom character system). Your best bet here would just be a fake rig to represent their character.

Hey, thanks for the provided suggestion. I talked however with the Fruits Battlegrounds developer and he told me that he does all CFrame manipulation and constraints on the client. WIthout creating a fake character.

I am very open to try your solution, but it would require me to rewrite a major part of my framework which Id rather prevent as long as I can haha

It seems like that the victim will KEEP control over their character like you mentioned, even if I give full network ownership to the attacker.