Jump to content

How to sync data w/o set/getElementData?


damage22

Recommended Posts

Hello!

I'm currently working on a trucking script and i think i'm a bit stuck.

The current version of the script uses setElementData and getElementData for storing information about cargo in the vehicle elements. But the setElementData function syncs that data with all the players by default . That means - every player will sync his data with every other player, hence potentially we get N*N syncs, and that is a waste, because only the player currently driving the car and the server have need for that info. The good thing is: i can have a function, that is availible at the clientside and simply returns all information needed, like

local a = simplyGetDataFromServer(vehicle)

Now when i switch the ElementData sync off, i cannot use getElementData to retrieve it from the serverside. I thought about using the event system, but i can't think of a way to send a request and recieve a reply right in the body of one given function, something like this:

function getData()
triggerServerEvent("onDataRequest",...)
local a
a = ... --data from server
return a
end

First i thought about something like

local a
function getData(vehicle)
triggerServerEvent("onDataRequest",...)
end
 
addEvent("onDataReply",true)
addEventHandler("onDataReply",getLocalPlayer(), function (newa) a = new a end)
 
function someFunction()
getData(vehicle1)
local b = a*a
...
end

but it seems unreliable to me. Any ideas on how to "manually" sync that data, easy and reliable way?

Link to comment

triggering an event has always tripped me up before, heres an example

before you run this inside a client function, you would need both theTruck and cargoValue as valid arguements above it.

triggerServerEvent ( "onTruckUpdate", theTruck, cargoValue )

"onTruckUpdate" is the event that i just triggered, with the theTruck as the source and cargoValue as the first arg.

then after that, in the server:

addEvent( "onTruckUpdate", true )
function setTruckCargo ( cargoValue )
--the function goes in here, and you can call up the arg cargoValue, and refer to theTruck as source
end
addEventHandler( "onTruckUpdate", getRootElement(), setTruckCargo )

Link to comment

Thank you for replying, but setting cargo works fine, that's what i did already. I've got problems getting that data back.

Let me explain what i mean:

What i had:

Client
function setCargo(theTruck, cargoValue)
return triggerServerEvent ( "onTruckUpdate", theTruck, cargoValue ) --for setting cargo value, i.e. when i load the truck
end
--and
function getCargo(theTruck)
return getElementData(theTruck,"cargo") -- to get my data back, easy, one line
end

Server
addEvent("onTruckUpdate", true)
addEventHandler( "onTruckUpdate", getRootElement(), setTruckCargo)
function setTruckCargo ( theTruck, cargoValue )
setElementData(theTruck,"cargo",cargoValue, [b][color=#FF0000]true[/color][/b])
end

This works just fine, except for that true, which means that data will be synced with all clients immediately. I simply don't need that, because it's not urgent and i don't need it on all the clients at the same time.

But when i change it to false, switching the sync off, i can no longer use getElementData to retrieve the data from the server. To use the event system, i'll have to use two events ("query" and "reply") and lots of code instead of that simple <> line. Is there another way to grab my data from server without those two events?

In other words, is it possible to "request" data from server by a convenient way? Or at least, is it possible to write an encapsulated function, that would make a request and return all the values i need? Like:

function getMyData(theTruck)
--get the data from the server--
return myData
end

Link to comment

The issue is that server and client communication is (and has to be) asynchronous. You could wrap things up with callbacks, using events as the underlying basis for them, though this is roughly what events are anyway...

THIS IS PSEUDO-CODE! Don't expect it to work, just an idea how you might do it...

replies = {}
uniqueid = 0
 
function getData(type, callback, ...)
  replies[uniqueid] = callback
  triggerServerEvent("requestData", uniqueid, type, {...})
end
 
addEvent("receieveData", true)
addEventHandler("receiveData", getRootElement(), 
function(id, ...)
   replies[id](...)
   replies[id] = nil
end)
 
handlers = {}
handler["getNumber5"] = function() return 5 end
 
addEvent("requestData", true)
addEventHandler("requestData", getRootElement(),
function(id, type, ...)
  triggerClientEvent("receiveData", id, handler[type])
end
 
getData("getNumber5", function(number) print(number) end)

Link to comment

Thanks, eAi!

Yes, that's what i thought about - writing my own client-server message dispatcher - but it's too complex for such a minor task. Now i see only two reasonable ways to deal with it - leave it as it is, with full sync and potentially a big waste of resources, or re-write the script, so all the checks are done on the serverside, and i'm leaning towards the last one.

Still it would be nice to have a built-in function, that would allow "on-request" syncing (ie when you call it, it requests the data from the server, waits for the reply and then returns the requested data) - simple, like getElementData, but with no excessive syncing, when you don't actually need it.

Link to comment

The problem is, you have to use callbacks - scripts cannot run for more than a few milliseconds before MTA will terminate them. While your script is running, nothing else is happening (MTA is basically single-threaded in most respects), so you can't wait for something to happen, because it won't!

I agree it would be useful, but as with most server-client systems, callbacks are required.

There might be some use for a simplified system for sending messages that avoids events. The only real advantage I can see in doing that is reducing the overhead (events are quite computationally expensive) - the code overhead of events is fairly minimal.

You're right though that element data is really not an ideal way to sync information. The network cost alone could be quite significant with a large number of players.

Most people seem to cope with using events - I'm not sure how well you know the system, but it can be quite powerful if used correctly, even if it is overkill for some simple uses.

Link to comment

to eAi

Alright, so i can't just break execution of a function, wait for reply and then continue from that exact position. I got the "callback" idea, but on the second thought, moving all my functions to serverside, except for GUI and marker hits, will make my life a lot easier and, probably, will save some resources by not having to send that data back and forth. By the way, speaking of computational costs, are there any tips on script optimization?

to robhol

Actually, that tutorial was the first thing i read, when i started scripting. And thanks, it was very useful and a good thing to start. :wink:

Link to comment

It's hard to say what you could optimise without seeing your code. Basic things tend to be highlighted on the wiki - such as not attaching event handlers to the root element unless you need to, not triggering events on the root element unless you need to (pretty important that one!)

I would also strongly encourage moving code server-side if it's practical. If nothing else, it's more hack-proof than client-side code.

Link to comment

I have a pretty similar goal to achieve, so I would like to use this topic to ask if nobody mind. Saying shortly I have a data "A" attached to a vehicle. The data is then changing client-side by vehicles driver. What I need is to sync changed data to a passenger of the same vehicle. Sounds easy, but I need the data to be synced every second, since it's changing that quick. That is where i expect troubles to appear when more and more people is going to use the synchronization. Will it be more efficient to use events system, or there's no matter how to kill the server with 50 requests in a second? Or maybe I'm worrying for nothing and this procedure won't stress the server and waste too much of bandwidth? I can't carry out such an experiment, that is why I have to ask for advice.

Link to comment
  • 1 month later...

Actually I have the same problem as you Antibird.

I have several vehicles positions that are changed by ONE player client-side and I need to dispatch this information to all others players (except himself because he needs to keep the "truth" on the elements and can not afford server lag on this).

What I have done is, in a 50ms timer, on the driver side, I call a server function (basically event) with the new positions of the desired objects.

When the server receives this event, it then dispatches this information to all players except the caller (the server could set the positions of the objects but then the driver's view won't be as smooth).

Client side, for all players, when they receive this information from the server they set the position and velocity of the objects accordingly.

All that sounds good on paper and indeed works fine with few players, but yesterday when installing this script on a real server, this caused massive lag. The website went down, and it was taking 10 minutes only to join the server. The only way it stopped (before we could join to disable that) was to ask players to stop using this feature.

So here again, I'm wondering what would be the best way to sync that kind of data?

It seems that if you do clientSide setPosition on elements for which the current player is the "syncer" (ped & vehicle for which they are the driver) then MTA can handle it properly.

Would there be a way to set a player as the "syncer" for other elements so the changes done client side are handled by MTA's sync methods?

Link to comment

Not actually that same, Kayl.

I need a set of some custom data produced by one player to be synced to another player with as least time intervals as possible while keeping server stable and saving bandwidth of other players. Element data, only needed by two, but not the others. Just a question: what loads the server more, synchronizing the data via events system with looping through all players server-side, or via one-line setElementData()?

P.S.

I definitely agree with and idea of having a "setElementSyncer" - like function, could help making some features in a much more easier way.

Link to comment

I understand Antibird.

It was only identical in that, without a setElementSyncer function, I need to do the "rapid" sync manually and was also wondering which method to use (event VS data). I tried the event method and that was pretty bad (because I need to dispatch it back). I'll personally (but here, I agree, our two uses of manual sync diverge) wait for the setElementSyncer function to be implemented (since I feel guilty for having created such an amazing server lag yesterday).

Link to comment

If you set it, it would override any built-in MTA functionality for switching the syncer.

It seems there's a fairly clear case for having a more 'raw' way to send packets of data to the server - or maybe looking at optimizing the existing element data/event stuff.

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...