Jump to content

Bugged trailers fix


Rat32

Recommended Posts

59 minutes ago, Ayush Rathore said:

well whats the error ? :)

what you mean by lagged?

Trailers are handled as empty vehicles in MTA and are only updated according to unoccupied_vehicle_sync_interval.
That causes problems for all other players who see you pull that trailer, while for you it seems fine other players see the trailers correct position only every x ms.

One fix would be to change the unoccupied_vehicle_sync_interval setting to a lower value but that will cause heavy server load.

There is also a bug on the bugtracker but I can't find it.

  • Like 1
Link to comment
14 minutes ago, 3aGl3 said:

Trailers are handled as empty vehicles in MTA and are only updated according to unoccupied_vehicle_sync_interval.
That causes problems for all other players who see you pull that trailer, while for you it seems fine other players see the trailers correct position only every x ms.

One fix would be to change the unoccupied_vehicle_sync_interval setting to a lower value but that will cause heavy server load.

There is also a bug on the bugtracker but I can't find it.

may be that server is running on an highly configured vps or host as i only know about  unoccupied_vehicle_sync_interval setting and in my opinion that's the only way of achieving it

  • Like 1
Link to comment

 

This is a complex problem but you can make it work almost perfect in most cases. Changing unoccupied_vehicle_sync_interval like 3aGl3 suggested (and the other sync intervals too) is a good start. I'm using 10ms on all of them except lightweight sync where 100ms is used:

<!-- Player sync interval. Default: 100 -->
<player_sync_interval>10</player_sync_interval>
<!-- Lightweight (player) sync interval. Used when players are far apart. Default: 1500 -->
<lightweight_sync_interval>100</lightweight_sync_interval>
<!-- Camera sync interval. Default: 500 -->
<camera_sync_interval>10</camera_sync_interval>
<!-- Ped sync interval. Default: 400 -->
<ped_sync_interval>10</ped_sync_interval>
<!-- Unoccupied_vehicle sync interval. Default: 400 -->
<unoccupied_vehicle_sync_interval>10</unoccupied_vehicle_sync_interval>
<!-- Keysync mouse rotation sync interval. For limiting key sync packets due to mouse movement. Default: 100 -->
<keysync_mouse_sync_interval>10</keysync_mouse_sync_interval>
<!-- Keysync analog movement sync interval. For limiting key sync packets due to joystick movement. Default: 100 -->
<keysync_analog_sync_interval>10</keysync_analog_sync_interval>

This high sync intervals are barely noticeable on the server's CPU usage (Debian 8.7, mtasa-1.5.3), same applies for the network speed (Avg: 30 kBit/s) with 2 players online. Now this isn't everything you need, you would also need something that detects and update differences in positioning. Here's one potential solution, first the server side code which will obtain the current coordinates of a first (and a second trailer attached to an invisible Tanker semi truck attached to the first trailer). Coordinates server side will match the element syncer which should be the player who is driving the big rig.

-- Trailer sync function 
trailerSyncTimers[client] = setTimer(function(client) 
	-- Sync first truck trailer if there is any
	if vehicles and vehicles[client] and isElement(vehicles[client]) and isElement(getElementData(vehicles[client], "GTWvehicles.attachedTrailer")) then
		local tx,ty,tz = getElementPosition(getElementData(vehicles[client], "GTWvehicles.attachedTrailer"))
		local trx,try,trz = getElementRotation(getElementData(vehicles[client], "GTWvehicles.attachedTrailer"))
		setElementData(getElementData(vehicles[client], "GTWvehicles.attachedTrailer"), "GTWvehicles.trailer.location", toJSON({tx,ty,tz, trx,try,trz}))
	else
		killTimer(trailerSyncTimers[client])
	end
    
	-- Sync first truck trailer if there is any
	if trailers and trailers[client] and trailers[client][1] and isElement(trailers[client][1]) and 
		isElement(getElementData(trailers[client][1], "GTWvehicles.second_trailer")) then
		local tx,ty,tz = getElementPosition(getElementData(trailers[client][1], "GTWvehicles.second_trailer"))
		local trx,try,trz = getElementRotation(getElementData(trailers[client][1], "GTWvehicles.second_trailer"))
		setElementData(getElementData(trailers[client][1], "GTWvehicles.second_trailer"), "GTWvehicles.trailer.location", toJSON({tx,ty,tz, trx,try,trz}))
	end
end, 250, 0, client)

Now on the client side. This is where the coordinates are obtained from the trailer object itself which we set on the server earlier. Here's where we'll look for the big changes like if the trailer is rotated ~45 degrees for a player looking at the rig from the outside while everything looks perfectly normal to the driver. We'll also check for differences in positioning, in this case a distance of 20 units are used while the difference in rotation are π/6 rad (30 degrees) 

setTimer(function() 
	for k,v in pairs(getElementsByType("vehicle", root, true)) do
		if getVehicleType(v) == "Trailer" and getElementData(v, "GTWvehicles.trailer.location") and 
			getElementData(v, "GTWvehicles.towingVehicle") and getElementData(v, "GTWvehicles.towingVehicle") ~= 
			getPedOccupiedVehicle(localPlayer) then
			local data = fromJSON(getElementData(v, "GTWvehicles.trailer.location"))
			--outputChatBox("Trailer "..k.." is streamed in at position: {"..math.floor(data[1])..", "..
			--	math.floor(data[2])..", "..math.floor(data[3]).."} with rotation: {"..math.floor(data[4])..", "..
			--	math.floor(data[5])..", "..math.floor(data[6]).."}")
			
			local tx,ty,tz = getElementPosition(v)
			local trx,try,trz = getElementRotation(v)
			--local sx,sy,sz = getElementVelocity(v)
			--outputChatBox("Updated trailer position for player: "..getPlayerName(localPlayer)..", Diff: x: "..
			--	math.floor(math.abs(tx-data[1])).." sx: ("..math.floor(sx).."), y: "..
			--	math.floor(math.abs(ty-data[2])).." sy: ("..math.floor(sy).."), z: "..
			--	math.floor(math.abs(tz-data[3])).." sz: ("..math.floor(sz)..
			--	"), Diff rot: rx: "..math.floor(math.abs(trx-data[4]))..
			--	", ry: "..math.floor(math.abs(try-data[5]))..", rz: "..math.floor(math.abs(trz-data[6])))
			local t_tower = getElementData(v, "GTWvehicles.towingVehicle")
			if t_tower and isElement(t_tower) then
				setTimer(attachTrailerToVehicle, 100, 1, t_tower, v)
			end
			local t2_tower = getElementData(t_tower, "GTWvehicles.second_tower")
			if t2_tower and isElement(t2_tower) then
				setTimer(attachTrailerToVehicle, 100, 1, t2_tower, v)
			end
			
			if math.abs(tx-data[1]) > 20 or math.abs(ty-data[2]) > 20 or math.abs(tz-data[3]) > 20 or (math.abs(trz-data[6]) > 30 and math.abs(trz-data[6]) < 150) then
				--outputChatBox("Old pos: "..math.floor(tx)..", "..math.floor(ty)..", "..math.floor(tz))
				setElementPosition(v, data[1],data[2],data[3])
				setElementRotation(v, data[4],data[5],data[6])
				--local tx,ty,tz = getElementPosition(v)
				--outputChatBox("New pos: "..math.floor(tx)..", "..math.floor(ty)..", "..math.floor(tz))
			end
		end
	end
end, 500, 0)

Next thing to do here would be to not allow an element to stream out. This is slightly easier tho since you only need to pass the newly created trailer element (and the semi truck) to the client and then use setElementStreamable client side. Here's an example I've been using to solve this issue with trains carrying 20-30 trailers.

Server:

triggerClientEvent(root, "GTWvehicles.onStreamOut", root, vehicles[client])

Client:

function check_stream_out(c_train)
	setElementStreamable(c_train, true)
end
addEvent("GTWvehicles.onStreamOut", true)
addEventHandler("GTWvehicles.onStreamOut", root, check_stream_out)

This code is a part of https://github.com/404rq/GTW-RPG/tree/v4.0-development and might need a few adjustments to work in your server but it shows the principles. vehicles[client] contains the semi truck and trailers[client][1] contains the first trailer. The trailer can identify it's tower from it's element data set to: GTWvehicles.towingVehicle which is set upon creation. If you're having any trouble, try changing the values in this line, that's pretty much how aggressive the sync will be, if it's too aggressive you may experience other issues:

if math.abs(tx-data[1]) > 20 or math.abs(ty-data[2]) > 20 or math.abs(tz-data[3]) > 20 or (math.abs(trz-data[6]) > 30 and math.abs(trz-data[6]) < 150) then

I hope this works for you too

  • Like 2
Link to comment

I don't think setting all sync intervals that low is a good idea if you are expecting more than a few players.
It might not be notable with 2 players but it sure will be with more...

Not to mention that 10 seems a little low, even the player sync is only 100 by default.

Edited by 3aGl3
  • Like 1
Link to comment

The only reason for choosing 10ms is that you'll get 1 update per frame on a server running at 100FPS. In reality however default FPS rate for a server is 36 (27.77..ms sync interval) and most displays today runs at 60FPS (16.66..ms sync interval). My test server runs at 60FPS so in my case I wouldn't have noticed any difference if I've used say 20ms, other than support for more players and objects before noticing any lag. I did try this with Crystals bot resource however and 50-75 bots works just fine with a 10ms sync interval, first after spawning more than 75 bots and vehicles I did notice some lag. 

Without testing I think a 100ms sync interval should be sufficient as well. Luckily it's easy to change these values while testing what works best for individual servers.

  • Like 1
Link to comment
On 13.03.2017 at 13:19, Mr_Moose said:

 

This is a complex problem but you can make it work almost perfect in most cases. Changing unoccupied_vehicle_sync_interval like 3aGl3 suggested (and the other sync intervals too) is a good start. I'm using 10ms on all of them except lightweight sync where 100ms is used:


<!-- Player sync interval. Default: 100 -->
<player_sync_interval>10</player_sync_interval>
<!-- Lightweight (player) sync interval. Used when players are far apart. Default: 1500 -->
<lightweight_sync_interval>100</lightweight_sync_interval>
<!-- Camera sync interval. Default: 500 -->
<camera_sync_interval>10</camera_sync_interval>
<!-- Ped sync interval. Default: 400 -->
<ped_sync_interval>10</ped_sync_interval>
<!-- Unoccupied_vehicle sync interval. Default: 400 -->
<unoccupied_vehicle_sync_interval>10</unoccupied_vehicle_sync_interval>
<!-- Keysync mouse rotation sync interval. For limiting key sync packets due to mouse movement. Default: 100 -->
<keysync_mouse_sync_interval>10</keysync_mouse_sync_interval>
<!-- Keysync analog movement sync interval. For limiting key sync packets due to joystick movement. Default: 100 -->
<keysync_analog_sync_interval>10</keysync_analog_sync_interval>

This high sync intervals are barely noticeable on the server's CPU usage (Debian 8.7, mtasa-1.5.3), same applies for the network speed (Avg: 30 kBit/s) with 2 players online. Now this isn't everything you need, you would also need something that detects and update differences in positioning. Here's one potential solution, first the server side code which will obtain the current coordinates of a first (and a second trailer attached to an invisible Tanker semi truck attached to the first trailer). Coordinates server side will match the element syncer which should be the player who is driving the big rig.


-- Trailer sync function 
trailerSyncTimers[client] = setTimer(function(client) 
	-- Sync first truck trailer if there is any
	if vehicles and vehicles[client] and isElement(vehicles[client]) and isElement(getElementData(vehicles[client], "GTWvehicles.attachedTrailer")) then
		local tx,ty,tz = getElementPosition(getElementData(vehicles[client], "GTWvehicles.attachedTrailer"))
		local trx,try,trz = getElementRotation(getElementData(vehicles[client], "GTWvehicles.attachedTrailer"))
		setElementData(getElementData(vehicles[client], "GTWvehicles.attachedTrailer"), "GTWvehicles.trailer.location", toJSON({tx,ty,tz, trx,try,trz}))
	else
		killTimer(trailerSyncTimers[client])
	end
    
	-- Sync first truck trailer if there is any
	if trailers and trailers[client] and trailers[client][1] and isElement(trailers[client][1]) and 
		isElement(getElementData(trailers[client][1], "GTWvehicles.second_trailer")) then
		local tx,ty,tz = getElementPosition(getElementData(trailers[client][1], "GTWvehicles.second_trailer"))
		local trx,try,trz = getElementRotation(getElementData(trailers[client][1], "GTWvehicles.second_trailer"))
		setElementData(getElementData(trailers[client][1], "GTWvehicles.second_trailer"), "GTWvehicles.trailer.location", toJSON({tx,ty,tz, trx,try,trz}))
	end
end, 250, 0, client)

Now on the client side. This is where the coordinates are obtained from the trailer object itself which we set on the server earlier. Here's where we'll look for the big changes like if the trailer is rotated ~45 degrees for a player looking at the rig from the outside while everything looks perfectly normal to the driver. We'll also check for differences in positioning, in this case a distance of 20 units are used while the difference in rotation are π/6 rad (30 degrees) 


setTimer(function() 
	for k,v in pairs(getElementsByType("vehicle", root, true)) do
		if getVehicleType(v) == "Trailer" and getElementData(v, "GTWvehicles.trailer.location") and 
			getElementData(v, "GTWvehicles.towingVehicle") and getElementData(v, "GTWvehicles.towingVehicle") ~= 
			getPedOccupiedVehicle(localPlayer) then
			local data = fromJSON(getElementData(v, "GTWvehicles.trailer.location"))
			--outputChatBox("Trailer "..k.." is streamed in at position: {"..math.floor(data[1])..", "..
			--	math.floor(data[2])..", "..math.floor(data[3]).."} with rotation: {"..math.floor(data[4])..", "..
			--	math.floor(data[5])..", "..math.floor(data[6]).."}")
			
			local tx,ty,tz = getElementPosition(v)
			local trx,try,trz = getElementRotation(v)
			--local sx,sy,sz = getElementVelocity(v)
			--outputChatBox("Updated trailer position for player: "..getPlayerName(localPlayer)..", Diff: x: "..
			--	math.floor(math.abs(tx-data[1])).." sx: ("..math.floor(sx).."), y: "..
			--	math.floor(math.abs(ty-data[2])).." sy: ("..math.floor(sy).."), z: "..
			--	math.floor(math.abs(tz-data[3])).." sz: ("..math.floor(sz)..
			--	"), Diff rot: rx: "..math.floor(math.abs(trx-data[4]))..
			--	", ry: "..math.floor(math.abs(try-data[5]))..", rz: "..math.floor(math.abs(trz-data[6])))
			local t_tower = getElementData(v, "GTWvehicles.towingVehicle")
			if t_tower and isElement(t_tower) then
				setTimer(attachTrailerToVehicle, 100, 1, t_tower, v)
			end
			local t2_tower = getElementData(t_tower, "GTWvehicles.second_tower")
			if t2_tower and isElement(t2_tower) then
				setTimer(attachTrailerToVehicle, 100, 1, t2_tower, v)
			end
			
			if math.abs(tx-data[1]) > 20 or math.abs(ty-data[2]) > 20 or math.abs(tz-data[3]) > 20 or (math.abs(trz-data[6]) > 30 and math.abs(trz-data[6]) < 150) then
				--outputChatBox("Old pos: "..math.floor(tx)..", "..math.floor(ty)..", "..math.floor(tz))
				setElementPosition(v, data[1],data[2],data[3])
				setElementRotation(v, data[4],data[5],data[6])
				--local tx,ty,tz = getElementPosition(v)
				--outputChatBox("New pos: "..math.floor(tx)..", "..math.floor(ty)..", "..math.floor(tz))
			end
		end
	end
end, 500, 0)

Next thing to do here would be to not allow an element to stream out. This is slightly easier tho since you only need to pass the newly created trailer element (and the semi truck) to the client and then use setElementStreamable client side. Here's an example I've been using to solve this issue with trains carrying 20-30 trailers.

Server:


triggerClientEvent(root, "GTWvehicles.onStreamOut", root, vehicles[client])

Client:


function check_stream_out(c_train)
	setElementStreamable(c_train, true)
end
addEvent("GTWvehicles.onStreamOut", true)
addEventHandler("GTWvehicles.onStreamOut", root, check_stream_out)

This code is a part of https://github.com/404rq/GTW-RPG/tree/v4.0-development and might need a few adjustments to work in your server but it shows the principles. vehicles[client] contains the semi truck and trailers[client][1] contains the first trailer. The trailer can identify it's tower from it's element data set to: GTWvehicles.towingVehicle which is set upon creation. If you're having any trouble, try changing the values in this line, that's pretty much how aggressive the sync will be, if it's too aggressive you may experience other issues:


if math.abs(tx-data[1]) > 20 or math.abs(ty-data[2]) > 20 or math.abs(tz-data[3]) > 20 or (math.abs(trz-data[6]) > 30 and math.abs(trz-data[6]) < 150) then

I hope this works for you too

 

Very thanks.

 

Hmm, your code generating errors, "attempt to index global "trailerSyncTimer" in line 6", I tried to download and modify code from github pasted for you, but still not work. I don't have idea to fix this code. Any ideas/fixes?

Link to comment
-- Trailer sync function 
trailerSyncTimers[client] = setTimer(function(client) 

trailerSyncTimers = { }

    -- Sync first truck trailer if there is any
    if vehicles and vehicles[client] and isElement(vehicles[client]) and isElement(getElementData(vehicles[client], "GTWvehicles.attachedTrailer")) then
        local tx,ty,tz = getElementPosition(getElementData(vehicles[client], "GTWvehicles.attachedTrailer"))
        local trx,try,trz = getElementRotation(getElementData(vehicles[client], "GTWvehicles.attachedTrailer"))
        setElementData(getElementData(vehicles[client], "GTWvehicles.attachedTrailer"), "GTWvehicles.trailer.location", toJSON({tx,ty,tz, trx,try,trz}))
    else
        killTimer(trailerSyncTimers[client])
    end
    
    -- Sync first truck trailer if there is any
    if trailers and trailers[client] and trailers[client][1] and isElement(trailers[client][1]) and 
        isElement(getElementData(trailers[client][1], "GTWvehicles.second_trailer")) then
        local tx,ty,tz = getElementPosition(getElementData(trailers[client][1], "GTWvehicles.second_trailer"))
        local trx,try,trz = getElementRotation(getElementData(trailers[client][1], "GTWvehicles.second_trailer"))
        setElementData(getElementData(trailers[client][1], "GTWvehicles.second_trailer"), "GTWvehicles.trailer.location", toJSON({tx,ty,tz, trx,try,trz}))
    end
end, 250, 0, client)

Same. I don't want to request you to write script for me, but my ideas ended - sorry.

xEzgdtd.png

Edited by Tasumi
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...