Moderators IIYAMA Posted December 1, 2020 Moderators Share Posted December 1, 2020 (edited) 5 minutes ago, Turbesz said: uh that's true, my bad! now i don't get any errors or warnings, and the file was created, but does not insert the script any data to that file, i just get only "<root></root>" as a result in my .xml file You also have to apply my feedback from before that: 9 hours ago, IIYAMA said: That is why I gave you a function for reformatting: xml:xmlSaveData("save", reformatToArray(menteshez), false, true) (don't forget to modify the key) And after that it is variable debugging time. ---- + And you might also need to encode the account name, so that all special characters are escaped: https://wiki.multitheftauto.com/wiki/Base64Encode Edited December 1, 2020 by IIYAMA Link to comment
Turbesz Posted December 1, 2020 Author Share Posted December 1, 2020 7 minutes ago, IIYAMA said: You also have to apply my feedback from before that: (don't forget to modify the key) And after that it is variable debugging time. ---- + And you might also need to encode the account name, so that all special characters are escaped: https://wiki.multitheftauto.com/wiki/Base64Encode i tried to modify 'menteshez' to 'reformatToArray(menteshez)' but then i get this error: bad argument #1 to 'pairs' (table expected got nil) the error refers to this loop in 'reformatToArray' func: for k, data in pairs(theTable) do table.insert(array, data) end Link to comment
Moderators IIYAMA Posted December 1, 2020 Moderators Share Posted December 1, 2020 1 minute ago, Turbesz said: the error refers to this loop in 'reformatToArray' func: The input has to be a table: reformatToArray(menteshez) Not something else. Link to comment
Turbesz Posted December 1, 2020 Author Share Posted December 1, 2020 1 minute ago, IIYAMA said: The input has to be a table: reformatToArray(menteshez) Not something else. that's how I added: xml:xmlSaveData("save" .. accountName, reformatToArray(menteshez), false, true) but i get the error Link to comment
Moderators IIYAMA Posted December 1, 2020 Moderators Share Posted December 1, 2020 1 minute ago, Turbesz said: but i get the error Are you 100000% sure that `menteshez`contains a table? Link to comment
Turbesz Posted December 1, 2020 Author Share Posted December 1, 2020 11 minutes ago, IIYAMA said: Are you 100000% sure that `menteshez`contains a table? Um, yes(?) This is my current code of save func: local menteshez = {} local xml = exports.xmldata function teszt(thePlayer) local object=getElementsByType("object") local theAcc = getPlayerAccount(thePlayer) local accname = getAccountName(theAcc) local menteshez = xml:xmlLoadData("save" .. accname, true) if not menteshez then xml:xmlSaveData("save" .. accname, {}, false, true) return end for k, v in ipairs(object) do if getElementData(v,"owner") == accname then local x,y,z = getElementPosition(v) local id = getElementModel(v) local owner = getElementData(v,"owner") or getAccountName(theAcc) local int = getElementInterior(v) local dim = getElementDimension(v) local Rx,Ry,Rz = getElementRotation ( v ) outputChatBox("mentve") menteshez[v] = {x,y,z,id,owner,int,dim,Rx,Ry,Rz} setCustomData(thePlayer, "menteshez", menteshez, true) end end local menteshez = getCustomData(thePlayer, "menteshez", true) local account = getPlayerAccount(thePlayer) local accountName = getAccountName(account) xml:xmlSaveData("save" .. accountName, reformatToArray(menteshez), false, true) end addCommandHandler("save",teszt) Link to comment
Moderators IIYAMA Posted December 1, 2020 Moderators Share Posted December 1, 2020 1 minute ago, Turbesz said: Um, yes(?) Nope it did not. Let me simplify it a bit, remove all tools that you are currently not using, since we get no-were otherwise. local xml = exports.xmldata function teszt(thePlayer) local object=getElementsByType("object") local theAcc = getPlayerAccount(thePlayer) local accname = getAccountName(theAcc) local menteshez = {} -- reset and fill up again for k, v in ipairs(object) do if getElementData(v,"owner") == accname then local x,y,z = getElementPosition(v) local id = getElementModel(v) local owner = getElementData(v,"owner") or accname local int = getElementInterior(v) local dim = getElementDimension(v) local Rx,Ry,Rz = getElementRotation ( v ) menteshez[#menteshez + 1] = {x,y,z,id,owner,int,dim,Rx,Ry,Rz} end end xml:xmlSaveData("save" .. base64Encode(accname), menteshez, false, true) end addCommandHandler("save",teszt) Link to comment
Turbesz Posted December 2, 2020 Author Share Posted December 2, 2020 10 hours ago, IIYAMA said: Nope it did not. Let me simplify it a bit, remove all tools that you are currently not using, since we get no-were otherwise. local xml = exports.xmldata function teszt(thePlayer) local object=getElementsByType("object") local theAcc = getPlayerAccount(thePlayer) local accname = getAccountName(theAcc) local menteshez = {} -- reset and fill up again for k, v in ipairs(object) do if getElementData(v,"owner") == accname then local x,y,z = getElementPosition(v) local id = getElementModel(v) local owner = getElementData(v,"owner") or accname local int = getElementInterior(v) local dim = getElementDimension(v) local Rx,Ry,Rz = getElementRotation ( v ) menteshez[#menteshez + 1] = {x,y,z,id,owner,int,dim,Rx,Ry,Rz} end end xml:xmlSaveData("save" .. base64Encode(accname), menteshez, false, true) end addCommandHandler("save",teszt) Thank you, save and load working fine now Btw, can't that cause some issues that it's saving the XML file on the server and not on the players PC? Because over time it can be up to more than 1000, or 2000 XML file (if we look at that my server has ~4000 registered account, and every player can register only one) Link to comment
Moderators IIYAMA Posted December 2, 2020 Moderators Share Posted December 2, 2020 (edited) 1 hour ago, Turbesz said: Btw, can't that cause some issues that it's saving the XML file on the server and not on the players PC? Because over time it can be up to more than 1000, or 2000 XML file (if we look at that my server has ~4000 registered account, and every player can register only one) That can become an issue, here is a list that current method is lacking: - Not able to use a-sync + queueing - Not able to saving/loading data by using a different thread. - XML uses more filespace - There is no cleaner for older account data / There is no archive system that moves account data that isn't used for a while to a separated environment. You can also decide to backup the data on to the clients their pc's. That way you can freely clean data on the server when accounts aren't used for more than a year. The client has a copy of the data and can upload it back to the server when the server has deleted it. (but more sure that it can't be abused, by encrypting the file) Clientside only datastorage would be a better a better solution to be honest, but then again if the client crashes... auto save might be recommended. Edited December 2, 2020 by IIYAMA Link to comment
Turbesz Posted December 2, 2020 Author Share Posted December 2, 2020 7 minutes ago, IIYAMA said: You can also decide to backup the data on to the clients their pc's. How can this be done? Or how can i easily move the save and load funcs to client side? Link to comment
Moderators IIYAMA Posted December 2, 2020 Moderators Share Posted December 2, 2020 2 minutes ago, Turbesz said: Or how can i easily move the save and load funcs to client side? There is no `easy` in doing that. For the example code, I will be using my library, so that I do not have to write so much code. Feel free to replace them with trigger events. Note: I did not test this, but it will at least give you an idea how it could be done. Server local xml = exports.xmldata function teszt(thePlayer) local object=getElementsByType("object") local theAcc = getPlayerAccount(thePlayer) local accname = getAccountName(theAcc) local menteshez = {} -- reset and fill up again for k, v in ipairs(object) do if getElementData(v,"owner") == accname then local x,y,z = getElementPosition(v) local id = getElementModel(v) local owner = getElementData(v,"owner") or accname local int = getElementInterior(v) local dim = getElementDimension(v) local Rx,Ry,Rz = getElementRotation ( v ) menteshez[#menteshez + 1] = {x,y,z,id,owner,int,dim,Rx,Ry,Rz} end end callClientAwait(thePlayer, "saveMapData", "save" .. base64Encode(accname), menteshez, function (successState) outputChatBox(client, "Map data has been saved.") end) end addCommandHandler("save",teszt) function testLoad (thePlayer) local theAcc = getPlayerAccount(thePlayer) local accname = getAccountName(theAcc) callClientAwait(thePlayer, "loadMapData", "save" .. base64Encode(accname), menteshez, function (data) outputChatBox(client, "Map data is here available, if it has been saved before") end) end addCommandHandler("load",testLoad) Client local xml = exports.xmldata function saveMapData (fileName, data) return xml:xmlSaveData(fileName, data, true, false, true) end function loadMapData (fileName) return xml:xmlLoadData ( fileName, true, true) end Link to comment
Turbesz Posted December 2, 2020 Author Share Posted December 2, 2020 24 minutes ago, IIYAMA said: There is no `easy` in doing that. For the example code, I will be using my library, so that I do not have to write so much code. Feel free to replace them with trigger events. Note: I did not test this, but it will at least give you an idea how it could be done. Server local xml = exports.xmldata function teszt(thePlayer) local object=getElementsByType("object") local theAcc = getPlayerAccount(thePlayer) local accname = getAccountName(theAcc) local menteshez = {} -- reset and fill up again for k, v in ipairs(object) do if getElementData(v,"owner") == accname then local x,y,z = getElementPosition(v) local id = getElementModel(v) local owner = getElementData(v,"owner") or accname local int = getElementInterior(v) local dim = getElementDimension(v) local Rx,Ry,Rz = getElementRotation ( v ) menteshez[#menteshez + 1] = {x,y,z,id,owner,int,dim,Rx,Ry,Rz} end end callClientAwait(thePlayer, "saveMapData", "save" .. base64Encode(accname), menteshez, function (successState) outputChatBox(client, "Map data has been saved.") end) end addCommandHandler("save",teszt) function testLoad (thePlayer) local theAcc = getPlayerAccount(thePlayer) local accname = getAccountName(theAcc) callClientAwait(thePlayer, "loadMapData", "save" .. base64Encode(accname), menteshez, function (data) outputChatBox(client, "Map data is here available, if it has been saved before") end) end addCommandHandler("load",testLoad) Client local xml = exports.xmldata function saveMapData (fileName, data) return xml:xmlSaveData(fileName, data, true, false, true) end function loadMapData (fileName) return xml:xmlLoadData ( fileName, true, true) end okay, i replaced them with trigger events, and triggers are working fine but how can i get datas in load func? function testLoad (thePlayer) local theAcc = getPlayerAccount(thePlayer) local accname = getAccountName(theAcc) triggerClientEvent(thePlayer,"sbetolt", thePlayer, "save"..base64Encode(accname), menteshez) end addCommandHandler("load",testLoad) Link to comment
Moderators IIYAMA Posted December 2, 2020 Moderators Share Posted December 2, 2020 2 minutes ago, Turbesz said: but how can i get datas in load func? By keeping a function alive within the testLoad function, until the message is send back. And how do you do that? Well, you can look at the source code of my library and see if you could replicate a part of it. Or just use the library. Or you can also not do it and return it in to a different function, that would be the easiest way without library. Link to comment
Turbesz Posted December 2, 2020 Author Share Posted December 2, 2020 37 minutes ago, IIYAMA said: By keeping a function alive within the testLoad function, until the message is send back. And how do you do that? Well, you can look at the source code of my library and see if you could replicate a part of it. Or just use the library. Or you can also not do it and return it in to a different function, that would be the easiest way without library. i tried make a new trigger to load from client to server, and then create the objects, but does not work server: function testLoad (thePlayer) local theAcc = getPlayerAccount(thePlayer) local accname = getAccountName(theAcc) triggerClientEvent(thePlayer,"sbetolt", thePlayer, "save"..base64Encode(accname), menteshez) end addCommandHandler("load",testLoad) function teszt2(thePlayer,x,y,z,id,owner,int,dim,Rx,Ry,Rz) local object=getElementsByType("object") local theAcc = getPlayerAccount(thePlayer) local accname = getAccountName(theAcc) for i,v in ipairs(getElementsByType("object")) do if getElementData(v,"owner") == owner then destroyElement(v) end end if owner == accname then id = id+1 local x, y, z = getElementPosition(thePlayer) local theAcc = getPlayerAccount(thePlayer) local accname = getAccountName(theAcc) targy = createObject(id, x, y,z) setElementData(targy, "owner", accname) setElementData(targy,"id",id) setElementInterior(targy,int) setElementDimension(targy,dim) setElementRotation(targy,Rx,Ry,Rz) setElementData(thePlayer,"torles",getElementData(targy,"id") or 0) outputChatBox("betöltve") end end addEvent("load2",true) addEventHandler("load2",root,teszt2) client: function loadMapData (fileName) local menteshez = xml:xmlLoadData ( fileName, true, true) for k, v in ipairs(menteshez) do --outputChatBox(v[1]) local x = v[1] local y = v[2] local z = v[3] local id = v[4] local owner = v[5] local int = v[6] local dim = v[7] local Rx = v[8] local Ry = v[9] local Rz = v[10] triggerServerEvent("load2",localPlayer,playerSource,x,y,z,id,owner,int,dim,Rx,Ry,Rz) end end addEvent("sbetolt",true) addEventHandler("sbetolt",root,loadMapData) what wrong? Link to comment
Moderators IIYAMA Posted December 2, 2020 Moderators Share Posted December 2, 2020 (edited) 8 minutes ago, Turbesz said: what wrong? Your code does this: Loop send over 1 object (network) delete all objects create 1 object send over 1 object (network) delete all objects (included the one you just created) create 1 object send over 1 object (network) delete all objects create 1 object etc. etc. etc. Just send over the whole menteshez table > loop, else you will also kill your network. Edited December 2, 2020 by IIYAMA Link to comment
Turbesz Posted December 2, 2020 Author Share Posted December 2, 2020 (edited) 7 minutes ago, IIYAMA said: Your code does this: Loop send over 1 object delete all objects create 1 object send over 1 object delete all objects (included the one you just created) create 1 object send over 1 object delete all objects create 1 object etc. etc. etc. Just send over the whole menteshez table > loop, else you will also kill your network. Um i send now the whole table, and i get these warnings: Bad argument @ 'getPlayerAccount' [Expected element at argument 1, got nil] Bad argument @ 'getAccountName' [Expected element at argument 1, got nil] client: function loadMapData (fileName) local menteshez = xml:xmlLoadData ( fileName, true, true) triggerServerEvent("load2",localPlayer,playerSource,menteshez) end addEvent("sbetolt",true) addEventHandler("sbetolt",root,loadMapData) server: function teszt2(thePlayer,menteshez) local account = getPlayerAccount(thePlayer) local accountName = getAccountName(account) local object=getElementsByType("object") local theAcc = getPlayerAccount(thePlayer) local accname = getAccountName(theAcc) for i,v in ipairs(getElementsByType("object")) do if getElementData(v,"owner") == accname then destroyElement(v) end end setTimer(function() for k, v in ipairs(menteshez) do if v[5] == accname then id = id+1 local x, y, z = getElementPosition(thePlayer) local theAcc = getPlayerAccount(thePlayer) local accname = getAccountName(theAcc) targy = createObject(v[4], v[1], v[2], v[3]) setElementData(targy, "owner", accname) setElementData(targy,"id",id) setElementInterior(targy,v[6]) setElementDimension(targy,v[7]) setElementRotation(targy,v[8],v[9],v[10]) setElementData(thePlayer,"torles",getElementData(targy,"id") or 0) outputChatBox("betöltve") end end end,500,1) end addEvent("load2",true) addEventHandler("load2",root,teszt2) why do i get those warnings? Edited December 2, 2020 by Turbesz Link to comment
Moderators IIYAMA Posted December 2, 2020 Moderators Share Posted December 2, 2020 1 minute ago, Turbesz said: playerSource playerSource does not exist. Use localPlayer instead. Link to comment
Turbesz Posted December 2, 2020 Author Share Posted December 2, 2020 1 hour ago, IIYAMA said: playerSource does not exist. Use localPlayer instead. if i use localPlayer, then the objects are visible to the local player only? Link to comment
Moderators IIYAMA Posted December 2, 2020 Moderators Share Posted December 2, 2020 (edited) 33 minutes ago, Turbesz said: if i use localPlayer, then the objects are visible to the local player only? no, If you only want to see your objects, I recommend to set all objects to another dimension than the players. And for every object you create: triggerClientEvent > Clientside: setElementDimension (to your own dimension) Edited December 2, 2020 by IIYAMA 1 Link to comment
Turbesz Posted December 3, 2020 Author Share Posted December 3, 2020 18 hours ago, IIYAMA said: no, If you only want to see your objects, I recommend to set all objects to another dimension than the players. And for every object you create: triggerClientEvent > Clientside: setElementDimension (to your own dimension) thank you very much for all the help, and your patience at least I just learned something new 1 Link to comment
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now