Train moving on Server with CFrame Lagging

At default, its nil…

It’s not nil by default… nil means the part’s owner is the server; otherwise, it is dynamically set to the closest player by default. Using :SetNetworkOwner disables the dynamic ownership.

1 Like

Every part in workspace is owned by server

As said in the Network Ownership Article:

When a Roblox game runs, several computers/devices are involved. To divide the work of calculating physics, Roblox automatically assigns parts to either the server or to a client. In general, if a part is near an in-game character, its physics will be calculated by that player’s device; otherwise it will be calculated by the server. In either case, the server or client that calculates a part’s physics is called its owner.

2 Likes

The client owns the part, which means that they own its physics. In other words, they can manipulate its CFrame to their heart’s content. They send the data to the server, which replicates it to other clients. The server can override those properties though, as it is the one in charge of replication. The server doesn’t own the part, it owns the network.

so it is exploitable, when i dont set network owner on parts, that i need to secure?

It depends on what you want to achieve. If the part is just a piece of rubble, then you just wait for the velocity to become 0, set the owner to be the server and anchor it. Stuff like vehicles are much harder to secure. The way I do this is by setting the network owner to be the driver, after which I do additional checks on the server. About the same as one would with characters, by checking for speed and fly hacks.

You have to move the train individually on each client using a .RenderStepped to ensure it’s smooth. Generally it will require a system where the server will periodically tell the clients which section of track the train is going on to next, and changes in speed. You can update the train server-side at a much lower rate without interfering with the client-side behaviour, so that the server position of the train is still roughly accurate.

The method with body movers and nodes posted above is very good, but depends on what you prioritise. There are a few issue with the body movers method:

  1. It only really works smoothly for one person at a time, the network owner. It will still be smooth-ish because Roblox’s physics networking has gotten much better, but it won’t be buttery smooth like a correctly built client-side solution.
  2. The train can still glitch out, particularly if the owner is laggy, and having other people standing on the train is a big no.
  3. The network owner has full control of the train and will be able to make it do whatever they want with basic exploit tools.

The main issue with sticking with CFrame is that you will need to also update the velocity property of any parts you want players to be able to stand upon, and as mentioned the train itself won’t respond to other physics objects (e.g. it would just phase through another train), and physics objects that collide with the train wont always respond as you expect.

2 Likes

For starting a project from scratch, what is the general or high level approach to a correctly built client-side solution?

I have a system in place that generates paths when the game begins for each section of track. When the train completes that section, it moved to the next one, which is given by that path itself. Each path has an Id as well. Could it be possible to have the server store the id of the track the train is on, and then the client changes the cframe with any of these given methods?

First remember this solution is good when:

  1. You need high reliability, no chance of it glitching out or whatever
  2. You want it as smooth as possible for multiple players simultaneously
  3. Physics interactions with other objects are not important - cars and players will still collide with the train and be pushed out the way, but they won’t necessarily respond realistically.
  4. Quite important This method will be more complicated than the minecart thread linked above.

The general idea is that the client deals with the fine details - it knows the path the train is going to take, and it updates the trains position from a local script for each client. So something like this:

local Speed = 1
local DistanceAlongPath = 0
game:GetService("RunService").Stepped:Connect(function(dt)
   DistanceAlongPath = DistanceAlongPath + Speed * dt
   Train.PrimaryPart.CFrame = CalculateCFrame(DistanceAlongPath)--Moving a part that the rest of the train is welded to is more efficient than SetPrimaryPartCFrame I believe
  --Where CalculateCFrame is some function you have to figure out where the train should actually be
end)

Some of the details depend on your game, for example if the train switched tracks at the last minute, the other clients will have a delay before they can know this from the server, and so will have to tween the train from the old path onto the new one.

Generally you should still be updating the position of the train on the server too, otherwise it can get confusing as the server will always see the train in the same spot. The stepped connection ensures that this does not effect the clients, how often the trains position is updated server side is up to you.

5 Likes

Any of the above methods should work fine for you - effectively you just take whatever code you currently have to determine the trains movement and put it inside a local script, or you take it and instead of CFraming the train, you repeatedly put the next node into the trains bodymovers.

Ok thank you for the help everyone. I will try out these methods as soon as possible. :+1:

1 Like

What i’d do is render the cframe position updating on server, and fireallclientevent to move train to lerp old position to new position.

1 Like

I would do that but lerp will not work for me since i am using a custom interpolation function for the curves which will not work with that.

I now am telling the client which part of the rail the train is on, and then the client runs the interpolation on its own copy of the train. This solution has worked for me, but i have now run into 2 more problems.

The client runs the interpolation every RenderStepped, but when it has completed on that section of rail, it has to wait until the server changes the RailLocation of the train, which is a value i have made to tell the train what seciton of track it is on. The server doesn’t know how fast the RenderStepped is going, and it may be different for every client, if im correct. Is this the wrong way to go about it?

Now also the player still can’t interact with the train, even though its cframe is being changed on the client’s side. Should i weld all the train’s parts to the PrimaryPart, and then just set the CFrame of the PrimaryPart of the train?

Ok. I have fixed the laggy CFrame problem now.

The only problem left is to do with physical interactions with the trains. The player can’t stand on the train when it moved, which is the only real physical interaction that i am worried about. Is there any way to allow the player to still interact with the train even though i am using CFrame to move it?

You’d have to do some math in regards to that. I’m not to sure what the math will look like but You have to declare your players position relative to the position of car. and increase player cframe based on the train cframe and any input movement u decide to incorporate.

If you want to have real-time physics interaction without having to write your own physics interaction/collision code, I would just use BodyMovers instead of individually CFraming.

1 Like

badcc explains how his Jailbreak train works, allowing you to stand on top of the train.

1 Like

You could also update the Velocity property of any part of the train you want players to stand on, just figure out how fast it’s going each frame and update it.

1 Like