Jump to content

How/Why to stop using setElementData and getElementData


aintaro

Recommended Posts

Hello,

Today I will be explaining why you should stop use setElementData and how to stop using it.

Why should you stop using setElementData?

As element data is synced to all clients, it can generate a lot of network traffic and consume server CPU.

How to stop using setElementData?

Example :

Lets say you want to save the total time of a player most people will do it like this :

local timePlayed = 0 --declare a variable timePlayed for every player 
  
function initPlayer() 
     setElementData(thePlayer, "player_time", timePlayed) --we  set the elementData player_time to timePlayed 
end 
  

THATS WRONG!

This is how you should do it :

local playerData = { --declare playerData for all the players data 
timePlayed = {} --first dataType = timePlayed 
} 
  
function initPlayer() 
     playerData.timePlayed[thePlayer] = 0 --set timePlayed of "thePlayer" to 0 
end 

playerData.timePlayed[thePlayer] = 0 --set timePlayed of "thePlayer" to 0

this will set timePlayed only to thePlayer userdata

PROOF :

for i = 1, 10000 do 
        setElementData(thePlayer, "test"..tostring(i), 1000) 
    end 

execute time : 47 ticks

for i = 1, 10000 do 
        setElementData(thePlayer, "test"..tostring(i), 1000,false) 
    end 

execute time : 40 ticks

for i = 1, 10000 do 
        playerData[thePlayer][i] = 1000 
    end 

execute time : 1 tick

thanks for reading, any questions can be posted under!

Edited by Guest
Link to comment

In fact I use whenever is possible Lua table, but however setElementData and getElementData are useful because you can keep the data among the different resources of your server. If you want to set a data on the "main" resource and use it on the resource concerning the vehicule, it's easy with elementData, and you can't do it with tables.

Link to comment
In fact I use whenever is possible Lua table, but however setElementData and getElementData are useful because you can keep the data among the different resources of your server. If you want to set a data on the "main" resource and use it on the resource concerning the vehicule, it's easy with elementData, and you can't do it with tables.

Yo can do it with tables, you just have to make an exported function that returns the table with the data. The bad thing is that you would have to do it with each table. But if you are concerned about server performance, you have to consider this system.

Link to comment
  • 4 weeks later...

If i understand it correctly, the table PlayerData has subtables of data ( like the key in setElementData ), and in that subtable there is another subtable with all the players in it?

So this is server sided. If i understand that correctly, then i have a question.

If the player leaves, how do i destroy the subtables that contain information of that player? Like, if thePlayer leaves, it still has the tables timePlayed = { [thePlayer] = 0 } inside of the table.

Link to comment

If i understand it correctly, the table PlayerData has subtables of data ( like the key in setElementData ), and in that subtable there is another subtable with all the players in it?

So this is server sided. If i understand that correctly, then i have a question.

If the player leaves, how do i destroy the subtables that contain information of that player? Like, if thePlayer leaves, it still has the tables timePlayed = { [thePlayer] = 0 } inside of the table.

player_data = {} 
  
function on_join() 
    player_data[source] = "something you want to save" 
end 
addEventHandler('onPlayerJoin', root, on_join) 
  
function on_quit() 
    player_data[source] = nil 
end 
addEventHandler('onPlayerQuit', root, on_quit) 

This is how you would delete the data

Link to comment

So if the table I have set up is to store all player data whilst the player is actively ingame, is this the right way to structure it?

playerData = { 
SQLID = {}, 
Username = {}, 
Password = {} 
} 

And will I be able to access these subtables through this exported function?

Link to comment

Yeah, but you need to set the player element as the key for the sub-tables. like this:

playerData = {} 
  
function set_data(player_element, data_key, data_value) -- export this function 
    if type(player_element) == "nil" or type(data_key) == "nil" or type(data_value) == "nil" then return false end 
  
    if not playerData[player_element] then 
        playerData[player_element] = {} 
    end 
  
    playerData[player_element][data_key] = data_value 
    return true 
end 
  
function get_data(player_element, data_key) -- export this function 
    if type(player_element) == "nil" or type(data_key) == "nil" then return false end 
  
    return playerData[player_element] and playerData[player_element][data_key] or false 
end 
  
function delete_data() -- you have to delete the data when the player quits 
    playerData[source] = nil 
end 
addEventHandler('onPlayerQuit', root, delete_data) 

Then, if you export those functions, you can call them from any resource this way:

exports.resourceName:set_data(player, "SQLID", 1231231) 
exports.resourceName:set_data(player, "Username", "Booth") 
exports.resourceName:set_data(player, "Password", "12345") 
  
exports.resourceName:get_data(player, "SQLID") 
exports.resourceName:get_data(player, "Username") 
exports.resourceName:get_data(player, "Password") 

And this is how you would do a basic good-enough data system. :)

Link to comment
Yeah, but you need to set the player element as the key for the sub-tables. like this:
playerData = {} 
  
function set_data(player_element, data_key, data_value) -- export this function 
    if type(player_element) == "nil" or type(data_key) == "nil" or type(data_value) == "nil" then return false end 
  
    if not playerData[player_element] then 
        playerData[player_element] = {} 
    end 
  
    playerData[player_element][data_key] = data_value 
    return true 
end 
  
function get_data(player_element, data_key) -- export this function 
    if type(player_element) == "nil" or type(data_key) == "nil" then return false end 
  
    return playerData[player_element] and playerData[player_element][data_key] or false 
end 
  
function delete_data() -- you have to delete the data when the player quits 
    playerData[source] = nil 
end 
addEventHandler('onPlayerQuit', root, delete_data) 

Then, if you export those functions, you can call them from any resource this way:

exports.resourceName:set_data(player, "SQLID", 1231231) 
exports.resourceName:set_data(player, "Username", "Booth") 
exports.resourceName:set_data(player, "Password", "12345") 
  
exports.resourceName:get_data(player, "SQLID") 
exports.resourceName:get_data(player, "Username") 
exports.resourceName:get_data(player, "Password") 

And this is how you would do a basic good-enough data system. :)

How to use this clientside?

Link to comment
  
playerData = {} 
  
function set_data(player_element, data_key, data_value) -- export this function 
    if type(player_element) == "nil" or type(data_key) == "nil" or type(data_value) == "nil" then return false end 
  
    if not playerData[player_element] then 
        playerData[player_element] = {} 
    end 
  
    playerData[player_element][data_key] = data_value 
    return true 
end 
  
function get_data(player_element, data_key) -- export this function 
    if type(player_element) == "nil" or type(data_key) == "nil" then return false end 
  
    return playerData[player_element] and playerData[player_element][data_key] or false 
end 
  
function delete_data() -- you have to delete the data when the player quits 
    playerData[source] = nil 
end 
addEventHandler('onClientPlayerQuit', root, delete_data) 
  

Link to comment
  
playerData = {} 
  
function set_data(player_element, data_key, data_value) -- export this function 
    if type(player_element) == "nil" or type(data_key) == "nil" or type(data_value) == "nil" then return false end 
  
    if not playerData[player_element] then 
        playerData[player_element] = {} 
    end 
  
    playerData[player_element][data_key] = data_value 
    return true 
end 
  
function get_data(player_element, data_key) -- export this function 
    if type(player_element) == "nil" or type(data_key) == "nil" then return false end 
  
    return playerData[player_element] and playerData[player_element][data_key] or false 
end 
  
function delete_data() -- you have to delete the data when the player quits 
    playerData[source] = nil 
end 
addEventHandler('onClientPlayerQuit', root, delete_data) 
  

That will not work, as onClientPlayerQuit is only triggered on remote clients. You have to make this system server side, and the use triggerServerEvent and triggerClientEvent to get the data client-side.

Link to comment
  • 2 weeks later...
How to use this clientside?

Storing such information on client-side is just a big NONO from me, once I had a player modify a variable client sided which caused a massive money glitch, apparently he made it using cheat engine. Not sure if he was bullshitting, it's been fixed or still working but hey, not a risk I'm willing to take.

Link to comment
  • 5 weeks later...
Thanks, good tutorial. So to understand correctly, there is absolutely no use for setElementData or getElementData?

Actually there is but depends on you when or how you use it. If you can do it without elemendata then it's really good but if you can't then it's ok to use it but try to use it in only extreme necessary.

Link to comment
Ok, thanks for tutorial. But.. Is this method really more useful than elementData? What about hackers? Can they hack client variable? Who use it instead of elementData? Sorry for my mistakes if they're.

I don't know about variables if they can hack it but if a hacker can get access to ftp then yes they can and about element data . It's better to check.

https://wiki.multitheftauto.com/wiki/On ... DataChange

Link to comment
  • Recently Browsing   0 members

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