How to translate positions between client and server?

I’ve heard that people apply knockback (vectorforce or applyimpulse) to a player on a localscript and then translate that to the server, because the client-server lag makes it delayed otherwise. Could I get an example of how I would do that?

Many thanks.

2 Likes

Hi there, in this case we’ll be using RemotEvents. From the client you’d send over a request to apply a knock-back using the FireServer function and the server receives that request and then sends that same request to all clients using FireAllClients, therefore allowing every player to see the effect locally, preventing the server from doing those physics calculations. If you need any more help, I’d be pleased to assist you. Enjoy.

3 Likes

Ok, I’m a little confused here. So I FireServer from the client, which causes an OnServerEvent where I create an Instance.new for BodyVelocity. You are saying that then I must FireAllClients and put the exact same code for the BodyVelocity into that OnClientEvent? I feel like that would not get rid of the client-server lag. Does it work for you?

1 Like

You don’t calculate or create anything on the server, but just send all the data to client and each individual client does it or just send it to the one client that needs it so their client does all physics calculations etc etc, it also isn’t expensive to do so and much more preferred than doing it all on the server. It would also reduce client-server lag if you used this for most if not all methods of effects and body movers.

1 Like

How do I “send the data”? (----empty space----)

Ok, I think I kinda understood what you said. So I used a FireServer to create an OnServerEvent, than within that OnServerEvent I put a FireAllClients, and within that OnClientEvent I put the “applyimpulse”. It still does not really work.
This is basically my code:

for i, v in pairs(workspace:GetPartsInPart(x)) do --In a localscript in StarterPlayer
						if v.Parent:FindFirstChild("Humanoid") and v.Parent ~= Character and v.Parent:FindFirstChild("Hit"..Player.Name) == nil then
							am:FireServer(v)
							local knockbackanimation = Instance.new('Animation')
							knockbackanimation.AnimationId = 'rbxassetid://14293116966'
							local playkbanim = v.Parent.Humanoid:LoadAnimation(knockbackanimation)
							damageevent1:FireServer(v)
						end
					end
damageevent1.OnServerEvent:Connect(function(player, v) --In a script in ServerScriptService
	kbe1:FireAllClients(v)
end)
kbe1.OnClientEvent:Connect(function(v) --In the same localscript as before
	local back = Character.HumanoidRootPart.CFrame.LookVector * 5000
	v.Parent:WaitForChild("HumanoidRootPart"):ApplyImpulse(back)
end)

Am I doing something wrong?

I believe the fact that the humanoid need to have Platform Standing on is the reason its not working. If you put a print statement in the on client event, then you’re receiving everything alright. I’ve always had issues with Impulses, usually setting the humanoid’s PlatformStand property to on fixes it, or just setting the HumanoidRootParts AssemblyLinearVelocity also works as a sort of impulse, which still requires the aforementioned fix.

In Roblox, positions can be represented in two main spaces: the client-side (local) and the server-side (world) space. It’s important to understand how to translate positions between these two spaces correctly to maintain consistency in your game. Here’s how you can do it:

  1. Client to Server (Local to World): When you want to send a position from the client to the server, you need to convert the client-side position into a server-side position. This is important for server-side calculations or interactions that require accurate positioning.

luaCopy code

-- Client-side code
local localPosition = Vector3.new(10, 5, 0)
local worldPosition = game.Workspace.CurrentCamera:ViewportToWorldPoint(localPosition)

-- Send the worldPosition to the server using remote events or functions
  1. Server to Client (World to Local): When you want to send a position from the server to the client, you need to convert the server-side position into a client-side position so it’s properly displayed to the player.

luaCopy code

-- Server-side code
local worldPosition = Vector3.new(20, 5, 0)
local player = game.Players:GetPlayerFromCharacter(character) -- Get the player
local localPosition = player:WaitForChild("PlayerGui").ScreenGui.Adornee:WorldToViewportPoint(worldPosition)

-- Send the localPosition to the client using remote events or functions

Remember that these conversions rely on the camera’s viewport. Make sure you have a valid camera and that it’s set up properly. Also, for networking between client and server, use RemoteEvents or RemoteFunctions to send and receive data securely.

Here’s a simplified example of how you might use RemoteEvents for client-server communication involving position translation:

luaCopy code

-- Client-side code
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = ReplicatedStorage:WaitForChild("PositionUpdateEvent")

local localPosition = Vector3.new(10, 5, 0)
remoteEvent:FireServer(localPosition)

-- Server-side code
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local remoteEvent = Instance.new("RemoteEvent")
remoteEvent.Name = "PositionUpdateEvent"
remoteEvent.Parent = ReplicatedStorage

remoteEvent.OnServerEvent:Connect(function(player, localPosition)
    local worldPosition = game.Workspace.CurrentCamera:ViewportToWorldPoint(localPosition)
    -- Use worldPosition for server-side calculations or interactions
end)

Keep in mind that this is a simplified example. In a real game, you should handle error checking, player authentication, and more.

So I enabled PlatformStand for the dummies and it still didn’t work. This is the issue:
https://streamable.com/hdgh0n
As you can see, there’s a weird stopping point that is held for about one second before the dummy is pushed back. And, if you noticed, for some reason there is a weird effect where the dummy is continuously pushed backwards the closer I get to it, although this is fairly rare and only happens once.

Any ideas?

Thank you very much for your comment, but I am too daft to understand most of it. I don’t think I would get it even if you explained it me caveman style. Thank you, though.

Thank CHATGPT not me :wink:
(30char)

Damn. ;( (-----i am sad------)

Better than the devforum ig :man_shrugging:
(thrirthychars)

I’m not too sure, this is a rare issue, I believe I had it once, however I do not remember the fix. If you haven’t already, try changing the MaxVelocity (If you’re using BodyVelocity) to Vector3.new(0,0,0) after an arbitrary amount of time once the knockback has been applied. I also think its a good idea to turn platform stand off as soon as the knockback is finished to prevent any other knockbacks from taking place.

I don’t know exactly how you’re using the system I mentioned, however, I think instead of firing to all clients, you should only fire to the specified client that needs to be moved, since all local movement will translate to server side movement. So again, try using Remote:FireClient(Player,Data), Data being whatever information you’re sending. If you’re still having issues, send over the code or a place file even and we’ll try to get it sorted.

Well, as is in the code, I’m using ApplyImpulse, not BodyVelocity. Also, how would I go about Firing the “v” client? Unless I can do "Instance.new(“LocalScript”, v.Parent) and also edit the script, it just seems impossible.

I don’t know what you quite mean. However, you can just as easily get the player using:

Players:GetPlayerFromCharacter(v)

and proceed to send that player to the server, which in turn then sends the data to that specific player. To make it more efficient you can send a table of players to the server if it might happen to multiple players, and then loop through the players on the server and send to each client too, using the above method.

Alright, I’m gonna be honest. I feel like just tweening the target is alot easier than having to do all this crap, and it’s honestly not terrible. The only problem with it is that the target goes through walls. I’ve come up with 2 solutions to this:

  1. Fire out a hitbox that senses for any walls within the knockback distance. If there is, the Vector3 in the tween changes accordingly.

  2. If a player touches a wall while being tweened, fire an event that stops them from moving.

Idk how to make either work. Any ideas? This is my code (with a few edits for simplicity):

local TS = game:GetService("TweenService")
local Info = TweenInfo.new(0.5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, 0, false, 0)
local back = player.Character.HumanoidRootPart.CFrame.LookVector * 50

damageevent1.OnServerEvent:Connect(function(player, v)
    TS:Create(v.Parent:WaitForChild("HumanoidRootPart"), Info, {Position = v.Parent:WaitForChild("HumanoidRootPart").Position + back}):Play()
    v.Parent:WaitForChild("HumanoidRootPart").Orientation = player.Character.HumanoidRootPart.Orientation - Vector3.new(0,180,0)
end)

Once again, it works fine, but I just want the player to stop moving when they hit a wall.

Id honestly do a raycast on the client first, so get your direction you want to go in, and the initial position, which is the targets position. Just do a simple raycast in that direction and if there’s a part there then just send over the RaycastResult.Position to the server and tween accordingly.

1 Like

I did what you said and it works, but how would I differentiate a wall and a player? I wouldn’t want the target to stop moving due to a player.

Just check if the part’s parent has a humanoid.