Jump to content

Search the Community

Showing results for tags 'tables'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Multi Theft Auto: San Andreas 1.x
    • Support for MTA:SA 1.x
    • User Guides
    • Open Source Contributors
    • Suggestions
    • Ban appeals
  • General MTA
    • News
    • Media
    • Site/Forum/Discord/Mantis/Wiki related
    • MTA Chat
    • Other languages
  • MTA Community
    • Scripting
    • Maps
    • Resources
    • Other Creations & GTA modding
    • Competitive gameplay
    • Servers
  • Other
    • General
    • Multi Theft Auto 0.5r2
    • Third party GTA mods
  • Archive
    • Archived Items
    • Trash

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


About Me


Member Title


Gang


Location


Occupation


Interests

Found 12 results

  1. Hey. After two years of scripting i've decided to shared a bit of my knowledge with community, which i've learnt - special thanks goes to @IIYAMA for teaching me trigger and tables related stuff. Therefore i present you: Custom element data It is data system based on Lua tables and trigger(Server)(Client)Event, which was created and released back in 2020, over few months received a significant updates which introduced useful client-side features and not-so complex logic to fully control data flow through server-side. I do plan to actively develop it, mainly in improving performance which is already great, but also introducing new features. But before going forward... Let's do some comparision to element data. Color of divbox explains whether is a pro, con, or neutral difference. Tables are resource dependent, that means you cannot get table and it's contents in other resource without special steps (using exports), while Element data is resource independent, it's possible to get data from any resource. Restarting resource causes table to lost stored data, while Element data keeps it, until element gets destroyed. Tables are considerably faster, while Element data is slower. After acknowledging differences you might say that advantage is taken by element data system because of resource independency, but in later part of tutorial i will point out and describe two scripted features in this data system (they aren't implemented in element data) which are important during sending anything to players, afromentioned features are heavily affecting both client and server performance. Source code Latest version is available on GitHub. Syntax Client: mixed getCustomData(mixed pElement, string pKey, string pType) mixed getElementsByKey(string pKey, mixed pValue, string pType, bool pMultipleResults) bool setCustomData(mixed pElement, string pKey, mixed pValue, string pType, mixed pEvent, mixed pSyncer) bool addDataHandler(mixed pElementTypes, mixed pTypes, mixed pKeys, function pFunction, mixed pEvent) Server: mixed getCustomData(mixed pElement, string pKey, string pType, mixed pRequester) mixed getElementsByKey(string pKey, mixed pValue, string pType, mixed pRequester, bool pMultipleResults) bool setCustomData(mixed pElement, string pKey, mixed pValue, string pType, mixed pReceivers, mixed pSyncer, mixed pEvent, mixed pBuffer, int pTimeout) bool forceBatchDataSync(mixed pQueue, mixed pType) Function acceptable types of data, returns and behaviours: Client: mixed getCustomData(mixed pElement, mixed pKey, string pType) pElement: element or a string which holds data pack pKey: string which holds data under certain name or nil pType: string which defines data type, can be "local", "synced" or "private" nil: on failure, or when certain key it's not existing table: with all data, on success, when pKey is equal to nil anything else: on success, this can be a string, number, table, bool This function is used for retrieving data stored under element, you can retrieve certain key or whole data. mixed getElementsByKey(string pKey, mixed pValue, string pType, bool pMultipleResults) pKey: string, which defines a key used by element pValue: string, bool, number, userdata in case if you want filter by certain value, or false/nil if you don't need value to be matching pType: string, which defines data types, can be "local", "synced" or "private" pMultipleResults: bool, which decides if you want get more than one element using certain data, true for multiple elements, false for single element false: on failure table: empty on failure, and containing element(s) on success - only if pMultipleResults is enabled element: on success This function allows you to get a element(s) which contains certain data key, if required you can enable matching key to specified value. bool setCustomData(mixed pElement, string pKey, mixed pValue, string pType, mixed pEvent, mixed pSyncer) pElement: element or string, which you wish to set data pKey: string, which defines a key used by element pValue: string, boolean, number, userdata or table which will be set as key value pType: string, which defines type of data, can be "local", "synced" or "private" pEvent: string or false/nil, defining which server event caused data to change pSyncer: element or false/nil, responsible for data syncing false: on failure true: on success This function allows you to set a data for element, with certain key, value and data type on client-side with some extras. It doesn't force sync due of security reasons. Server: mixed getCustomData(mixed pElement, string pKey, string pType, element pRequester) pElement: element or a string which holds data pack pKey: string which holds data under certain name or nil pType: string which defines data type, can be "local", "synced" or "private" pRequester: player or nil/false, which requests data - ignored when pType isn't equal to "private" nil: on failure, or when certain key it's not existing table: with all data, on success, when pKey is equal to nil anything else: on success, this can be a string, number, table, bool This function is used for retrieving data stored under element, you can retrieve certain key or whole data. mixed getElementsByKey(string pKey, mixed pValue, string pType, mixed pRequester, bool pMultipleResults) pKey: string, which defines a key used by element pValue: string, bool, number, userdata in case if you want filter by certain value, or false/nil if you don't need value to be matching pType: string, which defines data types, can be "local", "synced" or "private" pRequester: player or nil/false, which requests data - ignored when pType isn't equal to "private" pMultipleResults: bool, which decides if you want get more than one element using certain data, true for multiple elements, false for single element false: on failure table: on success/failure, when pMultipleResults is enabled element: on success, when pMultipleResults is disabled This function allows you to get a element(s) which contains certain data key, if required you can enable matching key to specified value. bool setCustomData(mixed pElement, string pKey, mixed pValue, string pType, mixed pReceivers, mixed pSyncer, mixed pEvent, mixed pBuffer, int pTimeout) pElement: element or string, which you wish to set data pKey: string, which defines a key used by element pValue: string, boolean, number, userdata or table which will be set as key value pType: string, which defines type of data, can be "local", "synced" or "private" pReceivers: player or table with players or nil/false, specifies which players will receive data, ignored if pType isn't equal to "private" pSyncer: element or false/nil, responsible for data syncing pEvent: string or false/nil, defining which server event caused data to change pBuffer: string or false/nil, if string passed it will enable batch or buffer functionality (see below for explanation) pTimeout: integer or false/nil, if it's == -1 then server will use batch, if it's >= 0 server will use buffer, ignored if pBuffer isn't enabled true: on success false: on failure This function allows you to set a data for element, with certain key, value and data type with some extras on server-side. bool forceBatchDataSync(mixed pQueue, mixed pType) pQueue: string/false/nil, when string is passed server will search for specified queue to sync, otherwise it will select all queues, not dependent on it's name pType: string/false/nil, when string is passed server will search for certain type of queue, can be "synced" or "private", otherwise it will select all queues, not dependent on type true: on success false: on failure This function allows you to optimise data flow by collecting pack of data and sending it with merged trigger, further explanations available in later part of tutorial. After reading detailed syntax, it's time to move on next topic and understand server-side data validation. Often skipped by majority of scripters, even though it's a very important thing. Server-side data validation It's a process when server validates data sent from client, if you aren't familiar with it, it might sound difficult, but in reality it isn't. Validation is made in server event function handler, via simple if conditions, it ensures that client sent valid data which later will be used by server. While MTA:SA anticheat is one of strongest ones and you can rely on it in most cases, it is scripter task to make sure that server-side logic is also scripted well, to completely eliminate possibility of harming your server by client sending fake (malicious variant), or incorrect data (default variant). Yes, even default client could be harmful, even unintentionally - let's take for a example ping as a main factor, due of delay between certain player and server, data for player A might have different value than for player B. What to do in that case? Answer is simple, get data value from server. Instead of: Client -> Request data change with player value -> Server -> Process it Do: Client -> Request data change -> Server -> Check for client variable -> Get value from server -> Process it But, what if (MTA) function isn't available server-side? Then you need use client for returning it and sending to server, e.g collision checks. While this might feels insecure you can (and should) always check whether type of data passed is valid. Special Lua function will be irreplaceable here. local clientData = {} local typeOfData = type(clientData) print(typeOfData) -- "table" You might wonder what is client variable? Shortly, it's a special global variable which is used in server events. This wiki article explains that when we want to receive a player who called the event, we should use client instead of source. Why? Because: Any player with access to runcode/Lua injector can pass another player which might have admin permissions. This will result in executing server code even though it shouldn't happen by default. Aforementioned source might be not an actual player, because you can pass pretty much every element e.g root, resourceRoot. Perhaps you already know that nothing is 100% safe? That is accurate sentence, but when it comes to scripted server-side data validation - you can't bypass it, if it's correctly written. Well, probably you could do that, but you'd need to access server itself, however if it'd happen then it's game over. Example of validation is available here, since i do not pass any data from player side, if client then condition with parent check is sufficient. Is there anything else you can do to protect your server more? Actually yes. Since trigger(Client)ServerEvent is a function which calls a counter-side functions (and pass data to it) it's affecting traffic and CPU. It should be well maintained (element data isn't exception). If you do not understand events then feel free to check IIYAMA's events tutorial, while he explains basics i will be expanding this by showing how you can reduce calls and optimise passing data between sides, because triggers are main component of my data system. We'll be moving step by step from easier to a bit harder topics, here comes our first step. Client-side delays As i mentioned before that triggers should be well maintained, we should add some delay for client-side, which will be a obstacle for someone, who'd try to spam server with triggerServerEvent calls. It's easily achievable with getTickCount function. --[[ /*************************************************** Client ***************************************************\ ]] local dataToPass = "string" -- data we want pass to server local lastTriggerCall = getTickCount() -- store last trigger call local delayValue = 500 -- ms function triggerEventByCommand() if getTickCount() - lastTriggerCall >= delayValue then -- if delay has passed triggerServerEvent("onServerEvent", localPlayer, dataToPass) -- trigger server event lastTriggerCall = getTickCount() -- update last trigger call end end addCommandHandler("trigger", triggerEventByCommand) --[[ /*************************************************** Server ***************************************************\ ]] function onServerEvent(pData) if client then -- check whether client exists (just for sake) local isString = type(pData) == "string" -- make sure that is string if isString then -- if so local validLength = #pData <= 4 -- check whether is less or equal to 4 chars if validLength then -- if so print("The checks have passed... Processing code.") end end end end addEvent("onServerEvent", true) addEventHandler("onServerEvent", root, onServerEvent) You can also implement same delay checks on server-side, but i believe that client-side should be sufficient. Selecting lowest possible source element for trigger Probably many of you (including myself), have passed root or resourceRoot as a 2-nd/3-rd argument in function: triggerServerEvent ( string event, element theElement, [arguments...] ) triggerClientEvent ( [ table/element sendTo = getRootElement(), ] string name, element sourceElement [, arguments... ] ) That shouldn't be done, unless you know what you are doing. Because of CPU impact which wiki states on client and server variation. Most of people (once again, including myself) misunderstood this note. Which is not about attaching custom events to root, but about passing it to trigger itself. While resourceRoot is lower than root in element tree, you should use localPlayer instead - on client-side. When it comes to server-side you can also use same player which triggered certain event, as for example this is handled similarly in server-side part of custom data. But i do also check if sourceElement (pSyncer) is actual element to avoid warnings. We could say that attachedTo is some kind of filter which checks if sourceElement which triggered certain event is allowed (depending on it's position in element tree) to process the function. But you've should already know that if you read events tutorial. addEventHandler ( string eventName, element attachedTo, function handlerFunction [, bool propagate = true, string priority = "normal" ] ) Optimising data flow First and foremost my favourite way - batching. What is it, why and when you should use it? Batching is a process when you place data in certain queue, this data however isn't synced instantly, it's stored at server-side in additional table, till force sync will be called (forceBatchDataSync). This is different scenario when we compare it to element data, while custom data with batching enabled sends pack of data in 1 trigger (1 queue = 1 trigger), element data sends each (!) data separately. In other words, you can do x100 setCustomData and they will be sent with 1 trigger, while x100 setElementData waste a lot of traffic and CPU by doing that separately. Generally you should use it always when you set more than one data. Practical example, setting data upon spawning vehicle: local dataTable = {{"Data 1", "Value 1"}, {"Data 2", "Value 2"}} function spawnInfernus(pPlayer) local playerType = getElementType(pPlayer) == "player" -- check if it's player if playerType then -- if so local dataPack = false -- store it for later reuse local dataName = false -- store it for later reuse local dataValue = false -- store it for later reuse local playerX, playerY, playerZ = getElementPosition(pPlayer) -- get player position local infernusElement = createVehicle(411, playerX + 5, playerY, playerZ) -- create vehicle for dataID = 1, #dataTable do -- loop through data table dataPack = dataTable[dataID] -- get data at certain index dataName = dataPack[1] -- get data name dataValue = dataPack[2] -- get data value setCustomData(infernusElement, dataName, dataValue, "synced", false, pPlayer, "spawn_infernus", "queue_spawn_infernus", -1) -- set data for vehicle, with specified name and value, with type "synced", receivers false, pPlayer as syncer, "spawn_infernus" as event name and queue "queue_spawn_infernus" with timeout -1 (batch) end forceBatchDataSync("queue_spawn_infernus", "synced") -- force "queue_spawn_infernus" to sync from "synced" type end end addCommandHandler("spawninfernus", spawnInfernus) Second way is using buffer, the difference between previous technique is that instead awaiting synchronization we create a timer which collects pack of data with given delay. Using it also results in data reduction, because calls are reduced. You can apply it to data which is being changed by multiple players, or in different scenario where you'd want to collect various data and sync them in same queue, i'll also include handy code by @IIYAMA which would help you adjust your delay. local sendingDelay = 100 -- ms local fps = 60 local timeSlice = 1000/fps local dataReduction = sendingDelay/timeSlice print("~"..(dataReduction - 1).." x times LESS per "..sendingDelay.." ms.") An simple buffer example: function bufferExample(pPlayer) local playerType = getElementType(pPlayer) == "player" -- check if it's player if playerType then -- if so local bufferChanges = getCustomData(pPlayer, "Buffer changes", "private", pPlayer) or 0 -- get changes for this data setCustomData(pPlayer, "Buffer changes", bufferChanges + 1, "private", pPlayer, pPlayer, "buffer_change", "queue_buffer_change", 3000) bufferChanges = getCustomData(pPlayer, "Buffer changes", "private", pPlayer) -- get once again changes for this data outputChatBox("Data has changed for player: "..getPlayerName(pPlayer).." -> Buffer changes: "..bufferChanges) end end addCommandHandler("buffertest", bufferExample) Data handlers - awesome addition Meet data handlers, equivalent of onClientElementDataChange, those are your own custom functions which could be attached to certain element, data type, key, and event. Once the function is triggered, it provides set of useful parameters which could be used inside function scope, this is another feature which makes this data system powerful. For examples, we'll refer to previously set data with batch and buffer. function onClientInternusDataChange(pElement, pKey, pType, pOldValue, pNewValue, pEvent, pSyncer) if pSyncer == localPlayer then print("I am syncer of this data! At event: "..tostring(pEvent)) end print("Key: "..pKey.." ("..pType..") has changed: "..tostring(pOldValue).." -> "..tostring(pNewValue)) end addDataHandler("vehicle", {}, {}, onClientInternusDataChange, "spawn_infernus") -- requirements to trigger function: element needs to be vehicle, any data type and key name can trigger this, event needs to be equal to "spawn_infernus" --[[ /*************************************************** ***************************************************\ ]] function onClientBufferChange(pElement, pKey, pType, pOldValue, pNewValue, pEvent, pSyncer) if pSyncer == localPlayer then print("I am syncer of this data! At event: "..tostring(pEvent)) end print("Key: "..pKey.." ("..pType..") has changed: "..tostring(pOldValue).." -> "..tostring(pNewValue)) end addDataHandler("player", "private", "Buffer changes", onClientBufferChange, "buffer_change") -- requirements to trigger function: element needs to be player, data type == "private" and key name == "Buffer changes" can trigger this, event needs to be equal to "buffer_change" How to use it? Download latest version, and add it directly to your gamemode, to use functions directly or leave it as a separate resource to use functions with exports. First option gives best performance, and allows you to use data handlers. Make sure that player parent isn't changed, in order for server-side to work correctly. Efficiency test Element data & Custom data in 100000 iterations (client-side, sync off) Set local data: ED: 31 ms < CD: 17 ms Get local data by key: ED: 19 ms < CD: 9 ms Get all local data: ED: n/a < CD: 10 ms
  2. Hello, i am trying to create a vehicle loader script that loads all the vehicle models from a Lua table instead of adding them manually one by one but i am getting "error unexpected symbol near .." Now i know my syntax is wrong in line 18 and 20 where i try to create a variable based from the name index on the Lua table but i don't know how to accomplish it. Any help would be appreciated. Thanks local vehiclesFileNames = { AE86 = 589, ToyotaSupra = 559, ToyotaAltezza = 402, Datsun240Z = 475, Nissan180SX = 602, SilviaS13 = 401, SilviaS14 = 576, SilviaS15 = 474, Skyline2000 = 535, SkylineR32 = 555, SkylineR34 = 562, SkylineGTR = 558, } function loadVehicleFiles() for name, id in ipairs(vehiclesFileNames) do local name..txd = engineLoadTXD ( "Cars/"..name.."/"..name..".txd") engineImportTXD ( name..txd, id ) local name..dff = engineLoadDFF ( "Cars/"..name.."/"..name..".dff") engineReplaceModel ( name..dff, id ) outputDebugString("name = "..name.." | id = "..id..".") end end addEventHandler("onClientResourceStart", resourceRoot, loadVehicleFiles())
  3. Hi there. Currently I'm writing large gamemode with smart NPCs and other features that needs a lot of data to be synchronized to all clients. Data update will be very short, I mean a lot of data needs to by sync every ~100ms. Should I use Element Data or may be I need to use one table with data every time sending to all clients? Please give me an advice. Because my current code seems to be really not good for server bandwidth. Also can somebody tell me how to track current bandwidth when scripts running? Thanks.
  4. client: local Admins = {} addEvent("updateAdmins",true) addEventHandler("updateAdmins",root, function(t) Admins = t end) function isPlayerAdmin(player) if(Admins[player]) then return true end return false end function asdi() for k,v in ipairs(Admins) do outputChatBox(k) end end addCommandHandler("asd",asdi) server: local Admins = {} function isPlayerAdmin(player) if(Admins[player]) then return true end return false end addEventHandler("onPlayerLogin",root, function() if isObjectInACLGroup ( "user." .. getAccountName ( getPlayerAccount ( source ) ), aclGetGroup ( "Admin" ))then if not(Admins[source])then Admins[source]= source triggerClientEvent("updateAdmins",source,Admins) end end end) addEventHandler("onPlayerQuit",root, function() if(Admins[source])then Admins[source]= nil triggerClientEvent("updateAdmins",source,Admins) end end) No errors, no warnings... What wrong?
  5. if i create a table, and i insert datas with table.insert, the datas are deleted when i reconnect.. why? how to save datas? sorry for my terrible english :ss
  6. APPENDIX DATA SYNCHRONIZATION. What is it? MTA's synchronization methods. Optimization tips. DATA SYNCHRONIZATION 1. What is it? Since unmemorable times humanity have faced problems caused mainly due to the storage of different ideas in almost each human. But thank God, machines storage methods are different and they have the possibility of having stored the same values in more than 100 machines. Well this is great, but those values must be set by someone, and here's where the server-side and client-side can be used as example of data synchronization. The server-side store's all the values given by each client-side and give's back those values to the all the client-sides ending up into something like this ( Figure 1 ). This is a way to get the same data in all the client-side, but there's also other methods well known like P2P. Figure 1. 2. MTA's synchronization methods. Since data sync it's a base element of every multiplayer game or mod, MTA is not an exception. That's why MTA scripting interface gives us two core ways to sync the server data with the client data or client data with server data. Well this two methods are the following one's. Element Data, it consists of assigning values to an element that are being stored under a key ( the key usually being a string like "health" ). This way is being used by a great amount of scripters in MTA because it's easy to use. But there are also negative points if this way is not being used properly like saving small amount of data in just one key and syncing it with the server or client's. An example of it would be: [[--CLIENT.LUA--]] local value = 0 local function handleStart() value = getTickCount() -- WE GET THE TIME THE SERVER HAS BEEN WORKING WHEN THE RESOURCE START setElementData( localPlayer, "start_tick", value, true ) -- WE SAVE THE 'value' VARIABLE INTO THE 'localPlayer' ELEMENT WITHIN THE KEY 'start_tick' AND WE SYNC IT TO GET THIS DATA TO THE SERVER. end addEventHandler( "onClientResourceStart", getResourceRootElement( getThisResource() ), handleStart ) [[--SERVER.LUA--]] local function handleCMD( thePlayer ) local mineTick = getElementData( thePlayer, "start_tick" ) -- WE RETRIEVE THE DATA, THAT HAS BEEN SAVED INTO 'thePlayer' DATA. local resultTick = getTickCount() - mineTick -- GET HOW MUCH TIME HAS PASSED SINCE THE RESOURCE STARTED FOR THE PLAYER outputChatBox( resultTick, thePlayer ) -- PRINT INTO THE CHAT THE RESULT end addCommandHandler( "mytime", handleCMD ) -- IN CASE YOU WANT TO TRY IT SAVE THE CODE WITH THE NAME MARKED ABOVE THEM. [[--META.XML--]] <meta> <script src="server.lua" type="server"/> <script src="client.lua" type="client"/> </meta> Events, this method is the one that elementData's one bases on, which means this is a 'rawer' method which can also be faster than elementData if it's being used efficiently. An event is just a message that's being send to one or various systems, if these systems handle the message then when the message is sent to the system there's a trigger which calls the functions that are defined like a reaction to that message that has been sent. It's pretty easy to understand, just think of this. You say hello to someone, the message in this case is 'Hello' and the system where is pointed to mainly is the person, the person gets the message and handles it by calling some cognitive functions, these functions at their time trigger another message as result which in the most common case would be 'Hello' or just a strange face motion because he or she doesn't know you. Maybe you will ask yourself about what does a hello to someone have to do with Events in MTA. Well let's convert the situation above into script. We've got to define first the message by using addEvent( "Hello" ), good we have defined our message, but if we stop here then we have made some useless stuff that's not going to be used ever, that's why we have to use this message somewhere and here is when we simulate the action of saying something the message by using triggerEvent( "Hello" ) but... wait who's supposed to say the message? Let's make it look like the localPlayer was saying the message so it would be like triggerEvent( "Hello", localPlayer ), okay we have said the message but do we talk alone? Maybe but it's not pretty normal, so we must find a receptor which in this case will be a ped so we add the a ped to the game by using createPed( 0, 105, 20, 5.5 ) supposing we are located in the position 104, 20, 5.5. Okay we have the receptor now but it won't answer to our message so let's obligate him to answer us by adding a handler for the message to the ped like this addEventHandler( "Hello", thePed ), okay but this way it will do the same as we wouldn't have used addEventHandler that's why we need to pass also a function to call like an argument which in this case is going to be called 'answerToHello' and we would finish up with addEventHandler( "Hello", thePed, answerToHello ). All this and little bit more of code below for simulating an answer to hello from a person in a non-realistic way. [[--CLIENT--]] -- EVENTS addEvent( "Hello", false ) -- LET'S MAKE IT LIKE JUST THE CLIENT CAN TRIGGER IT SO WE MAKE SURE JUST WE ARE GOING TO TALK TO THE PED -- VARIABLES local thePed = createPed( 0, 105, 20, 5.5 ) -- WE ADD THE PED SO WE DON'T FEEL LONELY -- FUNCTIONS -- SAY HELLO local function sayHello() -- THIS FUNCTION WILL BE USED TO SEND UP THE MESSAGE TO THE PED triggerEvent( "Hello", thePed ) -- WE SAY HELLO TO THE PED end -- ANSWER local function answerToHello() -- WE DEFINE THE MESSAGE HANDLER SO WE MAKE SURE THE PED ANSWERS TO US outputChatBox( "Hello to you too!" ) -- THE PED GET'S THE MESSAGE AND GIVES US BACK A MESSAGE THAT WE CAN CHECK INTO THE CHAT. end -- COMMANDS addCommandHandler( "sayit", sayHello ) -- WE'VE GOT TO SAY SOMEHOW HELLO TO THE PED SO LET'S USE A COMMAND -- EVENT HANDLERS addEventHandler( "Hello", thePed, answerToHello ) 3. Optimization tips. Well both methods can be used in large development but there are some tips you can follow to make sure your script will run in an efficient way. Pack reasonable amount of data into one's element data key, don't save values like ( health, armor, money ) into different keys, compress them into an only one by using tables, by using this method we pass 3 values packed in one sync meanwhile separating each value with one key creates upon 3 different syncs which would end up in a greater amount of packets sent between the server and the client. This tip can be used for both methods [ elementData, Events ]. local basic_data = { health = 100, armor = 100, money = 100 } -- COMPRESSED PLAYER INFO setElementData( thePlayer, "main", basic_data, true ) -- WE GIVE 3 DIFFERENT VALUES TO 'main' KEY BY USING JUST A VARIABLE THAT'S A TABLE 'basic_data' triggerClientEvent( thePlayer, "onSync", thePlayer, basic_data ) -- WE SEND A MESSAGE TO THE CLIENT IN ORDER TO MAKE IT SYNC THE DATA OF THE PLAYER TO THE ONE THAT IS BEING STORED IN THE SERVER Lua is a garbage collection language so the reduce the amount of global variables as much as possible in order to make it run faster. Hope you enjoyed the tutorial, if you have any question just feel free to ask it in this post or by PM, Skype ( killer.68x ) or Email ( [email protected] ) or Discord ( Simple01#1106 ).
  7. كيف اقدر اجيب قيم الجدول من الاول للنهاية ولما قيم الجدول توصل للنهاية تنعاد من اول مثلا مسوي مود يربح جوائز مثلا اول مرة يشوف اول قيمة بالجدول وياخذها بعدين لما يجي يشتري ثاني يجيب القيمة الثانية وإلخ لين يوصل للنهاية بعدين يعيد من اول
  8. Hi everyone, I am facing a small problem with tables, well I am not sure how to add something to a table by using addCommandHandler. Like, if this is my table local random = { -- x = y ['a'] = 'Two', ['b'] = 'One', ['c'] = 'Ten', } Then how can I add another line to this table by a command (addCommandHandler) For example If the command is "/add Q A" ~~~ ("/add d six") then it should add a new line to the table like -> local random = { ['a'] = 'Two', ['b'] = 'One', ['c'] = 'Ten', ['d'] = 'Six', } On the other hand, I have something like this in my mind for the command: local random = { -- x = y ['a'] = 'Two', ['b'] = 'One', ['c'] = 'Ten', ['d'] = 'Six', } function addabcdtotable(client, commandName, x, y) if (blabla ~= "18") then return false end if (x) then return false end --(Checks if (['d'] = 'Six',) already exists, if yes then it will simply return {where x = column and y = column-2}) Add-> (x,y) --(This will add {['d'] = 'Six',} to the table) end addCommandHandler("add", addabcdtotable) --For removing a line from table -> function removeabcdfromtable(client, commandName, x, y) if (blabla ~= "18") then return false end if (x) then --(Checks if (['d'] = 'Six',) already exists, if yes then it will be removed from the table {where x = column-1 and y = column-2) Remove-> (x, y) --(This will remove the whole line and fix the gap ['d'] = 'Six',) else return false end end end addCommandHandler("rem", removeabcdfromtable) -- NOW VERY IMPORTANT THE D IS ONLY THE EXAMPLE IT CAN BE ANYTHING LIKE (['ab'] = 'CD',) etc.. {X and Y is not the position please...}
  9. Приветствую всех. Уже давно не могу справится с одной проблемой. Схема такая: - Ресурс: vehicles - Ресурс: houses - Ресурс: businesses В каждом ресурсе есть своя глобальная таблица pl_vehs = {} houses = {} businesses = {} И проблема вот в чем, в ресурсе vehicles каждый игрок имеет 1-4 своих ячейки в таблице pl_vehs в таблицу pl_vehs = {} заносятся авто следующим образом: к примеру спавн: pl_vehs[carID] = createVehicle(tonumber(car_Info["model"]), x, y, z, 0, 0, rZ-90) Всё вроде хорошо, дальше задаётся элемент дата, играется прекрасно. Но вот спустя какое-то время при онлайне 100-300 чел. начинается следующая проблема: человек спавнит машину, и вместо неё телепортируется либо рандомный обьект маппинга, либо элемент (в виде пикапа) из houses[] или из bussineses[] Короче говоря функция createVehicle каким-то х... телепортирует уже существующий на сервере элемент, причем даже иногда игрока телепортирует. Как это возможно?! В дебаге и консоли никаких ошибок!(
  10. Alright, I've got the following JSON saved in my mysql: [ [ { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 } ], [ { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 } ] , [ { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 }, { "lastPlayed": 0, "experience": 0, "money": 20 } ] ] It are 6 elements inside 3 elements. Each of these 3 elements holds 6x the { "lastPlayed": 0, "experience": 0, "money": 20 }. Whenever I'm using fromJSON, it's returning the wrong information when I'm trying to access the first element out of the second collection. The code I'm using is as following: local saveData = fromJSON ( data [ 1 ].saves ); outputChatBox ( #saveData ); -- returns 6 elements (incorrect) outputChatBox ( #saveData [ 2 ] ); -- returns 3 properties (correct) outputChatBox ( tostring ( saveData [ 2 ] [ 1 ] ) ); -- returns nil The JSON is valid, I can use it in different languages too and every parser says it's correct. I'm starting to think that fromJSON is returning just the first collection instead of all 3. Has anyone encountered this problem? I'm not really a fan of putting it all into 1 collection, it's preventing me from adding more and more data later on.
  11. Hey, so, I would like to make a GTA like (it sounds strange) notification system, something like you can see in every singleplayer GTA, the upper left hand corner box notifications: I have the base script, everything renders and works fine, but I would like to make a special "timer" for it, which works like the following way: the longer the text is, the longer the notification lasts. This is one thing I would like to make, the other thing is: how is it possibble to make an export function for this, so I can make notifications from other resources with the text I give in the resource I'm calling it back from. I don't really understand tables and loops, I would be so happy if somebody could help me! I hope you can understand me, and what I am trying to do and explain, thanks for the help in advance! local displayWidth, displayHeight = guiGetScreenSize(); local borderDistance = 20 local tipBox = { string = "asfasfasafaasfasfasafsafsfasfasafsasfasfafsafssafasfsdwadsadwqwdasdasfasasafsaf" } local boxX, boxY = borderDistance * displayWidth / displayWidth, borderDistance * displayHeight / displayHeight local boxPadding = 10 local lineHeight = dxGetFontHeight( 1, "default-bold" ) local minimumWidth = 350 local offsetWidth = 25 addEventHandler( "onClientRender", root, function( ) local lines = 0 local wordbreak = false local lineWidth = dxGetTextWidth( tipBox.string, 1, "default-bold" ) while ( lineWidth + offsetWidth > minimumWidth ) do lineWidth = lineWidth - minimumWidth lines = lines + 1 wordbreak = true end local boxWidth, boxHeight = minimumWidth + ( boxPadding * 3 ), ( lineHeight * ( lines + 1 ) ) + ( boxPadding * 2 ) dxDrawRectangle( boxX, boxY, boxWidth, boxHeight, tocolor( 0, 0, 0, 180 ), true ) dxDrawRectangle( boxX, boxY+boxHeight, boxWidth, 4, tocolor( 200, 0, 100, 255 ), true ) local textX, textY = boxX + boxPadding, boxY + boxPadding local textWidth, textHeight = textX + minimumWidth + boxPadding, textY + lineHeight + boxPadding dxDrawText( tipBox.string, textX, textY, textWidth, textHeight, tocolor( 255, 255, 255, 255 ), 1, "default-bold", "left", "top", false, wordbreak, true ) end )
  12. السلام عليكم اليوم شفت واحد اسمه احمد 09 مشارك وكاتب local Buses = { {ID = 437, PosX = 0, PosY = 0, PosZ = 0, Freeze = true}, {ID = 431, PosX = 10, PosY = 0, PosZ = 0, Freeze = true} } addEventHandler("onResourceStart", resourceRoot, function() for _,v in ipairs(Buses) do local Bus = createVehicle(v["ID"], v["PosX"], v["PosY"], v["PosZ"]) setElementFrozen(Bus, v["Freeze"]) end end) أبي اعرف وش هي الجداول + وش الي بالسطر 8 وليش كتب 2 إند بالأخير ( 11 + 12 ) س
×
×
  • Create New...