Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 28/07/24 in all areas

  1. Normally you use a table. But if you aren't able to work with those yet. Here is a very dirty way of doing it: for index=1,50 do guiSetVisible ( _G["button_"..index.."_img"], true ) end The _G accesses global variables. (variables without the keyword local in front of them) It is not recommended to use this method more than once. It is purely to demonstrate how to do it your way. But not the way Lua intended it to be used For working with tables, please take a look at:
    2 points
  2. If you handle the outputChatBox messages in 1 resource or script, you can simply override the outputChatBox function, redefining to do your color changes and magic. -- serverside outputChatBoxOriginal = outputChatBox outputChatBox = function(text, element, r, g, b, colorCoded) -- here you can change text variable return outputChatBoxOriginal(text, element, r, g, b, colorCoded) end
    1 point
  3. Resource script bundler In some cases you want to intergrade one resource into another as if it is a kind of module. Currently we do not have many ways to create re-useable code. But in this example/snippet I will explain how to bundle resource files. You could in theory use this as a base to make your own resource importable like DGS DX Library that does. But importing is beyond the scope of this topic. Side note: This tutorial is created for programmers in mind. Some basic knowledge about Lua is required. Some comment lines starting with ---@, those are type annotations. Here you can find more information about those. I could have removed them, but I noticed that even without Lua Language Server some people still find them helpful. Only scripts are copied in this bundler. The other files have to be moved manually. While using the bundler: you need to have the debug console open, else you will not see the error/logs. Lets get started! The first step is to create a serverside file called bundler.lua and add it to the meta.xml of the resource you want to bundle. <script src="bundler.lua" /> Now we have our script, we can start with writing code for opening the meta.xml file. -- function () local metaFile = xmlLoadFile("meta.xml", true) -- true = read only if not metaFile then return end --- reading the meta.xml here ... xmlUnloadFile(metaFile) -- end To read the meta.xml we call the function xmlNodeGetChildren, which gets all the direct children of the meta.xml root: local nodes = xmlNodeGetChildren(metaFile) for index, node in ipairs(nodes) do -- Going through all nodes end While going through the nodes, we need to validate if each node/file is OK to be bundled. We need to check if the node is a <script> node. And we also do not want to bundle all files. For example, we do not want to bundle the the current bundler.lua . By adding the attribute bundle="true", we can selective pick the correct scripts. In this example I am using an IIFE (Immediately Invoked Function Expression), to be able to use a guard clauses inside of loops. local nodes = xmlNodeGetChildren(metaFile) for index, node in ipairs(nodes) do (function() -- IIFE -- File validation if xmlNodeGetName(node) ~= "script" or xmlNodeGetAttribute(node, "bundle") ~= "true" then return end -- File is OK to be added to the bundle end)() end IIFE (Immediately Invoked Function Expression) Guard clause If the files are bundle able, we need to: Get the type attribute. If none, the script is a serverside script. Get and check the src (source code) attribute And check if the script file actually exists on the disk. ---@alias scriptTypeClient "client" ---@alias scriptTypeServer "server" ---@alias scriptTypeShared "shared" --- ... (function() if xmlNodeGetName(node) ~= "script" or xmlNodeGetAttribute(node, "bundle") ~= "true" then return end ---@type scriptTypeClient|scriptTypeServer|scriptTypeShared local fileType = xmlNodeGetAttribute(node, "type") or "server" local src = xmlNodeGetAttribute(node, "src") if not src or src == "" or not fileExists(src) then outputDebugString("File is missing, index: " .. index .. ", src:" .. tostring(src), 2) return end end)() --- ... If that is OK, we can open the script ---@alias scriptTypeClient "client" ---@alias scriptTypeServer "server" ---@alias scriptTypeShared "shared" --- ... (function() if xmlNodeGetName(node) ~= "script" or xmlNodeGetAttribute(node, "bundle") ~= "true" then return end ---@type scriptTypeClient|scriptTypeServer|scriptTypeShared local fileType = xmlNodeGetAttribute(node, "type") or "server" local src = xmlNodeGetAttribute(node, "src") if not src or src == "" or not fileExists(src) then outputDebugString("File is missing, index: " .. index .. ", src:" .. tostring(src), 2) return end -- Here we open the script local scriptFile = fileOpen(src) if not scriptFile then outputDebugString("Unable to open file, index: " .. index .. ", src:" .. tostring(src), 2) return end fileClose(scriptFile) end)() --- ... Example meta.xml file: To bundle we need to read the files and save the content inside of memory. But some small tweaks have to be made. ---@alias scriptTypeClient "client" ---@alias scriptTypeServer "server" ---@alias scriptTypeShared "shared" ---@alias bundleType {client: string[], server: string[]} ---@type bundleType local bundleContent = { client = {}, server = {}, } --- ... (function() --- ... --- Start reading here ! local content = "do--FILE:" .. src .. "\n" .. fileRead(scriptFile, fileGetSize(scriptFile)) .. "\nend" if fileType == "shared" then ---@cast fileType -scriptTypeClient, -scriptTypeServer -- Bundle shared files in clientside and serverside to maintain startup order bundleContent.server[#bundleContent.server + 1] = content bundleContent.client[#bundleContent.client + 1] = content else ---@cast fileType -scriptTypeShared bundleContent[fileType][#bundleContent[fileType] + 1] = content end end)() --- ... Each file have to start with an additional do and ends with an extra end . This is will create a new block scope for each files, make sure that the local variables are not exposed in other files. The string "\n" represents a new line. The file content is saved inside of the table bundleContent.client/server. Concatenating the strings for each file might cause lag, better to do it in one go later. Putting it together + command handler: ---@alias scriptTypeClient "client" ---@alias scriptTypeServer "server" ---@alias scriptTypeShared "shared" addCommandHandler("bundle", function(playerSource, commandName, ...) local metaFile = xmlLoadFile("meta.xml", true) if not metaFile then return end ---@alias bundleType {client: string[], server: string[]} ---@type bundleType local bundleContent = { client = {}, server = {}, } --[[ START META.XML file read ]] local nodes = xmlNodeGetChildren(metaFile) for index, node in ipairs(nodes) do (function() if xmlNodeGetName(node) ~= "script" or xmlNodeGetAttribute(node, "bundle") ~= "true" then return end ---@type scriptTypeClient|scriptTypeServer|scriptTypeShared local fileType = xmlNodeGetAttribute(node, "type") or "server" local src = xmlNodeGetAttribute(node, "src") if not src or src == "" or not fileExists(src) then outputDebugString("File is missing, index: " .. index .. ", src:" .. tostring(src), 2) return end local scriptFile = fileOpen(src) if not scriptFile then outputDebugString("Unable to open file, index: " .. index .. ", src:" .. tostring(src), 2) return end local content = "do--FILE:" .. src .. "\n" .. fileRead(scriptFile, fileGetSize(scriptFile)) .. "\nend" if fileType == "shared" then ---@cast fileType -scriptTypeClient, -scriptTypeServer -- Bundle shared files in clientside and serverside to maintain startup order bundleContent.server[#bundleContent.server + 1] = content bundleContent.client[#bundleContent.client + 1] = content else ---@cast fileType -scriptTypeShared bundleContent[fileType][#bundleContent[fileType] + 1] = content end fileClose(scriptFile) end)() end xmlUnloadFile(metaFile) end) Functions used to bundle clientside/serverside: local bundleFilePath = "example_bundle" .. "/" --[[ * Returns 0 if there is no file to be deleted. * Returns 1 if the file is deleted. * Returns 2 if the file is unable to be deleted. ]] ---@alias fileDeleteState 0|1|2 ---@param bundleContent bundleType The bundle ---@param typeOfFile scriptTypeServer|scriptTypeClient String 'client' or 'server ---@return boolean function createBundleFile(bundleContent, typeOfFile) local file = fileCreate(bundleFilePath .. typeOfFile .. ".lua") if not file then return false end local bundleFile = table.concat(bundleContent[typeOfFile], "\n") fileWrite(file, bundleFile) fileFlush(file) fileClose(file) return true end ---@see fileDeleteState ---@param typeOfFile scriptTypeServer|scriptTypeClient String 'client' or 'server ---@return fileDeleteState state The delete state: 0, 1, 2 function deleteBundleFile(typeOfFile) if not fileExists(bundleFilePath .. typeOfFile .. ".lua") then return 0 end return fileDelete(bundleFilePath .. typeOfFile .. ".lua") and 1 or 2 end Functions used to generate meta.xml script lines. local bundleFilePath = "example_bundle" .. "/" local metaFileName = "meta_fragment" --[[ * Returns 0 if there is no file to be deleted. * Returns 1 if the file is deleted. * Returns 2 if the file is unable to be deleted. ]] ---@alias fileDeleteState 0|1|2 --[[ Creates the meta fragment file, which contains the generated meta.xml script lines ]] ---@type fun(): boolean function createMetaFragment() local file = xmlCreateFile(bundleFilePath .. metaFileName .. ".xml", "meta") if not file then return false end local serverNode = xmlCreateChild(file, "script") xmlNodeSetAttribute(serverNode, "src", bundleFilePath .. "server.lua") xmlNodeSetAttribute(serverNode, "type", "server") local clientNode = xmlCreateChild(file, "script") xmlNodeSetAttribute(clientNode, "src", bundleFilePath .. "client.lua") xmlNodeSetAttribute(clientNode, "type", "client") xmlSaveFile(file) xmlUnloadFile(file) return true end --[[ Delete the meta fragment file ]] ---@see fileDeleteState ---@return fileDeleteState state The delete state: 0, 1, 2 function deleteMetaFragment() if not fileExists(bundleFilePath .. metaFileName .. ".xml") then return 0 end return fileDelete(bundleFilePath .. metaFileName .. ".xml") and 1 or 2 end And now using the functions from above to make the bundle. if deleteBundleFile("server") == 2 then error("Unable to replace bundle file: server.lua") elseif createBundleFile(bundleContent, "server") then outputDebugString("Created bundle file: server.lua", 4) end if deleteBundleFile("client") == 2 then error("Unable to replace bundle file: client.lua") elseif createBundleFile(bundleContent, "client") then outputDebugString("Created bundle file: client.lua", 4) end if deleteMetaFragment() == 2 then error("Unable to replace bundle file: " .. metaFileName .. ".xml") elseif createMetaFragment() then outputDebugString("Created file: " .. metaFileName .. ".xml", 4) end This happens in the following order: Delete the bundle if already exist If there is a problem with deleting: stop with an error. This is the point were your text editor might be blocking the deletion of the current bundle files. You need to resolve this manually. You need to have the debug console open, else you will not see the error/logs. Create bundle files Full script:
    1 point
  4. The "table way" is actually pretty straight forward, here is a simple example: local guiStuff = {}; --create the table. guiStuff[ #guiStuff + 1 ] = guiCreateStaticImage("IMAGE1", x, y); --#guiStuff > gets the total number of items in the table and we add one so basically we do [0 + 1] then [1 + 1], [2 + 1] and so on.. guiStuff[ #guiStuff + 1 ] = guiCreateStaticImage("IMAGE2", x, y); guiStuff[ #guiStuff + 1 ] = guiCreateStaticImage("IMAGE3", x, y); guiStuff[ #guiStuff + 1 ] = guiCreateStaticImage("IMAGE4", x, y); --so on as many times you want.... for index = 1, #guiStuff do guiSetVisible(guiStuff[index], true); end --you can also acces any of the above like this guiSetVisible(guiStuff[3], false); --if you are sure of the index --imagine the table like this: local guiStuff = { [1] = guiCreateStaticImage("IMAGE1", x, y), [2] = guiCreateStaticImage("IMAGE2", x, y), [3] = guiCreateStaticImage("IMAGE3", x, y), [4] = guiCreateStaticImage("IMAGE4", x, y), };
    1 point
  5. Thanks IIYAMA, the dirty way does what I need it to do and it really saved a ton of lines in the code. I am however using it more than once in the same script, I think as long as it doesn't cause any major performance or security implications it should be okay until I figure out how to go about doing it the table way. Thanks again.
    1 point
  6. Hi, may I ask why is this a bad implementation ? Greetings.
    1 point
  7. Lua tables are a fundamental data structure that allows you to store key-value pairs and create complex data structures. Tables in Lua are versatile and can contain values of different types. Let's dive into a detailed explanation with examples : Table Creation: To create a table in Lua, you use curly braces { } and separate the elements with commas. Here's an example: local table = {1, 2, 3, 4, 5} -- table crt In the above example, we created a table named table and populated it with values 1, 2, 3, 4, and 5. Accessing Table Elements: You can access table elements by using square brackets [ ]. Indices in Lua start from 1. Here's an example: -- Accessing table elements print(table[1]) --output : 1 print(table[3]) --output : 3 In the above example, we access the value at the 1st index (1) and the 3rd index (3) of the table. Adding Elements to a Table: To add a new element to a table, you specify the index and the value. If the specified index already exists in the table, the value will be overwritten. Here's an example: -- Removing elements from a table table[3] = nil In the above example, we remove the element at the 3rd index of the table. Getting the Size of a Table: To get the size of a table (i.e., the number of elements), you can use the # operator. Here's an example: -- Getting the size of a table print(#table) -- 5 In the above example, we print the size of the table using the # operator. Table Iteration: You can iterate over the elements in a table using the ipairs or pairs functions. ipairs provides index-based iteration, while pairs provides key-based iteration. Here's an example: -- Table iteration for index, value in ipairs(table) do print(index, value) end In the above example, we iterate over the table using ipairs and print the index and value of each element. +---------------------------------------------------+ | Game Settings | +---------------------------------------------------+ | Difficulty: | Hard | | Sound Volume: | 80% | | Controls: | Keyboard & Mouse | | Graphics Quality: | High | +---------------------------------------------------+ In the above example, an ASCII art representation is used to display a Lua table representing game settings. The table consists of different elements representing various game settings. Here's the Lua code that represents the table: local gameSettings = { difficulty = "Hard", soundVolume = "80%", controls = "Keyboard & Mouse", graphicsQuality = "High" } In the Lua code, a table named "gameSettings" is created, and different elements representing game settings such as difficulty, sound volume, controls, and graphics quality are added to the table. local person = { name = "Eren", age = 20, occupation = "Software Engineer", country = "Germany" } local tableFormat = [[ +-----------------------+ | Person Info | +-----------------------+ | Name: %s | | Age: %d | | Occupation: %s | | Country: %s | +-----------------------+ ]] local formattedTable = string.format(tableFormat, person.name, person.age, person.occupation, person.country) print(formattedTable) In the example above, we create a Lua table named "person" and populate it with some sample information about a person. We then define a string format named "tableFormat" which represents an ASCII table structure. We use placeholders like %s and %d to indicate the places where the values from the "person" table will be inserted. Finally, we use the string.format function to fill in the format with the data from the "person" table and store it in the variable "formattedTable". We print the "formattedTable" to display the final result. I explained string methods in the previous tutorial, here is the link: string methods LINK Output : +-----------------------+ | Person Info | +-----------------------+ | Name: Eren | | Age: 20 | | Occupation: Software Engineer | | Country: Germany | +-----------------------+ Nested Tables: Tables can contain other tables, allowing you to create nested or multidimensional data structures. Here's an example: -- Nested tables local team = { name = "Team A", players = { { name = "Eren", age = 20 }, { name = "Emily", age = 27 }, { name = "Angela", age = 23 } } } print(team.name) -- Team A print(team.players[2].name) -- Emily In the above example, we created a table named team with two elements: name and players. The players element is a nested table that contains information about individual players. We access the name element of the team table and the name of the player at the 2nd index of the players table. Table Insertion and Removal: Lua provides various functions for inserting and removing elements from tables. Here's an example that demonstrates these operations: -- Table insertion and removal local fruits = {"apple", "banana"} table.insert(fruits, "orange") -- Insert an element at the end table.insert(fruits, 2, "grape") -- Insert an element at the 2nd index table.remove(fruits, 1) -- Remove the element at the 1st index for index, fruit in ipairs(fruits) do print(index, fruit) end In the above example, we start with a table named fruits containing two elements. Using table.insert, we add an element at the end and another element at the 2nd index. Then, using table.remove, we remove the element at the 1st index. Finally, we iterate over the modified fruits table and print the index and value of each element. Table Concatenation: Lua allows you to concatenate tables using the .. operator. Here's an example: -- Table concatenation local table1 = {1, 2, 3} local table2 = {4, 5, 6} local mergedTable = {} for _, value in ipairs(table1) do table.insert(mergedTable, value) end for _, value in ipairs(table2) do table.insert(mergedTable, value) end for index, value in ipairs(mergedTable) do print(index, value) end In the above example, we have two tables named table1 and table2. We create an empty table named mergedTable and use table.insert to concatenate the elements from table1 and table2 into mergedTable. Finally, we iterate over mergedTable and print the index and value of each element. for MTA:SA Player Information: Lua tables can be used to store player information in MTA:SA. Below is an example of a player table that contains details such as the player's name, level, and score: local player = { name = "Eren", level = 5, score = 1000 } In the above example, we create a table named "player" and populate it with the player's name, level, and score. Vehicle List: Lua tables can be utilized to store data related to vehicles in MTA:SA. Here's an example of a vehicle table that includes the model names and colors of the vehicles: local vehicles = { { model = "Infernus", color = {255, 0, 0} }, { model = "Bullet", color = {0, 0, 255} }, { model = "Sultan", color = {0, 255, 0} } } In the above example, we create a table named "vehicles" and store each vehicle as a separate table with its model name and color data. Colors are represented using RGB values. NPC (Non-Player Character) List: Lua tables can be used to store in-game NPCs in MTA:SA. Here's an example of an NPC list table that includes the model IDs and coordinates of the NPCs: local npcs = { { model = 23, x = 100, y = 200, z = 10 }, { model = 56, x = 150, y = 250, z = 15 }, { model = 89, x = 200, y = 300, z = 20 } } In the above example, we create a table named "npcs" and store each NPC as a separate table with their model ID and coordinates. I hope you will like it
    1 point
×
×
  • Create New...