Train lagging causing separation of train cars?

So lets say we have a train. It is moving along with the train cars. Its moving fine. You know, like Jailbreak.

The problem is… When i test the train on client and server, when it lags, the train cars on the back will start separating. Like someone pulled the pin off the train cars.

First of all before moderators send messages to me, I apologize if I do not include any code or screenshots because I am mobile right now. Soon when I get back on my pc, I will edit this topic the soonest including screenshots and code.

UPDATE 1/30/2020:
That is the picture of the train cars separating and sometimes being too close together.

Here is the script that requires the module

wait(8 + math.random())

--Variables

local Workspace = game:GetService("Workspace")
local ServerStorage = game:GetService("ServerStorage")


local Train = ServerStorage.Train
local Train = Train.Train


local TrainClass = require(Train.TrainClass)
local TrainSetup = TrainClass.new(Train,Workspace.Nodes)

TrainSetup:Setup()
wait(workspace.Train:WaitForChild("Train"))
script.Disabled = true

Parented in serverscriptservice

Here is the train mechanics code (That welds all train cars and move them):

local TrainSuperClass = {}
TrainSuperClass.__index = TrainSuperClass

local Workspace = game:GetService("Workspace")
local TweenService = game:GetService("TweenService")
local RunService = game:GetService("RunService")
local ServerStorage = game:GetService("ServerStorage")
local Carriages = ServerStorage.Carriages
local RunService = game:GetService("RunService")
local EasingModule = require(game.ReplicatedStorage.MainModule)

function TrainSuperClass.new(TrainModel,Nodes)
	local Train = {}
	
	setmetatable(Train,TrainSuperClass)
	
	Train.Nodes = Nodes
	Train.Dummy = TrainModel
	Train.Node = 0
	Train.LasCarriage = nil
	Train.BogeyOffset = Train.Dummy.BackBogeyRoot
	
	return Train	
end

function TrainSuperClass:Setup()
	print("Train has started!")
	self.Train = self.Dummy:Clone()
	self.Train.Parent = Workspace.Train
	self:Move()
end


function TrainSuperClass:GetTime(Distance)
	return Distance / self.Speed
end


function TrainSuperClass:Carriages(Node)
	local Carriage = Carriages:GetChildren()[math.random(1,#Carriages:GetChildren())]:Clone()
	
	local All = Carriage:GetChildren()
	
	for A = 1,#All do
		if (All[A].Name~= self.Train.PrimaryPart and All[A]:IsA("BasePart")) then
			local NewWeld = Instance.new("Weld")
			NewWeld.Name = "Weld"
			NewWeld.Part0,NewWeld.Part1 = All[A],Carriage.PrimaryPart
			NewWeld.C0 = All[A].CFrame:inverse()
			NewWeld.C1 = Carriage.PrimaryPart.CFrame:inverse()
			NewWeld.Parent = Carriage.PrimaryPart
		end
	end
	
	if not (self.LastCarriage) then
		self.LastCarriage = self.Train
	end
	
	local Range = NumberRange.new(1,2)
	
	Carriage:SetPrimaryPartCFrame(self.LastCarriage:GetPrimaryPartCFrame() * CFrame.new(0,0,Carriage.PrimaryPart.Size.Z+2))
	
	self.LastCarriage = Carriage
	Carriage.Parent = Workspace.Train
    
    spawn(function()
	    wait()
	    self:MoveCarriage(Node,Carriage)
    end)	
	
end

function TrainSuperClass:MoveCarriage(NodeNum,Carriage)
	
	local Node = self.Nodes:FindFirstChild("Node"..NodeNum)
	
	if not (Node) then
		Carriage:Destroy()
		return
	end
	
	local Distance = (Carriage.PrimaryPart.CFrame.p - Node.CFrame.p).Magnitude
	local BetweenDistance = (Carriage.PrimaryPart.CFrame.p - self.LastCarriage.PrimaryPart.CFrame.p).Magnitude
		
	local Time = self:GetTime(Distance)
	
	local TweenInfo = TweenInfo.new(
		Time,
		Enum.EasingStyle.Linear,
		Enum.EasingDirection.Out,
		0,
		false,
		0
	)
	
	local Range = NumberRange.new(1.5,2)
		
	TweenService:Create(Carriage.PrimaryPart,TweenInfo,{CFrame = Node.CFrame + Vector3.new(0,Carriage.PrimaryPart.Size.Y/3,Carriage.PrimaryPart.CFrame.LookVector/2)}):Play()	
	
	wait(Time)
	
	self:MoveCarriage(NodeNum + 1,Carriage)
	
end

function TrainSuperClass:Move()
	self.Node = self.Node + 1
	
	local Node = self.Nodes:FindFirstChild("Node"..self.Node)
	
	if not(Node) then
		self:Stop()
		return
	end	
	
	if self.Node == 1 then
		local All = self.Train:GetChildren()
		
		for A = 1,#All do
			if (All[A].Name~= self.Train.PrimaryPart and All[A]:IsA("BasePart")) then
				local NewWeld = Instance.new("Weld")
				NewWeld.Name = "Weld"
				NewWeld.Part0,NewWeld.Part1 = All[A],self.Train.PrimaryPart
				NewWeld.C0 = All[A].CFrame:inverse()
				NewWeld.C1 = self.Train.PrimaryPart.CFrame:inverse()
				NewWeld.Parent = self.Train.PrimaryPart
			end
		end
		wait()
		self.Train:SetPrimaryPartCFrame(Node.CFrame + Vector3.new(0,self.Train.PrimaryPart.Size.Y/2,0))
		
		for i = self.CarriagesCount,1,-1 do
			self:Carriages(self.Node)
		end
		
		self:Move()	
		
		return
	end
	
	local Distance = (self.Train.PrimaryPart.CFrame.p - Node.CFrame.p).Magnitude
	
	local Time = self:GetTime(Distance)
	
	local TweenInfo = TweenInfo.new(
		Time,
		Enum.EasingStyle.Linear,
		Enum.EasingDirection.Out,
		0,
		false,
		0
	)
	
	local Range = NumberRange.new(1.5,2)
	
	TweenService:Create(self.Train.PrimaryPart,TweenInfo,{CFrame = Node.CFrame + Vector3.new(0,self.Train.PrimaryPart.Size.Y/2,0)}):Play()
	
	wait(Time)
	self:Move()
	
	if (self.Node == 10) then
		print("Node is ten yen....")
	end
end


function TrainSuperClass:Stop()
	self.LastCarriage = nil
	self.Train:Destroy()
	self.Train.Parent = nil
	self.Node = 0
	print("Train has finished! Starting setup...")
	wait(14)
	self:Setup()
end

return TrainSuperClass

Parented in serverscriptservice in SuperClasses folder. Its a folder made by me so ignore it.

4 Likes

Please also include the model structure as well. Are you welding the cars together?

3 Likes

Yes. Sorry for late reply. I am welding each train car together. All of their parts are unanchored and the primarypart is anchored.

Alright so I have updated the topic including some screenshots and codes. Please reply me below when you know how to fix it.

@blazepinnaker Do you know how to fix it? Its been a few days I still havent got any replies or solutions

I see you posted on this thread too… Multiple moving models separate?

My one suggestion might be to write a script which does a “programmatic” weld. Eg, it moves the car into the right position based on the relative position of another model. It would need to update frequently.

This might be a bit compute intensive though. It’s the only thing that occurs to me.

1 Like

What do you mean by programmatic weld? I weld each carriage together. I cannot think of anyway of moving the train car into the right position based on relative position of another model you said. Also what do you mean by updating it frequently? Mind sharing your code with me of what you mean?

1 Like

Try to see if you can get that function executing more frequently.

Another thing you can do is create a new place and add the relevant models/scripts. Make sure they work as much as they can and invite me and/or others via Team Create. Will take a look when I have a moment.

1 Like

I am firing it rapidly. Sure I will upload the place as private and then I will invite you in team create.

@blazepinnaker I am adding you as a friend right now. And please accept it so you are in team create.

1 Like

Alright @blazepinnaker, I now invited you in team create. Check your shared with me in studio now!

Hey @blazepinnaker! Are you doing the fix in team create? When are we doing team create? We should text via discord, send me your name and tag

Just handle the train physics on the client. The server should never have to handle any intense calculations like this.

1 Like

@Kurookku I don’t use physics to move the train and its train cars. I use a modulescript and parented to serverscriptservice. Which means its running on server, causing jiterry and separaring train cars because of lag. I move them with tweenservice and the main train car is also used with tweenservice

That’s not what i’m saying. Even if you are using tween service the server still has to replicate the moving parts to all the users in the game. With network latency and the servers very very very small allocated bandwidth, you need to have the client handle the movement of the trains, not the server.

1 Like

How would I do it on the client? Yes i would use :FireAllClients() But which line of the TrainSuperClass module script I would put the remoteevent:FireAllClients(). Which line? Plus where I would put the remote event? In ReplicatedStorage? Also where i should parent a localscript that is going to pick up the fired remote event?

for example:

RemoteEvent.OnClientEvent:Connect(function()

end

Put a remote event in replicated storage, when ever you spawn a train just fire the event to all of the clients and then create the train on the client. moving the train wherever you chose for it to go.

1 Like

So I have to create to remote events. SpawnTrain and TrainClientReplication. Thats the names of the remotes i am creating.

As ive asked before, Where do i parent a local script to pick up the fired event?

You only need one remote event. That remote event would basically have the server send the train info to the client, the client then would create a train with the given info and do all the tweeting. The client script would go in StarterScripts > PlayerScripts

1 Like

Alright 1/2 solved. The localscript will be parented in StarterPlayerScripts. so would pickup the remoteevent with all the parameters. Also which line of the module script I would put :FireAllClients() as ive showned the full train mechanics code above.