Lua Programming and
MTA:SA Resource Development
Lua scripting ශුන්යයෙන් ඉගෙන ගෙන, MTA:SA සඳහා custom game resources සාදන්නේ කෙසේද යන්න ගැන සම්පූර්ණ මාර්ගෝපදේශය.
Lua හැඳින්වීම
Lua scripting language ගැන මූලික දැනුම
Lua යනු සරල, වේගවත්, සහ powerful scripting භාෂාවක්. එය game development, embedded systems, සහ web applications වල බහුලව භාවිතා වෙනවා.
පළමු Lua Program එක
-- මේක comment එකක්
print("Hello, World!") -- කොන්සෝලය මත output එකක් print කරනවා
Variables සහ Data Types
දත්ත ගබඩා කිරීම සහ variable වර්ග
Variable යනු data එකක් store කරන container එකක්. Lua වල variables declare කරන විට type එක specify කරන්න අවශ්ය නැහැ.
1. Local Variables (පෙදෙසික විචල්ය)
local name = "Kasun" -- local variable එකක්
local age = 25
2. Global Variables (ගෝලීය විචල්ය)
playerName = "Nimal" -- global variable එකක්
score = 100
local භාවිතා කරන්න. Global variables memory leak වලට හේතු වෙන්න පුළුවන්.Data Types (දත්ත වර්ග)
1. nil (හිස්)
local x = nil -- අගයක් නැති variable එකක්
print(type(x)) -- Output: nil
2. boolean (සත්ය/අසත්ය)
local isAlive = true
local isGameOver = false
3. number (සංඛ්යා)
local integerNum = 42
local floatNum = 3.14
local negative = -100
4. string (පෙළ)
local singleQuote = 'Hello'
local doubleQuote = "World"
local multiLine = [[මේක
multiple line
string එකක්]]
5. table (වගුව)
local fruits = {"amba", "puhul", "anoda"}
local person = {name = "Kamal", age = 30}
6. function (ක්රියාව)
local function greet()
print("ආයුබෝවන්!")
end
Type Checking
local x = 10
print(type(x)) -- Output: number
local name = "Saman"
print(type(name)) -- Output: string
Operators
ගණිතමය, සාපේක්ෂ සහ තාර්කික ක්රියාකරු
Arithmetic Operators (ගණිතමය ක්රියාකරු)
local a = 10
local b = 3
print(a + b) -- එකතු කිරීම: 13
print(a - b) -- අඩු කිරීම: 7
print(a * b) -- ගුණ කිරීම: 30
print(a / b) -- බෙදීම: 3.333...
print(a % b) -- Modulo (ඉතිරිය): 1
print(a ^ b) -- Power (බලය): 1000
Relational Operators (සාපේක්ෂ ක්රියාකරු)
local x = 5
local y = 10
print(x == y) -- සමාන: false
print(x ~= y) -- සමාන නොවේ: true
print(x < y) -- අඩු: true
print(x > y) -- වැඩි: false
print(x <= y) -- අඩු හෝ සමාන: true
print(x >= y) -- වැඩි හෝ සමාන: false
Logical Operators (තාර්කික ක්රියාකරු)
local a = true
local b = false
print(a and b) -- AND: false
print(a or b) -- OR: true
print(not a) -- NOT: false
String Concatenation (පෙළ එකතු කිරීම)
local firstName = "Nimal"
local lastName = "Silva"
local fullName = firstName .. " " .. lastName
print(fullName) -- Output: Nimal Silva
Control Structures
If-Else statements සහ conditional logic
මූලික if statement
local age = 18
if age >= 18 then
print("ඔබ වැඩිහිටියෙක්")
end
If-Else
local score = 45
if score >= 50 then
print("Pass")
else
print("Fail")
end
If-Elseif-Else
local marks = 75
if marks >= 75 then
print("A Grade")
elseif marks >= 65 then
print("B Grade")
elseif marks >= 55 then
print("C Grade")
elseif marks >= 35 then
print("S Grade")
else
print("Fail")
end
Nested If (කැදැලි if)
local age = 20
local hasLicense = true
if age >= 18 then
if hasLicense then
print("ඔබට drive කරන්න පුළුවන්")
else
print("පළමුව license එකක් ගන්න")
end
else
print("ඔබ තවමත් අඩුයි")
end
Functions
Code reuse සහ organize කිරීම සඳහා functions
Function එකක් යනු නිශ්චිත කාර්යයක් කරන code block එකක්. Functions භාවිතා කරන්නේ code එක reuse කරන්න සහ organize කරන්න.
Basic Function
function greet()
print("ආයුබෝවන්!")
end
greet() -- function එක call කරනවා
Parameters සමඟ Function
function greet(name)
print("ආයුබෝවන් " .. name .. "!")
end
greet("කමල්") -- Output: ආයුබෝවන් කමල්!
greet("නිමල්") -- Output: ආයුබෝවන් නිමල්!
Multiple Parameters
function add(a, b)
return a + b
end
local result = add(5, 3)
print(result) -- Output: 8
Multiple Return Values
function calculate(a, b)
local sum = a + b
local product = a * b
return sum, product
end
local s, p = calculate(4, 5)
print("එකතුව: " .. s) -- Output: එකතුව: 9
print("ගුණිතය: " .. p) -- Output: ගුණිතය: 20
Local Functions
local function privateFunction()
print("මේක local function එකක්")
end
privateFunction()
Anonymous Functions (නාමරහිත ක්රියා)
local square = function(x)
return x * x
end
print(square(5)) -- Output: 25
Default Parameters
function greet(name, greeting)
greeting = greeting or "ආයුබෝවන්" -- default value
print(greeting .. " " .. name)
end
greet("කමල්") -- Output: ආයුබෝවන් කමල්
greet("නිමල්", "සුබ දවසක්") -- Output: සුබ දවසක් නිමල්
Tables
Lua වල ඇති එකම data structure එක
Table එකක් යනු Lua වල ඇති එකම data structure එක. Arrays, dictionaries, objects හැමදේම tables භාවිතයෙන් හදන්න පුළුවන්.
Array-Style Tables
local fruits = {"amba", "puhul", "anoda", "දොඩම්"}
print(fruits[1]) -- Output: amba (Lua වල index 1 සිට පටන් ගන්නවා)
print(fruits[3]) -- Output: anoda
-- Table එකේ length එක
print(#fruits) -- Output: 4
Dictionary-Style Tables
local person = {
name = "කමල්",
age = 25,
city = "කොළඹ"
}
print(person.name) -- Output: කමල්
print(person["age"]) -- Output: 25
Nested Tables (කැදැලි වගු)
local school = {
name = "රාජකීය විද්යාලය",
students = {
{name = "කමල්", age = 15},
{name = "නිමල්", age = 16},
{name = "සුනිල්", age = 15}
}
}
print(school.students[1].name) -- Output: කමල්
Table Functions
-- table.insert() - අයිතම එකතු කරනවා
local colors = {"red", "green"}
table.insert(colors, "blue") -- අන්තයට එකතු කරනවා
table.insert(colors, 2, "yellow") -- position 2 වලට එකතු කරනවා
-- colors = {"red", "yellow", "green", "blue"}
-- table.remove() - අයිතම ඉවත් කරනවා
local numbers = {10, 20, 30, 40}
table.remove(numbers, 2) -- index 2 ඉවත් කරනවා
table.remove(numbers) -- අන්තිම element එක ඉවත් කරනවා
-- table.concat() - පෙළක් හදනවා
local words = {"Hello", "World", "Lua"}
local sentence = table.concat(words, " ")
print(sentence) -- Output: Hello World Lua
-- table.sort() - පිළිවෙල කරනවා
local nums = {5, 2, 8, 1, 9}
table.sort(nums)
-- nums = {1, 2, 5, 8, 9}
Iterating Tables (වගු පුනරාවර්තනය)
local fruits = {"amba", "puhul", "anoda"}
-- ipairs භාවිතයෙන් (arrays සඳහා)
for index, fruit in ipairs(fruits) do
print(index, fruit)
end
-- pairs භාවිතයෙන් (dictionaries සඳහා)
local person = {name = "කමල්", age = 25}
for key, value in pairs(person) do
print(key, value)
end
Strings
String operations සහ manipulation
-- String Length (දිග)
local text = "ආයුබෝවන්"
print(#text) -- string එකේ length එක
print(string.len(text)) -- alternate method
-- String Concatenation (එකතු කිරීම)
local first = "Hello"
local second = "World"
local combined = first .. " " .. second
print(combined) -- Output: Hello World
-- Uppercase/Lowercase
local txt = "Hello Lua"
print(string.upper(txt)) -- Output: HELLO LUA
print(string.lower(txt)) -- Output: hello lua
-- Substring (උප පෙළ)
local t = "Hello World"
print(string.sub(t, 1, 5)) -- Output: Hello
print(string.sub(t, 7)) -- Output: World
-- Find and Replace
local s = "I love Lua programming"
local start, finish = string.find(s, "Lua")
print(start, finish) -- Output: 8 10
local newText = string.gsub(s, "Lua", "Python")
print(newText) -- Output: I love Python programming
-- String Formatting
local name = "කමල්"
local age = 25
local formatted = string.format("නම: %s, වයස: %d", name, age)
print(formatted) -- Output: නම: කමල්, වයස: 25
-- Repeat
local star = "*"
print(string.rep(star, 5)) -- Output: *****
-- Reverse
local rev = "Lua"
print(string.reverse(rev)) -- Output: auL
Loops
For, While, Repeat-Until loops
Numeric For Loop
-- 1 සිට 5 දක්වා
for i = 1, 5 do
print(i)
end
-- Output: 1 2 3 4 5
-- Step සමඟ
for i = 0, 10, 2 do
print(i)
end
-- Output: 0 2 4 6 8 10
-- Reverse
for i = 5, 1, -1 do
print(i)
end
-- Output: 5 4 3 2 1
Generic For Loop (Tables සඳහා)
local fruits = {"amba", "puhul", "anoda"}
for index, fruit in ipairs(fruits) do
print(index .. ": " .. fruit)
end
While Loop
local count = 1
while count <= 5 do
print("Count: " .. count)
count = count + 1
end
Repeat-Until Loop
local x = 1
repeat
print(x)
x = x + 1
until x > 5
Break and Continue
-- Break භාවිතය
for i = 1, 10 do
if i == 5 then
break -- loop එක නතර කරනවා
end
print(i)
end
-- Continue effect (Lua වල continue නැහැ)
for i = 1, 10 do
if i % 2 == 0 then
goto continue -- skip කරනවා
end
print(i)
::continue::
end
Modules
Reusable code organize කිරීම
Module එකක් යනු reusable code එකක් තියෙන separate file එකක්.
Module එකක් හදන්නේ කොහොමද — mymodule.lua
local M = {} -- Module table එක
M.version = "1.0"
function M.greet(name)
return "ආයුබෝවන් " .. name
end
function M.add(a, b)
return a + b
end
return M
Module එකක් භාවිතා කිරීම
local mymodule = require("mymodule")
print(mymodule.version) -- Output: 1.0
print(mymodule.greet("කමල්")) -- Output: ආයුබෝවන් කමල්
print(mymodule.add(5, 3)) -- Output: 8
Error Handling
pcall, xpcall සහ assert භාවිතය
pcall (Protected Call)
local function riskyFunction()
error("මෙහි දෝෂයක් සිදු විය!")
end
local success, errorMessage = pcall(riskyFunction)
if success then
print("සාර්ථකයි!")
else
print("දෝෂය: " .. errorMessage)
end
xpcall (Extended Protected Call)
local function errorHandler(err)
return "දෝෂ හසුරුවන්නා: " .. err
end
local function riskyFunction()
local x = nil
return x.value -- මෙහි error එකක් ඇති වෙනවා
end
local success, result = xpcall(riskyFunction, errorHandler)
print(result)
assert භාවිතය
local function divide(a, b)
assert(b ~= 0, "ශුන්යයෙන් බෙදිය නොහැක!")
return a / b
end
print(divide(10, 2)) -- Output: 5
-- print(divide(10, 0)) -- Error: ශුන්යයෙන් බෙදිය නොහැක!
MTA:SA හැඳින්වීම
Multi Theft Auto: San Andreas ගැන මූලික දැනුම
Multi Theft Auto: San Andreas (MTA:SA) යනු GTA San Andreas game එක සඳහා multiplayer mod එකක්. මෙහි Lua භාවිතයෙන් custom game modes හදන්න පුළුවන්.
ප්රධාන සංකල්ප
සර්වරයේ run වෙන scripts. ක්රීඩකයින්ට source code බලන්න බැහැ. Database, economy, game logic handle කරනවා.
ක්රීඩකයාගේ computer එකේ run වෙන scripts. GUI, rendering, keyboard input handle කරනවා.
Resource Structure
Folder structure සහ meta.xml configuration
Resource Folder Structure
මූලික meta.xml
<meta>
<info author="YourName" version="1.0" name="My First Resource"
description="මගේ පළමු MTA resource එක" />
<!-- Server-side scripts -->
<script src="server.lua" type="server" />
<!-- Client-side scripts -->
<script src="client.lua" type="client" />
<!-- Shared scripts -->
<script src="shared.lua" type="shared" />
<!-- Files -->
<file src="images/logo.png" />
<file src="sounds/notification.mp3" />
</meta>
Advanced meta.xml
<meta>
<info author="YourName" version="2.0" type="gamemode" />
<!-- Scripts -->
<script src="server/main.lua" type="server" />
<script src="server/commands.lua" type="server" />
<script src="client/gui.lua" type="client" />
<script src="shared/config.lua" type="shared" />
<!-- Files -->
<file src="images/*.png" />
<file src="sounds/*.mp3" />
<!-- OOP භාවිතය -->
<oop>true</oop>
<!-- Exports -->
<export function="getPlayerMoney" type="server" />
<!-- Settings -->
<settings>
<setting name="*maxPlayers" value="32" />
<setting name="*gamemodeText" value="Roleplay" />
</settings>
</meta>
Server-Side Scripting
සර්වරයේ run වෙන scripts ලිවීම
server.lua — Basic Events
-- Server start වෙද්දී execute වෙන code
addEventHandler("onResourceStart", resourceRoot,
function()
outputDebugString("Resource එක ආරම්භ විය!")
end
)
-- Player join වෙද්දී
addEventHandler("onPlayerJoin", root,
function()
local playerName = getPlayerName(source)
outputChatBox("ආයුබෝවන් " .. playerName .. "!", root, 0, 255, 0)
end
)
-- Player quit වෙද්දී
addEventHandler("onPlayerQuit", root,
function(quitType)
local playerName = getPlayerName(source)
outputChatBox(playerName .. " ක්රීඩාවෙන් ඉවත් විය. (" .. quitType .. ")", root, 255, 0, 0)
end
)
Simple Command
addCommandHandler("heal",
function(player)
setElementHealth(player, 100)
outputChatBox("ඔබගේ සෞඛ්යය යථා තත්වයට පත් විය!", player, 0, 255, 0)
end
)
Command with Arguments
addCommandHandler("setmoney",
function(player, cmd, amount)
if not amount then
outputChatBox("භාවිතය: /setmoney ", player, 255, 0, 0)
return
end
amount = tonumber(amount)
if not amount then
outputChatBox("වලංගු මුදලක් ඇතුළත් කරන්න!", player, 255, 0, 0)
return
end
setPlayerMoney(player, amount)
outputChatBox("ඔබගේ මුදල් " .. amount .. " දක්වා සකසා ඇත!", player, 0, 255, 0)
end
)
Admin Command
addCommandHandler("kick",
function(player, cmd, targetName, ...)
-- Admin පරීක්ෂා කිරීම
if not isObjectInACLGroup("user." .. getAccountName(getPlayerAccount(player)), aclGetGroup("Admin")) then
outputChatBox("ඔබට අවසරයක් නැත!", player, 255, 0, 0)
return
end
if not targetName then
outputChatBox("භාවිතය: /kick ", player, 255, 0, 0)
return
end
local target = getPlayerFromName(targetName)
if not target then
outputChatBox("ක්රීඩකයා සොයාගත නොහැක!", player, 255, 0, 0)
return
end
local reason = table.concat({...}, " ") or "හේතුවක් දක්වා නැත"
outputChatBox(getPlayerName(target) .. " ක්රීඩාවෙන් දමා ඇත. හේතුව: " .. reason, root, 255, 100, 100)
kickPlayer(target, player, reason)
end
)
Element Data භාවිතය
-- Data set කිරීම
function givePlayerCash(player, amount)
local currentMoney = getElementData(player, "money") or 0
setElementData(player, "money", currentMoney + amount)
end
-- Data ලබා ගැනීම
function getPlayerCash(player)
return getElementData(player, "money") or 0
end
-- Player join වෙද්දී
addEventHandler("onPlayerJoin", root,
function()
setElementData(source, "money", 1000) -- Starting money
setElementData(source, "level", 1) -- Starting level
end
)
Client-Side Scripting
ක්රීඩකයාගේ computer එකේ run වෙන scripts
client.lua — Basic Events
-- Resource start වෙද්දී
addEventHandler("onClientResourceStart", resourceRoot,
function()
outputChatBox("Client resource ආරම්භ විය!", 0, 255, 0)
end
)
-- Key press detect කිරීම
bindKey("F1", "down",
function()
outputChatBox("ඔබ F1 ඔබනු ලැබීය!", 0, 255, 255)
end
)
-- Mouse click detect කිරීම
addEventHandler("onClientClick", root,
function(button, state, absoluteX, absoluteY, worldX, worldY, worldZ, clickedElement)
if button == "left" and state == "down" then
if clickedElement and getElementType(clickedElement) == "vehicle" then
local vehicleName = getVehicleName(clickedElement)
outputChatBox("ඔබ " .. vehicleName .. " එකක් click කළා!", 0, 255, 0)
end
end
end
)
dxDraw — Health Bar
function drawHealthBar()
local health = getElementHealth(localPlayer)
local maxHealth = 100
local barWidth = 200
local barHeight = 20
local x = 20
local y = 20
-- Background
dxDrawRectangle(x, y, barWidth, barHeight, tocolor(0, 0, 0, 150))
-- Health bar
local healthWidth = (health / maxHealth) * barWidth
dxDrawRectangle(x, y, healthWidth, barHeight, tocolor(255, 0, 0, 200))
-- Text
dxDrawText("HP: " .. math.floor(health), x, y, x + barWidth, y + barHeight,
tocolor(255, 255, 255, 255), 1, "default", "center", "center")
end
addEventHandler("onClientRender", root, drawHealthBar)
-- Screen text draw කිරීම
addEventHandler("onClientRender", root,
function()
local screenWidth, screenHeight = guiGetScreenSize()
dxDrawText("ආයුබෝවන් MTA:SA!",
0, 0, screenWidth, screenHeight,
tocolor(255, 255, 255, 255),
2, "default", "center", "center")
end
)
-- Image draw කිරීම
addEventHandler("onClientResourceStart", resourceRoot,
function()
local logoTexture = dxCreateTexture("images/logo.png")
addEventHandler("onClientRender", root,
function()
if logoTexture then
dxDrawImage(10, 10, 128, 128, logoTexture)
end
end
)
end
)
Events සහ Event Handlers
Server/Client events සහ custom events
Events යනු MTA වල සිදු වන විවිධ ක්රියා (player join, vehicle enter, chat message, etc). Event handlers භාවිතයෙන් මේවාට ප්රතිචාර දක්වනවා.
Server-Side Events
-- Player join event
addEventHandler("onPlayerJoin", root,
function()
local playerName = getPlayerName(source)
outputChatBox("[+] " .. playerName .. " සර්වරයට සම්බන්ධ විය!", root, 255, 255, 0)
setPlayerName(source, playerName)
end
)
-- Player quit event
addEventHandler("onPlayerQuit", root,
function(reason)
local playerName = getPlayerName(source)
outputChatBox("[-] " .. playerName .. " සර්වරයෙන් ඉවත් විය (" .. reason .. ")", root, 255, 100, 100)
end
)
-- Player chat event
addEventHandler("onPlayerChat", root,
function(message, messageType)
if messageType == 0 then -- Normal chat
local playerName = getPlayerName(source)
outputChatBox("[chat] " .. playerName .. ": " .. message, root, 255, 255, 255)
cancelEvent() -- Default chat message cancel කිරීම
end
end
)
Vehicle Events
-- Player vehicle enter
addEventHandler("onPlayerVehicleEnter", root,
function(vehicle, seat, jacked)
local playerName = getPlayerName(source)
local vehicleName = getVehicleName(vehicle)
if seat == 0 then -- Driver seat
outputChatBox("[car] " .. playerName .. " " .. vehicleName .. " රථය drive කරයි", root, 0, 255, 0)
else
outputChatBox("[car] " .. playerName .. " " .. vehicleName .. " රථයේ ගමන් කරයි", root, 0, 200, 0)
end
end
)
-- Vehicle damage
addEventHandler("onVehicleDamage", root,
function(loss)
local health = getElementHealth(source)
if health < 300 then
outputChatBox("[warn] රථය හානි වී ඇත! සෞඛ්යය: " .. math.floor(health), root, 255, 100, 0)
end
end
)
Custom Events
-- Custom event define කිරීම
function givePlayerReward(player, rewardType, amount)
if not isElement(player) then return false end
local rewardData = {
player = player,
type = rewardType,
amount = amount,
timestamp = getRealTime().timestamp
}
triggerEvent("onPlayerReward", player, rewardData)
return true
end
-- Custom event handle කිරීම
addEvent("onPlayerReward", true)
addEventHandler("onPlayerReward", root,
function(rewardData)
local playerName = getPlayerName(source)
outputChatBox("[reward] " .. playerName .. " සම්මානයක් ලැබුණි: " .. rewardData.type, root, 0, 255, 0)
if rewardData.type == "money" then
givePlayerMoney(source, rewardData.amount)
outputChatBox("[+] ඔබට ඩොලර් " .. rewardData.amount .. " ලැබුණි!", source, 0, 255, 0)
elseif rewardData.type == "experience" then
local currentXP = getElementData(source, "experience") or 0
setElementData(source, "experience", currentXP + rewardData.amount)
outputChatBox("[+] ඔබට XP " .. rewardData.amount .. " ලැබුණි!", source, 255, 255, 0)
end
end
)
Client to Server Communication
-- Client-side: Event trigger කිරීම
function requestVehicleSpawn(vehicleModel)
if not vehicleModel then return false end
triggerServerEvent("onClientRequestVehicle", localPlayer, vehicleModel)
return true
end
-- Server-side: Event handle කිරීම
addEvent("onClientRequestVehicle", true)
addEventHandler("onClientRequestVehicle", root,
function(vehicleModel)
if not isElement(source) then return end
local x, y, z = getElementPosition(source)
local vehicle = createVehicle(vehicleModel, x + 5, y, z)
if vehicle then
warpPedIntoVehicle(source, vehicle)
outputChatBox("[car] රථය spawn කරන ලදී!", source, 0, 255, 0)
else
outputChatBox("[x] රථය spawn කිරීමට නොහැක!", source, 255, 0, 0)
end
end
)
Elements සහ Data
Element types, creation සහ data management
Element Types
-- Element types
local elementTypes = {
"player", "vehicle", "object", "marker", "blip", "pickup", "radararea", "team"
}
-- Element type check කිරීම
function isValidPlayer(element)
return isElement(element) and getElementType(element) == "player"
end
function isValidVehicle(element)
return isElement(element) and getElementType(element) == "vehicle"
end
Element Data Management
function setupPlayerData(player)
if not isElement(player) then return false end
setElementData(player, "money", 1000)
setElementData(player, "level", 1)
setElementData(player, "experience", 0)
setElementData(player, "playTime", 0)
setElementData(player, "kills", 0)
setElementData(player, "deaths", 0)
return true
end
function getPlayerStats(player)
if not isValidPlayer(player) then return nil end
return {
money = getElementData(player, "money") or 0,
level = getElementData(player, "level") or 1,
experience = getElementData(player, "experience") or 0,
playTime = getElementData(player, "playTime") or 0,
kills = getElementData(player, "kills") or 0,
deaths = getElementData(player, "deaths") or 0
}
end
function addPlayerMoney(player, amount)
if not isValidPlayer(player) or not amount then return false end
local currentMoney = getElementData(player, "money") or 0
setElementData(player, "money", currentMoney + amount)
triggerEvent("onPlayerMoneyChange", player, amount, currentMoney + amount)
return true
end
Vehicle Spawn Function
function spawnPlayerVehicle(player, model, x, y, z)
if not isValidPlayer(player) then return nil end
-- Position නොමැතිනම් player position භාවිතා කිරීම
if not x or not y or not z then
x, y, z = getElementPosition(player)
x = x + 3
end
local vehicle = createVehicle(model or 411, x, y, z) -- Default: Infernus
if vehicle then
setElementData(vehicle, "owner", player)
setElementData(vehicle, "spawnTime", getRealTime().timestamp)
local playerVehicles = getElementData(player, "vehicles") or {}
table.insert(playerVehicles, vehicle)
setElementData(player, "vehicles", playerVehicles)
warpPedIntoVehicle(player, vehicle)
outputChatBox("[car] රථය spawn කරන ලදී!", player, 0, 255, 0)
else
outputChatBox("[x] රථය spawn කිරීමට නොහැක!", player, 255, 0, 0)
end
return vehicle
end
Markers සහ Blips
function createSafeZone(x, y, z, size)
local marker = createMarker(x, y, z, "cylinder", size, 0, 255, 0, 150)
if marker then
addEventHandler("onMarkerHit", marker, onSafeZoneEnter)
addEventHandler("onMarkerLeave", marker, onSafeZoneExit)
local blip = createBlip(x, y, z, 0, 2, 0, 255, 0, 255, 0, 99999)
setElementData(blip, "safeZone", true)
return marker, blip
end
return nil
end
function onSafeZoneEnter(hitElement, matchingDimension)
if getElementType(hitElement) == "player" and matchingDimension then
outputChatBox("[shield] ඔබ සුරක්ෂිත කලාපයකට පිවිසියි!", hitElement, 0, 255, 0)
setElementData(hitElement, "inSafeZone", true)
end
end
function onSafeZoneExit(hitElement, matchingDimension)
if getElementType(hitElement) == "player" and matchingDimension then
outputChatBox("[warn] ඔබ සුරක්ෂිත කලාපයෙන් පිටව ගියි!", hitElement, 255, 100, 0)
setElementData(hitElement, "inSafeZone", false)
end
end
GUI Development
In-game GUI elements සහ DX-based interfaces
Main Menu GUI
local screenWidth, screenHeight = guiGetScreenSize()
local guiElements = {}
function createMainMenu()
-- Window
guiElements.window = guiCreateWindow(
screenWidth/2-150, screenHeight/2-200, 300, 400, "මුල් මෙනුව", false
)
guiWindowSetSizable(guiElements.window, false)
-- Buttons
guiElements.playButton = guiCreateButton(50, 50, 200, 40, "ක්රීඩාව අරඹන්න", false, guiElements.window)
guiElements.settingsButton = guiCreateButton(50, 110, 200, 40, "සැකසුම්", false, guiElements.window)
guiElements.quitButton = guiCreateButton(50, 170, 200, 40, "පිටවීම", false, guiElements.window)
-- Labels
guiElements.titleLabel = guiCreateLabel(0, 10, 300, 30, "MTA:SA Roleplay", false, guiElements.window)
guiLabelSetHorizontalAlign(guiElements.titleLabel, "center")
-- Events
addEventHandler("onClientGUIClick", guiElements.playButton, onPlayClick, false)
addEventHandler("onClientGUIClick", guiElements.settingsButton, onSettingsClick, false)
addEventHandler("onClientGUIClick", guiElements.quitButton, onQuitClick, false)
guiSetVisible(guiElements.window, false)
end
function onPlayClick()
guiSetVisible(guiElements.window, false)
showCursor(false)
triggerServerEvent("onClientRequestSpawn", localPlayer)
end
function onSettingsClick()
createSettingsMenu()
end
function onQuitClick()
triggerServerEvent("onClientRequestQuit", localPlayer)
end
function toggleMainMenu()
local visible = not guiGetVisible(guiElements.window)
guiSetVisible(guiElements.window, visible)
showCursor(visible)
end
bindKey("F1", "down", toggleMainMenu)
DX-Based GUI
local dxGUI = {
visible = false,
elements = {}
}
function createDXButton(x, y, width, height, text, onClick)
local button = {
x = x, y = y, width = width, height = height,
text = text, onClick = onClick,
hover = false, click = false
}
table.insert(dxGUI.elements, button)
return button
end
function drawDXGUI()
if not dxGUI.visible then return end
-- Background overlay
dxDrawRectangle(0, 0, screenWidth, screenHeight, tocolor(0, 0, 0, 150))
-- Main panel
local panelWidth, panelHeight = 400, 300
local panelX = (screenWidth - panelWidth) / 2
local panelY = (screenHeight - panelHeight) / 2
dxDrawRectangle(panelX, panelY, panelWidth, panelHeight, tocolor(50, 50, 50, 200))
dxDrawRectangle(panelX, panelY, panelWidth, 30, tocolor(0, 100, 200, 255))
dxDrawText("DX GUI Panel", panelX, panelY, panelX + panelWidth, panelY + 30,
tocolor(255, 255, 255, 255), 1, "default", "center", "center")
-- Draw elements
for _, element in ipairs(dxGUI.elements) do
local color = tocolor(100, 100, 100, 200)
if element.hover then color = tocolor(120, 120, 120, 200) end
if element.click then color = tocolor(80, 80, 80, 200) end
dxDrawRectangle(element.x, element.y, element.width, element.height, color)
dxDrawText(element.text, element.x, element.y,
element.x + element.width, element.y + element.height,
tocolor(255, 255, 255, 255), 1, "default", "center", "center")
end
end
function handleDXGUIClick(button, state, absoluteX, absoluteY)
if not dxGUI.visible or button ~= "left" or state ~= "down" then return end
for _, element in ipairs(dxGUI.elements) do
if absoluteX >= element.x and absoluteX <= element.x + element.width and
absoluteY >= element.y and absoluteY <= element.y + element.height then
element.click = true
if element.onClick then element.onClick() end
end
end
end
addEventHandler("onClientRender", root, drawDXGUI)
addEventHandler("onClientClick", root, handleDXGUIClick)
Database Integration
SQLite database connection සහ data persistence
Database Connection
local db = nil
function connectDatabase()
if db then return db end
db = dbConnect("sqlite", ":/players.db")
if not db then
outputDebugString("Database connection failed!")
return nil
end
outputDebugString("Database connected successfully!")
createTables()
return db
end
function createTables()
if not db then return false end
-- Players table
dbExec(db, [[
CREATE TABLE IF NOT EXISTS players (
id INTEGER PRIMARY KEY AUTOINCREMENT,
account TEXT UNIQUE,
name TEXT,
money INTEGER DEFAULT 1000,
level INTEGER DEFAULT 1,
experience INTEGER DEFAULT 0,
play_time INTEGER DEFAULT 0,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
]])
-- Vehicles table
dbExec(db, [[
CREATE TABLE IF NOT EXISTS vehicles (
id INTEGER PRIMARY KEY AUTOINCREMENT,
owner_account TEXT,
model INTEGER,
pos_x REAL,
pos_y REAL,
pos_z REAL,
rotation REAL,
color1 INTEGER,
color2 INTEGER,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
]])
outputDebugString("Database tables created!")
return true
end
Player Data Save/Load
function savePlayerData(player)
if not isValidPlayer(player) or not db then return false end
local account = getPlayerAccount(player)
if not account or isGuestAccount(account) then return false end
local accountName = getAccountName(account)
local playerName = getPlayerName(player)
local money = getElementData(player, "money") or 0
local level = getElementData(player, "level") or 1
local experience = getElementData(player, "experience") or 0
local playTime = getElementData(player, "playTime") or 0
local query = dbQuery(db, "SELECT id FROM players WHERE account = ?", accountName)
local result = dbPoll(query, -1)
if result and #result > 0 then
dbExec(db,
"UPDATE players SET name = ?, money = ?, level = ?, experience = ?, play_time = ? WHERE account = ?",
playerName, money, level, experience, playTime, accountName
)
else
dbExec(db,
"INSERT INTO players (account, name, money, level, experience, play_time) VALUES (?, ?, ?, ?, ?, ?)",
accountName, playerName, money, level, experience, playTime
)
end
outputDebugString("Player data saved: " .. playerName)
return true
end
function loadPlayerData(player)
if not isValidPlayer(player) or not db then return false end
local account = getPlayerAccount(player)
if not account or isGuestAccount(account) then return false end
local accountName = getAccountName(account)
local query = dbQuery(db, "SELECT * FROM players WHERE account = ?", accountName)
local result = dbPoll(query, -1)
if result and #result > 0 then
local data = result[1]
setElementData(player, "money", data.money)
setElementData(player, "level", data.level)
setElementData(player, "experience", data.experience)
setElementData(player, "playTime", data.play_time)
outputChatBox("[db] ඔබගේ දත්ත ලබා ගන්නා ලදී!", player, 0, 255, 0)
return true
else
setupPlayerData(player)
outputChatBox("[+] සාදරයෙන් පිළිගනිමු! ඔබගේ නව ගිණුම සාදන ලදී.", player, 0, 255, 0)
return true
end
end
Auto-Save System
-- Auto-save timer (5 minutes)
setTimer(
function()
for _, player in ipairs(getElementsByType("player")) do
savePlayerData(player)
end
outputDebugString("Auto-save completed!")
end,
300000, 0
)
-- Player quit වෙද්දී save කිරීම
addEventHandler("onPlayerQuit", root,
function()
savePlayerData(source)
end
)
Advanced Concepts
OOP, Performance Optimization සහ Memory Management
OOP — Player Class
-- Player class definition
Player = {}
Player.__index = Player
function Player:create(account)
local instance = {}
setmetatable(instance, Player)
instance.account = account
instance.element = nil
instance.data = {}
return instance
end
function Player:setElement(playerElement)
if not isValidPlayer(playerElement) then return false end
self.element = playerElement
return true
end
function Player:getMoney()
return getElementData(self.element, "money") or 0
end
function Player:addMoney(amount)
if not amount then return false end
local current = self:getMoney()
setElementData(self.element, "money", current + amount)
triggerEvent("onPlayerMoneyChange", self.element, amount, current + amount)
return true
end
function Player:save()
return savePlayerData(self.element)
end
-- Player Manager
PlayerManager = {
players = {}
}
function PlayerManager:getPlayer(account)
return self.players[account]
end
function PlayerManager:addPlayer(account, playerElement)
local player = Player:create(account)
player:setElement(playerElement)
self.players[account] = player
return player
end
function PlayerManager:removePlayer(account)
local player = self.players[account]
if player then
player:save()
self.players[account] = nil
end
end
Performance Optimization
-- Event handler optimization
local eventHandlers = {}
function addOptimizedEventHandler(eventName, attachedTo, handler)
if not eventHandlers[eventName] then
eventHandlers[eventName] = {}
end
table.insert(eventHandlers[eventName], {
attachedTo = attachedTo,
handler = handler
})
addEventHandler(eventName, attachedTo, handler)
end
function removeOptimizedEventHandlers(eventName)
if eventHandlers[eventName] then
for _, handlerData in ipairs(eventHandlers[eventName]) do
removeEventHandler(eventName, handlerData.attachedTo, handlerData.handler)
end
eventHandlers[eventName] = nil
end
end
-- Memory Management
function cleanupUnusedElements()
local count = 0
for _, vehicle in ipairs(getElementsByType("vehicle")) do
if not getElementData(vehicle, "inUse") then
if getElementHealth(vehicle) < 250 then
destroyElement(vehicle)
count = count + 1
end
end
end
outputDebugString("Cleanup completed: " .. count .. " elements removed")
end
setTimer(cleanupUnusedElements, 60000, 0) -- 1 minute
Best Practices
Code organization, Security සහ Documentation
Modular Folder Structure
Input Validation
function validatePlayerInput(player, input, maxLength)
if not isValidPlayer(player) then return false end
if not input or type(input) ~= "string" then return false end
if #input > (maxLength or 128) then return false end
-- Remove harmful characters
local cleanInput = string.gsub(input, "[<>\"']", "")
return cleanInput
end
-- Admin validation
function isPlayerAdmin(player)
if not isValidPlayer(player) then return false end
local account = getPlayerAccount(player)
if not account or isGuestAccount(account) then return false end
local accountName = getAccountName(account)
return isObjectInACLGroup("user." .. accountName, aclGetGroup("Admin"))
end
Error Handling Wrapper
function safeFunctionCall(func, ...)
local results = {pcall(func, ...)}
if not results[1] then
local errorMsg = results[2] or "Unknown error"
outputDebugString("Function error: " .. errorMsg, 1)
return false, errorMsg
end
return unpack(results, 2)
end
-- Usage
local success, result = safeFunctionCall(riskyOperation, param1, param2)
if success then
-- Process result
else
-- Handle error
outputChatBox("Operation failed: " .. result, player, 255, 0, 0)
end
Code Documentation
--- Player money management system
-- @module player_money
-- @author Omindu Dissanayake
-- @license MIT
--- Adds money to player's account
-- @function addPlayerMoney
-- @param player userdata The player element
-- @param amount number The amount to add
-- @return boolean True if successful, false otherwise
-- @usage addPlayerMoney(player, 1000)
function addPlayerMoney(player, amount)
-- Function implementation
end
මෙම පාඨමාලාව Lua programming සහ MTA:SA development හි සම්පූර්ණ පදනම ලබා දෙනු ඇත.
ප්රධාන කරුණු
- Lua basics හොඳින් ඉගෙන ගන්න
- MTA events සහ element system හැසිරවීම
- Server-client communication තේරුම් ගන්න
- Database integration හොඳින් කරන්න
- Code organization best practices
ඊළඟ පියවර
- සරල resources සිට පටන් ගන්න
- ක්රමයෙන් complex features add කරන්න
- MTA wiki සහ forums භාවිතා කරන්න
- දෝෂ නිරාකරණය ඉගෙන ගන්න
- අන් අයගේ code අධ්යයනය කරන්න