<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.multitheftauto.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Flox</id>
	<title>Multi Theft Auto: Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.multitheftauto.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Flox"/>
	<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/wiki/Special:Contributions/Flox"/>
	<updated>2026-04-10T03:42:04Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.3</generator>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=GetVehicleComponentPosition&amp;diff=82790</id>
		<title>GetVehicleComponentPosition</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=GetVehicleComponentPosition&amp;diff=82790"/>
		<updated>2026-04-03T20:06:56Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{Client function}}&lt;br /&gt;
This function gets the component position of a [[vehicle]]. The vehicle must be streamed in.&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
float, float, float getVehicleComponentPosition ( vehicle theVehicle, string theComponent [, string base = &amp;quot;root&amp;quot; ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{OOP||[[vehicle]]:getComponentPosition||setVehicleComponentPosition}}&lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''theVehicle:''' The [[vehicle]] you wish to get component position of.&lt;br /&gt;
*'''theComponent:''' A [[Vehicle_Components|vehicle component]] (this is the frame name from the model file of the component you wish to modify)&lt;br /&gt;
&lt;br /&gt;
===Optional Arguments=== &lt;br /&gt;
{{New feature/item|3.0141|1.4.0|7013|&lt;br /&gt;
*'''base:''' A string representing what the returned position is relative to. It can be one of the following values:&lt;br /&gt;
**'''parent:''' The position is relative to the parent component.&lt;br /&gt;
**'''root:''' The position is relative to the root component.&lt;br /&gt;
**'''world:''' The position is a world position.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Returns=== &lt;br /&gt;
Returns three ''floats'' indicating the position of the component, ''x'', ''y'' and ''z'' respectively.&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&amp;lt;section class=&amp;quot;client&amp;quot; show=&amp;quot;true&amp;quot; name=&amp;quot;This example gets the name and the position of the components and outputs it in the chat.&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addCommandHandler(&amp;quot;vcp&amp;quot;, -- short for 'vehicle component position'&lt;br /&gt;
    function()&lt;br /&gt;
        local theVeh = getPedOccupiedVehicle(localPlayer)&lt;br /&gt;
	local getComponent = getVehicleComponents(theVeh) -- returns table with all the components of the vehicle&lt;br /&gt;
        if (theVeh) then&lt;br /&gt;
            for k in pairs (getComponent) do&lt;br /&gt;
		local x, y, z = getVehicleComponentPosition(theVeh, k)&lt;br /&gt;
                outputChatBox(&amp;quot;Position of &amp;quot;..k..&amp;quot; is&amp;quot;..x..&amp;quot; &amp;quot;..y..&amp;quot; &amp;quot;..z)&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;section class=&amp;quot;client&amp;quot; show=&amp;quot;true&amp;quot; name=&amp;quot;This example shows every components name in 3D(Only for streamedin vehicles)&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local showComponents = false&lt;br /&gt;
&lt;br /&gt;
bindKey(&amp;quot;F5&amp;quot;, &amp;quot;down&amp;quot;, function() showComponents = not showComponents end)&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onClientRender&amp;quot;, root, function()&lt;br /&gt;
    if not showComponents then return end&lt;br /&gt;
&lt;br /&gt;
    for _, veh in pairs(getElementsByType(&amp;quot;vehicle&amp;quot;, root, true)) do&lt;br /&gt;
        for compname in pairs(getVehicleComponents(veh)) do&lt;br /&gt;
            local x, y = getScreenFromWorldPosition(getVehicleComponentPosition(veh, compname, &amp;quot;world&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
            if x then&lt;br /&gt;
                dxDrawText(compname, x, y, 0, 0)&lt;br /&gt;
            end&lt;br /&gt;
        end &lt;br /&gt;
    end&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Rectify the warning code and render it.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local showComponents = false&lt;br /&gt;
&lt;br /&gt;
bindKey(&amp;quot;F5&amp;quot;, &amp;quot;down&amp;quot;, function() showComponents = not showComponents end)&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onClientRender&amp;quot;, root, function()&lt;br /&gt;
    if not showComponents then return end&lt;br /&gt;
    local playerVeh = getPedOccupiedVehicle(localPlayer) &lt;br /&gt;
    if not playerVeh then return end -- If we're not in the car, we don't do anything&lt;br /&gt;
    -- We only check the components of your machine&lt;br /&gt;
    local components = getVehicleComponents(playerVeh)&lt;br /&gt;
    if components then&lt;br /&gt;
        for compname in pairs(components) do&lt;br /&gt;
            local px, py, pz = getVehicleComponentPosition(playerVeh, compname, &amp;quot;world&amp;quot;)&lt;br /&gt;
            if px then&lt;br /&gt;
                local sx, sy = getScreenFromWorldPosition(px, py, pz)&lt;br /&gt;
                if sx then&lt;br /&gt;
                    local text = string.format(&amp;quot;%s\n[%.2f, %.2f, %.2f]&amp;quot;, compname, px, py, pz)&lt;br /&gt;
                    dxDrawText(text, sx, sy, sx, sy, tocolor(255, 255, 0, 255), 0.8, &amp;quot;default-bold&amp;quot;, &amp;quot;center&amp;quot;, &amp;quot;bottom&amp;quot;)&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end &lt;br /&gt;
    end&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Changelog==&lt;br /&gt;
{{ChangelogHeader}}&lt;br /&gt;
{{ChangelogItem|1.4.0-9.07013|Added '''base''' argument}}&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Client_vehicle_functions}}&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=GetVehicleComponentPosition&amp;diff=82789</id>
		<title>GetVehicleComponentPosition</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=GetVehicleComponentPosition&amp;diff=82789"/>
		<updated>2026-04-03T19:55:00Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{Client function}}&lt;br /&gt;
This function gets the component position of a [[vehicle]]. The vehicle must be streamed in.&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
float, float, float getVehicleComponentPosition ( vehicle theVehicle, string theComponent [, string base = &amp;quot;root&amp;quot; ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{OOP||[[vehicle]]:getComponentPosition||setVehicleComponentPosition}}&lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''theVehicle:''' The [[vehicle]] you wish to get component position of.&lt;br /&gt;
*'''theComponent:''' A [[Vehicle_Components|vehicle component]] (this is the frame name from the model file of the component you wish to modify)&lt;br /&gt;
&lt;br /&gt;
===Optional Arguments=== &lt;br /&gt;
{{New feature/item|3.0141|1.4.0|7013|&lt;br /&gt;
*'''base:''' A string representing what the returned position is relative to. It can be one of the following values:&lt;br /&gt;
**'''parent:''' The position is relative to the parent component.&lt;br /&gt;
**'''root:''' The position is relative to the root component.&lt;br /&gt;
**'''world:''' The position is a world position.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Returns=== &lt;br /&gt;
Returns three ''floats'' indicating the position of the component, ''x'', ''y'' and ''z'' respectively.&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&amp;lt;section class=&amp;quot;client&amp;quot; show=&amp;quot;true&amp;quot; name=&amp;quot;This example gets the name and the position of the components and outputs it in the chat.&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
addCommandHandler(&amp;quot;vcp&amp;quot;, -- short for 'vehicle component position'&lt;br /&gt;
    function()&lt;br /&gt;
        local theVeh = getPedOccupiedVehicle(localPlayer)&lt;br /&gt;
	local getComponent = getVehicleComponents(theVeh) -- returns table with all the components of the vehicle&lt;br /&gt;
        if (theVeh) then&lt;br /&gt;
            for k in pairs (getComponent) do&lt;br /&gt;
		local x, y, z = getVehicleComponentPosition(theVeh, k)&lt;br /&gt;
                outputChatBox(&amp;quot;Position of &amp;quot;..k..&amp;quot; is&amp;quot;..x..&amp;quot; &amp;quot;..y..&amp;quot; &amp;quot;..z)&lt;br /&gt;
            end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;section class=&amp;quot;client&amp;quot; show=&amp;quot;true&amp;quot; name=&amp;quot;This example shows every components name in 3D(Only for streamedin vehicles)&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local showComponents = false&lt;br /&gt;
&lt;br /&gt;
bindKey(&amp;quot;F5&amp;quot;, &amp;quot;down&amp;quot;, function() showComponents = not showComponents end)&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onClientRender&amp;quot;, root, function()&lt;br /&gt;
    if not showComponents then return end&lt;br /&gt;
&lt;br /&gt;
    for _, veh in pairs(getElementsByType(&amp;quot;vehicle&amp;quot;, root, true)) do&lt;br /&gt;
        for compname in pairs(getVehicleComponents(veh)) do&lt;br /&gt;
            local x, y = getScreenFromWorldPosition(getVehicleComponentPosition(veh, compname, &amp;quot;world&amp;quot;))&lt;br /&gt;
&lt;br /&gt;
            if x then&lt;br /&gt;
                dxDrawText(compname, x, y, 0, 0)&lt;br /&gt;
            end&lt;br /&gt;
        end &lt;br /&gt;
    end&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Fix warning code&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local showComponents = false&lt;br /&gt;
&lt;br /&gt;
bindKey(&amp;quot;F5&amp;quot;, &amp;quot;down&amp;quot;, function() showComponents = not showComponents end)&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onClientRender&amp;quot;, root, function()&lt;br /&gt;
    if not showComponents then return end&lt;br /&gt;
    &lt;br /&gt;
    local playerVeh = getPedOccupiedVehicle(localPlayer)&lt;br /&gt;
    if not playerVeh then return end -- If we're not in the car, we don't do anything&lt;br /&gt;
&lt;br /&gt;
    -- We only check the components of your machine&lt;br /&gt;
    local components = getVehicleComponents(playerVeh)&lt;br /&gt;
    if components then&lt;br /&gt;
        for compname in pairs(components) do&lt;br /&gt;
            local px, py, pz = getVehicleComponentPosition(playerVeh, compname, &amp;quot;world&amp;quot;)&lt;br /&gt;
            if px then&lt;br /&gt;
                local sx, sy = getScreenFromWorldPosition(px, py, pz)&lt;br /&gt;
                if sx then&lt;br /&gt;
                    dxDrawText(compname, sx, sy, 0, 0)&lt;br /&gt;
                end&lt;br /&gt;
            end&lt;br /&gt;
        end &lt;br /&gt;
    end&lt;br /&gt;
end)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Changelog==&lt;br /&gt;
{{ChangelogHeader}}&lt;br /&gt;
{{ChangelogItem|1.4.0-9.07013|Added '''base''' argument}}&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Client_vehicle_functions}}&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82788</id>
		<title>IsResourceRunning</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82788"/>
		<updated>2026-04-02T03:41:55Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* Example check isResourceRunning(resName) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
{{Shared function}}&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
*'''isResourceRunning''' You can insert this code example in your resources.&lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''isResourceRunning:''' The value to check resources&lt;br /&gt;
&lt;br /&gt;
==Example check isResourceRunning(resName)==&lt;br /&gt;
&amp;lt;section name=&amp;quot;isResourceRunning&amp;quot; class=&amp;quot;shared&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
You can insert this code example in your resources.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function isResourceRunning(resName)&lt;br /&gt;
   local res = getResourceFromName(resName)&lt;br /&gt;
   return (res) and (getResourceState(res) == &amp;quot;running&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Example of inserting into system code:&lt;br /&gt;
--[[&lt;br /&gt;
if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
   --code&lt;br /&gt;
else&lt;br /&gt;
   --alert&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addCommandHandler('pos', function (commandName)&lt;br /&gt;
    if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
       local x,y,z = getElementPosition(localPlayer)&lt;br /&gt;
       outputChatBox( x ..', '.. y ..', '.. z, 255, 255, 255 )&lt;br /&gt;
    else&lt;br /&gt;
       outputChatBox(&amp;quot;The resource is not running 'admin'.&amp;quot;, 255, 0, 0)&lt;br /&gt;
    end&lt;br /&gt;
end )&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Resource_functions}}&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=DbConnect&amp;diff=82787</id>
		<title>DbConnect</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=DbConnect&amp;diff=82787"/>
		<updated>2026-04-02T03:23:30Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{Server function}}&lt;br /&gt;
This function opens a connection to a database and returns an element that can be used with [[dbQuery]]. To disconnect use [[destroyElement]].&lt;br /&gt;
{{Note|Connecting and disconnecting many times can have a performance impact on the server. For optimal performance it is recommended that you use dbConnect only once when the resource starts, and share the connection element with the whole script.}}&lt;br /&gt;
{{Note|In MySQL 8.0 and later, you can choose between '''`caching_sha2_password`''', '''`sha256_password`''', or '''`mysql_native_password`''' for password management.&lt;br /&gt;
* If you opt for '''`caching_sha2_password`''' or '''`sha256_password`''', SSL is not mandatory but recommended for secure authentication.&lt;br /&gt;
* If you choose '''`mysql_native_password`''', you can set it as the default authentication plugin:&lt;br /&gt;
** In the '''`mysqld.cnf`''' configuration file, by adding or modifying the following line: '''&amp;lt;nowiki&amp;gt;default-authentication-plugin=mysql_native_password&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
** Using SQL queries (e.g., ALTER USER).&lt;br /&gt;
** In PHPMyAdmin (via the user settings page).&lt;br /&gt;
Please note that starting with MySQL 9.0, '''`mysql_native_password`''' will no longer be available, and only '''`caching_sha2_password`''' and '''`sha256_password`''' will be supported.&lt;br /&gt;
}}&lt;br /&gt;
==Syntax== &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
element dbConnect ( string databaseType, string host [, string username = &amp;quot;&amp;quot;, string password = &amp;quot;&amp;quot;, string options = &amp;quot;&amp;quot; ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{OOP||[[Connection]]}}&lt;br /&gt;
===Required Arguments===&lt;br /&gt;
*'''databaseType:''' The type of database. This can be either ''sqlite'' or ''mysql''&lt;br /&gt;
*'''host:''' The target to connect to. The format of this depends on the database type.&lt;br /&gt;
** For SQLite it is a [[filepath]] to a SQLite database file. If the filepath starts with &amp;quot;:/&amp;quot; then the server's global databases directory is used. The file will be created if it does not exist.&lt;br /&gt;
** For MySQL it is a list of key=value pairs separated by semicolons. Supported keys are:&lt;br /&gt;
*** '''dbname''': Name of the database to use e.g. ''dbname=test''&lt;br /&gt;
*** '''host''': Host address e.g. ''host=127.0.0.1''&lt;br /&gt;
*** '''port''': Host port e.g. ''port=3306'' (optional, defaults to standard MySQL port if not used)&lt;br /&gt;
*** '''unix_socket''': Unix socket or named pipe to use (optional)&lt;br /&gt;
***'''charset''': Communicate with the server using a character which is different from the default e.g. ''charset&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;utf8'' (optional)&lt;br /&gt;
&lt;br /&gt;
===Optional Arguments===&lt;br /&gt;
*'''username:''' Usually required for MySQL, ignored by SQLite &lt;br /&gt;
*'''password:''' Usually required for MySQL, ignored by SQLite &lt;br /&gt;
*'''options :''' List of key=value pairs separated by semicolons. Supported keys are:&lt;br /&gt;
**'''share''' which can be set to 0 or 1. (Default value for SQLite is &amp;quot;share=1&amp;quot;, for MySQL is &amp;quot;share=0&amp;quot;). When set to 1, the connection is shared and will be used by other calls to dbConnect with the same host string. This is usually a good thing for SQLite connections, but not so good for MySQL unless care is taken.&lt;br /&gt;
**'''batch''' which can be set to 0 or 1. (Default is &amp;quot;batch=1&amp;quot;). When set to 1, queries called in the same frame are automatically batched together which can significantly speed up inserts/updates. The downside is you lose control of the feature that is used to achieve batching (For SQLite it is transactions, for MySQL it is autocommit mode). Therefore, if you use transactions, lock tables or control autocommit yourself, you may want to disable this feature.&lt;br /&gt;
**'''autoreconnect''' which can be set to 0 or 1. (Default value &amp;quot;autoreconnect=1&amp;quot;). When set to 1, dropped connections will automatically be reconnected. Note that session variables (incl. SET NAMES), user variables, table locks and temporary tables will be reset because of the reconnection. So if you use these fancy features, you will need to turn autoreconnect off and cope with dropped connections some other way.&lt;br /&gt;
**'''log''' which can be set to 0 or 1. (Default value &amp;quot;log&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;1&amp;quot;). When set to 0, activity from this connection will not be recorded in the [[Server_Commands#debugdb|database debug log file]].&lt;br /&gt;
**'''tag''' (Default value &amp;quot;tag&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;script&amp;quot;). A string which helps identify activity from this connection in the [[Server_Commands#debugdb|database debug log file]].&lt;br /&gt;
**'''suppress''' A comma separated list of error codes to ignore. (eg. &amp;quot;suppress&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;1062,1169&amp;quot;).&lt;br /&gt;
**'''multi_statements''' Enable multiple statements (separated by a semi-colon) in one query. Use [[dbPrepareString]] when building a multiple statement query to reduce SQL injection risks.&lt;br /&gt;
**'''queue''' Name of the queue to use. (Default value for SQLite is &amp;quot;sqlite&amp;quot;, for MySQL default is the host string from the '''host''' argument). Asynchronous database queries in the same queue are processed in order, one at a time. Any name can be used.&lt;br /&gt;
**'''use_ssl''' which can be set to 0 or 1. (Default value is 0), ignored by SQLite&lt;br /&gt;
**{{New feature/item|3.0161|1.6.0|22497|'''get_server_public_key''' which can be set to 0 or 1. (Default value is 1), ignored by SQLite. When set to 1, this enables the client to request from the server the public key required for RSA key pair-based password exchange. This option applies to clients that authenticate with the &amp;lt;code&amp;gt;caching_sha2_password&amp;lt;/code&amp;gt; authentication plugin.}}&lt;br /&gt;
&lt;br /&gt;
===Returns===&lt;br /&gt;
Returns a database connection element unless there are problems, in which case it return ''false''.&lt;br /&gt;
&lt;br /&gt;
==Remarks==&lt;br /&gt;
Under certain platforms, for example on Unix-based OSes like Linux, using this function could fail with a debug warning containing &amp;quot;[Could not connect]&amp;quot; accompanied by a prior debug error explaining the problem. In that case you should check the [[Server Manual]] to see if you have missed any recommended (best-effort) steps for server set-up.&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
This example opens a connection to a SQLite database file in the current resource&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in another resource&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:resname/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in the global databases directory&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in a sub directory of the global databases directory&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:/example/sub/dir/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a MySQL database called 'frank' at server ip 1.2.3.4 using utf8 character set and allows the connection to be shared. Note that changing the database or other connection dependent settings affect all connections that are shared.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;mysql&amp;quot;, &amp;quot;dbname=frank;host=1.2.3.4;charset=utf8&amp;quot;, &amp;quot;username&amp;quot;, &amp;quot;password&amp;quot;, &amp;quot;share=1&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database is disallows sharing of the connection&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;share=0&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example output debug message, if the connection with SQLite database was established or not&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot; )&lt;br /&gt;
&lt;br /&gt;
if test_db then&lt;br /&gt;
    outputDebugString( &amp;quot;Connection with database was successfully established.&amp;quot; )&lt;br /&gt;
else&lt;br /&gt;
    outputDebugString( &amp;quot;Connection with database couldn't be established.&amp;quot; )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The folowing example shows how you could approach a common resource for database operations with exported functions ('''query''' and '''execute'''):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function connect()&lt;br /&gt;
    DBConnection = dbConnect( &amp;quot;mysql&amp;quot;, &amp;quot;dbname=DBNAME;host=HOST;charset=utf8&amp;quot;, &amp;quot;USERNAME&amp;quot;, &amp;quot;PASSWORD&amp;quot; )&lt;br /&gt;
    if (not DBConnection) then&lt;br /&gt;
        outputDebugString(&amp;quot;Error: Failed to establish connection to the MySQL database server&amp;quot;)&lt;br /&gt;
    else&lt;br /&gt;
        outputDebugString(&amp;quot;Success: Connected to the MySQL database server&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onResourceStart&amp;quot;,resourceRoot, connect)&lt;br /&gt;
 &lt;br /&gt;
function query(...)&lt;br /&gt;
    local queryHandle = dbQuery(DBConnection, ...)&lt;br /&gt;
    if (not queryHandle) then&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
    local rows = dbPoll(queryHandle, -1)&lt;br /&gt;
    return rows&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
function execute(...)&lt;br /&gt;
    local queryHandle = dbQuery(DBConnection, ...)&lt;br /&gt;
    local result, numRows = dbPoll(queryHandle, -1)&lt;br /&gt;
    return numRows&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function getDBConnection()&lt;br /&gt;
    return DBConnection&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following example illustrates an exemplary approach to utilizing a common resource for database operations, employing exported functions such as '''dbQuery''', '''dbExec''', '''dbQueryAsync''', '''dbPrepareString''', and '''dbQueryAsyncMultiple.''':&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
--[[&lt;br /&gt;
&lt;br /&gt;
```meta.xml```&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbQueryAsync&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbQuery&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbExec&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;getTableName&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbPrepareString&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbQueryAsyncMultiple&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
```meta.xml end```&lt;br /&gt;
]]&lt;br /&gt;
--[[&lt;br /&gt;
example exported: = &lt;br /&gt;
exports.nameres:dbQuery(-1, &amp;quot;test&amp;quot;, &amp;quot;SELECT ID FROM ?? WHERE ID = ?&amp;quot;, 1)&lt;br /&gt;
&lt;br /&gt;
exports.nameres:dbExec(&amp;quot;test&amp;quot;, &amp;quot;UPDATE ?? SET test= ? WHERE ID = ?;&amp;quot;, '0', 1)&lt;br /&gt;
exports.nameres:dbExec(&amp;quot;test&amp;quot;, &amp;quot;CREATE TABLE IF NOT EXISTS ?? (`ID` INT UNSIGNED NOT NULL PRIMARY KEY, `test` TEXT) COLLATE=utf8_unicode_ci;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
exports.nameres:dbExec(&amp;quot;test&amp;quot;, &amp;quot;INSERT INTO ?? (`ID`, `test`) VALUES (?, ?);&amp;quot;, '1', '1')&lt;br /&gt;
&lt;br /&gt;
function onPlayerQuit()&lt;br /&gt;
	exports.nameres:dbQueryAsync(&amp;quot;onPlayerQuitCallback&amp;quot;, {}, &amp;quot;test&amp;quot;, &amp;quot;SELECT ID FROM ?? WHERE owner = ?&amp;quot;, getAccountName(getPlayerAccount(source)))&lt;br /&gt;
end&lt;br /&gt;
function onPlayerQuitCallback(result, args)&lt;br /&gt;
	for _, row in ipairs(result) do&lt;br /&gt;
		destroyVehicle(vehiclesByID[row.ID])&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onPlayerQuit&amp;quot;, root, onPlayerQuit)&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;dbCallback&amp;quot;, false)&lt;br /&gt;
addEventHandler(&amp;quot;dbCallback&amp;quot;, resourceRoot, function(queryResult, callbackFunctionName, callbackArguments)&lt;br /&gt;
	_G[callbackFunctionName](queryResult, callbackArguments)&lt;br /&gt;
end)&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
host = &amp;quot;IPHost&amp;quot; --&amp;quot;127.0.0.1&amp;quot; -- &amp;quot;localhost&amp;quot;&lt;br /&gt;
--unix_socket = &amp;quot;/var/run/mysqld/mysqld.sock&amp;quot;&lt;br /&gt;
dbname = &amp;quot;namedb&amp;quot;&lt;br /&gt;
user = &amp;quot;rootname&amp;quot;&lt;br /&gt;
password = &amp;quot;pass&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local unix_socket, host = unix_socket, host&lt;br /&gt;
local dbname, user, password = dbname, user, password&lt;br /&gt;
local mainDB&lt;br /&gt;
&lt;br /&gt;
function connect()&lt;br /&gt;
	local startTick = getTickCount()&lt;br /&gt;
	mainDB = dbConnect(&amp;quot;mysql&amp;quot;, (unix_socket and &amp;quot;unix_socket=&amp;quot;..unix_socket or &amp;quot;host=&amp;quot;..host)..&amp;quot;;dbname=&amp;quot;..dbname, user, password)&lt;br /&gt;
	if (mainDB) then&lt;br /&gt;
		outputDebugString(&amp;quot;[MYSQL] Connection: &amp;quot;..getTickCount()-startTick..&amp;quot; ms.&amp;quot;)&lt;br /&gt;
	else&lt;br /&gt;
		outputDebugString(&amp;quot;[MYSQL][ERROR] Connection failed!&amp;quot;, 1)&lt;br /&gt;
		setTimer(connect, 5000, 1)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
connect()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbQuery = dbQuery&lt;br /&gt;
function dbQuery(timeout, tableName, query, ...)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(_dbQuery(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...), timeout)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString (string.format(&amp;quot;[MYSQL][ERROR] dbQuery error on %s (table `%s`)&amp;quot;, query, tableName), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	return result, errorCode, errorMessage&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function dbQueryAsync(callbackFunctionName, callbackArguments, tableName, query, ...)&lt;br /&gt;
	local extraData = {&lt;br /&gt;
		sourceResourceRoot,&lt;br /&gt;
		callbackFunctionName,&lt;br /&gt;
		callbackArguments,&lt;br /&gt;
	}&lt;br /&gt;
	return _dbQuery(dbCallback, extraData, mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
function dbCallback(queryHandle, srcResRoot, callbackFunctionName, callbackArguments)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(queryHandle, 0)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString (string.format(&amp;quot;[MYSQL][ERROR] dbCallback error %i (%s)&amp;quot;, errorCode, errorMessage), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	triggerEvent(&amp;quot;dbCallback&amp;quot;, srcResRoot, result, callbackFunctionName, callbackArguments)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbExec = dbExec&lt;br /&gt;
function dbExec(tableName, query, ...)&lt;br /&gt;
	-- We should also check if our database has fallen off, but unfortunately...&lt;br /&gt;
	return _dbExec(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function getTableName(tableName)&lt;br /&gt;
	return getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbPrepareString = dbPrepareString&lt;br /&gt;
function dbPrepareString(tableName, query, ...)&lt;br /&gt;
	return _dbPrepareString(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local multipleQueryTable = {}&lt;br /&gt;
function dbQueryAsyncMultiple(callbackFunctionName, callbackArguments, ...)&lt;br /&gt;
	local queries = {...}&lt;br /&gt;
	local packID = generateID()&lt;br /&gt;
	while (multipleQueryTable[packID]) do&lt;br /&gt;
		packID = generateID()&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	multipleQueryTable[packID] = {&lt;br /&gt;
		sourceResourceRoot = sourceResourceRoot,&lt;br /&gt;
		callbackFunctionName = callbackFunctionName,&lt;br /&gt;
		callbackArguments = callbackArguments,&lt;br /&gt;
		numberOfQueries = #queries,&lt;br /&gt;
		replies = {},&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	for queryNumber, query in ipairs(queries) do&lt;br /&gt;
		local extraData = {&lt;br /&gt;
			packID,&lt;br /&gt;
			queryNumber,&lt;br /&gt;
		}&lt;br /&gt;
		_dbQuery(multipleQueryCallback, extraData, mainDB, query.query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..query.tableName, unpack(query))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function multipleQueryCallback(queryHandle, packID, queryNumber)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(queryHandle, 0)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString(string.format(&amp;quot;[MYSQL][ERROR] multipleQueryCallback error %i (%s)&amp;quot;, errorCode, errorMessage), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local queryTable = multipleQueryTable[packID]&lt;br /&gt;
	queryTable.replies[queryNumber] = {&lt;br /&gt;
		result = result,&lt;br /&gt;
		errorCode = errorCode,&lt;br /&gt;
		errorMessage = errorMessage,&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	if (#queryTable.replies == queryTable.numberOfQueries) then&lt;br /&gt;
		triggerEvent(&amp;quot;dbCallback&amp;quot;, queryTable.sourceResourceRoot, queryTable.replies, queryTable.callbackFunctionName, queryTable.callbackArguments)&lt;br /&gt;
		multipleQueryTable[packID] = nil&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
dbQueryAsyncMultiple(string callbackFunctionName, table callbackArguments, ...)&lt;br /&gt;
Where there is an ellipsis, there is a table of this kind for each request:&lt;br /&gt;
{&lt;br /&gt;
	string tableName,&lt;br /&gt;
	string query,&lt;br /&gt;
	arguments separated by commas&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
--The results will be displayed in a table, preserving the order of the executed queries. The table will look like this:&lt;br /&gt;
{&lt;br /&gt;
	{&lt;br /&gt;
		table result,&lt;br /&gt;
		number errorCode,&lt;br /&gt;
		string errorMessage,&lt;br /&gt;
	},&lt;br /&gt;
}&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
-- Generating a string of characters&lt;br /&gt;
local symbols = {}&lt;br /&gt;
for _, range in ipairs({{48, 57}, {65, 90}, {97, 122}}) do -- numbers/lowercase chars/uppercase chars&lt;br /&gt;
	for i = range[1], range[2] do&lt;br /&gt;
		table.insert(symbols, string.char(i))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
local symbolCount = #symbols&lt;br /&gt;
function generateID()&lt;br /&gt;
	local str = &amp;quot;&amp;quot;&lt;br /&gt;
	for i = 1, 8 do&lt;br /&gt;
		str = str..symbols[math.random(1, symbolCount)]&lt;br /&gt;
	end&lt;br /&gt;
	return str&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Changelog==&lt;br /&gt;
{{ChangelogHeader}}&lt;br /&gt;
{{ChangelogItem|1.3.1-9.04817|Added options 'log', 'tag' and 'suppress'}}&lt;br /&gt;
{{ChangelogItem|1.3.5-9.06386|Added option 'charset'}}&lt;br /&gt;
{{ChangelogItem|1.5.2-9.07972|Added option 'multi_statements'}}&lt;br /&gt;
{{ChangelogItem|1.5.4-9.11138|Added option 'queue'}}&lt;br /&gt;
{{ChangelogItem|1.6.0-9.22396|Added option 'use_ssl'}}&lt;br /&gt;
{{ChangelogItem|1.6.0-9.22497|Added option 'get_server_public_key'}}&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{SQL_functions}}&lt;br /&gt;
&lt;br /&gt;
[[ru:dbConnect]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=DbConnect&amp;diff=82786</id>
		<title>DbConnect</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=DbConnect&amp;diff=82786"/>
		<updated>2026-04-02T03:22:54Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{Server function}}&lt;br /&gt;
This function opens a connection to a database and returns an element that can be used with [[dbQuery]]. To disconnect use [[destroyElement]].&lt;br /&gt;
{{Note|Connecting and disconnecting many times can have a performance impact on the server. For optimal performance it is recommended that you use dbConnect only once when the resource starts, and share the connection element with the whole script.}}&lt;br /&gt;
{{Note|In MySQL 8.0 and later, you can choose between '''`caching_sha2_password`''', '''`sha256_password`''', or '''`mysql_native_password`''' for password management.&lt;br /&gt;
* If you opt for '''`caching_sha2_password`''' or '''`sha256_password`''', SSL is not mandatory but recommended for secure authentication.&lt;br /&gt;
* If you choose '''`mysql_native_password`''', you can set it as the default authentication plugin:&lt;br /&gt;
** In the '''`mysqld.cnf`''' configuration file, by adding or modifying the following line: '''&amp;lt;nowiki&amp;gt;default-authentication-plugin=mysql_native_password&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
** Using SQL queries (e.g., ALTER USER).&lt;br /&gt;
** In PHPMyAdmin (via the user settings page).&lt;br /&gt;
Please note that starting with MySQL 9.0, '''`mysql_native_password`''' will no longer be available, and only '''`caching_sha2_password`''' and '''`sha256_password`''' will be supported.&lt;br /&gt;
}}&lt;br /&gt;
==Syntax== &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
element dbConnect ( string databaseType, string host [, string username = &amp;quot;&amp;quot;, string password = &amp;quot;&amp;quot;, string options = &amp;quot;&amp;quot; ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{OOP||[[Connection]]}}&lt;br /&gt;
===Required Arguments===&lt;br /&gt;
*'''databaseType:''' The type of database. This can be either ''sqlite'' or ''mysql''&lt;br /&gt;
*'''host:''' The target to connect to. The format of this depends on the database type.&lt;br /&gt;
** For SQLite it is a [[filepath]] to a SQLite database file. If the filepath starts with &amp;quot;:/&amp;quot; then the server's global databases directory is used. The file will be created if it does not exist.&lt;br /&gt;
** For MySQL it is a list of key=value pairs separated by semicolons. Supported keys are:&lt;br /&gt;
*** '''dbname''': Name of the database to use e.g. ''dbname=test''&lt;br /&gt;
*** '''host''': Host address e.g. ''host=127.0.0.1''&lt;br /&gt;
*** '''port''': Host port e.g. ''port=3306'' (optional, defaults to standard MySQL port if not used)&lt;br /&gt;
*** '''unix_socket''': Unix socket or named pipe to use (optional)&lt;br /&gt;
***'''charset''': Communicate with the server using a character which is different from the default e.g. ''charset&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;utf8'' (optional)&lt;br /&gt;
&lt;br /&gt;
===Optional Arguments===&lt;br /&gt;
*'''username:''' Usually required for MySQL, ignored by SQLite &lt;br /&gt;
*'''password:''' Usually required for MySQL, ignored by SQLite &lt;br /&gt;
*'''options :''' List of key=value pairs separated by semicolons. Supported keys are:&lt;br /&gt;
**'''share''' which can be set to 0 or 1. (Default value for SQLite is &amp;quot;share=1&amp;quot;, for MySQL is &amp;quot;share=0&amp;quot;). When set to 1, the connection is shared and will be used by other calls to dbConnect with the same host string. This is usually a good thing for SQLite connections, but not so good for MySQL unless care is taken.&lt;br /&gt;
**'''batch''' which can be set to 0 or 1. (Default is &amp;quot;batch=1&amp;quot;). When set to 1, queries called in the same frame are automatically batched together which can significantly speed up inserts/updates. The downside is you lose control of the feature that is used to achieve batching (For SQLite it is transactions, for MySQL it is autocommit mode). Therefore, if you use transactions, lock tables or control autocommit yourself, you may want to disable this feature.&lt;br /&gt;
**'''autoreconnect''' which can be set to 0 or 1. (Default value &amp;quot;autoreconnect=1&amp;quot;). When set to 1, dropped connections will automatically be reconnected. Note that session variables (incl. SET NAMES), user variables, table locks and temporary tables will be reset because of the reconnection. So if you use these fancy features, you will need to turn autoreconnect off and cope with dropped connections some other way.&lt;br /&gt;
**'''log''' which can be set to 0 or 1. (Default value &amp;quot;log&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;1&amp;quot;). When set to 0, activity from this connection will not be recorded in the [[Server_Commands#debugdb|database debug log file]].&lt;br /&gt;
**'''tag''' (Default value &amp;quot;tag&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;script&amp;quot;). A string which helps identify activity from this connection in the [[Server_Commands#debugdb|database debug log file]].&lt;br /&gt;
**'''suppress''' A comma separated list of error codes to ignore. (eg. &amp;quot;suppress&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;1062,1169&amp;quot;).&lt;br /&gt;
**'''multi_statements''' Enable multiple statements (separated by a semi-colon) in one query. Use [[dbPrepareString]] when building a multiple statement query to reduce SQL injection risks.&lt;br /&gt;
**'''queue''' Name of the queue to use. (Default value for SQLite is &amp;quot;sqlite&amp;quot;, for MySQL default is the host string from the '''host''' argument). Asynchronous database queries in the same queue are processed in order, one at a time. Any name can be used.&lt;br /&gt;
**'''use_ssl''' which can be set to 0 or 1. (Default value is 0), ignored by SQLite&lt;br /&gt;
**{{New feature/item|3.0161|1.6.0|22497|'''get_server_public_key''' which can be set to 0 or 1. (Default value is 1), ignored by SQLite. When set to 1, this enables the client to request from the server the public key required for RSA key pair-based password exchange. This option applies to clients that authenticate with the &amp;lt;code&amp;gt;caching_sha2_password&amp;lt;/code&amp;gt; authentication plugin.}}&lt;br /&gt;
&lt;br /&gt;
===Returns===&lt;br /&gt;
Returns a database connection element unless there are problems, in which case it return ''false''.&lt;br /&gt;
&lt;br /&gt;
==Remarks==&lt;br /&gt;
Under certain platforms, for example on Unix-based OSes like Linux, using this function could fail with a debug warning containing &amp;quot;[Could not connect]&amp;quot; accompanied by a prior debug error explaining the problem. In that case you should check the [[Server Manual]] to see if you have missed any recommended (best-effort) steps for server set-up.&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
This example opens a connection to a SQLite database file in the current resource&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in another resource&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:resname/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in the global databases directory&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in a sub directory of the global databases directory&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:/example/sub/dir/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a MySQL database called 'frank' at server ip 1.2.3.4 using utf8 character set and allows the connection to be shared. Note that changing the database or other connection dependent settings affect all connections that are shared.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;mysql&amp;quot;, &amp;quot;dbname=frank;host=1.2.3.4;charset=utf8&amp;quot;, &amp;quot;username&amp;quot;, &amp;quot;password&amp;quot;, &amp;quot;share=1&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database is disallows sharing of the connection&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;share=0&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example output debug message, if the connection with SQLite database was established or not&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot; )&lt;br /&gt;
&lt;br /&gt;
if test_db then&lt;br /&gt;
    outputDebugString( &amp;quot;Connection with database was successfully established.&amp;quot; )&lt;br /&gt;
else&lt;br /&gt;
    outputDebugString( &amp;quot;Connection with database couldn't be established.&amp;quot; )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The folowing example shows how you could approach a common resource for database operations with exported functions ('''query''' and '''execute'''):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function connect()&lt;br /&gt;
    DBConnection = dbConnect( &amp;quot;mysql&amp;quot;, &amp;quot;dbname=DBNAME;host=HOST;charset=utf8&amp;quot;, &amp;quot;USERNAME&amp;quot;, &amp;quot;PASSWORD&amp;quot; )&lt;br /&gt;
    if (not DBConnection) then&lt;br /&gt;
        outputDebugString(&amp;quot;Error: Failed to establish connection to the MySQL database server&amp;quot;)&lt;br /&gt;
    else&lt;br /&gt;
        outputDebugString(&amp;quot;Success: Connected to the MySQL database server&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onResourceStart&amp;quot;,resourceRoot, connect)&lt;br /&gt;
 &lt;br /&gt;
function query(...)&lt;br /&gt;
    local queryHandle = dbQuery(DBConnection, ...)&lt;br /&gt;
    if (not queryHandle) then&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
    local rows = dbPoll(queryHandle, -1)&lt;br /&gt;
    return rows&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
function execute(...)&lt;br /&gt;
    local queryHandle = dbQuery(DBConnection, ...)&lt;br /&gt;
    local result, numRows = dbPoll(queryHandle, -1)&lt;br /&gt;
    return numRows&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function getDBConnection()&lt;br /&gt;
    return DBConnection&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following example illustrates an exemplary approach to utilizing a common resource for database operations, employing exported functions such as '''dbQuery''', '''dbExec''', '''dbQueryAsync''', '''dbPrepareString''', and '''dbQueryAsyncMultiple.''':&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
--[[&lt;br /&gt;
&lt;br /&gt;
```meta.xml```&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbQueryAsync&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbQuery&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbExec&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;getTableName&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbPrepareString&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbQueryAsyncMultiple&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
```meta.xml end```&lt;br /&gt;
]]&lt;br /&gt;
--[[&lt;br /&gt;
example exported: = &lt;br /&gt;
exports.nameres:dbQuery(-1, &amp;quot;test&amp;quot;, &amp;quot;SELECT ID FROM ?? WHERE ID = ?&amp;quot;, 1)&lt;br /&gt;
&lt;br /&gt;
exports.nameres:dbExec(&amp;quot;test&amp;quot;, &amp;quot;UPDATE ?? SET test= ? WHERE ID = ?;&amp;quot;, '0', 1)&lt;br /&gt;
exports.nameres:dbExec(&amp;quot;test&amp;quot;, &amp;quot;CREATE TABLE IF NOT EXISTS ?? (`ID` INT UNSIGNED NOT NULL PRIMARY KEY, `test` TEXT) COLLATE=utf8_unicode_ci;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
exports.nameres:dbExec(&amp;quot;test&amp;quot;, &amp;quot;INSERT INTO ?? (`ID`, `test`) VALUES (?, ?);&amp;quot;, '1', '1')&lt;br /&gt;
&lt;br /&gt;
function onPlayerQuit()&lt;br /&gt;
	exports.nameres:dbQueryAsync(&amp;quot;onPlayerQuitCallback&amp;quot;, {}, &amp;quot;test&amp;quot;, &amp;quot;SELECT ID FROM ?? WHERE owner = ?&amp;quot;, getAccountName(getPlayerAccount(source)))&lt;br /&gt;
end&lt;br /&gt;
function onPlayerQuitCallback(result, args)&lt;br /&gt;
	for _, row in ipairs(result) do&lt;br /&gt;
		destroyVehicle(vehiclesByID[row.ID])&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onPlayerQuit&amp;quot;, root, onPlayerQuit)&lt;br /&gt;
&lt;br /&gt;
addEvent(&amp;quot;dbCallback&amp;quot;, false)&lt;br /&gt;
addEventHandler(&amp;quot;dbCallback&amp;quot;, resourceRoot, function(queryResult, callbackFunctionName, callbackArguments)&lt;br /&gt;
	_G[callbackFunctionName](queryResult, callbackArguments)&lt;br /&gt;
end)&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
host = &amp;quot;IPHost&amp;quot; --&amp;quot;127.0.0.1&amp;quot; -- &amp;quot;localhost&amp;quot;&lt;br /&gt;
--unix_socket = &amp;quot;/var/run/mysqld/mysqld.sock&amp;quot;&lt;br /&gt;
dbname = &amp;quot;namedb&amp;quot;&lt;br /&gt;
user = &amp;quot;rootname&amp;quot;&lt;br /&gt;
password = &amp;quot;pass&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local unix_socket, host = unix_socket, host&lt;br /&gt;
local dbname, user, password = dbname, user, password&lt;br /&gt;
local mainDB&lt;br /&gt;
&lt;br /&gt;
function connect()&lt;br /&gt;
	local startTick = getTickCount()&lt;br /&gt;
	mainDB = dbConnect(&amp;quot;mysql&amp;quot;, (unix_socket and &amp;quot;unix_socket=&amp;quot;..unix_socket or &amp;quot;host=&amp;quot;..host)..&amp;quot;;dbname=&amp;quot;..dbname, user, password)&lt;br /&gt;
	if (mainDB) then&lt;br /&gt;
		outputDebugString(&amp;quot;[MYSQL] Connection: &amp;quot;..getTickCount()-startTick..&amp;quot; ms.&amp;quot;)&lt;br /&gt;
	else&lt;br /&gt;
		outputDebugString(&amp;quot;[MYSQL][ERROR] Connection failed!&amp;quot;, 1)&lt;br /&gt;
		setTimer(connect, 5000, 1)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
connect()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbQuery = dbQuery&lt;br /&gt;
function dbQuery(timeout, tableName, query, ...)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(_dbQuery(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...), timeout)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString (string.format(&amp;quot;[MYSQL][ERROR] dbQuery error on %s (table `%s`)&amp;quot;, query, tableName), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	return result, errorCode, errorMessage&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function dbQueryAsync(callbackFunctionName, callbackArguments, tableName, query, ...)&lt;br /&gt;
	local extraData = {&lt;br /&gt;
		sourceResourceRoot,&lt;br /&gt;
		callbackFunctionName,&lt;br /&gt;
		callbackArguments,&lt;br /&gt;
	}&lt;br /&gt;
	return _dbQuery(dbCallback, extraData, mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
function dbCallback(queryHandle, srcResRoot, callbackFunctionName, callbackArguments)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(queryHandle, 0)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString (string.format(&amp;quot;[MYSQL][ERROR] dbCallback error %i (%s)&amp;quot;, errorCode, errorMessage), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	triggerEvent(&amp;quot;dbCallback&amp;quot;, srcResRoot, result, callbackFunctionName, callbackArguments)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbExec = dbExec&lt;br /&gt;
function dbExec(tableName, query, ...)&lt;br /&gt;
	-- We should also check if our database has fallen off, but unfortunately...&lt;br /&gt;
	return _dbExec(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function getTableName(tableName)&lt;br /&gt;
	return getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbPrepareString = dbPrepareString&lt;br /&gt;
function dbPrepareString(tableName, query, ...)&lt;br /&gt;
	return _dbPrepareString(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local multipleQueryTable = {}&lt;br /&gt;
function dbQueryAsyncMultiple(callbackFunctionName, callbackArguments, ...)&lt;br /&gt;
	local queries = {...}&lt;br /&gt;
	local packID = generateID()&lt;br /&gt;
	while (multipleQueryTable[packID]) do&lt;br /&gt;
		packID = generateID()&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	multipleQueryTable[packID] = {&lt;br /&gt;
		sourceResourceRoot = sourceResourceRoot,&lt;br /&gt;
		callbackFunctionName = callbackFunctionName,&lt;br /&gt;
		callbackArguments = callbackArguments,&lt;br /&gt;
		numberOfQueries = #queries,&lt;br /&gt;
		replies = {},&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	for queryNumber, query in ipairs(queries) do&lt;br /&gt;
		local extraData = {&lt;br /&gt;
			packID,&lt;br /&gt;
			queryNumber,&lt;br /&gt;
		}&lt;br /&gt;
		_dbQuery(multipleQueryCallback, extraData, mainDB, query.query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..query.tableName, unpack(query))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function multipleQueryCallback(queryHandle, packID, queryNumber)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(queryHandle, 0)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString(string.format(&amp;quot;[MYSQL][ERROR] multipleQueryCallback error %i (%s)&amp;quot;, errorCode, errorMessage), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local queryTable = multipleQueryTable[packID]&lt;br /&gt;
	queryTable.replies[queryNumber] = {&lt;br /&gt;
		result = result,&lt;br /&gt;
		errorCode = errorCode,&lt;br /&gt;
		errorMessage = errorMessage,&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	if (#queryTable.replies == queryTable.numberOfQueries) then&lt;br /&gt;
		triggerEvent(&amp;quot;dbCallback&amp;quot;, queryTable.sourceResourceRoot, queryTable.replies, queryTable.callbackFunctionName, queryTable.callbackArguments)&lt;br /&gt;
		multipleQueryTable[packID] = nil&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
dbQueryAsyncMultiple(string callbackFunctionName, table callbackArguments, ...)&lt;br /&gt;
Where there is an ellipsis, there is a table of this kind for each request:&lt;br /&gt;
{&lt;br /&gt;
	string tableName,&lt;br /&gt;
	string query,&lt;br /&gt;
	аргументы через запятую&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
--The results will be displayed in a table, preserving the order of the executed queries. The table will look like this:&lt;br /&gt;
{&lt;br /&gt;
	{&lt;br /&gt;
		table result,&lt;br /&gt;
		number errorCode,&lt;br /&gt;
		string errorMessage,&lt;br /&gt;
	},&lt;br /&gt;
}&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
-- Generating a string of characters&lt;br /&gt;
local symbols = {}&lt;br /&gt;
for _, range in ipairs({{48, 57}, {65, 90}, {97, 122}}) do -- numbers/lowercase chars/uppercase chars&lt;br /&gt;
	for i = range[1], range[2] do&lt;br /&gt;
		table.insert(symbols, string.char(i))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
local symbolCount = #symbols&lt;br /&gt;
function generateID()&lt;br /&gt;
	local str = &amp;quot;&amp;quot;&lt;br /&gt;
	for i = 1, 8 do&lt;br /&gt;
		str = str..symbols[math.random(1, symbolCount)]&lt;br /&gt;
	end&lt;br /&gt;
	return str&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Changelog==&lt;br /&gt;
{{ChangelogHeader}}&lt;br /&gt;
{{ChangelogItem|1.3.1-9.04817|Added options 'log', 'tag' and 'suppress'}}&lt;br /&gt;
{{ChangelogItem|1.3.5-9.06386|Added option 'charset'}}&lt;br /&gt;
{{ChangelogItem|1.5.2-9.07972|Added option 'multi_statements'}}&lt;br /&gt;
{{ChangelogItem|1.5.4-9.11138|Added option 'queue'}}&lt;br /&gt;
{{ChangelogItem|1.6.0-9.22396|Added option 'use_ssl'}}&lt;br /&gt;
{{ChangelogItem|1.6.0-9.22497|Added option 'get_server_public_key'}}&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{SQL_functions}}&lt;br /&gt;
&lt;br /&gt;
[[ru:dbConnect]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=DbConnect&amp;diff=82785</id>
		<title>DbConnect</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=DbConnect&amp;diff=82785"/>
		<updated>2026-04-02T03:20:09Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{Server function}}&lt;br /&gt;
This function opens a connection to a database and returns an element that can be used with [[dbQuery]]. To disconnect use [[destroyElement]].&lt;br /&gt;
{{Note|Connecting and disconnecting many times can have a performance impact on the server. For optimal performance it is recommended that you use dbConnect only once when the resource starts, and share the connection element with the whole script.}}&lt;br /&gt;
{{Note|In MySQL 8.0 and later, you can choose between '''`caching_sha2_password`''', '''`sha256_password`''', or '''`mysql_native_password`''' for password management.&lt;br /&gt;
* If you opt for '''`caching_sha2_password`''' or '''`sha256_password`''', SSL is not mandatory but recommended for secure authentication.&lt;br /&gt;
* If you choose '''`mysql_native_password`''', you can set it as the default authentication plugin:&lt;br /&gt;
** In the '''`mysqld.cnf`''' configuration file, by adding or modifying the following line: '''&amp;lt;nowiki&amp;gt;default-authentication-plugin=mysql_native_password&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
** Using SQL queries (e.g., ALTER USER).&lt;br /&gt;
** In PHPMyAdmin (via the user settings page).&lt;br /&gt;
Please note that starting with MySQL 9.0, '''`mysql_native_password`''' will no longer be available, and only '''`caching_sha2_password`''' and '''`sha256_password`''' will be supported.&lt;br /&gt;
}}&lt;br /&gt;
==Syntax== &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
element dbConnect ( string databaseType, string host [, string username = &amp;quot;&amp;quot;, string password = &amp;quot;&amp;quot;, string options = &amp;quot;&amp;quot; ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{OOP||[[Connection]]}}&lt;br /&gt;
===Required Arguments===&lt;br /&gt;
*'''databaseType:''' The type of database. This can be either ''sqlite'' or ''mysql''&lt;br /&gt;
*'''host:''' The target to connect to. The format of this depends on the database type.&lt;br /&gt;
** For SQLite it is a [[filepath]] to a SQLite database file. If the filepath starts with &amp;quot;:/&amp;quot; then the server's global databases directory is used. The file will be created if it does not exist.&lt;br /&gt;
** For MySQL it is a list of key=value pairs separated by semicolons. Supported keys are:&lt;br /&gt;
*** '''dbname''': Name of the database to use e.g. ''dbname=test''&lt;br /&gt;
*** '''host''': Host address e.g. ''host=127.0.0.1''&lt;br /&gt;
*** '''port''': Host port e.g. ''port=3306'' (optional, defaults to standard MySQL port if not used)&lt;br /&gt;
*** '''unix_socket''': Unix socket or named pipe to use (optional)&lt;br /&gt;
***'''charset''': Communicate with the server using a character which is different from the default e.g. ''charset&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;utf8'' (optional)&lt;br /&gt;
&lt;br /&gt;
===Optional Arguments===&lt;br /&gt;
*'''username:''' Usually required for MySQL, ignored by SQLite &lt;br /&gt;
*'''password:''' Usually required for MySQL, ignored by SQLite &lt;br /&gt;
*'''options :''' List of key=value pairs separated by semicolons. Supported keys are:&lt;br /&gt;
**'''share''' which can be set to 0 or 1. (Default value for SQLite is &amp;quot;share=1&amp;quot;, for MySQL is &amp;quot;share=0&amp;quot;). When set to 1, the connection is shared and will be used by other calls to dbConnect with the same host string. This is usually a good thing for SQLite connections, but not so good for MySQL unless care is taken.&lt;br /&gt;
**'''batch''' which can be set to 0 or 1. (Default is &amp;quot;batch=1&amp;quot;). When set to 1, queries called in the same frame are automatically batched together which can significantly speed up inserts/updates. The downside is you lose control of the feature that is used to achieve batching (For SQLite it is transactions, for MySQL it is autocommit mode). Therefore, if you use transactions, lock tables or control autocommit yourself, you may want to disable this feature.&lt;br /&gt;
**'''autoreconnect''' which can be set to 0 or 1. (Default value &amp;quot;autoreconnect=1&amp;quot;). When set to 1, dropped connections will automatically be reconnected. Note that session variables (incl. SET NAMES), user variables, table locks and temporary tables will be reset because of the reconnection. So if you use these fancy features, you will need to turn autoreconnect off and cope with dropped connections some other way.&lt;br /&gt;
**'''log''' which can be set to 0 or 1. (Default value &amp;quot;log&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;1&amp;quot;). When set to 0, activity from this connection will not be recorded in the [[Server_Commands#debugdb|database debug log file]].&lt;br /&gt;
**'''tag''' (Default value &amp;quot;tag&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;script&amp;quot;). A string which helps identify activity from this connection in the [[Server_Commands#debugdb|database debug log file]].&lt;br /&gt;
**'''suppress''' A comma separated list of error codes to ignore. (eg. &amp;quot;suppress&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;1062,1169&amp;quot;).&lt;br /&gt;
**'''multi_statements''' Enable multiple statements (separated by a semi-colon) in one query. Use [[dbPrepareString]] when building a multiple statement query to reduce SQL injection risks.&lt;br /&gt;
**'''queue''' Name of the queue to use. (Default value for SQLite is &amp;quot;sqlite&amp;quot;, for MySQL default is the host string from the '''host''' argument). Asynchronous database queries in the same queue are processed in order, one at a time. Any name can be used.&lt;br /&gt;
**'''use_ssl''' which can be set to 0 or 1. (Default value is 0), ignored by SQLite&lt;br /&gt;
**{{New feature/item|3.0161|1.6.0|22497|'''get_server_public_key''' which can be set to 0 or 1. (Default value is 1), ignored by SQLite. When set to 1, this enables the client to request from the server the public key required for RSA key pair-based password exchange. This option applies to clients that authenticate with the &amp;lt;code&amp;gt;caching_sha2_password&amp;lt;/code&amp;gt; authentication plugin.}}&lt;br /&gt;
&lt;br /&gt;
===Returns===&lt;br /&gt;
Returns a database connection element unless there are problems, in which case it return ''false''.&lt;br /&gt;
&lt;br /&gt;
==Remarks==&lt;br /&gt;
Under certain platforms, for example on Unix-based OSes like Linux, using this function could fail with a debug warning containing &amp;quot;[Could not connect]&amp;quot; accompanied by a prior debug error explaining the problem. In that case you should check the [[Server Manual]] to see if you have missed any recommended (best-effort) steps for server set-up.&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
This example opens a connection to a SQLite database file in the current resource&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in another resource&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:resname/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in the global databases directory&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in a sub directory of the global databases directory&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:/example/sub/dir/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a MySQL database called 'frank' at server ip 1.2.3.4 using utf8 character set and allows the connection to be shared. Note that changing the database or other connection dependent settings affect all connections that are shared.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;mysql&amp;quot;, &amp;quot;dbname=frank;host=1.2.3.4;charset=utf8&amp;quot;, &amp;quot;username&amp;quot;, &amp;quot;password&amp;quot;, &amp;quot;share=1&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database is disallows sharing of the connection&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;share=0&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example output debug message, if the connection with SQLite database was established or not&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot; )&lt;br /&gt;
&lt;br /&gt;
if test_db then&lt;br /&gt;
    outputDebugString( &amp;quot;Connection with database was successfully established.&amp;quot; )&lt;br /&gt;
else&lt;br /&gt;
    outputDebugString( &amp;quot;Connection with database couldn't be established.&amp;quot; )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The folowing example shows how you could approach a common resource for database operations with exported functions ('''query''' and '''execute'''):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function connect()&lt;br /&gt;
    DBConnection = dbConnect( &amp;quot;mysql&amp;quot;, &amp;quot;dbname=DBNAME;host=HOST;charset=utf8&amp;quot;, &amp;quot;USERNAME&amp;quot;, &amp;quot;PASSWORD&amp;quot; )&lt;br /&gt;
    if (not DBConnection) then&lt;br /&gt;
        outputDebugString(&amp;quot;Error: Failed to establish connection to the MySQL database server&amp;quot;)&lt;br /&gt;
    else&lt;br /&gt;
        outputDebugString(&amp;quot;Success: Connected to the MySQL database server&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onResourceStart&amp;quot;,resourceRoot, connect)&lt;br /&gt;
 &lt;br /&gt;
function query(...)&lt;br /&gt;
    local queryHandle = dbQuery(DBConnection, ...)&lt;br /&gt;
    if (not queryHandle) then&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
    local rows = dbPoll(queryHandle, -1)&lt;br /&gt;
    return rows&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
function execute(...)&lt;br /&gt;
    local queryHandle = dbQuery(DBConnection, ...)&lt;br /&gt;
    local result, numRows = dbPoll(queryHandle, -1)&lt;br /&gt;
    return numRows&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function getDBConnection()&lt;br /&gt;
    return DBConnection&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following example illustrates an exemplary approach to utilizing a common resource for database operations, employing exported functions such as '''dbQuery''', '''dbExec''', '''dbQueryAsync''', '''dbPrepareString''', and '''dbQueryAsyncMultiple.''':&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
--[[&lt;br /&gt;
&lt;br /&gt;
```meta.xml```&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbQueryAsync&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbQuery&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbExec&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;getTableName&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbPrepareString&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbQueryAsyncMultiple&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
```meta.xml end```&lt;br /&gt;
]]&lt;br /&gt;
--[[&lt;br /&gt;
example exported: = &lt;br /&gt;
exports.nameres:dbQuery(-1, &amp;quot;test&amp;quot;, &amp;quot;SELECT ID FROM ?? WHERE ID = ?&amp;quot;, 1)&lt;br /&gt;
&lt;br /&gt;
exports.nameres:dbExec(&amp;quot;test&amp;quot;, &amp;quot;UPDATE ?? SET test= ? WHERE ID = ?;&amp;quot;, '0', 1)&lt;br /&gt;
exports.nameres:dbExec(&amp;quot;test&amp;quot;, &amp;quot;CREATE TABLE IF NOT EXISTS ?? (`ID` INT UNSIGNED NOT NULL PRIMARY KEY, `test` TEXT) COLLATE=utf8_unicode_ci;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
exports.nameres:dbExec(&amp;quot;test&amp;quot;, &amp;quot;INSERT INTO ?? (`ID`, `test`) VALUES (?, ?);&amp;quot;, '1', '1')&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
host = &amp;quot;IPHost&amp;quot; --&amp;quot;127.0.0.1&amp;quot; -- &amp;quot;localhost&amp;quot;&lt;br /&gt;
--unix_socket = &amp;quot;/var/run/mysqld/mysqld.sock&amp;quot;&lt;br /&gt;
dbname = &amp;quot;namedb&amp;quot;&lt;br /&gt;
user = &amp;quot;rootname&amp;quot;&lt;br /&gt;
password = &amp;quot;pass&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local unix_socket, host = unix_socket, host&lt;br /&gt;
local dbname, user, password = dbname, user, password&lt;br /&gt;
local mainDB&lt;br /&gt;
&lt;br /&gt;
function connect()&lt;br /&gt;
	local startTick = getTickCount()&lt;br /&gt;
	mainDB = dbConnect(&amp;quot;mysql&amp;quot;, (unix_socket and &amp;quot;unix_socket=&amp;quot;..unix_socket or &amp;quot;host=&amp;quot;..host)..&amp;quot;;dbname=&amp;quot;..dbname, user, password)&lt;br /&gt;
	if (mainDB) then&lt;br /&gt;
		outputDebugString(&amp;quot;[MYSQL] Connection: &amp;quot;..getTickCount()-startTick..&amp;quot; ms.&amp;quot;)&lt;br /&gt;
	else&lt;br /&gt;
		outputDebugString(&amp;quot;[MYSQL][ERROR] Connection failed!&amp;quot;, 1)&lt;br /&gt;
		setTimer(connect, 5000, 1)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
connect()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbQuery = dbQuery&lt;br /&gt;
function dbQuery(timeout, tableName, query, ...)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(_dbQuery(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...), timeout)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString (string.format(&amp;quot;[MYSQL][ERROR] dbQuery error on %s (table `%s`)&amp;quot;, query, tableName), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	return result, errorCode, errorMessage&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function dbQueryAsync(callbackFunctionName, callbackArguments, tableName, query, ...)&lt;br /&gt;
	local extraData = {&lt;br /&gt;
		sourceResourceRoot,&lt;br /&gt;
		callbackFunctionName,&lt;br /&gt;
		callbackArguments,&lt;br /&gt;
	}&lt;br /&gt;
	return _dbQuery(dbCallback, extraData, mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
function dbCallback(queryHandle, srcResRoot, callbackFunctionName, callbackArguments)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(queryHandle, 0)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString (string.format(&amp;quot;[MYSQL][ERROR] dbCallback error %i (%s)&amp;quot;, errorCode, errorMessage), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	triggerEvent(&amp;quot;dbCallback&amp;quot;, srcResRoot, result, callbackFunctionName, callbackArguments)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbExec = dbExec&lt;br /&gt;
function dbExec(tableName, query, ...)&lt;br /&gt;
	-- We should also check if our database has fallen off, but unfortunately...&lt;br /&gt;
	return _dbExec(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function getTableName(tableName)&lt;br /&gt;
	return getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbPrepareString = dbPrepareString&lt;br /&gt;
function dbPrepareString(tableName, query, ...)&lt;br /&gt;
	return _dbPrepareString(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local multipleQueryTable = {}&lt;br /&gt;
function dbQueryAsyncMultiple(callbackFunctionName, callbackArguments, ...)&lt;br /&gt;
	local queries = {...}&lt;br /&gt;
	local packID = generateID()&lt;br /&gt;
	while (multipleQueryTable[packID]) do&lt;br /&gt;
		packID = generateID()&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	multipleQueryTable[packID] = {&lt;br /&gt;
		sourceResourceRoot = sourceResourceRoot,&lt;br /&gt;
		callbackFunctionName = callbackFunctionName,&lt;br /&gt;
		callbackArguments = callbackArguments,&lt;br /&gt;
		numberOfQueries = #queries,&lt;br /&gt;
		replies = {},&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	for queryNumber, query in ipairs(queries) do&lt;br /&gt;
		local extraData = {&lt;br /&gt;
			packID,&lt;br /&gt;
			queryNumber,&lt;br /&gt;
		}&lt;br /&gt;
		_dbQuery(multipleQueryCallback, extraData, mainDB, query.query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..query.tableName, unpack(query))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function multipleQueryCallback(queryHandle, packID, queryNumber)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(queryHandle, 0)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString(string.format(&amp;quot;[MYSQL][ERROR] multipleQueryCallback error %i (%s)&amp;quot;, errorCode, errorMessage), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local queryTable = multipleQueryTable[packID]&lt;br /&gt;
	queryTable.replies[queryNumber] = {&lt;br /&gt;
		result = result,&lt;br /&gt;
		errorCode = errorCode,&lt;br /&gt;
		errorMessage = errorMessage,&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	if (#queryTable.replies == queryTable.numberOfQueries) then&lt;br /&gt;
		triggerEvent(&amp;quot;dbCallback&amp;quot;, queryTable.sourceResourceRoot, queryTable.replies, queryTable.callbackFunctionName, queryTable.callbackArguments)&lt;br /&gt;
		multipleQueryTable[packID] = nil&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
dbQueryAsyncMultiple(string callbackFunctionName, table callbackArguments, ...)&lt;br /&gt;
Where there is an ellipsis, there is a table of this kind for each request:&lt;br /&gt;
{&lt;br /&gt;
	string tableName,&lt;br /&gt;
	string query,&lt;br /&gt;
	аргументы через запятую&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
--The results will be displayed in a table, preserving the order of the executed queries. The table will look like this:&lt;br /&gt;
{&lt;br /&gt;
	{&lt;br /&gt;
		table result,&lt;br /&gt;
		number errorCode,&lt;br /&gt;
		string errorMessage,&lt;br /&gt;
	},&lt;br /&gt;
}&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
-- Generating a string of characters&lt;br /&gt;
local symbols = {}&lt;br /&gt;
for _, range in ipairs({{48, 57}, {65, 90}, {97, 122}}) do -- numbers/lowercase chars/uppercase chars&lt;br /&gt;
	for i = range[1], range[2] do&lt;br /&gt;
		table.insert(symbols, string.char(i))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
local symbolCount = #symbols&lt;br /&gt;
function generateID()&lt;br /&gt;
	local str = &amp;quot;&amp;quot;&lt;br /&gt;
	for i = 1, 8 do&lt;br /&gt;
		str = str..symbols[math.random(1, symbolCount)]&lt;br /&gt;
	end&lt;br /&gt;
	return str&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Changelog==&lt;br /&gt;
{{ChangelogHeader}}&lt;br /&gt;
{{ChangelogItem|1.3.1-9.04817|Added options 'log', 'tag' and 'suppress'}}&lt;br /&gt;
{{ChangelogItem|1.3.5-9.06386|Added option 'charset'}}&lt;br /&gt;
{{ChangelogItem|1.5.2-9.07972|Added option 'multi_statements'}}&lt;br /&gt;
{{ChangelogItem|1.5.4-9.11138|Added option 'queue'}}&lt;br /&gt;
{{ChangelogItem|1.6.0-9.22396|Added option 'use_ssl'}}&lt;br /&gt;
{{ChangelogItem|1.6.0-9.22497|Added option 'get_server_public_key'}}&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{SQL_functions}}&lt;br /&gt;
&lt;br /&gt;
[[ru:dbConnect]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=DbConnect&amp;diff=82784</id>
		<title>DbConnect</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=DbConnect&amp;diff=82784"/>
		<updated>2026-04-02T03:19:27Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{Server function}}&lt;br /&gt;
This function opens a connection to a database and returns an element that can be used with [[dbQuery]]. To disconnect use [[destroyElement]].&lt;br /&gt;
{{Note|Connecting and disconnecting many times can have a performance impact on the server. For optimal performance it is recommended that you use dbConnect only once when the resource starts, and share the connection element with the whole script.}}&lt;br /&gt;
{{Note|In MySQL 8.0 and later, you can choose between '''`caching_sha2_password`''', '''`sha256_password`''', or '''`mysql_native_password`''' for password management.&lt;br /&gt;
* If you opt for '''`caching_sha2_password`''' or '''`sha256_password`''', SSL is not mandatory but recommended for secure authentication.&lt;br /&gt;
* If you choose '''`mysql_native_password`''', you can set it as the default authentication plugin:&lt;br /&gt;
** In the '''`mysqld.cnf`''' configuration file, by adding or modifying the following line: '''&amp;lt;nowiki&amp;gt;default-authentication-plugin=mysql_native_password&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
** Using SQL queries (e.g., ALTER USER).&lt;br /&gt;
** In PHPMyAdmin (via the user settings page).&lt;br /&gt;
Please note that starting with MySQL 9.0, '''`mysql_native_password`''' will no longer be available, and only '''`caching_sha2_password`''' and '''`sha256_password`''' will be supported.&lt;br /&gt;
}}&lt;br /&gt;
==Syntax== &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
element dbConnect ( string databaseType, string host [, string username = &amp;quot;&amp;quot;, string password = &amp;quot;&amp;quot;, string options = &amp;quot;&amp;quot; ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{OOP||[[Connection]]}}&lt;br /&gt;
===Required Arguments===&lt;br /&gt;
*'''databaseType:''' The type of database. This can be either ''sqlite'' or ''mysql''&lt;br /&gt;
*'''host:''' The target to connect to. The format of this depends on the database type.&lt;br /&gt;
** For SQLite it is a [[filepath]] to a SQLite database file. If the filepath starts with &amp;quot;:/&amp;quot; then the server's global databases directory is used. The file will be created if it does not exist.&lt;br /&gt;
** For MySQL it is a list of key=value pairs separated by semicolons. Supported keys are:&lt;br /&gt;
*** '''dbname''': Name of the database to use e.g. ''dbname=test''&lt;br /&gt;
*** '''host''': Host address e.g. ''host=127.0.0.1''&lt;br /&gt;
*** '''port''': Host port e.g. ''port=3306'' (optional, defaults to standard MySQL port if not used)&lt;br /&gt;
*** '''unix_socket''': Unix socket or named pipe to use (optional)&lt;br /&gt;
***'''charset''': Communicate with the server using a character which is different from the default e.g. ''charset&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;utf8'' (optional)&lt;br /&gt;
&lt;br /&gt;
===Optional Arguments===&lt;br /&gt;
*'''username:''' Usually required for MySQL, ignored by SQLite &lt;br /&gt;
*'''password:''' Usually required for MySQL, ignored by SQLite &lt;br /&gt;
*'''options :''' List of key=value pairs separated by semicolons. Supported keys are:&lt;br /&gt;
**'''share''' which can be set to 0 or 1. (Default value for SQLite is &amp;quot;share=1&amp;quot;, for MySQL is &amp;quot;share=0&amp;quot;). When set to 1, the connection is shared and will be used by other calls to dbConnect with the same host string. This is usually a good thing for SQLite connections, but not so good for MySQL unless care is taken.&lt;br /&gt;
**'''batch''' which can be set to 0 or 1. (Default is &amp;quot;batch=1&amp;quot;). When set to 1, queries called in the same frame are automatically batched together which can significantly speed up inserts/updates. The downside is you lose control of the feature that is used to achieve batching (For SQLite it is transactions, for MySQL it is autocommit mode). Therefore, if you use transactions, lock tables or control autocommit yourself, you may want to disable this feature.&lt;br /&gt;
**'''autoreconnect''' which can be set to 0 or 1. (Default value &amp;quot;autoreconnect=1&amp;quot;). When set to 1, dropped connections will automatically be reconnected. Note that session variables (incl. SET NAMES), user variables, table locks and temporary tables will be reset because of the reconnection. So if you use these fancy features, you will need to turn autoreconnect off and cope with dropped connections some other way.&lt;br /&gt;
**'''log''' which can be set to 0 or 1. (Default value &amp;quot;log&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;1&amp;quot;). When set to 0, activity from this connection will not be recorded in the [[Server_Commands#debugdb|database debug log file]].&lt;br /&gt;
**'''tag''' (Default value &amp;quot;tag&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;script&amp;quot;). A string which helps identify activity from this connection in the [[Server_Commands#debugdb|database debug log file]].&lt;br /&gt;
**'''suppress''' A comma separated list of error codes to ignore. (eg. &amp;quot;suppress&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;1062,1169&amp;quot;).&lt;br /&gt;
**'''multi_statements''' Enable multiple statements (separated by a semi-colon) in one query. Use [[dbPrepareString]] when building a multiple statement query to reduce SQL injection risks.&lt;br /&gt;
**'''queue''' Name of the queue to use. (Default value for SQLite is &amp;quot;sqlite&amp;quot;, for MySQL default is the host string from the '''host''' argument). Asynchronous database queries in the same queue are processed in order, one at a time. Any name can be used.&lt;br /&gt;
**'''use_ssl''' which can be set to 0 or 1. (Default value is 0), ignored by SQLite&lt;br /&gt;
**{{New feature/item|3.0161|1.6.0|22497|'''get_server_public_key''' which can be set to 0 or 1. (Default value is 1), ignored by SQLite. When set to 1, this enables the client to request from the server the public key required for RSA key pair-based password exchange. This option applies to clients that authenticate with the &amp;lt;code&amp;gt;caching_sha2_password&amp;lt;/code&amp;gt; authentication plugin.}}&lt;br /&gt;
&lt;br /&gt;
===Returns===&lt;br /&gt;
Returns a database connection element unless there are problems, in which case it return ''false''.&lt;br /&gt;
&lt;br /&gt;
==Remarks==&lt;br /&gt;
Under certain platforms, for example on Unix-based OSes like Linux, using this function could fail with a debug warning containing &amp;quot;[Could not connect]&amp;quot; accompanied by a prior debug error explaining the problem. In that case you should check the [[Server Manual]] to see if you have missed any recommended (best-effort) steps for server set-up.&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
This example opens a connection to a SQLite database file in the current resource&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in another resource&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:resname/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in the global databases directory&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in a sub directory of the global databases directory&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:/example/sub/dir/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a MySQL database called 'frank' at server ip 1.2.3.4 using utf8 character set and allows the connection to be shared. Note that changing the database or other connection dependent settings affect all connections that are shared.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;mysql&amp;quot;, &amp;quot;dbname=frank;host=1.2.3.4;charset=utf8&amp;quot;, &amp;quot;username&amp;quot;, &amp;quot;password&amp;quot;, &amp;quot;share=1&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database is disallows sharing of the connection&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;share=0&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example output debug message, if the connection with SQLite database was established or not&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot; )&lt;br /&gt;
&lt;br /&gt;
if test_db then&lt;br /&gt;
    outputDebugString( &amp;quot;Connection with database was successfully established.&amp;quot; )&lt;br /&gt;
else&lt;br /&gt;
    outputDebugString( &amp;quot;Connection with database couldn't be established.&amp;quot; )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The folowing example shows how you could approach a common resource for database operations with exported functions ('''query''' and '''execute'''):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function connect()&lt;br /&gt;
    DBConnection = dbConnect( &amp;quot;mysql&amp;quot;, &amp;quot;dbname=DBNAME;host=HOST;charset=utf8&amp;quot;, &amp;quot;USERNAME&amp;quot;, &amp;quot;PASSWORD&amp;quot; )&lt;br /&gt;
    if (not DBConnection) then&lt;br /&gt;
        outputDebugString(&amp;quot;Error: Failed to establish connection to the MySQL database server&amp;quot;)&lt;br /&gt;
    else&lt;br /&gt;
        outputDebugString(&amp;quot;Success: Connected to the MySQL database server&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onResourceStart&amp;quot;,resourceRoot, connect)&lt;br /&gt;
 &lt;br /&gt;
function query(...)&lt;br /&gt;
    local queryHandle = dbQuery(DBConnection, ...)&lt;br /&gt;
    if (not queryHandle) then&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
    local rows = dbPoll(queryHandle, -1)&lt;br /&gt;
    return rows&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
function execute(...)&lt;br /&gt;
    local queryHandle = dbQuery(DBConnection, ...)&lt;br /&gt;
    local result, numRows = dbPoll(queryHandle, -1)&lt;br /&gt;
    return numRows&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function getDBConnection()&lt;br /&gt;
    return DBConnection&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following example illustrates an exemplary approach to utilizing a common resource for database operations, employing exported functions such as '''dbQuery''', '''dbExec''', '''dbQueryAsync''', '''dbPrepareString''', and '''dbQueryAsyncMultiple.''':&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
--[[&lt;br /&gt;
&lt;br /&gt;
```meta.xml```&lt;br /&gt;
[[ &lt;br /&gt;
&amp;lt;export function=&amp;quot;dbQueryAsync&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbQuery&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbExec&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;getTableName&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbPrepareString&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
&amp;lt;export function=&amp;quot;dbQueryAsyncMultiple&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt;&lt;br /&gt;
]]&lt;br /&gt;
```meta.xml end```&lt;br /&gt;
&lt;br /&gt;
example exported: = &lt;br /&gt;
exports.nameres:dbQuery(-1, &amp;quot;test&amp;quot;, &amp;quot;SELECT ID FROM ?? WHERE ID = ?&amp;quot;, 1)&lt;br /&gt;
&lt;br /&gt;
exports.nameres:dbExec(&amp;quot;test&amp;quot;, &amp;quot;UPDATE ?? SET test= ? WHERE ID = ?;&amp;quot;, '0', 1)&lt;br /&gt;
exports.nameres:dbExec(&amp;quot;test&amp;quot;, &amp;quot;CREATE TABLE IF NOT EXISTS ?? (`ID` INT UNSIGNED NOT NULL PRIMARY KEY, `test` TEXT) COLLATE=utf8_unicode_ci;&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
exports.nameres:dbExec(&amp;quot;test&amp;quot;, &amp;quot;INSERT INTO ?? (`ID`, `test`) VALUES (?, ?);&amp;quot;, '1', '1')&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
host = &amp;quot;IPHost&amp;quot; --&amp;quot;127.0.0.1&amp;quot; -- &amp;quot;localhost&amp;quot;&lt;br /&gt;
--unix_socket = &amp;quot;/var/run/mysqld/mysqld.sock&amp;quot;&lt;br /&gt;
dbname = &amp;quot;namedb&amp;quot;&lt;br /&gt;
user = &amp;quot;rootname&amp;quot;&lt;br /&gt;
password = &amp;quot;pass&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local unix_socket, host = unix_socket, host&lt;br /&gt;
local dbname, user, password = dbname, user, password&lt;br /&gt;
local mainDB&lt;br /&gt;
&lt;br /&gt;
function connect()&lt;br /&gt;
	local startTick = getTickCount()&lt;br /&gt;
	mainDB = dbConnect(&amp;quot;mysql&amp;quot;, (unix_socket and &amp;quot;unix_socket=&amp;quot;..unix_socket or &amp;quot;host=&amp;quot;..host)..&amp;quot;;dbname=&amp;quot;..dbname, user, password)&lt;br /&gt;
	if (mainDB) then&lt;br /&gt;
		outputDebugString(&amp;quot;[MYSQL] Connection: &amp;quot;..getTickCount()-startTick..&amp;quot; ms.&amp;quot;)&lt;br /&gt;
	else&lt;br /&gt;
		outputDebugString(&amp;quot;[MYSQL][ERROR] Connection failed!&amp;quot;, 1)&lt;br /&gt;
		setTimer(connect, 5000, 1)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
connect()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbQuery = dbQuery&lt;br /&gt;
function dbQuery(timeout, tableName, query, ...)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(_dbQuery(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...), timeout)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString (string.format(&amp;quot;[MYSQL][ERROR] dbQuery error on %s (table `%s`)&amp;quot;, query, tableName), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	return result, errorCode, errorMessage&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function dbQueryAsync(callbackFunctionName, callbackArguments, tableName, query, ...)&lt;br /&gt;
	local extraData = {&lt;br /&gt;
		sourceResourceRoot,&lt;br /&gt;
		callbackFunctionName,&lt;br /&gt;
		callbackArguments,&lt;br /&gt;
	}&lt;br /&gt;
	return _dbQuery(dbCallback, extraData, mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
function dbCallback(queryHandle, srcResRoot, callbackFunctionName, callbackArguments)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(queryHandle, 0)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString (string.format(&amp;quot;[MYSQL][ERROR] dbCallback error %i (%s)&amp;quot;, errorCode, errorMessage), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	triggerEvent(&amp;quot;dbCallback&amp;quot;, srcResRoot, result, callbackFunctionName, callbackArguments)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbExec = dbExec&lt;br /&gt;
function dbExec(tableName, query, ...)&lt;br /&gt;
	-- We should also check if our database has fallen off, but unfortunately...&lt;br /&gt;
	return _dbExec(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function getTableName(tableName)&lt;br /&gt;
	return getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbPrepareString = dbPrepareString&lt;br /&gt;
function dbPrepareString(tableName, query, ...)&lt;br /&gt;
	return _dbPrepareString(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local multipleQueryTable = {}&lt;br /&gt;
function dbQueryAsyncMultiple(callbackFunctionName, callbackArguments, ...)&lt;br /&gt;
	local queries = {...}&lt;br /&gt;
	local packID = generateID()&lt;br /&gt;
	while (multipleQueryTable[packID]) do&lt;br /&gt;
		packID = generateID()&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	multipleQueryTable[packID] = {&lt;br /&gt;
		sourceResourceRoot = sourceResourceRoot,&lt;br /&gt;
		callbackFunctionName = callbackFunctionName,&lt;br /&gt;
		callbackArguments = callbackArguments,&lt;br /&gt;
		numberOfQueries = #queries,&lt;br /&gt;
		replies = {},&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	for queryNumber, query in ipairs(queries) do&lt;br /&gt;
		local extraData = {&lt;br /&gt;
			packID,&lt;br /&gt;
			queryNumber,&lt;br /&gt;
		}&lt;br /&gt;
		_dbQuery(multipleQueryCallback, extraData, mainDB, query.query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..query.tableName, unpack(query))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function multipleQueryCallback(queryHandle, packID, queryNumber)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(queryHandle, 0)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString(string.format(&amp;quot;[MYSQL][ERROR] multipleQueryCallback error %i (%s)&amp;quot;, errorCode, errorMessage), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local queryTable = multipleQueryTable[packID]&lt;br /&gt;
	queryTable.replies[queryNumber] = {&lt;br /&gt;
		result = result,&lt;br /&gt;
		errorCode = errorCode,&lt;br /&gt;
		errorMessage = errorMessage,&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	if (#queryTable.replies == queryTable.numberOfQueries) then&lt;br /&gt;
		triggerEvent(&amp;quot;dbCallback&amp;quot;, queryTable.sourceResourceRoot, queryTable.replies, queryTable.callbackFunctionName, queryTable.callbackArguments)&lt;br /&gt;
		multipleQueryTable[packID] = nil&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
dbQueryAsyncMultiple(string callbackFunctionName, table callbackArguments, ...)&lt;br /&gt;
Where there is an ellipsis, there is a table of this kind for each request:&lt;br /&gt;
{&lt;br /&gt;
	string tableName,&lt;br /&gt;
	string query,&lt;br /&gt;
	аргументы через запятую&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
--The results will be displayed in a table, preserving the order of the executed queries. The table will look like this:&lt;br /&gt;
{&lt;br /&gt;
	{&lt;br /&gt;
		table result,&lt;br /&gt;
		number errorCode,&lt;br /&gt;
		string errorMessage,&lt;br /&gt;
	},&lt;br /&gt;
}&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
-- Generating a string of characters&lt;br /&gt;
local symbols = {}&lt;br /&gt;
for _, range in ipairs({{48, 57}, {65, 90}, {97, 122}}) do -- numbers/lowercase chars/uppercase chars&lt;br /&gt;
	for i = range[1], range[2] do&lt;br /&gt;
		table.insert(symbols, string.char(i))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
local symbolCount = #symbols&lt;br /&gt;
function generateID()&lt;br /&gt;
	local str = &amp;quot;&amp;quot;&lt;br /&gt;
	for i = 1, 8 do&lt;br /&gt;
		str = str..symbols[math.random(1, symbolCount)]&lt;br /&gt;
	end&lt;br /&gt;
	return str&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Changelog==&lt;br /&gt;
{{ChangelogHeader}}&lt;br /&gt;
{{ChangelogItem|1.3.1-9.04817|Added options 'log', 'tag' and 'suppress'}}&lt;br /&gt;
{{ChangelogItem|1.3.5-9.06386|Added option 'charset'}}&lt;br /&gt;
{{ChangelogItem|1.5.2-9.07972|Added option 'multi_statements'}}&lt;br /&gt;
{{ChangelogItem|1.5.4-9.11138|Added option 'queue'}}&lt;br /&gt;
{{ChangelogItem|1.6.0-9.22396|Added option 'use_ssl'}}&lt;br /&gt;
{{ChangelogItem|1.6.0-9.22497|Added option 'get_server_public_key'}}&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{SQL_functions}}&lt;br /&gt;
&lt;br /&gt;
[[ru:dbConnect]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=DbConnect&amp;diff=82783</id>
		<title>DbConnect</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=DbConnect&amp;diff=82783"/>
		<updated>2026-04-02T03:12:02Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{Server function}}&lt;br /&gt;
This function opens a connection to a database and returns an element that can be used with [[dbQuery]]. To disconnect use [[destroyElement]].&lt;br /&gt;
{{Note|Connecting and disconnecting many times can have a performance impact on the server. For optimal performance it is recommended that you use dbConnect only once when the resource starts, and share the connection element with the whole script.}}&lt;br /&gt;
{{Note|In MySQL 8.0 and later, you can choose between '''`caching_sha2_password`''', '''`sha256_password`''', or '''`mysql_native_password`''' for password management.&lt;br /&gt;
* If you opt for '''`caching_sha2_password`''' or '''`sha256_password`''', SSL is not mandatory but recommended for secure authentication.&lt;br /&gt;
* If you choose '''`mysql_native_password`''', you can set it as the default authentication plugin:&lt;br /&gt;
** In the '''`mysqld.cnf`''' configuration file, by adding or modifying the following line: '''&amp;lt;nowiki&amp;gt;default-authentication-plugin=mysql_native_password&amp;lt;/nowiki&amp;gt;'''&lt;br /&gt;
** Using SQL queries (e.g., ALTER USER).&lt;br /&gt;
** In PHPMyAdmin (via the user settings page).&lt;br /&gt;
Please note that starting with MySQL 9.0, '''`mysql_native_password`''' will no longer be available, and only '''`caching_sha2_password`''' and '''`sha256_password`''' will be supported.&lt;br /&gt;
}}&lt;br /&gt;
==Syntax== &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
element dbConnect ( string databaseType, string host [, string username = &amp;quot;&amp;quot;, string password = &amp;quot;&amp;quot;, string options = &amp;quot;&amp;quot; ] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
{{OOP||[[Connection]]}}&lt;br /&gt;
===Required Arguments===&lt;br /&gt;
*'''databaseType:''' The type of database. This can be either ''sqlite'' or ''mysql''&lt;br /&gt;
*'''host:''' The target to connect to. The format of this depends on the database type.&lt;br /&gt;
** For SQLite it is a [[filepath]] to a SQLite database file. If the filepath starts with &amp;quot;:/&amp;quot; then the server's global databases directory is used. The file will be created if it does not exist.&lt;br /&gt;
** For MySQL it is a list of key=value pairs separated by semicolons. Supported keys are:&lt;br /&gt;
*** '''dbname''': Name of the database to use e.g. ''dbname=test''&lt;br /&gt;
*** '''host''': Host address e.g. ''host=127.0.0.1''&lt;br /&gt;
*** '''port''': Host port e.g. ''port=3306'' (optional, defaults to standard MySQL port if not used)&lt;br /&gt;
*** '''unix_socket''': Unix socket or named pipe to use (optional)&lt;br /&gt;
***'''charset''': Communicate with the server using a character which is different from the default e.g. ''charset&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;utf8'' (optional)&lt;br /&gt;
&lt;br /&gt;
===Optional Arguments===&lt;br /&gt;
*'''username:''' Usually required for MySQL, ignored by SQLite &lt;br /&gt;
*'''password:''' Usually required for MySQL, ignored by SQLite &lt;br /&gt;
*'''options :''' List of key=value pairs separated by semicolons. Supported keys are:&lt;br /&gt;
**'''share''' which can be set to 0 or 1. (Default value for SQLite is &amp;quot;share=1&amp;quot;, for MySQL is &amp;quot;share=0&amp;quot;). When set to 1, the connection is shared and will be used by other calls to dbConnect with the same host string. This is usually a good thing for SQLite connections, but not so good for MySQL unless care is taken.&lt;br /&gt;
**'''batch''' which can be set to 0 or 1. (Default is &amp;quot;batch=1&amp;quot;). When set to 1, queries called in the same frame are automatically batched together which can significantly speed up inserts/updates. The downside is you lose control of the feature that is used to achieve batching (For SQLite it is transactions, for MySQL it is autocommit mode). Therefore, if you use transactions, lock tables or control autocommit yourself, you may want to disable this feature.&lt;br /&gt;
**'''autoreconnect''' which can be set to 0 or 1. (Default value &amp;quot;autoreconnect=1&amp;quot;). When set to 1, dropped connections will automatically be reconnected. Note that session variables (incl. SET NAMES), user variables, table locks and temporary tables will be reset because of the reconnection. So if you use these fancy features, you will need to turn autoreconnect off and cope with dropped connections some other way.&lt;br /&gt;
**'''log''' which can be set to 0 or 1. (Default value &amp;quot;log&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;1&amp;quot;). When set to 0, activity from this connection will not be recorded in the [[Server_Commands#debugdb|database debug log file]].&lt;br /&gt;
**'''tag''' (Default value &amp;quot;tag&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;script&amp;quot;). A string which helps identify activity from this connection in the [[Server_Commands#debugdb|database debug log file]].&lt;br /&gt;
**'''suppress''' A comma separated list of error codes to ignore. (eg. &amp;quot;suppress&amp;lt;nowiki&amp;gt;=&amp;lt;/nowiki&amp;gt;1062,1169&amp;quot;).&lt;br /&gt;
**'''multi_statements''' Enable multiple statements (separated by a semi-colon) in one query. Use [[dbPrepareString]] when building a multiple statement query to reduce SQL injection risks.&lt;br /&gt;
**'''queue''' Name of the queue to use. (Default value for SQLite is &amp;quot;sqlite&amp;quot;, for MySQL default is the host string from the '''host''' argument). Asynchronous database queries in the same queue are processed in order, one at a time. Any name can be used.&lt;br /&gt;
**'''use_ssl''' which can be set to 0 or 1. (Default value is 0), ignored by SQLite&lt;br /&gt;
**{{New feature/item|3.0161|1.6.0|22497|'''get_server_public_key''' which can be set to 0 or 1. (Default value is 1), ignored by SQLite. When set to 1, this enables the client to request from the server the public key required for RSA key pair-based password exchange. This option applies to clients that authenticate with the &amp;lt;code&amp;gt;caching_sha2_password&amp;lt;/code&amp;gt; authentication plugin.}}&lt;br /&gt;
&lt;br /&gt;
===Returns===&lt;br /&gt;
Returns a database connection element unless there are problems, in which case it return ''false''.&lt;br /&gt;
&lt;br /&gt;
==Remarks==&lt;br /&gt;
Under certain platforms, for example on Unix-based OSes like Linux, using this function could fail with a debug warning containing &amp;quot;[Could not connect]&amp;quot; accompanied by a prior debug error explaining the problem. In that case you should check the [[Server Manual]] to see if you have missed any recommended (best-effort) steps for server set-up.&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
This example opens a connection to a SQLite database file in the current resource&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in another resource&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:resname/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in the global databases directory&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database file in a sub directory of the global databases directory&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;:/example/sub/dir/file.db&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a MySQL database called 'frank' at server ip 1.2.3.4 using utf8 character set and allows the connection to be shared. Note that changing the database or other connection dependent settings affect all connections that are shared.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;mysql&amp;quot;, &amp;quot;dbname=frank;host=1.2.3.4;charset=utf8&amp;quot;, &amp;quot;username&amp;quot;, &amp;quot;password&amp;quot;, &amp;quot;share=1&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example opens a connection to a SQLite database is disallows sharing of the connection&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;&amp;quot;, &amp;quot;share=0&amp;quot; )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example output debug message, if the connection with SQLite database was established or not&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
test_db = dbConnect( &amp;quot;sqlite&amp;quot;, &amp;quot;file.db&amp;quot; )&lt;br /&gt;
&lt;br /&gt;
if test_db then&lt;br /&gt;
    outputDebugString( &amp;quot;Connection with database was successfully established.&amp;quot; )&lt;br /&gt;
else&lt;br /&gt;
    outputDebugString( &amp;quot;Connection with database couldn't be established.&amp;quot; )&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The folowing example shows how you could approach a common resource for database operations with exported functions ('''query''' and '''execute'''):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function connect()&lt;br /&gt;
    DBConnection = dbConnect( &amp;quot;mysql&amp;quot;, &amp;quot;dbname=DBNAME;host=HOST;charset=utf8&amp;quot;, &amp;quot;USERNAME&amp;quot;, &amp;quot;PASSWORD&amp;quot; )&lt;br /&gt;
    if (not DBConnection) then&lt;br /&gt;
        outputDebugString(&amp;quot;Error: Failed to establish connection to the MySQL database server&amp;quot;)&lt;br /&gt;
    else&lt;br /&gt;
        outputDebugString(&amp;quot;Success: Connected to the MySQL database server&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
addEventHandler(&amp;quot;onResourceStart&amp;quot;,resourceRoot, connect)&lt;br /&gt;
 &lt;br /&gt;
function query(...)&lt;br /&gt;
    local queryHandle = dbQuery(DBConnection, ...)&lt;br /&gt;
    if (not queryHandle) then&lt;br /&gt;
        return nil&lt;br /&gt;
    end&lt;br /&gt;
    local rows = dbPoll(queryHandle, -1)&lt;br /&gt;
    return rows&lt;br /&gt;
end&lt;br /&gt;
 &lt;br /&gt;
function execute(...)&lt;br /&gt;
    local queryHandle = dbQuery(DBConnection, ...)&lt;br /&gt;
    local result, numRows = dbPoll(queryHandle, -1)&lt;br /&gt;
    return numRows&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function getDBConnection()&lt;br /&gt;
    return DBConnection&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The following example illustrates an exemplary approach to utilizing a common resource for database operations, employing exported functions such as '''dbQuery''', '''dbExec''', '''dbQueryAsync''', '''dbPrepareString''', and '''dbQueryAsyncMultiple.''':&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
host = &amp;quot;IPHost&amp;quot; --&amp;quot;127.0.0.1&amp;quot; -- &amp;quot;localhost&amp;quot;&lt;br /&gt;
--unix_socket = &amp;quot;/var/run/mysqld/mysqld.sock&amp;quot;&lt;br /&gt;
dbname = &amp;quot;namedb&amp;quot;&lt;br /&gt;
user = &amp;quot;rootname&amp;quot;&lt;br /&gt;
password = &amp;quot;pass&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local unix_socket, host = unix_socket, host&lt;br /&gt;
local dbname, user, password = dbname, user, password&lt;br /&gt;
local mainDB&lt;br /&gt;
&lt;br /&gt;
function connect()&lt;br /&gt;
	local startTick = getTickCount()&lt;br /&gt;
	mainDB = dbConnect(&amp;quot;mysql&amp;quot;, (unix_socket and &amp;quot;unix_socket=&amp;quot;..unix_socket or &amp;quot;host=&amp;quot;..host)..&amp;quot;;dbname=&amp;quot;..dbname, user, password)&lt;br /&gt;
	if (mainDB) then&lt;br /&gt;
		outputDebugString(&amp;quot;[MYSQL] Connection: &amp;quot;..getTickCount()-startTick..&amp;quot; ms.&amp;quot;)&lt;br /&gt;
	else&lt;br /&gt;
		outputDebugString(&amp;quot;[MYSQL][ERROR] Connection failed!&amp;quot;, 1)&lt;br /&gt;
		setTimer(connect, 5000, 1)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
connect()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbQuery = dbQuery&lt;br /&gt;
function dbQuery(timeout, tableName, query, ...)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(_dbQuery(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...), timeout)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString (string.format(&amp;quot;[MYSQL][ERROR] dbQuery error on %s (table `%s`)&amp;quot;, query, tableName), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	return result, errorCode, errorMessage&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function dbQueryAsync(callbackFunctionName, callbackArguments, tableName, query, ...)&lt;br /&gt;
	local extraData = {&lt;br /&gt;
		sourceResourceRoot,&lt;br /&gt;
		callbackFunctionName,&lt;br /&gt;
		callbackArguments,&lt;br /&gt;
	}&lt;br /&gt;
	return _dbQuery(dbCallback, extraData, mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
function dbCallback(queryHandle, srcResRoot, callbackFunctionName, callbackArguments)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(queryHandle, 0)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString (string.format(&amp;quot;[MYSQL][ERROR] dbCallback error %i (%s)&amp;quot;, errorCode, errorMessage), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	triggerEvent(&amp;quot;dbCallback&amp;quot;, srcResRoot, result, callbackFunctionName, callbackArguments)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbExec = dbExec&lt;br /&gt;
function dbExec(tableName, query, ...)&lt;br /&gt;
	-- We should also check if our database has fallen off, but unfortunately...&lt;br /&gt;
	return _dbExec(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function getTableName(tableName)&lt;br /&gt;
	return getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
_dbPrepareString = dbPrepareString&lt;br /&gt;
function dbPrepareString(tableName, query, ...)&lt;br /&gt;
	return _dbPrepareString(mainDB, query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..tableName, ...)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local multipleQueryTable = {}&lt;br /&gt;
function dbQueryAsyncMultiple(callbackFunctionName, callbackArguments, ...)&lt;br /&gt;
	local queries = {...}&lt;br /&gt;
	local packID = generateID()&lt;br /&gt;
	while (multipleQueryTable[packID]) do&lt;br /&gt;
		packID = generateID()&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	multipleQueryTable[packID] = {&lt;br /&gt;
		sourceResourceRoot = sourceResourceRoot,&lt;br /&gt;
		callbackFunctionName = callbackFunctionName,&lt;br /&gt;
		callbackArguments = callbackArguments,&lt;br /&gt;
		numberOfQueries = #queries,&lt;br /&gt;
		replies = {},&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	for queryNumber, query in ipairs(queries) do&lt;br /&gt;
		local extraData = {&lt;br /&gt;
			packID,&lt;br /&gt;
			queryNumber,&lt;br /&gt;
		}&lt;br /&gt;
		_dbQuery(multipleQueryCallback, extraData, mainDB, query.query, getResourceName(sourceResource)..&amp;quot;_&amp;quot;..query.tableName, unpack(query))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function multipleQueryCallback(queryHandle, packID, queryNumber)&lt;br /&gt;
	local result, errorCode, errorMessage = dbPoll(queryHandle, 0)&lt;br /&gt;
	if (not result) then&lt;br /&gt;
		outputDebugString(string.format(&amp;quot;[MYSQL][ERROR] multipleQueryCallback error %i (%s)&amp;quot;, errorCode, errorMessage), 1)   &lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local queryTable = multipleQueryTable[packID]&lt;br /&gt;
	queryTable.replies[queryNumber] = {&lt;br /&gt;
		result = result,&lt;br /&gt;
		errorCode = errorCode,&lt;br /&gt;
		errorMessage = errorMessage,&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	if (#queryTable.replies == queryTable.numberOfQueries) then&lt;br /&gt;
		triggerEvent(&amp;quot;dbCallback&amp;quot;, queryTable.sourceResourceRoot, queryTable.replies, queryTable.callbackFunctionName, queryTable.callbackArguments)&lt;br /&gt;
		multipleQueryTable[packID] = nil&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
dbQueryAsyncMultiple(string callbackFunctionName, table callbackArguments, ...)&lt;br /&gt;
Where there is an ellipsis, there is a table of this kind for each request:&lt;br /&gt;
{&lt;br /&gt;
	string tableName,&lt;br /&gt;
	string query,&lt;br /&gt;
	аргументы через запятую&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
--The results will be displayed in a table, preserving the order of the executed queries. The table will look like this:&lt;br /&gt;
{&lt;br /&gt;
	{&lt;br /&gt;
		table result,&lt;br /&gt;
		number errorCode,&lt;br /&gt;
		string errorMessage,&lt;br /&gt;
	},&lt;br /&gt;
}&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
-- Generating a string of characters&lt;br /&gt;
local symbols = {}&lt;br /&gt;
for _, range in ipairs({{48, 57}, {65, 90}, {97, 122}}) do -- numbers/lowercase chars/uppercase chars&lt;br /&gt;
	for i = range[1], range[2] do&lt;br /&gt;
		table.insert(symbols, string.char(i))&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
local symbolCount = #symbols&lt;br /&gt;
function generateID()&lt;br /&gt;
	local str = &amp;quot;&amp;quot;&lt;br /&gt;
	for i = 1, 8 do&lt;br /&gt;
		str = str..symbols[math.random(1, symbolCount)]&lt;br /&gt;
	end&lt;br /&gt;
	return str&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Changelog==&lt;br /&gt;
{{ChangelogHeader}}&lt;br /&gt;
{{ChangelogItem|1.3.1-9.04817|Added options 'log', 'tag' and 'suppress'}}&lt;br /&gt;
{{ChangelogItem|1.3.5-9.06386|Added option 'charset'}}&lt;br /&gt;
{{ChangelogItem|1.5.2-9.07972|Added option 'multi_statements'}}&lt;br /&gt;
{{ChangelogItem|1.5.4-9.11138|Added option 'queue'}}&lt;br /&gt;
{{ChangelogItem|1.6.0-9.22396|Added option 'use_ssl'}}&lt;br /&gt;
{{ChangelogItem|1.6.0-9.22497|Added option 'get_server_public_key'}}&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{SQL_functions}}&lt;br /&gt;
&lt;br /&gt;
[[ru:dbConnect]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82782</id>
		<title>IsResourceRunning</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82782"/>
		<updated>2026-04-02T02:34:23Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* Example check isResourceRunning(resName) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
{{Shared function}}&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
*'''isResourceRunning''' You can insert this code example in your resources.&lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''isResourceRunning:''' The value to check resources&lt;br /&gt;
&lt;br /&gt;
==Example check isResourceRunning(resName)==&lt;br /&gt;
&amp;lt;section name=&amp;quot;isResourceRunning&amp;quot; class=&amp;quot;shared&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
You can insert this code example in your resources.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function isResourceRunning(resName)&lt;br /&gt;
   local res = getResourceFromName(resName)&lt;br /&gt;
   return (res) and (getResourceState(res) == &amp;quot;running&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Example of inserting into system code:&lt;br /&gt;
--[[&lt;br /&gt;
if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
   --code&lt;br /&gt;
else&lt;br /&gt;
   --alert&lt;br /&gt;
end&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
addCommandHandler('pos', function (commandName)&lt;br /&gt;
    if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
       local x,y,z = getElementPosition(localPlayer)&lt;br /&gt;
       outputChatBox( x ..', '.. y ..', '.. z, 255, 255, 255 )&lt;br /&gt;
    else&lt;br /&gt;
       outputChatBox(&amp;quot;The resource is not running 'admin'.&amp;quot;, 255, 0, 0)&lt;br /&gt;
    end&lt;br /&gt;
end )&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Resource_functions}}&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82781</id>
		<title>IsResourceRunning</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82781"/>
		<updated>2026-04-02T02:32:30Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
{{Shared function}}&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
*'''isResourceRunning''' You can insert this code example in your resources.&lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''isResourceRunning:''' The value to check resources&lt;br /&gt;
&lt;br /&gt;
==Example check isResourceRunning(resName)==&lt;br /&gt;
&amp;lt;section name=&amp;quot;Example1&amp;quot; class=&amp;quot;shared&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
You can insert this code example in your resources.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function isResourceRunning(resName)&lt;br /&gt;
   local res = getResourceFromName(resName)&lt;br /&gt;
   return (res) and (getResourceState(res) == &amp;quot;running&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Example of inserting into system code:&lt;br /&gt;
--[[&lt;br /&gt;
if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
   --code&lt;br /&gt;
else&lt;br /&gt;
   --alert&lt;br /&gt;
end&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
addCommandHandler('pos', function (commandName)&lt;br /&gt;
    if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
       local x,y,z = getElementPosition(localPlayer)&lt;br /&gt;
       outputChatBox( x ..', '.. y ..', '.. z, 255, 255, 255 )&lt;br /&gt;
    else&lt;br /&gt;
       outputChatBox(&amp;quot;The resource is not running 'admin'.&amp;quot;, 255, 0, 0)&lt;br /&gt;
    end&lt;br /&gt;
end )&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Resource_functions}}&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82780</id>
		<title>IsResourceRunning</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82780"/>
		<updated>2026-04-02T02:17:20Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
{{Shared function}}&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
*'''isResourceRunning''' You can insert this code example in your resources.&lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''isResourceRunning:''' The value to check resources&lt;br /&gt;
&lt;br /&gt;
==Example check isResourceRunning(resName)==&lt;br /&gt;
&amp;lt;section name=&amp;quot;Example1&amp;quot; class=&amp;quot;shared&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
You can insert this code example in your resources.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function isResourceRunning(resName)&lt;br /&gt;
	local res = getResourceFromName(resName)&lt;br /&gt;
	return (res) and (getResourceState(res) == &amp;quot;running&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Example of inserting into system code:&lt;br /&gt;
--[[&lt;br /&gt;
if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
   --code&lt;br /&gt;
else&lt;br /&gt;
   --alert&lt;br /&gt;
end&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
addCommandHandler('pos', function (commandName)&lt;br /&gt;
    if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
       local x,y,z = getElementPosition(localPlayer)&lt;br /&gt;
       outputChatBox( x ..', '.. y ..', '.. z, 255, 255, 255 )&lt;br /&gt;
    else&lt;br /&gt;
       outputChatBox(&amp;quot;The resource is not running 'admin'.&amp;quot;, 255, 0, 0)&lt;br /&gt;
    end&lt;br /&gt;
end )&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Resource_functions}}&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Resource&amp;diff=82779</id>
		<title>Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Resource&amp;diff=82779"/>
		<updated>2026-04-02T02:15:27Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A [[resource]] object refers to a resource that is loaded in the server.&lt;br /&gt;
&lt;br /&gt;
A name, state, root element, base directory path are associated to a [[resource]], among other attributes.&lt;br /&gt;
&lt;br /&gt;
==Related scripting functions==&lt;br /&gt;
===Server===&lt;br /&gt;
{{Resource functions}}&lt;br /&gt;
===Client===&lt;br /&gt;
{{Client resource functions}}&lt;br /&gt;
[[Category:Scripting Concepts]]&lt;br /&gt;
&lt;br /&gt;
===Util (Shared)===&lt;br /&gt;
[[IsResourceRunning]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Resource&amp;diff=82778</id>
		<title>Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Resource&amp;diff=82778"/>
		<updated>2026-04-02T02:15:01Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A [[resource]] object refers to a resource that is loaded in the server.&lt;br /&gt;
&lt;br /&gt;
A name, state, root element, base directory path are associated to a [[resource]], among other attributes.&lt;br /&gt;
&lt;br /&gt;
==Related scripting functions==&lt;br /&gt;
===Server===&lt;br /&gt;
{{Resource functions}}&lt;br /&gt;
===Client===&lt;br /&gt;
{{Client resource functions}}&lt;br /&gt;
[[Category:Scripting Concepts]]&lt;br /&gt;
&lt;br /&gt;
==Util==&lt;br /&gt;
[[IsResourceRunning]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Resource&amp;diff=82777</id>
		<title>Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Resource&amp;diff=82777"/>
		<updated>2026-04-02T02:13:24Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A [[resource]] object refers to a resource that is loaded in the server.&lt;br /&gt;
&lt;br /&gt;
A name, state, root element, base directory path are associated to a [[resource]], among other attributes.&lt;br /&gt;
&lt;br /&gt;
==Related scripting functions==&lt;br /&gt;
===Server===&lt;br /&gt;
{{Resource functions}}&lt;br /&gt;
===Client===&lt;br /&gt;
{{Client resource functions}}&lt;br /&gt;
[[Category:Scripting Concepts]]&lt;br /&gt;
&lt;br /&gt;
[[IsResourceRunning]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Resource&amp;diff=82776</id>
		<title>Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Resource&amp;diff=82776"/>
		<updated>2026-04-02T02:11:14Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A [[resource]] object refers to a resource that is loaded in the server.&lt;br /&gt;
&lt;br /&gt;
A name, state, root element, base directory path are associated to a [[resource]], among other attributes.&lt;br /&gt;
&lt;br /&gt;
==Related scripting functions==&lt;br /&gt;
===Server===&lt;br /&gt;
{{Resource functions}}&lt;br /&gt;
===Client===&lt;br /&gt;
{{Client resource functions}}&lt;br /&gt;
[[Category:Scripting Concepts]]&lt;br /&gt;
&lt;br /&gt;
[[https://wiki.multitheftauto.com/wiki/IsResourceRunning|IsResourceRunning]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Resource&amp;diff=82775</id>
		<title>Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Resource&amp;diff=82775"/>
		<updated>2026-04-02T02:10:34Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A [[resource]] object refers to a resource that is loaded in the server.&lt;br /&gt;
&lt;br /&gt;
A name, state, root element, base directory path are associated to a [[resource]], among other attributes.&lt;br /&gt;
&lt;br /&gt;
==Related scripting functions==&lt;br /&gt;
===Server===&lt;br /&gt;
{{Resource functions}}&lt;br /&gt;
===Client===&lt;br /&gt;
{{Client resource functions}}&lt;br /&gt;
[[Category:Scripting Concepts]]&lt;br /&gt;
&lt;br /&gt;
https://wiki.multitheftauto.com/wiki/IsResourceRunning&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Resource&amp;diff=82774</id>
		<title>Resource</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Resource&amp;diff=82774"/>
		<updated>2026-04-02T02:08:29Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A [[resource]] object refers to a resource that is loaded in the server.&lt;br /&gt;
&lt;br /&gt;
A name, state, root element, base directory path are associated to a [[resource]], among other attributes.&lt;br /&gt;
&lt;br /&gt;
==Related scripting functions==&lt;br /&gt;
===Server===&lt;br /&gt;
{{Resource functions}}&lt;br /&gt;
===Client===&lt;br /&gt;
{{Client resource functions}}&lt;br /&gt;
[[Category:Scripting Concepts]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82773</id>
		<title>IsResourceRunning</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82773"/>
		<updated>2026-04-02T02:05:06Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
{{Shared function}}&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
*'''isResourceRunning''' You can insert this code example in your resources.&lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''isResourceRunning:''' The value to check resources&lt;br /&gt;
&lt;br /&gt;
==Example check isResourceRunning(resName)==&lt;br /&gt;
&amp;lt;section name=&amp;quot;Example1&amp;quot; class=&amp;quot;shared&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
You can insert this code example in your resources.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function isResourceRunning(resName)&lt;br /&gt;
	local res = getResourceFromName(resName)&lt;br /&gt;
	return (res) and (getResourceState(res) == &amp;quot;running&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Example of inserting into system code:&lt;br /&gt;
--[[&lt;br /&gt;
if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
   --code&lt;br /&gt;
else&lt;br /&gt;
   --alert&lt;br /&gt;
end&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
addCommandHandler('pos', function (commandName)&lt;br /&gt;
    if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
       local x,y,z = getElementPosition(localPlayer)&lt;br /&gt;
       outputChatBox( x ..', '.. y ..', '.. z, 255, 255, 255 )&lt;br /&gt;
    else&lt;br /&gt;
       outputChatBox(&amp;quot;The resource is not running 'admin'.&amp;quot;, 255, 0, 0)&lt;br /&gt;
    end&lt;br /&gt;
end )&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Resource_functions}}&lt;br /&gt;
[[ru:isBan]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82772</id>
		<title>IsResourceRunning</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82772"/>
		<updated>2026-04-02T02:04:31Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
{{Shared function}}&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
*'''isResourceRunning''' You can insert this code example in your resources.&lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''isResourceRunning:''' The value to check resources&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&amp;lt;section name=&amp;quot;Example1&amp;quot; class=&amp;quot;shared&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
You can insert this code example in your resources.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function isResourceRunning(resName)&lt;br /&gt;
	local res = getResourceFromName(resName)&lt;br /&gt;
	return (res) and (getResourceState(res) == &amp;quot;running&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Example of inserting into system code:&lt;br /&gt;
--[[&lt;br /&gt;
if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
   --code&lt;br /&gt;
else&lt;br /&gt;
   --alert&lt;br /&gt;
end&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
addCommandHandler('pos', function (commandName)&lt;br /&gt;
    if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
       local x,y,z = getElementPosition(localPlayer)&lt;br /&gt;
       outputChatBox( x ..', '.. y ..', '.. z, 255, 255, 255 )&lt;br /&gt;
    else&lt;br /&gt;
       outputChatBox(&amp;quot;The resource is not running 'admin'.&amp;quot;, 255, 0, 0)&lt;br /&gt;
    end&lt;br /&gt;
end )&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Resource_functions}}&lt;br /&gt;
[[ru:isBan]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82771</id>
		<title>IsResourceRunning</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82771"/>
		<updated>2026-04-02T02:04:18Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
{{Shared function}}&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
*''isResourceRunning''' You can insert this code example in your resources.&lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''isResourceRunning:''' The value to check resources&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&amp;lt;section name=&amp;quot;Example1&amp;quot; class=&amp;quot;shared&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
You can insert this code example in your resources.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function isResourceRunning(resName)&lt;br /&gt;
	local res = getResourceFromName(resName)&lt;br /&gt;
	return (res) and (getResourceState(res) == &amp;quot;running&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Example of inserting into system code:&lt;br /&gt;
--[[&lt;br /&gt;
if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
   --code&lt;br /&gt;
else&lt;br /&gt;
   --alert&lt;br /&gt;
end&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
addCommandHandler('pos', function (commandName)&lt;br /&gt;
    if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
       local x,y,z = getElementPosition(localPlayer)&lt;br /&gt;
       outputChatBox( x ..', '.. y ..', '.. z, 255, 255, 255 )&lt;br /&gt;
    else&lt;br /&gt;
       outputChatBox(&amp;quot;The resource is not running 'admin'.&amp;quot;, 255, 0, 0)&lt;br /&gt;
    end&lt;br /&gt;
end )&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Resource_functions}}&lt;br /&gt;
[[ru:isBan]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82770</id>
		<title>IsResourceRunning</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82770"/>
		<updated>2026-04-02T02:03:47Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* See Also */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
{{Shared function}}&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
You can insert this code example in your resources.&lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''isResourceRunning:''' The value to check resources&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&amp;lt;section name=&amp;quot;Example1&amp;quot; class=&amp;quot;shared&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
You can insert this code example in your resources.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function isResourceRunning(resName)&lt;br /&gt;
	local res = getResourceFromName(resName)&lt;br /&gt;
	return (res) and (getResourceState(res) == &amp;quot;running&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Example of inserting into system code:&lt;br /&gt;
--[[&lt;br /&gt;
if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
   --code&lt;br /&gt;
else&lt;br /&gt;
   --alert&lt;br /&gt;
end&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
addCommandHandler('pos', function (commandName)&lt;br /&gt;
    if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
       local x,y,z = getElementPosition(localPlayer)&lt;br /&gt;
       outputChatBox( x ..', '.. y ..', '.. z, 255, 255, 255 )&lt;br /&gt;
    else&lt;br /&gt;
       outputChatBox(&amp;quot;The resource is not running 'admin'.&amp;quot;, 255, 0, 0)&lt;br /&gt;
    end&lt;br /&gt;
end )&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Resource_functions}}&lt;br /&gt;
[[ru:isBan]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82769</id>
		<title>IsResourceRunning</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=IsResourceRunning&amp;diff=82769"/>
		<updated>2026-04-02T02:03:14Z</updated>

		<summary type="html">&lt;p&gt;Flox: Created page with &amp;quot;__NOTOC__  {{Shared function}}  ==Syntax==  You can insert this code example in your resources.  ===Required Arguments===  *'''isResourceRunning:''' The value to check resources  ==Example== &amp;lt;section name=&amp;quot;Example1&amp;quot; class=&amp;quot;shared&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt; You can insert this code example in your resources. &amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt; function isResourceRunning(resName) 	local res = getResourceFromName(resName) 	return (res) and (getResourceState(res) == &amp;quot;running&amp;quot;) end  -- Example o...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ &lt;br /&gt;
{{Shared function}}&lt;br /&gt;
&lt;br /&gt;
==Syntax== &lt;br /&gt;
You can insert this code example in your resources.&lt;br /&gt;
&lt;br /&gt;
===Required Arguments=== &lt;br /&gt;
*'''isResourceRunning:''' The value to check resources&lt;br /&gt;
&lt;br /&gt;
==Example==&lt;br /&gt;
&amp;lt;section name=&amp;quot;Example1&amp;quot; class=&amp;quot;shared&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
You can insert this code example in your resources.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function isResourceRunning(resName)&lt;br /&gt;
	local res = getResourceFromName(resName)&lt;br /&gt;
	return (res) and (getResourceState(res) == &amp;quot;running&amp;quot;)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- Example of inserting into system code:&lt;br /&gt;
--[[&lt;br /&gt;
if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
   --code&lt;br /&gt;
else&lt;br /&gt;
   --alert&lt;br /&gt;
end&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
addCommandHandler('pos', function (commandName)&lt;br /&gt;
    if isResourceRunning(&amp;quot;admin&amp;quot;) then&lt;br /&gt;
       local x,y,z = getElementPosition(localPlayer)&lt;br /&gt;
       outputChatBox( x ..', '.. y ..', '.. z, 255, 255, 255 )&lt;br /&gt;
    else&lt;br /&gt;
       outputChatBox(&amp;quot;The resource is not running 'admin'.&amp;quot;, 255, 0, 0)&lt;br /&gt;
    end&lt;br /&gt;
end )&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Resource}}&lt;br /&gt;
[[ru:isBan]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=ConvertServerTickToTimeStamp&amp;diff=82768</id>
		<title>ConvertServerTickToTimeStamp</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=ConvertServerTickToTimeStamp&amp;diff=82768"/>
		<updated>2026-04-02T01:04:30Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Useful Function}}&lt;br /&gt;
__NOTOC__&lt;br /&gt;
This function converts server ticks to a unix timestamp. '''Note''': this was built to work with the server tick timestamp returned by [[onPlayerScreenShot]].&lt;br /&gt;
Author: qaisjp&lt;br /&gt;
&lt;br /&gt;
==Syntax==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;int convertServerTickToTimeStamp( int ticks )&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Required Arguments===&lt;br /&gt;
* '''ticks''': The ticks to be converted. '''REMEMBER:''' the input tick cannot be from a different server session, this is because ticks are &amp;quot;reset&amp;quot; when the server is booted. &lt;br /&gt;
&lt;br /&gt;
===Returns===&lt;br /&gt;
Returns an int containing the unix timestamp number.&lt;br /&gt;
&lt;br /&gt;
==Code==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function convertServerTickToTimeStamp(tick) &lt;br /&gt;
   -- Get the current time (table).&lt;br /&gt;
   -- Note: getRealtime() creates a table that consumes memory when called frequently.&lt;br /&gt;
&lt;br /&gt;
   local time = getRealtime()&lt;br /&gt;
&lt;br /&gt;
   -- Calculate the difference between the passed tick and the current one in seconds&lt;br /&gt;
   -- and add it to the current Unix time.&lt;br /&gt;
   return time.timestamp + ((tick - getTickCount()) * 0.001)&lt;br /&gt;
&lt;br /&gt;
   -- refactoring code&lt;br /&gt;
   --return getRealtime().timestamp+((getTickCount()*0.001)-(tick*0.001)); &lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
{{Useful_Functions}}&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/triggerClientEvent&amp;diff=82729</id>
		<title>RU/triggerClientEvent</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/triggerClientEvent&amp;diff=82729"/>
		<updated>2026-02-10T15:49:03Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{RU/Server function}}&lt;br /&gt;
Эта функция позволяет вызвать срабатывание события, предварительно созданного на клиенте. Она относится к основным средствам обмена информацией между сервером и клиентом. На клиентской стороне существует аналогичная функция [[RU/triggerServerEvent|triggerServerEvent]] работающая в противоположном направлении. Эту функцию можно рассматривать как асинхронный вызов функции с использованием [[RU/triggerServerEvent|triggerServerEvent]] для получения ответа\результата, если таковой требуется.&lt;br /&gt;
&lt;br /&gt;
Передавать можно почти любые типы данных, включая элементы ([[element]]) и сложные вложенные таблицы ([[table]]). Данные неэлементных типов МТА, например указатели на xml (xmlNodes) или указатели на ресурсы не могут быть переданы, поскольку у них может и не существовать какого-либо представления на стороне клиента.&lt;br /&gt;
&lt;br /&gt;
Вызовы посылаются надежно, поэтому клиенты их получат, однако возможны (хотя, как правило, незначительные) задержки в получении, что также следует принимать во внимание. Также следует учитывать вопросы пропускной способности канала - не отправляйте большой объем данных без необходимости. Отправка одного большого вызова ненамного эффективнее отправки нескольких маленьких.&lt;br /&gt;
&lt;br /&gt;
==Синтаксис== &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
bool triggerClientEvent ( [element triggerFor=getRootElement()], string name, element theElement, [arguments...] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Обязательные аргументы=== &lt;br /&gt;
*'''name:''' Название события на стороне клиента. Оно должно быть зарегистрировано на стороне клиента с помощью [[RU/addEvent|addEvent]] и иметь хотя бы один обработчик, добавленный с помощью [[RU/addEventHandler|addEventHandler]].&lt;br /&gt;
*'''theElement:''' Элемент, который будет источником [[Event system#Event handlers|source]] события. Это может быть, например, другой игрок, или корень (root element), если это непринципиально.&lt;br /&gt;
&lt;br /&gt;
===Дополнительные аргументы=== &lt;br /&gt;
{{OptionalArg}} &lt;br /&gt;
*'''triggerFor:''' Событие будет вызвано для всех игроков ( [[player]] ) которые являются потомками этого элемента. По умолчанию это корень, поэтому событие будет вызвано для всех элементов (для всех игроков). Если вы укажете только конкретного игрока, событие будет вызвано только для него. &lt;br /&gt;
*'''arguments...:''' Список аргументов, которые будут передаваться вместе с событием. Можно передавать любые типы lua (кроме функций), а также любые элементы ([[element]]).&lt;br /&gt;
&lt;br /&gt;
===Вывод===&lt;br /&gt;
Возвращает ''true'' если вызов события был успешно сделан, ''false'' если указаны некорректные аргументы.&lt;br /&gt;
&lt;br /&gt;
==Примеры== &lt;br /&gt;
===Пример 1===&lt;br /&gt;
В этом примере сервер передает простое сообщение &amp;quot;Превед медвед!&amp;quot; всем клиентам.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;section name=&amp;quot;Client&amp;quot; class=&amp;quot;client&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function greetingHandler ( message )&lt;br /&gt;
    outputChatBox ( &amp;quot;The server says: &amp;quot; .. message )&lt;br /&gt;
end&lt;br /&gt;
addEvent( &amp;quot;onGreeting&amp;quot;, true )&lt;br /&gt;
addEventHandler( &amp;quot;onGreeting&amp;quot;, getRootElement(), greetingHandler )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function greetingCommand ( playerSource, commandName )&lt;br /&gt;
    triggerClientEvent ( &amp;quot;onGreeting&amp;quot;, getRootElement(), &amp;quot;Превед медвед!&amp;quot; )&lt;br /&gt;
end&lt;br /&gt;
addCommandHandler ( &amp;quot;greet&amp;quot;, greetingCommand )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Когда выполняется консольная команда &amp;quot;greet&amp;quot; (вводится через консоль сервера или игрока), на стороне сервера вызывается функция ''greetingCommand''. Она вызывает срабатывание на стороне клиента события ''onGreeting'' с параметром &amp;quot;Превед медвед!&amp;quot;. В результате вызывается функция-обработчик ''greetingHandler'', которая и пишет полученное с сервера сообщение в чат.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Пример 2===&lt;br /&gt;
В этом примере сервер передает простое сообщение &amp;quot;Превед медвед!&amp;quot; только '''одному''' клиенту.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;section name=&amp;quot;Client&amp;quot; class=&amp;quot;client&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function greetingHandler ( message )&lt;br /&gt;
    outputChatBox ( &amp;quot;The server says: &amp;quot; .. message )&lt;br /&gt;
end&lt;br /&gt;
addEvent( &amp;quot;onGreeting&amp;quot;, true )&lt;br /&gt;
addEventHandler( &amp;quot;onGreeting&amp;quot;, getRootElement(), greetingHandler )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function greetingCommandOne ( playerSource, commandName, playerName )&lt;br /&gt;
    if playerName then&lt;br /&gt;
        local thePlayer = getPlayerFromName ( playerName )&lt;br /&gt;
        if thePlayer then&lt;br /&gt;
            triggerClientEvent ( thePlayer, &amp;quot;onGreeting&amp;quot;, getRootElement(), &amp;quot;Превед медвед!&amp;quot; )&lt;br /&gt;
        else&lt;br /&gt;
            -- указано неправильное имя&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        -- не указано имя&lt;br /&gt;
    end &lt;br /&gt;
end&lt;br /&gt;
addCommandHandler ( &amp;quot;greet_one&amp;quot;, greetingCommandOne )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример работает так же, как и предыдущий, за исключением того, что для triggerClientEvent указывается дополнительный аргумент ''thePlayer''.&lt;br /&gt;
&lt;br /&gt;
==Смотрите также==&lt;br /&gt;
{{RU/Event functions}}&lt;br /&gt;
&lt;br /&gt;
[[en:triggerClientEvent]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/triggerClientEvent&amp;diff=82728</id>
		<title>RU/triggerClientEvent</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/triggerClientEvent&amp;diff=82728"/>
		<updated>2026-02-10T15:48:30Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
{{RU/Server function}}&lt;br /&gt;
Эта функция позволяет вызвать срабатывание события, предварительно созданного на клиенте. Она относится к основным средствам обмена информацией между сервером и клиентом. На клиентской стороне существует аналогичная функция [[RU/triggerServerEvent|triggerServerEvent]] работающая в противоположном направлении. Эту функцию можно рассматривать как асинхронный вызов функции с использованием [[RU/triggerServerEvent|triggerServerEvent]] для получения ответа\результата, если таковой требуется.&lt;br /&gt;
&lt;br /&gt;
Передавать можно почти любые типы данных, включая элементы ([[element]]) и сложные вложенные таблицы ([[table]]). Данные неэлементных типов МТА, например указатели на xml (xmlNodes) или указатели на ресурсы не могут быть переданы, поскольку у них может и не существовать какого-либо представления на стороне клиента.&lt;br /&gt;
&lt;br /&gt;
Вызовы посылаются надежно, поэтому клиенты их получат, однако возможны (хотя, как правило, незначительные) задержки в получении, что также следует принимать во внимание. Также следует учитывать вопросы пропускной способности канала - не отправляйте большой объем данных без необходимости. Отправка одного большого вызова ненамного эффективнее отправки нескольких маленьких.&lt;br /&gt;
&lt;br /&gt;
==Синтаксис== &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
bool triggerClientEvent ( [element triggerFor=getRootElement()], string name, element theElement, [arguments...] )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt; &lt;br /&gt;
&lt;br /&gt;
===Обязательные аргументы=== &lt;br /&gt;
*'''name:''' Название события на стороне клиента. Оно должно быть зарегистрировано на стороне клиента с помощью [[RU/addEvent|addEvent]] и иметь хотя бы один обработчик, добавленный с помощью [[RU/addEventHandler|addEventHandler]].&lt;br /&gt;
*'''theElement:''' Элемент, который будет источником [[Event system#Event handlers|source]] события. Это может быть, например, другой игрок, или корень (root element), если это непринципиально.&lt;br /&gt;
&lt;br /&gt;
===Дополнительные аргументы=== &lt;br /&gt;
{{OptionalArg}} &lt;br /&gt;
*'''triggerFor:''' Событие будет вызвано для всех игроков ( [[player]] ) которые являются потомками этого элемента. По умолчанию это корень, поэтому событие будет вызвано для всех элементов (для всех игроков). Если вы укажете только конкретного игрока, событие будет вызвано только для него. &lt;br /&gt;
*'''arguments...:''' Список аргументов, которые будут передаваться вместе с событием. Можно передавать любые типы lua (кроме функций), а также любые элементы ([[element]]).&lt;br /&gt;
&lt;br /&gt;
===Вывод===&lt;br /&gt;
Возвращает ''true'' если вызов события был успешно сделан, ''false'' если указаны некорректные аргументы.&lt;br /&gt;
&lt;br /&gt;
==Примеры== &lt;br /&gt;
===Пример 1===&lt;br /&gt;
В этом примере сервер передает простое сообщение &amp;quot;Превед медвед!&amp;quot; всем клиентам.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;section name=&amp;quot;Client&amp;quot; class=&amp;quot;client&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function greetingHandler ( message )&lt;br /&gt;
    outputChatBox ( &amp;quot;The server says: &amp;quot; .. message )&lt;br /&gt;
end&lt;br /&gt;
addEvent( &amp;quot;onGreeting&amp;quot;, true )&lt;br /&gt;
addEventHandler( &amp;quot;onGreeting&amp;quot;, getRootElement(), greetingHandler )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function greetingCommand ( playerSource, commandName )&lt;br /&gt;
    triggerClientEvent ( &amp;quot;onGreeting&amp;quot;, getRootElement(), &amp;quot;Превед медвед!&amp;quot; )&lt;br /&gt;
end&lt;br /&gt;
addCommandHandler ( &amp;quot;greet&amp;quot;, greetingCommand )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Когда выполняется консольная команда &amp;quot;greet&amp;quot; (вводится через консоль сервера или игрока), на стороне сервера вызывается функция ''greetingCommand''. Она вызывает срабатывание на стороне клиента события ''onGreeting'' с параметром &amp;quot;Превед медвед!&amp;quot;. В результате вызывается функция-обработчик ''greetingHandler'', которая и пишет полученное с сервера сообщение в чат.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Пример 2===&lt;br /&gt;
В этом примере сервер передает простое сообщение &amp;quot;Превед медвед!&amp;quot; только '''одному''' клиенту.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;section name=&amp;quot;Client&amp;quot; class=&amp;quot;client&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function greetingHandler ( message )&lt;br /&gt;
    outputChatBox ( &amp;quot;The server says: &amp;quot; .. message )&lt;br /&gt;
end&lt;br /&gt;
addEvent( &amp;quot;onGreeting&amp;quot;, true )&lt;br /&gt;
addEventHandler( &amp;quot;onGreeting&amp;quot;, getRootElement(), greetingHandler )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function greetingCommandOne ( playerSource, commandName, playerName )&lt;br /&gt;
    if playerName then&lt;br /&gt;
        local thePlayer = getPlayerFromName ( playerName )&lt;br /&gt;
        if thePlayer then&lt;br /&gt;
            triggerClientEvent ( thePlayer, &amp;quot;onGreeting&amp;quot;, getRootElement(), &amp;quot;Превед медвед!&amp;quot; )&lt;br /&gt;
        else&lt;br /&gt;
            -- указано неправильное имя&lt;br /&gt;
        end&lt;br /&gt;
    else&lt;br /&gt;
        -- не указано имя&lt;br /&gt;
    end &lt;br /&gt;
end&lt;br /&gt;
addCommandHandler ( &amp;quot;greet_one&amp;quot;, greetingCommandOne )&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример работает так же, как и предыдущий, за исключением того, что для triggerClientEvent указывается дополнительный аргумент ''thePlayer''.&lt;br /&gt;
&lt;br /&gt;
==Смотрите также==&lt;br /&gt;
{{/Event functions}}&lt;br /&gt;
&lt;br /&gt;
[[en:triggerClientEvent]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Main_Page&amp;diff=82702</id>
		<title>RU/Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Main_Page&amp;diff=82702"/>
		<updated>2026-01-08T19:21:42Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| width=&amp;quot;100%&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
&amp;lt;div style=&amp;quot;/*border: 1px solid #D8D8D8;*/ padding-left: 15px; padding-right: 15px; height: 100%;&amp;quot;&amp;gt;&lt;br /&gt;
[[File:Mtalogo.png|left|100px|link=https://wiki.multitheftauto.com/wiki/RU/Main_Page]]'''Добро пожаловать в вики о модификации [[RU/Multi Theft Auto|Multi Theft Auto]] для игры Grand Theft Auto: San Andreas.''' Здесь вы найдёте множество информации об использовании этой модификации.&lt;br /&gt;
 &lt;br /&gt;
Есть много [[Как ты можешь помочь|вещей]], которые вы можете сделать, чтобы помочь нам улучшить Multi Theft Auto - создать карту, игровой режим, добавить описание функций скриптинга, написать пример кода, руководство, или просто поиграть в Multi Theft Auto и сообщить о найденных недоработках.&lt;br /&gt;
 &lt;br /&gt;
Если у вас есть какие-либо вопросы или проблемы, связанные со скриптингом, вы можете [[RU/Places_To_Chat|связаться с нами]].&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;[ Перестань играть с собой ]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
|width=&amp;quot;50%&amp;quot; style=&amp;quot;vertical-align:top;&amp;quot; |&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px; background: #FFFCF2;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Input-gaming.png‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Играть&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;background: #FFEEAA; border: 1px solid #FFCD19;&amp;quot;&amp;gt;&lt;br /&gt;
[[File:Go-down.png|link=https://mtasa.com/]] ''' [https://mtasa.com/ Скачать Multi Theft Auto {{Current Version|full}}]'''&amp;lt;/div&amp;gt;&lt;br /&gt;
* [[RU/Where to buy GTASA|Где купить Grand Theft Auto: San Andreas]]&lt;br /&gt;
* [[RU/Client Manual|Руководство о клиенте]]&lt;br /&gt;
&amp;lt;!-- * [[Changes_in_{{padleft:|3|{{Current Version|full}}}}| Changes in {{padleft:|3|{{Current Version|full}}}}]] --&amp;gt;&lt;br /&gt;
* [[Changes_in_{{padleft:|5|{{Current Version|full}}}}| Изменения в версии {{padleft:|5|{{Current Version|full}}}}]]&lt;br /&gt;
* [[RU/Known Issues_-_FAQ|Известные проблемы]]&lt;br /&gt;
* [[RU/Upgrading_from_MTA:Race|Переход из MTA:Race в MTA:SA {{padleft:|3|{{Current Version|full}}}}]]&lt;br /&gt;
* [[RU/Server Manual|Руководство о сервере]]&lt;br /&gt;
* [[RU/Map manager|Менеджер карт]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;Редактор карт&amp;lt;/h3&amp;gt;&lt;br /&gt;
*[[RU/Resource:Editor|Руководство]]&lt;br /&gt;
*[[RU/Resource:Editor/EDF|Формат определения редактора]]&lt;br /&gt;
*[[RU/Resource:Editor/Plugins|Плагины]]&lt;br /&gt;
*[[RU/Resource:Editor#FAQ|Часто задаваемые вопросы]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Package-x-generic.png‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Базы данных&amp;lt;/h3&amp;gt;&lt;br /&gt;
В этом разделе описаны все возможности Lua, предоставляемые Multi Theft Auto и ресурсами.&lt;br /&gt;
* [[:RU/Category:Resource|Каталог ресурсов]] - изучите их, чтобы создавать правильные скрипты&lt;br /&gt;
* [[RU/Client side scripts|Клиентские скрипты]]&lt;br /&gt;
* [[Modules|Модули]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Applications-development.png‎‎‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Разработка Multi Theft Auto&amp;lt;/h3&amp;gt;&lt;br /&gt;
[[File:Go-down.png|link=https://nightly.mtasa.com/]] [https://nightly.mtasa.com/ Ночные сборки]&lt;br /&gt;
* [[RU/Compiling_MTASA|Компилирование MTA:SA на Windows]]&lt;br /&gt;
&amp;lt;!--* [[Building_MTASA_Server_on_Mac_OS_X|Compiling MTASA on Mac OS X]]--&amp;gt;&lt;br /&gt;
* [[RU/Building_MTASA_Server_on_GNU_Linux|Компилирование MTA:SA на GNU/Linux]]&lt;br /&gt;
* [[RU/Coding guidelines|Рекомендации по написанию кода]]&lt;br /&gt;
* [https://github.com/multitheftauto/mtasa-blue Главный репозиторий GitHub]&lt;br /&gt;
* [[RU/Roadmap|План разработки]]&lt;br /&gt;
* [https://bugs.mtasa.com/ Багтрекер]&lt;br /&gt;
* [[RU/Branches|Ответвления]]&lt;br /&gt;
* [[RU/Forks|Forks and anti cheat]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Applications-office.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Вики - как вы можете помочь&amp;lt;/h3&amp;gt;&lt;br /&gt;
* Заполните документацию для [[:Category:RU/Incomplete|незавершённых функций]].&lt;br /&gt;
* Добавьте [[:Category:RU/Needs_Example|примеры использования функций и событий]].&lt;br /&gt;
* Просмотрите и проверьте [[:Category:RU/Needs Checking|страницы, требующие проверки]].&lt;br /&gt;
* Напишите руководства для помощи новичкам.&lt;br /&gt;
* Переводите страницы вики.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Internet-group-chat.png‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Сообщество&amp;lt;/h3&amp;gt;&lt;br /&gt;
* [https://forum.multitheftauto.com/ Англоязычный форум]&lt;br /&gt;
* [https://forum.multitheftauto.com/forum/100-russian-русский/ Русскоязычный форум]&lt;br /&gt;
* Discord: [https://forum.mtasa.com/topic/95008-multi-theft-autos-official-discord-server/ Официальный MTA Discord сервер]&lt;br /&gt;
* IRC: [irc://irc.multitheftauto.com/mta irc.multitheftauto.com #mta]&lt;br /&gt;
* [https://community.mtasa.com/ Сообщество MTA] - обмен и закачка ресурсов&lt;br /&gt;
* [https://twitter.com/#!/MTAQA/ Twitter] - [https://www.youtube.com/user/MTAQA YouTube] - [https://plus.google.com/102014133442331779727/ Google+] - [https://www.moddb.com/mods/multi-theft-auto-san-andreas Mod DB]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
| width=&amp;quot;50%&amp;quot; style=&amp;quot;vertical-align:top;&amp;quot; |&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Accessories-text-editor.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Скриптинг&amp;lt;/h3&amp;gt;&lt;br /&gt;
* [[RU/Scripting Introduction|Введение в скриптинг]]&lt;br /&gt;
* [[RU/Introduction to Scripting the GUI|Введение в GUI-скриптинг]]&lt;br /&gt;
* [[RU/Debugging|Руководство по отладке]] - как найти ошибки в ваших скриптах&lt;br /&gt;
* [[RU/Resources|Введение в ресурсы]]&lt;br /&gt;
** [[RU/Resource Web Access|Веб-доступ к ресурсам]] - как можно связать сайт и ресурсы&lt;br /&gt;
** [[:Category:RU/Resource|Каталог ресурсов]]&lt;br /&gt;
** [[RU/Meta.xml|Meta.xml]] - имеющийся у каждого ресурса файл-описание&lt;br /&gt;
** [[RU/ACL|ACL]] - список контроля доступа, важный для работы комплексных скриптов&lt;br /&gt;
* [[RU/Writing_Gamemodes|Создание игровых ресурсов]]&lt;br /&gt;
* [[RU/Script_security|Как писать безопасные скрипты и не бояться читеров]]&lt;br /&gt;
* [[RU/Useful_Functions|Полезные функции]]&lt;br /&gt;
Форумные ссылки&lt;br /&gt;
* [https://forum.mtasa.com/forum/71-scripting/ Скриптинг]&lt;br /&gt;
* [https://forum.mtasa.com/forum/123-tutorials/ Руководства по скриптингу]&lt;br /&gt;
* [https://forum.mtasa.com/topic/24702-mtasa-wiki-offline-copies-online-mirrors/ Вики-копии офлайн]&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:start-here.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Общая информация о Lua&amp;lt;/h3&amp;gt;&lt;br /&gt;
Страницы, которые могут вам помочь в изучении Lua&lt;br /&gt;
*[http://www.lua.ru/doc/ Руководство по программированию на Lua (русск.)] &lt;br /&gt;
*[http://www.lua.org/pil/index.html Руководство по программированию на Lua (англ.)]&lt;br /&gt;
*[http://lua-users.org/wiki/TutorialDirectory Lua-вики (англ.)]&lt;br /&gt;
*[http://nixstaller.berlios.de/manual/0.2/nixstaller_9.html Базовое руководство по Lua от Nixstaller (англ.)]&lt;br /&gt;
*[https://forum.multitheftauto.com/viewtopic.php?f=141&amp;amp;t=32458 Справочник статей (русск.)]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px; background:#F2F2FF;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Preferences-system.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Справка&amp;lt;/h3&amp;gt;&lt;br /&gt;
* [[RU/Client Scripting Functions|Клиентские функции]]&lt;br /&gt;
* [[RU/Client Scripting Events|Клиентские события]]&lt;br /&gt;
* [[RU/Server Scripting Functions|Серверные функции]]&lt;br /&gt;
* [[RU/Server Scripting Events|Серверные события]]&lt;br /&gt;
&amp;lt;!-- Incomplete * [[Module functions|Server-side external module scripting functions list]] --&amp;gt;&lt;br /&gt;
* [[RU/MTA Classes|Классы MTA]] - подробное описание всех настраиваемых типов MTA&lt;br /&gt;
** [[RU/Element|Элементы MTA]]/[[RU/Element tree|Дерево элементов]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:System-file-manager.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;[[RU/Id|Списки идентификаторов]]&amp;lt;/h3&amp;gt;&lt;br /&gt;
*[[RU/Animations|Анимации]]&lt;br /&gt;
*[[RU/Character Skins|Скины персонажей]]&lt;br /&gt;
*[[RU/CJ_Clothes|Одежда CJ]]&lt;br /&gt;
*[[RU/Garage|Гаражи]]&lt;br /&gt;
*[[RU/Interior IDs|Интерьеры]]&lt;br /&gt;
*[[RU/Material IDs|Материалы]]&lt;br /&gt;
*[[RU/Projectiles|Снаряды]]&lt;br /&gt;
*[[RU/Radar Blips|Метки радара]]&lt;br /&gt;
*[[RU/Sounds|Звуки]]&lt;br /&gt;
*[[RU/Vehicle IDs|Транспорт]]&lt;br /&gt;
*[[RU/Vehicle Colors|Цвета транспорта]]&lt;br /&gt;
*[[RU/Vehicle Upgrades|Модернизация транспорта]]&lt;br /&gt;
*[[RU/Vehicle variants|Варианты транспорта]]&lt;br /&gt;
*[[RU/Vehicle component manipulation|Манипуляция компонентов транспорта]]&lt;br /&gt;
*[[RU/Weapons|Оружие]]&lt;br /&gt;
*[[RU/Weather|Погода]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
[[File:Osi symbol.png|75px|link=https://opensource.org/|left]]&lt;br /&gt;
'''Multi Theft Auto''' имеет '''открытый исходный код'''. &lt;br /&gt;
&amp;lt;br/&amp;gt;Это значит, что каждый может помочь сделать Multi Theft Auto еще лучше!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding-left: 15px; padding-right: 15px;&amp;quot; class=&amp;quot;plainlinks&amp;quot;&amp;gt;&lt;br /&gt;
[[File:MTALogo_8ball.png|left|85px|link=Archive]]&lt;br /&gt;
&amp;lt;ul style=&amp;quot;list-style: none; width: 200px; float: left;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;'''О [[Multi Theft Auto]]'''&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[RU/Archive|Архив]]&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[RU/Press Coverage|В прессе]]&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[https://github.com/multitheftauto/mtasa-blue/graphs/contributors Разработчики]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;ul style=&amp;quot;list-style: none; width: 200px; float: left;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;'''Multi Theft Auto 0.5'''&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[Archive#Multi_Theft_Auto_0.5|Скачать]]&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[MTA 0.5r2 Known Issues|Известные проблемы]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;ul style=&amp;quot;list-style: none; width: 200px; float: left;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;'''Статистика вики'''&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Статей: {{NUMBEROFARTICLES}}&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Страниц: {{NUMBEROFPAGES}}&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Зарегистрированных пользователей: {{NUMBEROFUSERS}}&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
[[ar:Main Page‎]]&lt;br /&gt;
[[cs:hlavni‎]]&lt;br /&gt;
[[sk:Main Page‎]]&lt;br /&gt;
[[de:Hauptseite]]&lt;br /&gt;
[[en:Main Page]]&lt;br /&gt;
[[es:Página Principal]]&lt;br /&gt;
[[fr:Main Page]]&lt;br /&gt;
[[hu:Main Page‎]]&lt;br /&gt;
[[it:Pagina principale]]&lt;br /&gt;
[[nl:Main Page]]&lt;br /&gt;
[[pl:Strona_Główna]]&lt;br /&gt;
[[pt-br:Página Inicial‎]]&lt;br /&gt;
[[tr:Anasayfa]]&lt;br /&gt;
[[zh-cn:Main Page]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Main_Page&amp;diff=82701</id>
		<title>RU/Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Main_Page&amp;diff=82701"/>
		<updated>2026-01-08T19:19:28Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| width=&amp;quot;100%&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
&amp;lt;div style=&amp;quot;/*border: 1px solid #D8D8D8;*/ padding-left: 15px; padding-right: 15px; height: 100%;&amp;quot;&amp;gt;&lt;br /&gt;
[[File:Mtalogo.png|left|100px|link=https://wiki.multitheftauto.com/wiki/RU/Main_Page]]'''Добро пожаловать в вики о модификации [[RU/Multi Theft Auto|Multi Theft Auto]] для игры Grand Theft Auto: San Andreas.''' Здесь вы найдёте множество информации об использовании этой модификации.&lt;br /&gt;
 &lt;br /&gt;
Есть много [[Как ты можешь помочь|вещей]], которые вы можете сделать, чтобы помочь нам улучшить Multi Theft Auto - создать карту, игровой режим, добавить описание функций скриптинга, написать пример кода, руководство, или просто поиграть в Multi Theft Auto и сообщить о найденных недоработках.&lt;br /&gt;
 &lt;br /&gt;
Если у вас есть какие-либо вопросы или проблемы, связанные со скриптингом, вы можете [[RU/Places_To_Chat|связаться с нами]].&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;[ Перестань играть с собой ]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
|width=&amp;quot;50%&amp;quot; style=&amp;quot;vertical-align:top;&amp;quot; |&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px; background: #FFFCF2;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Input-gaming.png‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Играть&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;background: #FFEEAA; border: 1px solid #FFCD19;&amp;quot;&amp;gt;&lt;br /&gt;
[[File:Go-down.png|link=https://mtasa.com/]] ''' [https://mtasa.com/ Скачать Multi Theft Auto {{Current Version|full}}]'''&amp;lt;/div&amp;gt;&lt;br /&gt;
* [[RU/Where to buy GTASA|Где купить Grand Theft Auto: San Andreas]]&lt;br /&gt;
* [[RU/Client Manual|Руководство о клиенте]]&lt;br /&gt;
&amp;lt;!-- * [[Changes_in_{{padleft:|3|{{Current Version|full}}}}| Changes in {{padleft:|3|{{Current Version|full}}}}]] --&amp;gt;&lt;br /&gt;
* [[RU/Changes_in_{{padleft:|5|{{Current Version|full}}}}| Изменения в версии {{padleft:|5|{{Current Version|full}}}}]]&lt;br /&gt;
* [[RU/Known Issues_-_FAQ|Известные проблемы]]&lt;br /&gt;
* [[RU/Upgrading_from_MTA:Race|Переход из MTA:Race в MTA:SA {{padleft:|3|{{Current Version|full}}}}]]&lt;br /&gt;
* [[RU/Server Manual|Руководство о сервере]]&lt;br /&gt;
* [[RU/Map manager|Менеджер карт]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;Редактор карт&amp;lt;/h3&amp;gt;&lt;br /&gt;
*[[RU/Resource:Editor|Руководство]]&lt;br /&gt;
*[[RU/Resource:Editor/EDF|Формат определения редактора]]&lt;br /&gt;
*[[RU/Resource:Editor/Plugins|Плагины]]&lt;br /&gt;
*[[RU/Resource:Editor#FAQ|Часто задаваемые вопросы]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Package-x-generic.png‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Базы данных&amp;lt;/h3&amp;gt;&lt;br /&gt;
В этом разделе описаны все возможности Lua, предоставляемые Multi Theft Auto и ресурсами.&lt;br /&gt;
* [[:RU/Category:Resource|Каталог ресурсов]] - изучите их, чтобы создавать правильные скрипты&lt;br /&gt;
* [[RU/Client side scripts|Клиентские скрипты]]&lt;br /&gt;
* [[Modules|Модули]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Applications-development.png‎‎‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Разработка Multi Theft Auto&amp;lt;/h3&amp;gt;&lt;br /&gt;
[[File:Go-down.png|link=https://nightly.mtasa.com/]] [https://nightly.mtasa.com/ Ночные сборки]&lt;br /&gt;
* [[RU/Compiling_MTASA|Компилирование MTA:SA на Windows]]&lt;br /&gt;
&amp;lt;!--* [[Building_MTASA_Server_on_Mac_OS_X|Compiling MTASA on Mac OS X]]--&amp;gt;&lt;br /&gt;
* [[RU/Building_MTASA_Server_on_GNU_Linux|Компилирование MTA:SA на GNU/Linux]]&lt;br /&gt;
* [[RU/Coding guidelines|Рекомендации по написанию кода]]&lt;br /&gt;
* [https://github.com/multitheftauto/mtasa-blue Главный репозиторий GitHub]&lt;br /&gt;
* [[RU/Roadmap|План разработки]]&lt;br /&gt;
* [https://bugs.mtasa.com/ Багтрекер]&lt;br /&gt;
* [[RU/Branches|Ответвления]]&lt;br /&gt;
* [[RU/Forks|Forks and anti cheat]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Applications-office.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Вики - как вы можете помочь&amp;lt;/h3&amp;gt;&lt;br /&gt;
* Заполните документацию для [[:Category:RU/Incomplete|незавершённых функций]].&lt;br /&gt;
* Добавьте [[:Category:RU/Needs_Example|примеры использования функций и событий]].&lt;br /&gt;
* Просмотрите и проверьте [[:Category:RU/Needs Checking|страницы, требующие проверки]].&lt;br /&gt;
* Напишите руководства для помощи новичкам.&lt;br /&gt;
* Переводите страницы вики.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Internet-group-chat.png‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Сообщество&amp;lt;/h3&amp;gt;&lt;br /&gt;
* [https://forum.multitheftauto.com/ Англоязычный форум]&lt;br /&gt;
* [https://forum.multitheftauto.com/forum/100-russian-русский/ Русскоязычный форум]&lt;br /&gt;
* Discord: [https://forum.mtasa.com/topic/95008-multi-theft-autos-official-discord-server/ Официальный MTA Discord сервер]&lt;br /&gt;
* IRC: [irc://irc.multitheftauto.com/mta irc.multitheftauto.com #mta]&lt;br /&gt;
* [https://community.mtasa.com/ Сообщество MTA] - обмен и закачка ресурсов&lt;br /&gt;
* [https://twitter.com/#!/MTAQA/ Twitter] - [https://www.youtube.com/user/MTAQA YouTube] - [https://plus.google.com/102014133442331779727/ Google+] - [https://www.moddb.com/mods/multi-theft-auto-san-andreas Mod DB]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
| width=&amp;quot;50%&amp;quot; style=&amp;quot;vertical-align:top;&amp;quot; |&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Accessories-text-editor.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Скриптинг&amp;lt;/h3&amp;gt;&lt;br /&gt;
* [[RU/Scripting Introduction|Введение в скриптинг]]&lt;br /&gt;
* [[RU/Introduction to Scripting the GUI|Введение в GUI-скриптинг]]&lt;br /&gt;
* [[RU/Debugging|Руководство по отладке]] - как найти ошибки в ваших скриптах&lt;br /&gt;
* [[RU/Resources|Введение в ресурсы]]&lt;br /&gt;
** [[RU/Resource Web Access|Веб-доступ к ресурсам]] - как можно связать сайт и ресурсы&lt;br /&gt;
** [[:Category:RU/Resource|Каталог ресурсов]]&lt;br /&gt;
** [[RU/Meta.xml|Meta.xml]] - имеющийся у каждого ресурса файл-описание&lt;br /&gt;
** [[RU/ACL|ACL]] - список контроля доступа, важный для работы комплексных скриптов&lt;br /&gt;
* [[RU/Writing_Gamemodes|Создание игровых ресурсов]]&lt;br /&gt;
* [[RU/Script_security|Как писать безопасные скрипты и не бояться читеров]]&lt;br /&gt;
* [[RU/Useful_Functions|Полезные функции]]&lt;br /&gt;
Форумные ссылки&lt;br /&gt;
* [https://forum.mtasa.com/forum/71-scripting/ Скриптинг]&lt;br /&gt;
* [https://forum.mtasa.com/forum/123-tutorials/ Руководства по скриптингу]&lt;br /&gt;
* [https://forum.mtasa.com/topic/24702-mtasa-wiki-offline-copies-online-mirrors/ Вики-копии офлайн]&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:start-here.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Общая информация о Lua&amp;lt;/h3&amp;gt;&lt;br /&gt;
Страницы, которые могут вам помочь в изучении Lua&lt;br /&gt;
*[http://www.lua.ru/doc/ Руководство по программированию на Lua (русск.)] &lt;br /&gt;
*[http://www.lua.org/pil/index.html Руководство по программированию на Lua (англ.)]&lt;br /&gt;
*[http://lua-users.org/wiki/TutorialDirectory Lua-вики (англ.)]&lt;br /&gt;
*[http://nixstaller.berlios.de/manual/0.2/nixstaller_9.html Базовое руководство по Lua от Nixstaller (англ.)]&lt;br /&gt;
*[https://forum.multitheftauto.com/viewtopic.php?f=141&amp;amp;t=32458 Справочник статей (русск.)]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px; background:#F2F2FF;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Preferences-system.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Справка&amp;lt;/h3&amp;gt;&lt;br /&gt;
* [[RU/Client Scripting Functions|Клиентские функции]]&lt;br /&gt;
* [[RU/Client Scripting Events|Клиентские события]]&lt;br /&gt;
* [[RU/Server Scripting Functions|Серверные функции]]&lt;br /&gt;
* [[RU/Server Scripting Events|Серверные события]]&lt;br /&gt;
&amp;lt;!-- Incomplete * [[Module functions|Server-side external module scripting functions list]] --&amp;gt;&lt;br /&gt;
* [[RU/MTA Classes|Классы MTA]] - подробное описание всех настраиваемых типов MTA&lt;br /&gt;
** [[RU/Element|Элементы MTA]]/[[RU/Element tree|Дерево элементов]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:System-file-manager.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;[[RU/Id|Списки идентификаторов]]&amp;lt;/h3&amp;gt;&lt;br /&gt;
*[[RU/Animations|Анимации]]&lt;br /&gt;
*[[RU/Character Skins|Скины персонажей]]&lt;br /&gt;
*[[RU/CJ_Clothes|Одежда CJ]]&lt;br /&gt;
*[[RU/Garage|Гаражи]]&lt;br /&gt;
*[[RU/Interior IDs|Интерьеры]]&lt;br /&gt;
*[[RU/Material IDs|Материалы]]&lt;br /&gt;
*[[RU/Projectiles|Снаряды]]&lt;br /&gt;
*[[RU/Radar Blips|Метки радара]]&lt;br /&gt;
*[[RU/Sounds|Звуки]]&lt;br /&gt;
*[[RU/Vehicle IDs|Транспорт]]&lt;br /&gt;
*[[RU/Vehicle Colors|Цвета транспорта]]&lt;br /&gt;
*[[RU/Vehicle Upgrades|Модернизация транспорта]]&lt;br /&gt;
*[[RU/Vehicle variants|Варианты транспорта]]&lt;br /&gt;
*[[RU/Vehicle component manipulation|Манипуляция компонентов транспорта]]&lt;br /&gt;
*[[RU/Weapons|Оружие]]&lt;br /&gt;
*[[RU/Weather|Погода]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
[[File:Osi symbol.png|75px|link=https://opensource.org/|left]]&lt;br /&gt;
'''Multi Theft Auto''' имеет '''открытый исходный код'''. &lt;br /&gt;
&amp;lt;br/&amp;gt;Это значит, что каждый может помочь сделать Multi Theft Auto еще лучше!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding-left: 15px; padding-right: 15px;&amp;quot; class=&amp;quot;plainlinks&amp;quot;&amp;gt;&lt;br /&gt;
[[File:MTALogo_8ball.png|left|85px|link=Archive]]&lt;br /&gt;
&amp;lt;ul style=&amp;quot;list-style: none; width: 200px; float: left;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;'''О [[Multi Theft Auto]]'''&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[RU/Archive|Архив]]&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[RU/Press Coverage|В прессе]]&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[https://github.com/multitheftauto/mtasa-blue/graphs/contributors Разработчики]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;ul style=&amp;quot;list-style: none; width: 200px; float: left;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;'''Multi Theft Auto 0.5'''&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[Archive#Multi_Theft_Auto_0.5|Скачать]]&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[MTA 0.5r2 Known Issues|Известные проблемы]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;ul style=&amp;quot;list-style: none; width: 200px; float: left;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;'''Статистика вики'''&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Статей: {{NUMBEROFARTICLES}}&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Страниц: {{NUMBEROFPAGES}}&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Зарегистрированных пользователей: {{NUMBEROFUSERS}}&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
[[ar:Main Page‎]]&lt;br /&gt;
[[cs:hlavni‎]]&lt;br /&gt;
[[sk:Main Page‎]]&lt;br /&gt;
[[de:Hauptseite]]&lt;br /&gt;
[[en:Main Page]]&lt;br /&gt;
[[es:Página Principal]]&lt;br /&gt;
[[fr:Main Page]]&lt;br /&gt;
[[hu:Main Page‎]]&lt;br /&gt;
[[it:Pagina principale]]&lt;br /&gt;
[[nl:Main Page]]&lt;br /&gt;
[[pl:Strona_Główna]]&lt;br /&gt;
[[pt-br:Página Inicial‎]]&lt;br /&gt;
[[tr:Anasayfa]]&lt;br /&gt;
[[zh-cn:Main Page]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Main_Page&amp;diff=82700</id>
		<title>RU/Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Main_Page&amp;diff=82700"/>
		<updated>2026-01-08T19:17:34Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| width=&amp;quot;100%&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
&amp;lt;div style=&amp;quot;/*border: 1px solid #D8D8D8;*/ padding-left: 15px; padding-right: 15px; height: 100%;&amp;quot;&amp;gt;&lt;br /&gt;
[[File:Mtalogo.png|left|100px|link=https://wiki.multitheftauto.com/wiki/RU/Main_Page]]'''Добро пожаловать в вики о модификации [[RU/Multi Theft Auto|Multi Theft Auto]] для игры Grand Theft Auto: San Andreas.''' Здесь вы найдёте множество информации об использовании этой модификации.&lt;br /&gt;
 &lt;br /&gt;
Есть много [[Как ты можешь помочь|вещей]], которые вы можете сделать, чтобы помочь нам улучшить Multi Theft Auto - создать карту, игровой режим, добавить описание функций скриптинга, написать пример кода, руководство, или просто поиграть в Multi Theft Auto и сообщить о найденных недоработках.&lt;br /&gt;
 &lt;br /&gt;
Если у вас есть какие-либо вопросы или проблемы, связанные со скриптингом, вы можете [[RU/Places_To_Chat|связаться с нами]].&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;[ Перестань играть с собой ]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
|width=&amp;quot;50%&amp;quot; style=&amp;quot;vertical-align:top;&amp;quot; |&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px; background: #FFFCF2;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Input-gaming.png‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Играть&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;background: #FFEEAA; border: 1px solid #FFCD19;&amp;quot;&amp;gt;&lt;br /&gt;
[[File:Go-down.png|link=https://mtasa.com/]] ''' [https://mtasa.com/ Скачать Multi Theft Auto {{Current Version|full}}]'''&amp;lt;/div&amp;gt;&lt;br /&gt;
* [[RU/Where to buy GTASA|Где купить Grand Theft Auto: San Andreas]]&lt;br /&gt;
* [[RU/Client Manual|Руководство о клиенте]]&lt;br /&gt;
&amp;lt;!-- * [[Changes_in_{{padleft:|3|{{Current Version|full}}}}| Changes in {{padleft:|3|{{Current Version|full}}}}]] --&amp;gt;&lt;br /&gt;
* [[RU/Changes_in_{{padleft:|5|{{Current Version|full}}}}| Изменения в версии {{padleft:|5|{{Current Version|full}}}}]]&lt;br /&gt;
* [[RU/Known Issues_-_FAQ|Известные проблемы]]&lt;br /&gt;
* [[RU/Upgrading_from_MTA:Race|Переход из MTA:Race в MTA:SA {{padleft:|3|{{Current Version|full}}}}]]&lt;br /&gt;
* [[RU/Server Manual|Руководство о сервере]]&lt;br /&gt;
* [[RU/Map manager|Менеджер карт]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;Редактор карт&amp;lt;/h3&amp;gt;&lt;br /&gt;
*[[RU/Resource:Editor|Руководство]]&lt;br /&gt;
*[[RU/Resource:Editor/EDF|Формат определения редактора]]&lt;br /&gt;
*[[RU/Resource:Editor/Plugins|Плагины]]&lt;br /&gt;
*[[RU/Resource:Editor#FAQ|Часто задаваемые вопросы]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Package-x-generic.png‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Базы данных&amp;lt;/h3&amp;gt;&lt;br /&gt;
В этом разделе описаны все возможности Lua, предоставляемые Multi Theft Auto и ресурсами.&lt;br /&gt;
* [[:RU/Category:Resource|Каталог ресурсов]] - изучите их, чтобы создавать правильные скрипты&lt;br /&gt;
* [[RU/Client side scripts|Клиентские скрипты]]&lt;br /&gt;
* [[Modules|Модули]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Applications-development.png‎‎‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Разработка Multi Theft Auto&amp;lt;/h3&amp;gt;&lt;br /&gt;
[[File:Go-down.png|link=https://nightly.mtasa.com/]] [https://nightly.mtasa.com/ Ночные сборки]&lt;br /&gt;
* [[RU/Compiling_MTASA|Компилирование MTA:SA на Windows]]&lt;br /&gt;
&amp;lt;!--* [[Building_MTASA_Server_on_Mac_OS_X|Compiling MTASA on Mac OS X]]--&amp;gt;&lt;br /&gt;
* [[RU/Building_MTASA_Server_on_GNU_Linux|Компилирование MTA:SA на GNU/Linux]]&lt;br /&gt;
* [[RU/Coding guidelines|Рекомендации по написанию кода]]&lt;br /&gt;
* [https://github.com/multitheftauto/mtasa-blue Главный репозиторий GitHub]&lt;br /&gt;
* [[RU/Roadmap|План разработки]]&lt;br /&gt;
* [https://bugs.mtasa.com/ Багтрекер]&lt;br /&gt;
* [[RU/Branches|Ответвления]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Applications-office.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Вики - как вы можете помочь&amp;lt;/h3&amp;gt;&lt;br /&gt;
* Заполните документацию для [[:Category:RU/Incomplete|незавершённых функций]].&lt;br /&gt;
* Добавьте [[:Category:RU/Needs_Example|примеры использования функций и событий]].&lt;br /&gt;
* Просмотрите и проверьте [[:Category:RU/Needs Checking|страницы, требующие проверки]].&lt;br /&gt;
* Напишите руководства для помощи новичкам.&lt;br /&gt;
* Переводите страницы вики.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Internet-group-chat.png‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Сообщество&amp;lt;/h3&amp;gt;&lt;br /&gt;
* [https://forum.multitheftauto.com/ Англоязычный форум]&lt;br /&gt;
* [https://forum.multitheftauto.com/forum/100-russian-русский/ Русскоязычный форум]&lt;br /&gt;
* Discord: [https://forum.mtasa.com/topic/95008-multi-theft-autos-official-discord-server/ Официальный MTA Discord сервер]&lt;br /&gt;
* IRC: [irc://irc.multitheftauto.com/mta irc.multitheftauto.com #mta]&lt;br /&gt;
* [https://community.mtasa.com/ Сообщество MTA] - обмен и закачка ресурсов&lt;br /&gt;
* [https://twitter.com/#!/MTAQA/ Twitter] - [https://www.youtube.com/user/MTAQA YouTube] - [https://plus.google.com/102014133442331779727/ Google+] - [https://www.moddb.com/mods/multi-theft-auto-san-andreas Mod DB]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
| width=&amp;quot;50%&amp;quot; style=&amp;quot;vertical-align:top;&amp;quot; |&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Accessories-text-editor.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Скриптинг&amp;lt;/h3&amp;gt;&lt;br /&gt;
* [[RU/Scripting Introduction|Введение в скриптинг]]&lt;br /&gt;
* [[RU/Introduction to Scripting the GUI|Введение в GUI-скриптинг]]&lt;br /&gt;
* [[RU/Debugging|Руководство по отладке]] - как найти ошибки в ваших скриптах&lt;br /&gt;
* [[RU/Resources|Введение в ресурсы]]&lt;br /&gt;
** [[RU/Resource Web Access|Веб-доступ к ресурсам]] - как можно связать сайт и ресурсы&lt;br /&gt;
** [[:Category:RU/Resource|Каталог ресурсов]]&lt;br /&gt;
** [[RU/Meta.xml|Meta.xml]] - имеющийся у каждого ресурса файл-описание&lt;br /&gt;
** [[RU/ACL|ACL]] - список контроля доступа, важный для работы комплексных скриптов&lt;br /&gt;
* [[RU/Writing_Gamemodes|Создание игровых ресурсов]]&lt;br /&gt;
* [[RU/Script_security|Как писать безопасные скрипты и не бояться читеров]]&lt;br /&gt;
* [[RU/Useful_Functions|Полезные функции]]&lt;br /&gt;
Форумные ссылки&lt;br /&gt;
* [https://forum.mtasa.com/forum/71-scripting/ Скриптинг]&lt;br /&gt;
* [https://forum.mtasa.com/forum/123-tutorials/ Руководства по скриптингу]&lt;br /&gt;
* [https://forum.mtasa.com/topic/24702-mtasa-wiki-offline-copies-online-mirrors/ Вики-копии офлайн]&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:start-here.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Общая информация о Lua&amp;lt;/h3&amp;gt;&lt;br /&gt;
Страницы, которые могут вам помочь в изучении Lua&lt;br /&gt;
*[http://www.lua.ru/doc/ Руководство по программированию на Lua (русск.)] &lt;br /&gt;
*[http://www.lua.org/pil/index.html Руководство по программированию на Lua (англ.)]&lt;br /&gt;
*[http://lua-users.org/wiki/TutorialDirectory Lua-вики (англ.)]&lt;br /&gt;
*[http://nixstaller.berlios.de/manual/0.2/nixstaller_9.html Базовое руководство по Lua от Nixstaller (англ.)]&lt;br /&gt;
*[https://forum.multitheftauto.com/viewtopic.php?f=141&amp;amp;t=32458 Справочник статей (русск.)]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px; background:#F2F2FF;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Preferences-system.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Справка&amp;lt;/h3&amp;gt;&lt;br /&gt;
* [[RU/Client Scripting Functions|Клиентские функции]]&lt;br /&gt;
* [[RU/Client Scripting Events|Клиентские события]]&lt;br /&gt;
* [[RU/Server Scripting Functions|Серверные функции]]&lt;br /&gt;
* [[RU/Server Scripting Events|Серверные события]]&lt;br /&gt;
&amp;lt;!-- Incomplete * [[Module functions|Server-side external module scripting functions list]] --&amp;gt;&lt;br /&gt;
* [[RU/MTA Classes|Классы MTA]] - подробное описание всех настраиваемых типов MTA&lt;br /&gt;
** [[RU/Element|Элементы MTA]]/[[RU/Element tree|Дерево элементов]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:System-file-manager.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;[[RU/Id|Списки идентификаторов]]&amp;lt;/h3&amp;gt;&lt;br /&gt;
*[[RU/Animations|Анимации]]&lt;br /&gt;
*[[RU/Character Skins|Скины персонажей]]&lt;br /&gt;
*[[RU/CJ_Clothes|Одежда CJ]]&lt;br /&gt;
*[[RU/Garage|Гаражи]]&lt;br /&gt;
*[[RU/Interior IDs|Интерьеры]]&lt;br /&gt;
*[[RU/Material IDs|Материалы]]&lt;br /&gt;
*[[RU/Projectiles|Снаряды]]&lt;br /&gt;
*[[RU/Radar Blips|Метки радара]]&lt;br /&gt;
*[[RU/Sounds|Звуки]]&lt;br /&gt;
*[[RU/Vehicle IDs|Транспорт]]&lt;br /&gt;
*[[RU/Vehicle Colors|Цвета транспорта]]&lt;br /&gt;
*[[RU/Vehicle Upgrades|Модернизация транспорта]]&lt;br /&gt;
*[[RU/Vehicle variants|Варианты транспорта]]&lt;br /&gt;
*[[RU/Vehicle component manipulation|Манипуляция компонентов транспорта]]&lt;br /&gt;
*[[RU/Weapons|Оружие]]&lt;br /&gt;
*[[RU/Weather|Погода]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
[[File:Osi symbol.png|75px|link=https://opensource.org/|left]]&lt;br /&gt;
'''Multi Theft Auto''' имеет '''открытый исходный код'''. &lt;br /&gt;
&amp;lt;br/&amp;gt;Это значит, что каждый может помочь сделать Multi Theft Auto еще лучше!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding-left: 15px; padding-right: 15px;&amp;quot; class=&amp;quot;plainlinks&amp;quot;&amp;gt;&lt;br /&gt;
[[File:MTALogo_8ball.png|left|85px|link=Archive]]&lt;br /&gt;
&amp;lt;ul style=&amp;quot;list-style: none; width: 200px; float: left;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;'''О [[Multi Theft Auto]]'''&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[RU/Archive|Архив]]&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[RU/Press Coverage|В прессе]]&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[https://github.com/multitheftauto/mtasa-blue/graphs/contributors Разработчики]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;ul style=&amp;quot;list-style: none; width: 200px; float: left;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;'''Multi Theft Auto 0.5'''&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[Archive#Multi_Theft_Auto_0.5|Скачать]]&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[MTA 0.5r2 Known Issues|Известные проблемы]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;ul style=&amp;quot;list-style: none; width: 200px; float: left;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;'''Статистика вики'''&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Статей: {{NUMBEROFARTICLES}}&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Страниц: {{NUMBEROFPAGES}}&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Зарегистрированных пользователей: {{NUMBEROFUSERS}}&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
[[ar:Main Page‎]]&lt;br /&gt;
[[cs:hlavni‎]]&lt;br /&gt;
[[sk:Main Page‎]]&lt;br /&gt;
[[de:Hauptseite]]&lt;br /&gt;
[[en:Main Page]]&lt;br /&gt;
[[es:Página Principal]]&lt;br /&gt;
[[fr:Main Page]]&lt;br /&gt;
[[hu:Main Page‎]]&lt;br /&gt;
[[it:Pagina principale]]&lt;br /&gt;
[[nl:Main Page]]&lt;br /&gt;
[[pl:Strona_Główna]]&lt;br /&gt;
[[pt-br:Página Inicial‎]]&lt;br /&gt;
[[tr:Anasayfa]]&lt;br /&gt;
[[zh-cn:Main Page]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Main_Page&amp;diff=82699</id>
		<title>RU/Main Page</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Main_Page&amp;diff=82699"/>
		<updated>2026-01-08T19:17:21Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{| width=&amp;quot;100%&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
&amp;lt;div style=&amp;quot;/*border: 1px solid #D8D8D8;*/ padding-left: 15px; padding-right: 15px; height: 100%;&amp;quot;&amp;gt;&lt;br /&gt;
[[File:Mtalogo.png|left|100px|link=https://wiki.multitheftauto.com/wiki/RU/Main_Page]]'''Добро пожаловать в вики о модификации [[RU/Multi Theft Auto|Multi Theft Auto]] для игры Grand Theft Auto: San Andreas.''' Здесь вы найдёте множество информации об использовании этой модификации.&lt;br /&gt;
 &lt;br /&gt;
Есть много [[Как ты можешь помочь|вещей]], которые вы можете сделать, чтобы помочь нам улучшить Multi Theft Auto - создать карту, игровой режим, добавить описание функций скриптинга, написать пример кода, руководство, или просто поиграть в Multi Theft Auto и сообщить о найденных недоработках.&lt;br /&gt;
 &lt;br /&gt;
Если у вас есть какие-либо вопросы или проблемы, связанные со скриптингом, вы можете [[RU/Places_To_Chat|связаться с нами]].&lt;br /&gt;
&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;[ Перестань играть с собой ]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
|-&lt;br /&gt;
|width=&amp;quot;50%&amp;quot; style=&amp;quot;vertical-align:top;&amp;quot; |&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px; background: #FFFCF2;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Input-gaming.png‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Играть&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;background: #FFEEAA; border: 1px solid #FFCD19;&amp;quot;&amp;gt;&lt;br /&gt;
[[File:Go-down.png|link=https://mtasa.com/]] ''' [https://mtasa.com/ Скачать Multi Theft Auto {{Current Version|full}}]'''&amp;lt;/div&amp;gt;&lt;br /&gt;
* [[RU/Where to buy GTASA|Где купить Grand Theft Auto: San Andreas]]&lt;br /&gt;
* [[RU/Client Manual|Руководство о клиенте]]&lt;br /&gt;
&amp;lt;!-- * [[Changes_in_{{padleft:|3|{{Current Version|full}}}}| Changes in {{padleft:|3|{{Current Version|full}}}}]] --&amp;gt;&lt;br /&gt;
* [[RU/Changes_in_{{padleft:|5|{{Current Version|full}}}}| Изменения в версии {{padleft:|5|{{Current Version|full}}}}]]&lt;br /&gt;
* [[RU/Known Issues_-_FAQ|Известные проблемы]]&lt;br /&gt;
* [[RU/Upgrading_from_MTA:Race|Переход из MTA:Race в MTA:SA {{padleft:|3|{{Current Version|full}}}}]]&lt;br /&gt;
* [[RU/Server Manual|Руководство о сервере]]&lt;br /&gt;
* [[RU/Map manager|Менеджер карт]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;h3&amp;gt;Редактор карт&amp;lt;/h3&amp;gt;&lt;br /&gt;
*[[RU/Resource:Editor|Руководство]]&lt;br /&gt;
*[[RU/Resource:Editor/EDF|Формат определения редактора]]&lt;br /&gt;
*[[RU/Resource:Editor/Plugins|Плагины]]&lt;br /&gt;
*[[RU/Resource:Editor#FAQ|Часто задаваемые вопросы]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Package-x-generic.png‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Базы данных&amp;lt;/h3&amp;gt;&lt;br /&gt;
В этом разделе описаны все возможности Lua, предоставляемые Multi Theft Auto и ресурсами.&lt;br /&gt;
* [[:RU/Category:Resource|Каталог ресурсов]] - изучите их, чтобы создавать правильные скрипты&lt;br /&gt;
* [[RU/Client side scripts|Клиентские скрипты]]&lt;br /&gt;
* [[Modules|Модули]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Applications-development.png‎‎‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Разработка Multi Theft Auto&amp;lt;/h3&amp;gt;&lt;br /&gt;
[[File:Go-down.png|link=https://nightly.mtasa.com/]] [https://nightly.mtasa.com/ Ночные сборки]&lt;br /&gt;
* [[RU/Compiling_MTASA|Компилирование MTA:SA на Windows]]&lt;br /&gt;
&amp;lt;!--* [[Building_MTASA_Server_on_Mac_OS_X|Compiling MTASA on Mac OS X]]--&amp;gt;&lt;br /&gt;
* [[RU/Building_MTASA_Server_on_GNU_Linux|Компилирование MTA:SA на GNU/Linux]]&lt;br /&gt;
* [[RU/Coding guidelines|Рекомендации по написанию кода]]&lt;br /&gt;
* [https://github.com/multitheftauto/mtasa-blue Главный репозиторий GitHub]&lt;br /&gt;
* [[RU/Roadmap|План разработки]]&lt;br /&gt;
* [https://bugs.mtasa.com/ Багтрекер]&lt;br /&gt;
* [[RU/Branches|Ответвления]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Applications-office.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Вики - как вы можете помочь&amp;lt;/h3&amp;gt;&lt;br /&gt;
* Заполните документацию для [[:Category:RU/Incomplete|незавершённых функций]].&lt;br /&gt;
* Добавьте [[:Category:RU/Needs_Example|примеры использования функций и событий]].&lt;br /&gt;
* Просмотрите и проверьте [[:Category:RU/Needs Checking|страницы, требующие проверки]].&lt;br /&gt;
* Напишите руководства для помощи новичкам.&lt;br /&gt;
* Переводите страницы вики.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Internet-group-chat.png‎|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Сообщество&amp;lt;/h3&amp;gt;&lt;br /&gt;
* [https://forum.multitheftauto.com/ Англоязычный форум]&lt;br /&gt;
* [https://forum.multitheftauto.com/forum/100-russian-русский/ Русскоязычный форум]&lt;br /&gt;
* Discord: [https://forum.mtasa.com/topic/95008-multi-theft-autos-official-discord-server/ Официальный MTA Discord сервер]&lt;br /&gt;
* IRC: [irc://irc.multitheftauto.com/mta irc.multitheftauto.com #mta]&lt;br /&gt;
* [https://community.mtasa.com/ Сообщество MTA] - обмен и закачка ресурсов&lt;br /&gt;
* [https://twitter.com/#!/MTAQA/ Twitter] - [https://www.youtube.com/user/MTAQA YouTube] - [https://plus.google.com/102014133442331779727/ Google+] - [https://www.moddb.com/mods/multi-theft-auto-san-andreas Mod DB]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
| width=&amp;quot;50%&amp;quot; style=&amp;quot;vertical-align:top;&amp;quot; |&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Accessories-text-editor.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Скриптинг&amp;lt;/h3&amp;gt;&lt;br /&gt;
* [[RU/Scripting Introduction|Введение в скриптинг]]&lt;br /&gt;
* [[RU/Introduction to Scripting the GUI|Введение в GUI-скриптинг]]&lt;br /&gt;
* [[RU/Debugging|Руководство по отладке]] - как найти ошибки в ваших скриптах&lt;br /&gt;
* [[RU/Resources|Введение в ресурсы]]&lt;br /&gt;
** [[RU/Resource Web Access|Веб-доступ к ресурсам]] - как можно связать сайт и ресурсы&lt;br /&gt;
** [[:Category:RU/Resource|Каталог ресурсов]]&lt;br /&gt;
** [[RU/Meta.xml|Meta.xml]] - имеющийся у каждого ресурса файл-описание&lt;br /&gt;
** [[RU/ACL|ACL]] - список контроля доступа, важный для работы комплексных скриптов&lt;br /&gt;
* [[RU/Writing_Gamemodes|Создание игровых ресурсов]]&lt;br /&gt;
* [[RU/Script_security|- Как писать безопасные скрипты и не бояться читеров]]&lt;br /&gt;
* [[RU/Useful_Functions|Полезные функции]]&lt;br /&gt;
Форумные ссылки&lt;br /&gt;
* [https://forum.mtasa.com/forum/71-scripting/ Скриптинг]&lt;br /&gt;
* [https://forum.mtasa.com/forum/123-tutorials/ Руководства по скриптингу]&lt;br /&gt;
* [https://forum.mtasa.com/topic/24702-mtasa-wiki-offline-copies-online-mirrors/ Вики-копии офлайн]&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:start-here.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Общая информация о Lua&amp;lt;/h3&amp;gt;&lt;br /&gt;
Страницы, которые могут вам помочь в изучении Lua&lt;br /&gt;
*[http://www.lua.ru/doc/ Руководство по программированию на Lua (русск.)] &lt;br /&gt;
*[http://www.lua.org/pil/index.html Руководство по программированию на Lua (англ.)]&lt;br /&gt;
*[http://lua-users.org/wiki/TutorialDirectory Lua-вики (англ.)]&lt;br /&gt;
*[http://nixstaller.berlios.de/manual/0.2/nixstaller_9.html Базовое руководство по Lua от Nixstaller (англ.)]&lt;br /&gt;
*[https://forum.multitheftauto.com/viewtopic.php?f=141&amp;amp;t=32458 Справочник статей (русск.)]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px; background:#F2F2FF;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:Preferences-system.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;Справка&amp;lt;/h3&amp;gt;&lt;br /&gt;
* [[RU/Client Scripting Functions|Клиентские функции]]&lt;br /&gt;
* [[RU/Client Scripting Events|Клиентские события]]&lt;br /&gt;
* [[RU/Server Scripting Functions|Серверные функции]]&lt;br /&gt;
* [[RU/Server Scripting Events|Серверные события]]&lt;br /&gt;
&amp;lt;!-- Incomplete * [[Module functions|Server-side external module scripting functions list]] --&amp;gt;&lt;br /&gt;
* [[RU/MTA Classes|Классы MTA]] - подробное описание всех настраиваемых типов MTA&lt;br /&gt;
** [[RU/Element|Элементы MTA]]/[[RU/Element tree|Дерево элементов]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;border: 1px solid #D8D8D8; padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;float:right; width: 32px;&amp;quot;&amp;gt;[[File:System-file-manager.png|link=]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;h3&amp;gt;[[RU/Id|Списки идентификаторов]]&amp;lt;/h3&amp;gt;&lt;br /&gt;
*[[RU/Animations|Анимации]]&lt;br /&gt;
*[[RU/Character Skins|Скины персонажей]]&lt;br /&gt;
*[[RU/CJ_Clothes|Одежда CJ]]&lt;br /&gt;
*[[RU/Garage|Гаражи]]&lt;br /&gt;
*[[RU/Interior IDs|Интерьеры]]&lt;br /&gt;
*[[RU/Material IDs|Материалы]]&lt;br /&gt;
*[[RU/Projectiles|Снаряды]]&lt;br /&gt;
*[[RU/Radar Blips|Метки радара]]&lt;br /&gt;
*[[RU/Sounds|Звуки]]&lt;br /&gt;
*[[RU/Vehicle IDs|Транспорт]]&lt;br /&gt;
*[[RU/Vehicle Colors|Цвета транспорта]]&lt;br /&gt;
*[[RU/Vehicle Upgrades|Модернизация транспорта]]&lt;br /&gt;
*[[RU/Vehicle variants|Варианты транспорта]]&lt;br /&gt;
*[[RU/Vehicle component manipulation|Манипуляция компонентов транспорта]]&lt;br /&gt;
*[[RU/Weapons|Оружие]]&lt;br /&gt;
*[[RU/Weather|Погода]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:4px 8px 8px 8px; margin:10px;&amp;quot;&amp;gt;&lt;br /&gt;
[[File:Osi symbol.png|75px|link=https://opensource.org/|left]]&lt;br /&gt;
'''Multi Theft Auto''' имеет '''открытый исходный код'''. &lt;br /&gt;
&amp;lt;br/&amp;gt;Это значит, что каждый может помочь сделать Multi Theft Auto еще лучше!&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
|}&lt;br /&gt;
{| width=&amp;quot;100%&amp;quot; cellspacing=&amp;quot;0&amp;quot; cellpadding=&amp;quot;0&amp;quot;&lt;br /&gt;
| colspan=&amp;quot;2&amp;quot; |&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding-left: 15px; padding-right: 15px;&amp;quot; class=&amp;quot;plainlinks&amp;quot;&amp;gt;&lt;br /&gt;
[[File:MTALogo_8ball.png|left|85px|link=Archive]]&lt;br /&gt;
&amp;lt;ul style=&amp;quot;list-style: none; width: 200px; float: left;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;'''О [[Multi Theft Auto]]'''&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[RU/Archive|Архив]]&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[RU/Press Coverage|В прессе]]&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[https://github.com/multitheftauto/mtasa-blue/graphs/contributors Разработчики]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;ul style=&amp;quot;list-style: none; width: 200px; float: left;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;'''Multi Theft Auto 0.5'''&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[Archive#Multi_Theft_Auto_0.5|Скачать]]&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;[[MTA 0.5r2 Known Issues|Известные проблемы]]&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;ul style=&amp;quot;list-style: none; width: 200px; float: left;&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;'''Статистика вики'''&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Статей: {{NUMBEROFARTICLES}}&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Страниц: {{NUMBEROFPAGES}}&amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Зарегистрированных пользователей: {{NUMBEROFUSERS}}&amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ul&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
[[ar:Main Page‎]]&lt;br /&gt;
[[cs:hlavni‎]]&lt;br /&gt;
[[sk:Main Page‎]]&lt;br /&gt;
[[de:Hauptseite]]&lt;br /&gt;
[[en:Main Page]]&lt;br /&gt;
[[es:Página Principal]]&lt;br /&gt;
[[fr:Main Page]]&lt;br /&gt;
[[hu:Main Page‎]]&lt;br /&gt;
[[it:Pagina principale]]&lt;br /&gt;
[[nl:Main Page]]&lt;br /&gt;
[[pl:Strona_Główna]]&lt;br /&gt;
[[pt-br:Página Inicial‎]]&lt;br /&gt;
[[tr:Anasayfa]]&lt;br /&gt;
[[zh-cn:Main Page]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Script_security&amp;diff=82698</id>
		<title>RU/Script security</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Script_security&amp;diff=82698"/>
		<updated>2026-01-08T19:13:07Z</updated>

		<summary type="html">&lt;p&gt;Flox: Created page with &amp;quot;==Внимание к клиентской памяти ==  Начнем с самых основ:  * Вы должны знать, что все, что вы храните на стороне клиента, подвержено риску, в том числе и lua-файлы. Злоумышленники могут получить доступ к любым конфиденциальным (и/или) важным данным, которые хранятся ил...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Внимание к клиентской памяти ==&lt;br /&gt;
&lt;br /&gt;
Начнем с самых основ:&lt;br /&gt;
&lt;br /&gt;
* Вы должны знать, что все, что вы храните на стороне клиента, подвержено риску, в том числе и lua-файлы. Злоумышленники могут получить доступ к любым конфиденциальным (и/или) важным данным, которые хранятся или передаются на стороне клиента (ПК игрока).&lt;br /&gt;
* Для обеспечения безопасности конфиденциальных данных (и/или) логики Lua используйте серверную часть.&lt;br /&gt;
* Обратите внимание, что скрипты, помеченные как '''shared''', также действуют как '''client code''', что означает, что к ним применимо все вышесказанное. Например, определение:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;script.lua&amp;quot; type=&amp;quot;shared&amp;quot;/&amp;gt; &amp;lt;!-- этот скрипт будет выполняться отдельно как на клиенте, так и на сервере --&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это то же самое, что делать:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;script.lua&amp;quot; type=&amp;quot;client&amp;quot;/&amp;gt; &amp;lt;!-- define it separately on client --&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;script.lua&amp;quot; type=&amp;quot;server&amp;quot;/&amp;gt; &amp;lt;!-- do the same, but on server --&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Дополнительный уровень защиты ==&lt;br /&gt;
&lt;br /&gt;
Чтобы ''немного усложнить'' задачу для тех, у кого плохие намерения по отношению к вашему серверу, вы можете использовать атрибут cache (и/или [https://luac.mtasa.com / Lua compile (также известный как Luac) с дополнительной настройкой запутывания на уровне ''3''] - [https://wiki.multitheftauto.com/wiki/Lua_compilation_API API]), доступный в [https://wiki.multitheftauto.com/wiki/Meta.xml meta.xml ], а также о настройке встроенного AC в MTA путем переключения SD (Специальные средства обнаружения), смотрите: [https://wiki.multitheftauto.com/wiki/Anti-cheat_guide Руководство по борьбе с читерством].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;shared.lua&amp;quot; type=&amp;quot;shared&amp;quot; cache=&amp;quot;false&amp;quot;/&amp;gt; &amp;lt;!-- cache=&amp;quot;false&amp;quot; означает, что этот Lua-файл не будет сохранен на ПК игрока --&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client.lua&amp;quot; type=&amp;quot;client&amp;quot; cache=&amp;quot;false&amp;quot;/&amp;gt; &amp;lt;!-- cache=&amp;quot;false&amp;quot; означает, что этот Lua-файл не будет сохранен на ПК игрока --&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* ''Для некоторых'' ''немного сложнее'', ''но не невозможно'', получить клиентский код, но при этом он отлично справляется с тем, что удерживает ''большинство'' пользователей от проверки ваших lua-файлов - тех, кто ищет возможные логические ошибки (баги) или отсутствующие / некорректные проверки на основе безопасности.&lt;br /&gt;
* Может использоваться как для ''клиентских (client)'', так и для ''общих (shared)'' скриптов (не влияет на Lua на стороне сервера).&lt;br /&gt;
* Не удаляет файлы Lua, которые были загружены ранее.&lt;br /&gt;
&lt;br /&gt;
==Обнаружение бэкдоров и читерских программ и борьба с ними==&lt;br /&gt;
'''Для обеспечения минимального ущерба (или его отсутствия) от Lua-скриптов:'''&lt;br /&gt;
* Поддерживайте свой сервер в актуальном состоянии, вы можете [https://nightly.multitheftauto.com/ загружать последние сборки сервера с сайта MTA:SA nightly.] Информацию о конкретных сборках можно [https://buildinfo.multitheftauto.com/ найти здесь.]&lt;br /&gt;
* Поддерживайте свои ресурсы в актуальном состоянии, вы можете \ [https://github.com/multitheftauto/mtasa-resources загружать последние (по умолчанию) ресурсы из репозитория GitHub.] Они часто содержат последние исправления для системы безопасности, что может привести к тому, что ваш сервер будет защищен от атак или нет.&lt;br /&gt;
* Убедитесь в правильной настройке [https://wiki.multitheftauto.com/wiki/Access%20Control%20List ACL (Список контроля доступа)], который будет блокировать использование ресурсами определенных потенциально опасных функций.&lt;br /&gt;
* Нулевое доверие с предоставлением прав администратора для ресурсов (включая карты), поступающих из неизвестных источников.&lt;br /&gt;
* Перед запуском любого ресурса, которому вы не доверяете, проанализируйте его:&lt;br /&gt;
** [https://wiki.multitheftauto.com/wiki/Meta.xml meta.xml] на предмет возможных скрытых скриптов, скрывающихся под другими расширениями файлов.&lt;br /&gt;
** Это исходный код, на предмет вредоносной логики.&lt;br /&gt;
* Не запускайте и не продолжайте использовать скомпилированные ресурсы (скрипты), в легитимности которых вы не уверены.&lt;br /&gt;
&lt;br /&gt;
'''Чтобы обеспечить минимальный ущерб при подключении мошенника к вашему серверу:'''&lt;br /&gt;
* При создании скриптов помните, что никогда не следует доверять данным, поступающим от клиента.&lt;br /&gt;
* При проверке скриптов на предмет возможных дыр в системе безопасности. Обратите внимание на любые данные, поступающие от клиента, которым вы доверяете.&lt;br /&gt;
* Могут быть отправлены любые данные, следовательно, серверные скрипты, которые взаимодействуют с клиентом, получая данные, отправленные игроками, должны проверить их перед дальнейшим использованием в последующих частях кода. В основном, это будет сделано либо с помощью [[setElementData]], либо с помощью [[triggerServerEvent]].&lt;br /&gt;
* Вам не следует полагаться только на игрока [https://wiki.multitheftauto.com/wiki/Serial серийный номер ], когда речь заходит о выполнении важных операций (авторегистрация/действия администратора). '''Не гарантируется, что серийные номера будут уникальными или не поддающимися подделке'''. Вот почему вам следует &amp;quot;оставить это позади&amp;quot; системы учетных записей, как '''важный фактор аутентификации''' (например, '''логин и пароль''').&lt;br /&gt;
* Логика на стороне сервера '''не может быть обойдена''' или '''изменена''' (если только сервер не взломан или если в коде есть ошибка, но это совсем другой сценарий) - &amp;quot;используйте это в своих интересах&amp;quot;. В большинстве случаев вы сможете выполнить проверку безопасности без участия клиента.&lt;br /&gt;
* Используя концепцию &amp;quot;&amp;quot;'“, все параметры, включая источник, могут быть подделаны, и им не следует доверять. Глобальной переменной client можно доверять.”&amp;quot;&amp;quot;&amp;quot; - дает вам надежную гарантию того, что игрок, на которого вы ссылаетесь (через &amp;quot;&amp;quot;client&amp;quot;&amp;quot;) &amp;quot;&amp;quot;на самом деле&amp;quot;&amp;quot;тот, кто действительно вызвал событие&amp;quot;&amp;quot;. Такой подход защитит вас от ситуаций, когда мошенник может вызывать и обрабатывать, например, события администратора (например, кикнуть/забанить игрока), передавая фактический администратор (&amp;quot;'2-й&amp;quot;' аргумент в &amp;quot;'[[triggerServerEvent]]&amp;quot;'), или запускать события для других целей. игроки (как будто это они их вызвали, но на самом деле это было принудительно сделано читером) - как следствие использования неправильной переменной. Чтобы убедиться, что вы полностью поняли это, взгляните на примеры ниже:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
--[[&lt;br /&gt;
   НИКОГДА НЕ ДЕЛАЙТЕ ЭТОГО - ЭТО СОВЕРШЕННО НЕПРАВИЛЬНО И НЕБЕЗОПАСНО&lt;br /&gt;
   ПРОБЛЕМА: ИСПОЛЬЗУЯ &amp;quot;source&amp;quot; В hasObjectPermissionTo, ВЫ ОСТАВЛЯЕТЕ ДВЕРЬ ОТКРЫТОЙ ДЛЯ МОШЕННИКОВ&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
function onServerWrongAdminEvent(playerToBan)&lt;br /&gt;
	if (not client) then -- &amp;quot;client&amp;quot; указывает на игрока, который инициировал событие, и должен использоваться в качестве меры безопасности (чтобы предотвратить подделку игрока).&lt;br /&gt;
		return false -- если эта переменная в данный момент не существует (по неизвестной причине, или это сервер инициировал это событие), остановите выполнение кода&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local defaultPermission = false -- не разрешайте действие по умолчанию, смотрите (defaultPermission): https://wiki.multitheftauto.com/wiki/HasObjectPermissionTo&lt;br /&gt;
	local canAdminBanPlayer = hasObjectPermissionTo(source, &amp;quot;function.banPlayer&amp;quot;, defaultPermission) -- уязвимость кроется именно здесь...&lt;br /&gt;
&lt;br /&gt;
	if (not canAdminBanPlayer) then -- если у игрока нет прав доступа&lt;br /&gt;
		return false -- не делайте этого&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local validElement = isElement(playerToBan) -- проверяет, является ли аргумент, переданный от клиента, элементом&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then -- it is not&lt;br /&gt;
		return false -- остановить обработку кода&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local elementType = getElementType(playerToBan) -- это элемент, поэтому укажите его тип&lt;br /&gt;
	local playerType = (elementType == &amp;quot;player&amp;quot;) -- убедитесь, что это игрок&lt;br /&gt;
&lt;br /&gt;
	if (not playerType) then -- it's not a player&lt;br /&gt;
		return false - остановись здесь&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- banPlayer(...) -- do what needs to be done&lt;br /&gt;
end&lt;br /&gt;
addEvent(&amp;quot;onServerWrongAdminEvent&amp;quot;, true)&lt;br /&gt;
addEventHandler(&amp;quot;onServerWrongAdminEvent&amp;quot;, root, onServerWrongAdminEvent)&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
   onServerCorrectAdminEvent ПОЛНОСТЬЮ ЗАЩИЩЕН, КАК И ДОЛЖНО БЫТЬ&lt;br /&gt;
   ЗДЕСЬ НЕТ ПРОБЛЕМ: МЫ ИСПОЛЬЗОВАЛИ &amp;quot;клиент&amp;quot; В hasObjectPermissionTo, ЧТО ПОЗВОЛЯЕТ ЗАЩИТИТЬ ЕГО ОТ ПОДДЕЛКИ ИГРОКОМ, ВЫЗВАВШИМ СОБЫТИЕ&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
function onServerCorrectAdminEvent(playerToBan)&lt;br /&gt;
	if (not client) then -- 'client' points to the player who triggered the event, and should be used as security measure (in order to prevent player faking)&lt;br /&gt;
		return false -- if this variable doesn't exists at the moment (for unknown reason, or it was the server who triggered this event), stop code execution&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local defaultPermission = false -- do not allow action by default, see (defaultPermission): https://wiki.multitheftauto.com/wiki/HasObjectPermissionTo&lt;br /&gt;
	local canAdminBanPlayer = hasObjectPermissionTo(client, &amp;quot;function.banPlayer&amp;quot;, defaultPermission) -- is player allowed to do that?&lt;br /&gt;
&lt;br /&gt;
	if (not canAdminBanPlayer) then -- if player doesn't have permissions&lt;br /&gt;
		return false -- don't do it&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local validElement = isElement(playerToBan) -- check whether argument passed from client is an element&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then -- it is not&lt;br /&gt;
		return false -- stop code processing&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local elementType = getElementType(playerToBan) -- it's an element, so get it's type&lt;br /&gt;
	local playerType = (elementType == &amp;quot;player&amp;quot;) -- make sure that it's a player&lt;br /&gt;
&lt;br /&gt;
	if (not playerType) then -- it's not a player&lt;br /&gt;
		return false -- stop here&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- banPlayer(...) -- do what needs to be done&lt;br /&gt;
end&lt;br /&gt;
addEvent(&amp;quot;onServerCorrectAdminEvent&amp;quot;, true)&lt;br /&gt;
addEventHandler(&amp;quot;onServerCorrectAdminEvent&amp;quot;, root, onServerCorrectAdminEvent)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Защита данных setElementData==&lt;br /&gt;
&lt;br /&gt;
* Вам следует воздержаться от использования [[element data]] везде, его следует использовать только тогда, когда это действительно необходимо. Рекомендуется заменить его на [[triggerClientEvent]].&lt;br /&gt;
* Если вы все еще настаиваете на его использовании, рекомендуется установить для '''4-го''' аргумента в [[setElementData]] значение '''false''' (отключив синхронизацию для этих определенных данных) и использовать режим подписчика - [[addElementDataSubscriber]], как по соображениям безопасности, так и по соображениям производительности, описанным в [https://wiki.multitheftauto.com/wiki/Script_security#Securing_triggerServerEvent разделе &amp;quot;события&amp;quot;.]&lt;br /&gt;
{{Важное примечание|Отключение синхронизации, однако, не обеспечивает полной защиты ключа данных. По умолчанию он по-прежнему уязвим, но в этом случае вы не оставляете его на виду. Использование [[getAllElementData]] или копание в оперативной памяти не выявит его, поскольку оно не будет синхронизировано с клиентом в первую очередь. Следовательно, его также необходимо добавить в античит.}}&lt;br /&gt;
* Все параметры, включая '''source''', могут быть подделаны, и им не следует доверять.&lt;br /&gt;
* Глобальной переменной '''client''' можно доверять.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
Пример защиты данных базового элемента от обмана.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local function reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue) -- вспомогательная функция для логирования и отката изменений&lt;br /&gt;
	local logClient = inspect(clientElement) -- подробный вид игрока, который инициировал синхронизацию данных элемента&lt;br /&gt;
	local logSerial = getPlayerSerial(clientElement) or &amp;quot;N/A&amp;quot; -- серийник клиента, или &amp;quot;N/A&amp;quot;, если по какой-то причине это невозможно&lt;br /&gt;
	local logSource = tostring(sourceElement) -- элемент, который получил данные&lt;br /&gt;
	local logOldValue = tostring(oldValue) -- старое значение&lt;br /&gt;
	local logNewValue = tostring(newValue) -- новое значение&lt;br /&gt;
	local logText = -- заполняем наш отчет данными&lt;br /&gt;
		&amp;quot;=======================================\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Detected element data abnormality:\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Client: &amp;quot;..logClient..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Client serial: &amp;quot;..logSerial..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Source: &amp;quot;..logSource..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Data key: &amp;quot;..dataKey..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Old data value: &amp;quot;..logOldValue..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;New data value: &amp;quot;..logNewValue..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;=======================================&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	local logVisibleTo = root -- указываем, кто увидит этот лог в консоли, в данном случае каждый игрок, подключенный к серверу&lt;br /&gt;
	local hadData = (oldValue ~= nil) -- проверяем, был ли у элемента такой данные раньше&lt;br /&gt;
&lt;br /&gt;
	if (hadData) then -- если у элемента ранее были такие данные&lt;br /&gt;
		setElementData(sourceElement, dataKey, oldValue, true) -- откатываем изменения, это вызовет событие onElementDataChange, но не пройдет (остановится) на первом условии - потому что сервер (не клиент) принудительно изменил данные&lt;br /&gt;
	else&lt;br /&gt;
		removeElementData(sourceElement, dataKey) -- полностью удаляем его&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	outputConsole(logText, logVisibleTo) -- выводим это в консоль&lt;br /&gt;
&lt;br /&gt;
	return true -- все успешно&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onElementDataChangeBasicAC(dataKey, oldValue, newValue) -- сердце нашего античита, которое выполняет все магические меры безопасности&lt;br /&gt;
	if (not client) then -- проверяем, идут ли данные от клиента&lt;br /&gt;
		return false -- если нет, не идем дальше&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local checkSpecialThing = (dataKey == &amp;quot;special_thing&amp;quot;) -- сравниваем, совпадает ли dataKey с &amp;quot;special_thing&amp;quot;&lt;br /&gt;
	local checkFlagWaving = (dataKey == &amp;quot;flag_waving&amp;quot;) -- сравниваем, совпадает ли dataKey с &amp;quot;flag_waving&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	if (checkSpecialThing) then -- если совпадает, проводим проверки безопасности&lt;br /&gt;
		local invalidElement = (client ~= source) -- проверяем, отличается ли исходный элемент от игрока, изменившего данные&lt;br /&gt;
&lt;br /&gt;
		if (invalidElement) then -- если так и есть&lt;br /&gt;
			reportAndRevertDataChange(client, source, dataKey, oldValue, newValue) -- откатываем изменение данных, потому что &amp;quot;special_thing&amp;quot; может быть установлен только для самого игрока&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (checkFlagWaving) then -- если совпадает, проводим проверки безопасности&lt;br /&gt;
		local playerVehicle = getPedOccupiedVehicle(client) -- получаем текущий транспорт игрока&lt;br /&gt;
		local invalidVehicle = (playerVehicle ~= source) -- проверяем, отличается ли исходный элемент от транспорта игрока&lt;br /&gt;
&lt;br /&gt;
		if (invalidVehicle) then -- если так и есть&lt;br /&gt;
			reportAndRevertDataChange(client, source, dataKey, oldValue, newValue) -- откатываем изменение данных, потому что &amp;quot;flag_waving&amp;quot; может быть установлен только для собственного транспорта игрока&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onElementDataChange&amp;quot;, root, onElementDataChangeBasicAC)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
Пример расширенной защиты данных element от обмана.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
--[[&lt;br /&gt;
	Для максимальной безопасности установите punishPlayerOnDetect, punishmentBan, allowOnlyProtectedKeys в true (как настроено по умолчанию)&lt;br /&gt;
	Если включен allowOnlyProtectedKeys, не забудьте добавить каждый ключ элемент данных на стороне клиента в таблицу protectedKeys - иначе возникнут ложные срабатывания&lt;br /&gt;
&lt;br /&gt;
	Структура таблицы античита (handleDataChange) и её параметры:&lt;br /&gt;
&lt;br /&gt;
	[&amp;quot;keyName&amp;quot;] = { -- имя ключа, который будет защищен&lt;br /&gt;
		onlyForPlayerHimself = true, -- включение этого (true) гарантирует, что этот ключ данных элемента может быть установлен только игроком, который его синхронизировал (игнорирует onlyForOwnPlayerVeh и allowForElements), используйте false/nil для отключения&lt;br /&gt;
		onlyForOwnPlayerVeh = false, -- включение этого (true) гарантирует, что этот ключ данных элемента может быть установлен только на текущем транспорте игрока, который его синхронизировал (игнорирует allowForElements), используйте false/nil для отключения&lt;br /&gt;
		allowForElements = { -- ограничить этот ключ для определенных типов элементов, установите false/nil или оставьте пустым, чтобы не проверять это (полный список типов элементов: https://wiki.multitheftauto.com/wiki/GetElementsByType)&lt;br /&gt;
			[&amp;quot;player&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;ped&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;vehicle&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;object&amp;quot;] = true,&lt;br /&gt;
		},&lt;br /&gt;
		allowedDataTypes = { -- ограничить этот ключ для определенных типов значений, установите false/nil или оставьте пустым, чтобы не проверять это&lt;br /&gt;
			[&amp;quot;string&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;number&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;table&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;boolean&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;nil&amp;quot;] = true,&lt;br /&gt;
		},&lt;br /&gt;
		allowedStringLength = {1, 32}, -- если значение является строкой, то её длина должна быть в пределах (мин-макс), установите false/nil, чтобы не проверять длину строки - учтите, что allowedDataTypes должен содержать [&amp;quot;string&amp;quot;] = true&lt;br /&gt;
		allowedTableLength = {1, 64}, -- если значение является таблицей, то её длина должна быть в пределах (мин-макс), установите false/nil, чтобы не проверять длину таблицы - учтите, что allowedDataTypes должен содержать [&amp;quot;table&amp;quot;] = true&lt;br /&gt;
		allowedNumberRange = {1, 128}, -- если значение является числом, то оно должно быть в пределах (мин-макс), установите false/nil, чтобы не проверять диапазон чисел - учтите, что allowedDataTypes должен содержать [&amp;quot;number&amp;quot;] = true&lt;br /&gt;
	}&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local punishPlayerOnDetect = true -- должен ли игрок быть наказан при обнаружении (убедитесь, что ресурс, запускающий этот код, имеет права администратора)&lt;br /&gt;
local punishmentBan = true -- актуально только если punishPlayerOnDetect установлен в true; используйте true для бана или false для кика&lt;br /&gt;
local punishmentReason = &amp;quot;Altering element data&amp;quot; -- актуально только если punishPlayerOnDetect установлен в true; причина, которая будет показана наказанному игроку&lt;br /&gt;
local punishedBy = &amp;quot;Console&amp;quot; -- актуально только если punishPlayerOnDetect установлен в true; кто ответственен за наказание, также показывается наказанному игроку&lt;br /&gt;
local banByIP = false -- актуально только если punishPlayerOnDetect и punishmentBan установлены в true; бан по IP в настоящее время не рекомендуется (...)&lt;br /&gt;
local banByUsername = false -- имя пользователя сообщества - устаревшая вещь, поэтому установлено в false и должно оставаться таким&lt;br /&gt;
local banBySerial = true -- актуально только если punishPlayerOnDetect и punishmentBan установлены в true; (...) если есть серийный номер игрока, который можно использовать вместо этого&lt;br /&gt;
local banTime = 0 -- актуально только если punishPlayerOnDetect и punishmentBan установлены в true; время в секундах, 0 навсегда&lt;br /&gt;
local allowOnlyProtectedKeys = true -- запрещать (удалять с помощью removeElementData) любые данные элементов, кроме тех, что указаны в таблице protectedKeys; на случай, если кто-то захочет завалить сервер мусорными ключами, которые будут храниться в памяти до перезапуска сервера или ручного удаления - setElementData(source, key, nil) не удалит их; необходимо использовать removeElementData&lt;br /&gt;
local debugLevel = 4 -- этот уровень отладки позволяет скрыть префикс INFO: и использовать пользовательские цвета&lt;br /&gt;
local debugR = 255 -- сообщение отладки - красный цвет&lt;br /&gt;
local debugG = 127 -- сообщение отладки - зеленый цвет&lt;br /&gt;
local debugB = 0 -- сообщение отладки - синий цвет&lt;br /&gt;
local protectedKeys = {&lt;br /&gt;
	[&amp;quot;vehicleNumber&amp;quot;] = { -- мы хотим, чтобы vehicleNumber устанавливался только на транспорте, с четкими числами в диапазоне 1-100&lt;br /&gt;
		allowForElements = {&lt;br /&gt;
			[&amp;quot;vehicle&amp;quot;] = true,&lt;br /&gt;
		},&lt;br /&gt;
		allowedDataTypes = {&lt;br /&gt;
			[&amp;quot;number&amp;quot;] = true,&lt;br /&gt;
		},&lt;br /&gt;
		allowedNumberRange = {1, 100},&lt;br /&gt;
	},&lt;br /&gt;
	[&amp;quot;personalVehData&amp;quot;] = { -- мы хотим иметь возможность устанавливать personalVehData только на текущем транспорте, также это должна быть строка длиной от 1 до 24&lt;br /&gt;
		onlyForOwnPlayerVeh = true,&lt;br /&gt;
		allowedDataTypes = {&lt;br /&gt;
			[&amp;quot;string&amp;quot;] = true,&lt;br /&gt;
		},&lt;br /&gt;
		allowedStringLength = {1, 24},&lt;br /&gt;
	},&lt;br /&gt;
	-- выполнять проверки безопасности для ключей, хранящихся в этой таблице, удобным способом&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local function reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- вспомогательная функция для логирования и отката изменений&lt;br /&gt;
	local logClient = inspect(clientElement) -- подробный вид игрока, который инициировал синхронизацию данных элемента&lt;br /&gt;
	local logSerial = getPlayerSerial(clientElement) or &amp;quot;N/A&amp;quot; -- серийник клиента, или &amp;quot;N/A&amp;quot;, если по какой-то причине это невозможно&lt;br /&gt;
	local logSource = inspect(sourceElement) -- подробный вид элемента, который получил данные&lt;br /&gt;
	local logOldValue = inspect(oldValue) -- подробный вид старого значения&lt;br /&gt;
	local logNewValue = inspect(newValue) -- подробный вид нового значения&lt;br /&gt;
	local logText = -- заполняем наш отчет данными&lt;br /&gt;
		&amp;quot;*\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Detected element data abnormality:\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Client: &amp;quot;..logClient..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Client serial: &amp;quot;..logSerial..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Source: &amp;quot;..logSource..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Data key: &amp;quot;..dataKey..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Old data value: &amp;quot;..logOldValue..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;New data value: &amp;quot;..logNewValue..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Fail reason: &amp;quot;..failReason..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;*&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	outputDebugString(logText, debugLevel, debugR, debugG, debugB) -- выводим это в отладку&lt;br /&gt;
&lt;br /&gt;
	if (forceRemove) then -- мы вообще не хотим, чтобы этот ключ данных элемента существовал&lt;br /&gt;
		removeElementData(sourceElement, dataKey) -- удаляем его&lt;br /&gt;
&lt;br /&gt;
		return true -- возвращаем успех и останавливаемся здесь, дальнейшие проверки не нужны&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	setElementData(sourceElement, dataKey, oldValue, true) -- откатываем изменения, это вызовет событие onElementDataChange, но не пройдет (остановится) на первом условии - потому что сервер (не клиент) принудительно изменил данные&lt;br /&gt;
&lt;br /&gt;
	return true -- возвращаем успех&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function handleDataChange(clientElement, sourceElement, dataKey, oldValue, newValue) -- сердце нашего античита, которое выполняет все магические меры безопасности, возвращает true, если не было изменений от клиента (на основе данных из protectedKeys), иначе false&lt;br /&gt;
	local protectedKey = protectedKeys[dataKey] -- проверяем, хранится ли измененный ключ в таблице protectedKeys&lt;br /&gt;
&lt;br /&gt;
	if (not protectedKey) then -- если его нет&lt;br /&gt;
&lt;br /&gt;
		if (allowOnlyProtectedKeys) then -- если мы не хотим мусорные ключи&lt;br /&gt;
			local failReason = &amp;quot;Key isn't present in protectedKeys&amp;quot; -- причина, показанная в отчете&lt;br /&gt;
			local forceRemove = true -- должен ли ключ быть полностью удален&lt;br /&gt;
&lt;br /&gt;
			reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
			return false -- вернуть неудачу&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return true -- этот ключ не защищен, пропускаем его&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local onlyForPlayerHimself = protectedKey.onlyForPlayerHimself -- если у ключа есть блокировка &amp;quot;только для себя&amp;quot;&lt;br /&gt;
	local onlyForOwnPlayerVeh = protectedKey.onlyForOwnPlayerVeh -- если у ключа есть блокировка &amp;quot;свой транспорт&amp;quot;&lt;br /&gt;
	local allowForElements = protectedKey.allowForElements -- если у ключа есть проверка типа элемента&lt;br /&gt;
	local allowedDataTypes = protectedKey.allowedDataTypes -- если у ключа есть проверка разрешенного типа данных&lt;br /&gt;
&lt;br /&gt;
	if (onlyForPlayerHimself) then -- если блокировка &amp;quot;только для себя&amp;quot; активна&lt;br /&gt;
		local matchingElement = (clientElement == sourceElement) -- проверяем, равен ли игрок, установивший данные, элементу, который получил данные&lt;br /&gt;
&lt;br /&gt;
		if (not matchingElement) then -- если не совпадает&lt;br /&gt;
			local failReason = &amp;quot;Can only set on player himself&amp;quot; -- причина, показанная в отчете&lt;br /&gt;
			local forceRemove = false -- должен ли ключ быть полностью удален&lt;br /&gt;
&lt;br /&gt;
			reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
			return false -- вернуть неудачу&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (onlyForOwnPlayerVeh) then -- если блокировка &amp;quot;свой транспорт&amp;quot; активна&lt;br /&gt;
		local playerVehicle = getPedOccupiedVehicle(clientElement) -- получить текущий транспорт игрока, который установил данные&lt;br /&gt;
		local matchingVehicle = (playerVehicle == sourceElement) -- проверяем, совпадает ли он с тем, который получил данные&lt;br /&gt;
&lt;br /&gt;
		if (not matchingVehicle) then -- если не совпадает&lt;br /&gt;
			local failReason = &amp;quot;Can only set on player's own vehicle&amp;quot; -- причина, показанная в отчете&lt;br /&gt;
			local forceRemove = false -- должен ли ключ быть полностью удален&lt;br /&gt;
&lt;br /&gt;
			reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
			return false -- вернуть неудачу&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (allowForElements) then -- проверяем, является ли оно одним из них&lt;br /&gt;
		local elementType = getElementType(sourceElement) -- получить тип элемента, данные которого изменились&lt;br /&gt;
		local matchingElementType = allowForElements[elementType] -- проверяем, разрешено ли это&lt;br /&gt;
&lt;br /&gt;
		if (not matchingElementType) then -- это не совпадает&lt;br /&gt;
			local failReason = &amp;quot;Invalid element type&amp;quot; -- причина, показанная в отчете&lt;br /&gt;
			local forceRemove = false -- должен ли ключ быть полностью удален&lt;br /&gt;
&lt;br /&gt;
			reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
			return false -- вернуть неудачу&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (allowedDataTypes) then -- если есть разрешенные типы данных&lt;br /&gt;
		local valueType = type(newValue) -- получить тип данных значения&lt;br /&gt;
		local matchingType = allowedDataTypes[valueType] -- проверяем, является ли оно одним из разрешенных&lt;br /&gt;
&lt;br /&gt;
		if (not matchingType) then -- если нет, тогда&lt;br /&gt;
			local failReason = &amp;quot;Invalid data type&amp;quot; -- причина, показанная в отчете&lt;br /&gt;
			local forceRemove = false -- должен ли ключ быть полностью удален&lt;br /&gt;
&lt;br /&gt;
			reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
			return false -- вернуть неудачу&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local allowedStringLength = protectedKey.allowedStringLength -- если у ключа есть указанная проверка длины строки&lt;br /&gt;
		local dataString = (valueType == &amp;quot;string&amp;quot;) -- убеждаемся, что это строка&lt;br /&gt;
&lt;br /&gt;
		if (allowedStringLength and dataString) then -- если мы должны проверить длину строки&lt;br /&gt;
			local minLength = allowedStringLength[1] -- получить минимальную длину&lt;br /&gt;
			local maxLength = allowedStringLength[2] -- получить максимальную длину&lt;br /&gt;
			local stringLength = utf8.len(newValue) -- получить длину строки данных&lt;br /&gt;
			local matchingLength = (stringLength &amp;gt;= minLength) and (stringLength &amp;lt;= maxLength) -- сравниваем, подходит ли значение в промежуток&lt;br /&gt;
&lt;br /&gt;
			if (not matchingLength) then -- если не подходит&lt;br /&gt;
				local failReason = &amp;quot;Invalid string length (must be between &amp;quot;..minLength..&amp;quot;-&amp;quot;..maxLength..&amp;quot;)&amp;quot; -- причина, показанная в отчете&lt;br /&gt;
				local forceRemove = false -- должен ли ключ быть полностью удален&lt;br /&gt;
&lt;br /&gt;
				reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
				return false -- вернуть неудачу&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local allowedTableLength = protectedKey.allowedTableLength -- если у ключа есть проверка длины таблицы&lt;br /&gt;
		local dataTable = (valueType == &amp;quot;table&amp;quot;) -- убеждаемся, что это таблица&lt;br /&gt;
&lt;br /&gt;
		if (allowedTableLength and dataTable) then -- если мы должны проверить длину таблицы&lt;br /&gt;
			local minLength = allowedTableLength[1] -- получить минимальную длину&lt;br /&gt;
			local maxLength = allowedTableLength[2] -- получить максимальную длину&lt;br /&gt;
			local minLengthAchieved = false -- переменная, которая проверяет 'была ли достигнута минимальная длина'&lt;br /&gt;
			local maxLengthExceeded = false -- переменная, которая проверяет 'превысила ли длина разрешенный максимум'&lt;br /&gt;
			local tableLength = 0 -- сохранить начальную длину таблицы&lt;br /&gt;
&lt;br /&gt;
			for _, _ in pairs(newValue) do -- проходим по всей таблице&lt;br /&gt;
				tableLength = (tableLength + 1) -- добавляем + 1 для каждой записи таблицы&lt;br /&gt;
				minLengthAchieved = (tableLength &amp;gt;= minLength) -- больше ли длина или по крайней мере такой минимум, который мы требуем&lt;br /&gt;
				maxLengthExceeded = (tableLength &amp;gt; maxLength) -- превысила ли таблица максимальную длину?&lt;br /&gt;
&lt;br /&gt;
				if (maxLengthExceeded) then -- она больше, чем должна быть&lt;br /&gt;
					break -- прерываем цикл (из-за того, что условие выше выполнено, нет смысла считать дальше и тратить процессор на таблицу, которая потенциально может иметь огромное количество записей)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			local matchingLength = (minLengthAchieved and not maxLengthExceeded) -- проверяем, достигнута ли минимальная длина, и убеждаемся, что она не превышает максимальную&lt;br /&gt;
&lt;br /&gt;
			if (not matchingLength) then -- эта таблица не соответствует требованиям&lt;br /&gt;
				local failReason = &amp;quot;Invalid table length (must be between &amp;quot;..minLength..&amp;quot;-&amp;quot;..maxLength..&amp;quot;)&amp;quot; -- причина, показанная в отчете&lt;br /&gt;
				local forceRemove = false -- должен ли ключ быть полностью удален&lt;br /&gt;
&lt;br /&gt;
				reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
				return false -- вернуть неудачу&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local allowedNumberRange = protectedKey.allowedNumberRange -- если у ключа есть проверка разрешенного диапазона чисел&lt;br /&gt;
		local dataNumber = (valueType == &amp;quot;number&amp;quot;) -- убеждаемся, что это число&lt;br /&gt;
&lt;br /&gt;
		if (allowedNumberRange and dataNumber) then -- если мы должны проверить диапазон чисел&lt;br /&gt;
			local minRange = allowedNumberRange[1] -- получить минимальный диапазон чисел&lt;br /&gt;
			local maxRange = allowedNumberRange[2] -- получить максимальный диапазон чисел&lt;br /&gt;
			local matchingRange = (newValue &amp;gt;= minRange) and (newValue &amp;lt;= maxRange) -- сравниваем, подходит ли значение в промежуток&lt;br /&gt;
&lt;br /&gt;
			if (not matchingRange) then -- если не подходит&lt;br /&gt;
				local failReason = &amp;quot;Invalid number range (must be between &amp;quot;..minRange..&amp;quot;-&amp;quot;..maxRange..&amp;quot;)&amp;quot; -- причина, показанная в отчете&lt;br /&gt;
				local forceRemove = false -- должен ли ключ быть полностью удален&lt;br /&gt;
&lt;br /&gt;
				reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
				return false -- вернуть неудачу&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return true -- проверки безопасности пройдены, с этим ключом данных всё в порядке&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onElementDataChangeAdvancedAC(dataKey, oldValue, newValue) -- это событие использует handleDataChange, код был разделен для лучшей читаемости&lt;br /&gt;
	if (not client) then -- проверяем, идут ли данные от клиента&lt;br /&gt;
		return false -- если нет, не продолжаем&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local approvedChange = handleDataChange(client, source, dataKey, oldValue, newValue) -- запускаем наши проверки безопасности&lt;br /&gt;
&lt;br /&gt;
	if (approvedChange) then -- всё круто и хорошо&lt;br /&gt;
		return false -- нам не нужны дальнейшие действия&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (not punishPlayerOnDetect) then -- мы не хотим наказывать игрока по какой-то причине&lt;br /&gt;
		return false -- так что останавливаемся здесь&lt;br /&gt;
	end&lt;br /&gt;
		&lt;br /&gt;
	if (punishmentBan) then -- если это бан&lt;br /&gt;
		banPlayer(client, banByIP, banByUsername, banBySerial, punishedBy, punishmentReason, banTime) -- удаляем его присутствие с сервера&lt;br /&gt;
	else -- иначе&lt;br /&gt;
		kickPlayer(client, punishedBy, punishmentReason) -- просто кикаем игрока с сервера&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onElementDataChange&amp;quot;, root, onElementDataChangeAdvancedAC)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Защита triggerServerEvent==&lt;br /&gt;
* Все параметры, включая &amp;quot;source&amp;quot;, могут быть подделаны, и им не следует доверять.&lt;br /&gt;
* Глобальной переменной &amp;quot;client&amp;quot; можно доверять.&lt;br /&gt;
* &amp;quot;События&amp;quot; в стиле &amp;quot;Admin&amp;quot; должны подтверждать &amp;quot;права доступа&amp;quot; игрока (клиента) либо с помощью [https://wiki.multitheftauto.com/wiki/IsObjectInACLGroup isObjectInACLGroup], либо [https://wiki.multitheftauto.com/wiki/HasObjectPermissionTo hasObjectPermissionTo].&lt;br /&gt;
* Не используйте для своего пользовательского события то же имя, что и для событий собственного сервера MTA (которые по умолчанию не запускаются удаленно), например: &amp;quot;onPlayerLogin&amp;quot;; это откроет дверь для манипуляций мошенников.&lt;br /&gt;
* Будьте в курсе, каким игрокам отправляется событие через [[triggerClientEvent]]. Как по соображениям безопасности, так и по соображениям производительности, события, подобные admin, должны приниматься только администраторами (чтобы предотвратить доступ к конфиденциальным данным), в то же время вы не должны отправлять каждое событие всем пользователям сервера (например, событие успешного входа в систему, которое скрывает панель входа для определенного игрока). [[triggerClientEvent]] позволяет вам указать получатель события в качестве первого (необязательного) аргумента. По умолчанию используется значение [[root]], что означает, что если вы его не укажете, оно будет отправлено всем, кто подключен к серверу, даже тем, кто все еще загружает серверный кэш (что приводит к &amp;quot;событию, инициированному сервером на стороне клиента, eventName, но событие не добавлено на стороне клиента&amp;quot;). Вы можете передать либо элемент игрока, либо таблицу с получателями:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local playersToReceiveEvent = {player1, player2, player3} -- каждый PlayerX является элементом игрока&lt;br /&gt;
&lt;br /&gt;
triggerClientEvent(playersToReceiveEvent, ...) -- не забудьте заполнить последнюю часть аргументов&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----------&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
Пример функции защиты от мошенничества, разработанной для событий, используемых для проверки данных как для обычных, так и для административных событий, которые вызываются со стороны клиента.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
--[[&lt;br /&gt;
	Для максимальной безопасности установите punishPlayerOnDetect, punishmentBan в true (как настроено по умолчанию)&lt;br /&gt;
&lt;br /&gt;
	Структура таблицы античита (processServerEventData) и её параметры:&lt;br /&gt;
&lt;br /&gt;
	checkACLGroup = { -- проверить, принадлежит ли игрок, вызвавший событие, хотя бы к одной из групп ниже, установите false/nil, чтобы не проверять это&lt;br /&gt;
		&amp;quot;Admin&amp;quot;,&lt;br /&gt;
	},&lt;br /&gt;
	checkPermissions = { -- проверить, есть ли у игрока, вызвавшего событие, разрешение хотя бы на одно из нижеперечисленного, установите false/nil, чтобы не проверять это&lt;br /&gt;
		&amp;quot;function.kickPlayer&amp;quot;,&lt;br /&gt;
	},&lt;br /&gt;
	checkEventData = {&lt;br /&gt;
		{&lt;br /&gt;
			debugData = &amp;quot;source&amp;quot;, -- дополнительные данные для отчета, показанные в сообщении отладки&lt;br /&gt;
			eventData = source, -- данные, которые мы хотим проверить&lt;br /&gt;
			equalTo = client, -- сравнить, совпадают ли eventData и equalTo&lt;br /&gt;
			allowedElements = { -- ограничить eventData определенными типами элементов, установите false/nil или оставьте пустым, чтобы не проверять это (полный список типов элементов: https://wiki.multitheftauto.com/wiki/GetElementsByType)&lt;br /&gt;
				[&amp;quot;player&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;ped&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;vehicle&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;object&amp;quot;] = true,&lt;br /&gt;
			},&lt;br /&gt;
			allowedDataTypes = { -- ограничить eventData определенными типами значений, установите false/nil или оставьте пустым, чтобы не проверять это&lt;br /&gt;
				[&amp;quot;string&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;number&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;table&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;boolean&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;nil&amp;quot;] = true,&lt;br /&gt;
			},&lt;br /&gt;
			allowedStringLength = {1, 32}, -- если eventData является строкой, то её длина должна быть в пределах (мин-макс), установите false/nil, чтобы не проверять длину строки - учтите, что allowedDataTypes должен содержать [&amp;quot;string&amp;quot;] = true&lt;br /&gt;
			allowedTableLength = {1, 64}, -- если eventData является таблицей, то её длина должна быть в пределах (мин-макс), установите false/nil, чтобы не проверять длину таблицы - учтите, что allowedDataTypes должен содержать [&amp;quot;table&amp;quot;] = true&lt;br /&gt;
			allowedNumberRange = {1, 128}, -- если eventData является числом, то оно должно быть в пределах (мин-макс), установите false/nil, чтобы не проверять диапазон чисел - учтите, что allowedDataTypes должен содержать [&amp;quot;number&amp;quot;] = true&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local punishPlayerOnDetect = true -- должен ли игрок быть наказан при обнаружении (убедитесь, что ресурс, запускающий этот код, имеет права администратора)&lt;br /&gt;
local punishmentBan = true -- актуально только если punishPlayerOnDetect установлен в true; используйте true для бана или false для кика&lt;br /&gt;
local punishmentReason = &amp;quot;Altering server event data&amp;quot; -- актуально только если punishPlayerOnDetect установлен в true; причина, которая будет показана наказанному игроку&lt;br /&gt;
local punishedBy = &amp;quot;Console&amp;quot; -- актуально только если punishPlayerOnDetect установлен в true; кто ответственен за наказание, также показывается наказанному игроку&lt;br /&gt;
local banByIP = false -- актуально только если punishPlayerOnDetect и punishmentBan установлены в true; бан по IP в настоящее время не рекомендуется (...)&lt;br /&gt;
local banByUsername = false -- имя пользователя сообщества - устаревшая вещь, поэтому установлено в false и должно оставаться таким&lt;br /&gt;
local banBySerial = true -- актуально только если punishPlayerOnDetect и punishmentBan установлены в true; (...) если есть серийный номер игрока, который можно использовать вместо этого&lt;br /&gt;
local banTime = 0 -- актуально только если punishPlayerOnDetect и punishmentBan установлены в true; время в секундах, 0 навсегда&lt;br /&gt;
local debugLevel = 4 -- этот уровень отладки позволяет скрыть префикс INFO: и использовать пользовательские цвета&lt;br /&gt;
local debugR = 255 -- сообщение отладки - красный цвет&lt;br /&gt;
local debugG = 127 -- сообщение отладки - зеленый цвет&lt;br /&gt;
local debugB = 0 -- сообщение отладки - синий цвет&lt;br /&gt;
&lt;br /&gt;
function processServerEventData(clientElement, sourceElement, serverEvent, securityChecks) -- сердце нашего античита, которое выполняет все магические меры безопасности, возвращает true, если не было изменений от клиента (на основе данных из securityChecks), иначе false&lt;br /&gt;
	if (not securityChecks) then -- если мы не передали никаких проверок безопасности&lt;br /&gt;
		return true -- нечего проверять, даем коду идти дальше&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if (not clientElement) then -- если переменная client недоступна по какой-то причине (хотя это не должно произойти)&lt;br /&gt;
		local failReason = &amp;quot;Client variable not present&amp;quot; -- причина, показанная в отчете&lt;br /&gt;
		local skipPunishment = true -- должен ли сервер пропустить наказание&lt;br /&gt;
&lt;br /&gt;
		reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
		return false -- вернуть неудачу&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local checkACLGroup = securityChecks.checkACLGroup -- если есть какие-либо группы ACL для проверки&lt;br /&gt;
	local checkPermissions = securityChecks.checkPermissions -- если есть какие-либо разрешения для проверки&lt;br /&gt;
	local checkEventData = securityChecks.checkEventData -- если есть какие-либо проверки данных&lt;br /&gt;
&lt;br /&gt;
	if (checkACLGroup) then -- проверим группы ACL игрока&lt;br /&gt;
		local playerAccount = getPlayerAccount(clientElement) -- получить текущий аккаунт игрока&lt;br /&gt;
		local guestAccount = isGuestAccount(playerAccount) -- если аккаунт гость (это значит, что игрок не вошел в систему)&lt;br /&gt;
&lt;br /&gt;
		if (guestAccount) then -- это так&lt;br /&gt;
			local failReason = &amp;quot;Can't retrieve player login - guest account&amp;quot; -- причина, показанная в отчете&lt;br /&gt;
			local skipPunishment = true -- должен ли сервер пропустить наказание&lt;br /&gt;
&lt;br /&gt;
			reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
			return false -- вернуть неудачу&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local accountName = getAccountName(playerAccount) -- получить имя текущего аккаунта игрока&lt;br /&gt;
		local aclString = &amp;quot;user.&amp;quot;..accountName -- форматируем это для дальнейшего использования в функции isObjectInACLGroup&lt;br /&gt;
&lt;br /&gt;
		for groupID = 1, #checkACLGroup do -- перебираем таблицу заданных групп&lt;br /&gt;
			local groupName = checkACLGroup[groupID] -- получить имя каждой группы&lt;br /&gt;
			local aclGroup = aclGetGroup(groupName) -- проверить, существует ли такая группа&lt;br /&gt;
&lt;br /&gt;
			if (not aclGroup) then -- не существует&lt;br /&gt;
				local failReason = &amp;quot;ACL group '&amp;quot;..groupName..&amp;quot;' is missing&amp;quot; -- причина, показанная в отчете&lt;br /&gt;
				local skipPunishment = true -- должен ли сервер пропустить наказание&lt;br /&gt;
&lt;br /&gt;
				reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
				return false -- вернуть неудачу&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			local playerInACLGroup = isObjectInACLGroup(aclString, aclGroup) -- проверить, принадлежит ли игрок к группе&lt;br /&gt;
&lt;br /&gt;
			if (playerInACLGroup) then -- да, это так&lt;br /&gt;
				return true -- значит, успех&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local failReason = &amp;quot;Player doesn't belong to any given ACL group&amp;quot; -- причина, показанная в отчете&lt;br /&gt;
		local skipPunishment = true -- должен ли сервер пропустить наказание&lt;br /&gt;
&lt;br /&gt;
		reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
		return false -- вернуть неудачу&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (checkPermissions) then -- проверить, есть ли у игрока хотя бы одно желаемое разрешение&lt;br /&gt;
		local allowedByDefault = false -- есть ли у него доступ по умолчанию&lt;br /&gt;
&lt;br /&gt;
		for permissionID = 1, #checkPermissions do -- перебираем все разрешения&lt;br /&gt;
			local permissionName = checkPermissions[permissionID] -- получить имя разрешения&lt;br /&gt;
			local hasPermission = hasObjectPermissionTo(clientElement, permissionName, allowedByDefault) -- проверить, разрешено ли игроку выполнять определенное действие&lt;br /&gt;
&lt;br /&gt;
			if (hasPermission) then -- если у игрока есть доступ&lt;br /&gt;
				return true -- одно доступно (и достаточно), сервер не станет проверять остальные (так как return также прерывает цикл)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local failReason = &amp;quot;Not enough permissions&amp;quot; -- причина, показанная в отчете&lt;br /&gt;
		local skipPunishment = true -- должен ли сервер пропустить наказание&lt;br /&gt;
&lt;br /&gt;
		reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
		return false -- вернуть неудачу&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (checkEventData) then -- если есть какие-то данные для проверки&lt;br /&gt;
&lt;br /&gt;
		for dataID = 1, #checkEventData do -- перебираем каждые данные&lt;br /&gt;
			local dataToCheck = checkEventData[dataID] -- получить каждый набор данных&lt;br /&gt;
			local eventData = dataToCheck.eventData -- это то, что мы будем проверять&lt;br /&gt;
			local equalTo = dataToCheck.equalTo -- мы хотим сравнить, совпадают ли eventData и equalTo&lt;br /&gt;
			local allowedElements = dataToCheck.allowedElements -- проверить, является ли это элементом и принадлежит ли к определенным типам элементов&lt;br /&gt;
			local allowedDataTypes = dataToCheck.allowedDataTypes -- ограничиваем ли мы данные определенным типом?&lt;br /&gt;
			local debugData = dataToCheck.debugData -- дополнительные вспомогательные данные&lt;br /&gt;
			local debugText = debugData and &amp;quot; (&amp;quot;..debugData..&amp;quot;)&amp;quot; or &amp;quot;&amp;quot; -- если оно присутствует, красиво форматируем&lt;br /&gt;
&lt;br /&gt;
			if (equalTo) then -- проверка на равенство существует&lt;br /&gt;
				local matchingData = (eventData == equalTo) -- сравнить, равны ли эти два значения&lt;br /&gt;
&lt;br /&gt;
				if (not matchingData) then -- они не равны&lt;br /&gt;
					local failReason = &amp;quot;Data isn't equal @ argument &amp;quot;..dataID..debugText -- причина, показанная в отчете&lt;br /&gt;
					local skipPunishment = false -- должен ли сервер пропустить наказание&lt;br /&gt;
&lt;br /&gt;
					reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
					return false -- вернуть неудачу&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			if (allowedElements) then -- мы проверяем, является ли это элементом и принадлежит ли хотя бы одному из списка&lt;br /&gt;
				local validElement = isElement(eventData) -- проверить, является ли это фактическим элементом&lt;br /&gt;
&lt;br /&gt;
				if (not validElement) then -- это не так&lt;br /&gt;
					local failReason = &amp;quot;Data isn't element @ argument &amp;quot;..dataID..debugText -- причина, показанная в отчете&lt;br /&gt;
					local skipPunishment = false -- должен ли сервер пропустить наказание&lt;br /&gt;
&lt;br /&gt;
					reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
					return false -- вернуть неудачу&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local elementType = getElementType(eventData) -- это элемент, поэтому мы хотим узнать его тип&lt;br /&gt;
				local matchingElementType = allowedElements[elementType] -- проверить, разрешено ли это&lt;br /&gt;
&lt;br /&gt;
				if (not matchingElementType) then -- не разрешено&lt;br /&gt;
					local failReason = &amp;quot;Invalid element type @ argument &amp;quot;..dataID..debugText -- причина, показанная в отчете&lt;br /&gt;
					local skipPunishment = false -- должен ли сервер пропустить наказание&lt;br /&gt;
&lt;br /&gt;
					reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
					return false -- вернуть неудачу&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			if (allowedDataTypes) then -- проверим разрешенные типы данных&lt;br /&gt;
				local dataType = type(eventData) -- получить тип данных&lt;br /&gt;
				local matchingType = allowedDataTypes[dataType] -- проверить, разрешено ли это&lt;br /&gt;
&lt;br /&gt;
				if (not matchingType) then -- не разрешено&lt;br /&gt;
					local failReason = &amp;quot;Invalid data type @ argument &amp;quot;..dataID..debugText -- причина, показанная в отчете&lt;br /&gt;
					local skipPunishment = false -- должен ли сервер пропустить наказание&lt;br /&gt;
&lt;br /&gt;
					reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
					return false -- вернуть неудачу&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local allowedStringLength = dataToCheck.allowedStringLength -- если данные имеют проверку длины строки&lt;br /&gt;
				local dataString = (dataType == &amp;quot;string&amp;quot;) -- убеждаемся, что это строка&lt;br /&gt;
&lt;br /&gt;
				if (allowedStringLength and dataString) then -- если мы должны проверить длину строки&lt;br /&gt;
					local minLength = allowedStringLength[1] -- получить минимальную длину&lt;br /&gt;
					local maxLength = allowedStringLength[2] -- получить максимальную длину&lt;br /&gt;
					local stringLength = utf8.len(eventData) -- получить длину строки данных&lt;br /&gt;
					local matchingLength = (stringLength &amp;gt;= minLength) and (stringLength &amp;lt;= maxLength) -- сравниваем, подходит ли значение в промежуток&lt;br /&gt;
&lt;br /&gt;
					if (not matchingLength) then -- если не подходит&lt;br /&gt;
						local failReason = &amp;quot;Invalid string length (must be between &amp;quot;..minLength..&amp;quot;-&amp;quot;..maxLength..&amp;quot;) @ argument &amp;quot;..dataID..debugText -- причина, показанная в отчете&lt;br /&gt;
						local skipPunishment = false -- должен ли сервер пропустить наказание&lt;br /&gt;
&lt;br /&gt;
						reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
						return false -- вернуть неудачу&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local allowedTableLength = dataToCheck.allowedTableLength -- если данные имеют проверку длины таблицы&lt;br /&gt;
				local dataTable = (dataType == &amp;quot;table&amp;quot;) -- убеждаемся, что это таблица&lt;br /&gt;
&lt;br /&gt;
				if (allowedTableLength and dataTable) then -- если мы должны проверить длину таблицы&lt;br /&gt;
					local minLength = allowedTableLength[1] -- получить минимальную длину&lt;br /&gt;
					local maxLength = allowedTableLength[2] -- получить максимальную длину&lt;br /&gt;
					local minLengthAchieved = false -- переменная, которая проверяет 'была ли достигнута минимальная длина'&lt;br /&gt;
					local maxLengthExceeded = false -- переменная, которая проверяет 'превысила ли длина разрешенный максимум'&lt;br /&gt;
					local tableLength = 0 -- сохранить начальную длину таблицы&lt;br /&gt;
&lt;br /&gt;
					for _, _ in pairs(eventData) do -- проходим по всей таблице&lt;br /&gt;
						tableLength = (tableLength + 1) -- добавляем + 1 для каждой записи таблицы&lt;br /&gt;
						minLengthAchieved = (tableLength &amp;gt;= minLength) -- больше ли длина или по крайней мере такой минимум, который мы требуем&lt;br /&gt;
						maxLengthExceeded = (tableLength &amp;gt; maxLength) -- превысила ли таблица максимальную длину?&lt;br /&gt;
&lt;br /&gt;
						if (maxLengthExceeded) then -- она больше, чем должна быть&lt;br /&gt;
							break -- прерываем цикл (из-за того, что условие выше выполнено, нет смысла считать дальше и тратить процессор на таблицу, которая потенциально может иметь огромное количество записей)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					local matchingLength = (minLengthAchieved and not maxLengthExceeded) -- проверяем, достигнута ли минимальная длина, и убеждаемся, что она не превышает максимальную&lt;br /&gt;
&lt;br /&gt;
					if (not matchingLength) then -- эта таблица не соответствует требованиям&lt;br /&gt;
						local failReason = &amp;quot;Invalid table length (must be between &amp;quot;..minLength..&amp;quot;-&amp;quot;..maxLength..&amp;quot;) @ argument &amp;quot;..dataID..debugText -- причина, показанная в отчете&lt;br /&gt;
						local skipPunishment = false -- должен ли сервер пропустить наказание&lt;br /&gt;
&lt;br /&gt;
						reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
						return false -- вернуть неудачу&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local allowedNumberRange = dataToCheck.allowedNumberRange -- если данные имеют проверку диапазона чисел&lt;br /&gt;
				local dataNumber = (dataType == &amp;quot;number&amp;quot;) -- убеждаемся, что это число&lt;br /&gt;
&lt;br /&gt;
				if (allowedNumberRange and dataNumber) then -- если мы должны проверить диапазон чисел&lt;br /&gt;
					local minRange = allowedNumberRange[1] -- получить минимальный диапазон чисел&lt;br /&gt;
					local maxRange = allowedNumberRange[2] -- получить максимальный диапазон чисел&lt;br /&gt;
					local matchingRange = (eventData &amp;gt;= minRange) and (eventData &amp;lt;= maxRange) -- сравниваем, подходит ли значение в промежуток&lt;br /&gt;
&lt;br /&gt;
					if (not matchingRange) then -- если не подходит&lt;br /&gt;
						local failReason = &amp;quot;Invalid number range (must be between &amp;quot;..minRange..&amp;quot;-&amp;quot;..maxRange..&amp;quot;) @ argument &amp;quot;..dataID..debugText -- причина, показанная в отчете&lt;br /&gt;
						local skipPunishment = false -- должен ли сервер пропустить наказание&lt;br /&gt;
&lt;br /&gt;
						reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- сообщить о происшествии и обработать (или нет) этого игрока&lt;br /&gt;
&lt;br /&gt;
						return false -- вернуть неудачу&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return true -- проверки безопасности пройдены, с этим вызовом события всё в порядке&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- вспомогательная функция для логирования и обработки инцидентов&lt;br /&gt;
	local logClient = inspect(clientElement) -- подробный вид игрока, вызвавшего событие&lt;br /&gt;
	local logSerial = getPlayerSerial(clientElement) or &amp;quot;N/A&amp;quot; -- серийник клиента, или &amp;quot;N/A&amp;quot;, если по какой-то причине это невозможно&lt;br /&gt;
	local logSource = inspect(sourceElement) -- подробный вид исходного элемента&lt;br /&gt;
	local logText = -- заполняем наш отчет данными&lt;br /&gt;
		&amp;quot;*\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Detected event abnormality:\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Client: &amp;quot;..logClient..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Client serial: &amp;quot;..logSerial..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Source: &amp;quot;..logSource..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Event: &amp;quot;..serverEvent..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Reason: &amp;quot;..failReason..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;*&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	outputDebugString(logText, debugLevel, debugR, debugG, debugB) -- выводим это в отладку&lt;br /&gt;
&lt;br /&gt;
	if (not punishPlayerOnDetect or skipPunishment) then -- мы не хотим наказывать игрока по какой-то причине&lt;br /&gt;
		return true -- останавливаемся здесь&lt;br /&gt;
	end&lt;br /&gt;
		&lt;br /&gt;
	if (punishmentBan) then -- если это бан&lt;br /&gt;
		banPlayer(clientElement, banByIP, banByUsername, banBySerial, punishedBy, punishmentReason, banTime) -- удаляем его присутствие с сервера&lt;br /&gt;
	else -- иначе&lt;br /&gt;
		kickPlayer(clientElement, punishedBy, punishmentReason) -- просто кикаем игрока с сервера&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return true -- всё готово, сообщаем об успехе&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onServerEvent(clientData)&lt;br /&gt;
	--[[&lt;br /&gt;
		Предположим, что это серверское событие (функция) вызывается следующим образом:&lt;br /&gt;
&lt;br /&gt;
		local dataToPass = 10&lt;br /&gt;
&lt;br /&gt;
		triggerServerEvent(&amp;quot;onServerEvent&amp;quot;, localPlayer, dataToPass)&lt;br /&gt;
	]]&lt;br /&gt;
&lt;br /&gt;
	local shouldProcessServerCode = processServerEventData(&lt;br /&gt;
		client, -- элемент клиента - ответственный за вызов события&lt;br /&gt;
		source, -- исходный элемент - переданный в triggerServerEvent (в качестве 2-го аргумента)&lt;br /&gt;
		eventName, -- имя события - в данном случае 'onServerEvent'&lt;br /&gt;
		{&lt;br /&gt;
			checkEventData = { -- мы хотим проверить всё, что приходит от клиента&lt;br /&gt;
				{&lt;br /&gt;
					eventData = source, -- первое на проверку, переменная source&lt;br /&gt;
					equalTo = client, -- мы хотим проверить, совпадает ли это с игроком, вызвавшим событие&lt;br /&gt;
					debugData = &amp;quot;source&amp;quot;, -- вспомогательные данные, которые будут показаны в отчете отладки&lt;br /&gt;
				},&lt;br /&gt;
				{&lt;br /&gt;
					eventData = clientData, -- давайте проверим данные, которые клиент прислал нам&lt;br /&gt;
					allowedDataTypes = {&lt;br /&gt;
						[&amp;quot;number&amp;quot;] = true, -- мы хотим, чтобы это было только число&lt;br /&gt;
					},&lt;br /&gt;
					allowedNumberRange = {1, 100}, -- в диапазоне от 1 до 100&lt;br /&gt;
					debugData = &amp;quot;clientData&amp;quot;, -- если что-то пойдет не так, дадим серверу знать где (это появится в отчете отладки)&lt;br /&gt;
				},&lt;br /&gt;
			},&lt;br /&gt;
		}&lt;br /&gt;
	)&lt;br /&gt;
&lt;br /&gt;
	if (not shouldProcessServerCode) then -- что-то не так, зеленого света для выполнения кода за этим пределом нет&lt;br /&gt;
		return false -- остановить выполнение кода&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- выполняем код как обычно&lt;br /&gt;
end&lt;br /&gt;
addEvent(&amp;quot;onServerEvent&amp;quot;, true)&lt;br /&gt;
addEventHandler(&amp;quot;onServerEvent&amp;quot;, root, onServerEvent)&lt;br /&gt;
&lt;br /&gt;
function onServerAdminEvent(playerToBan)&lt;br /&gt;
	--[[&lt;br /&gt;
		Предположим, что это серверское событие администратора (функция) вызывается следующим образом:&lt;br /&gt;
&lt;br /&gt;
		local playerToBan = getPlayerFromName(&amp;quot;playerToBan&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		triggerServerEvent(&amp;quot;onServerAdminEvent&amp;quot;, localPlayer, playerToBan)&lt;br /&gt;
	]]&lt;br /&gt;
&lt;br /&gt;
	local shouldProcessServerCode = processServerEventData(&lt;br /&gt;
		client, -- элемент клиента - ответственный за вызов события&lt;br /&gt;
		source, -- исходный элемент - переданный в triggerServerEvent (в качестве 2-го аргумента)&lt;br /&gt;
		eventName, -- имя события - в данном случае 'onServerAdminEvent'&lt;br /&gt;
		{&lt;br /&gt;
			checkACLGroup = { -- нам нужно проверить, принадлежит ли игрок, вызвавший событие, к группам ACL&lt;br /&gt;
				&amp;quot;Admin&amp;quot;, -- в данном случае группа администраторов&lt;br /&gt;
			},&lt;br /&gt;
			checkEventData = { -- мы хотим проверить всё, что приходит от клиента&lt;br /&gt;
				{&lt;br /&gt;
					eventData = source, -- первое на проверку, переменная source&lt;br /&gt;
					equalTo = client, -- мы хотим проверить, совпадает ли это с игроком, вызвавшим событие&lt;br /&gt;
					debugData = &amp;quot;source&amp;quot;, -- вспомогательные данные, которые будут показаны в отчете отладки&lt;br /&gt;
				},&lt;br /&gt;
				{&lt;br /&gt;
					eventData = playerToBan, -- давайте проверим данные, которые клиент прислал нам&lt;br /&gt;
					allowedDataTypes = {&lt;br /&gt;
						[&amp;quot;player&amp;quot;] = true, -- мы хотим, чтобы это был игрок&lt;br /&gt;
					},&lt;br /&gt;
					debugData = &amp;quot;playerToBan&amp;quot;, -- если что-то пойдет не так, дадим серверу знать где (это появится в отчете отладки)&lt;br /&gt;
				},&lt;br /&gt;
			},&lt;br /&gt;
		}&lt;br /&gt;
	)&lt;br /&gt;
&lt;br /&gt;
	if (not shouldProcessServerCode) then -- что-то не так, зеленого света для выполнения кода за этим пределом нет&lt;br /&gt;
		return false -- остановить выполнение кода&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- выполняем код как обычно&lt;br /&gt;
end&lt;br /&gt;
addEvent(&amp;quot;onServerAdminEvent&amp;quot;, true)&lt;br /&gt;
addEventHandler(&amp;quot;onServerAdminEvent&amp;quot;, root, onServerAdminEvent)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Защита событий, относящихся только к серверу ==&lt;br /&gt;
* Очень важно отключить удаленный запуск''' в [https://wiki.multitheftauto.com/wiki/AddEvent addEvent], чтобы предотвратить вызов событий, относящихся только к серверу, со стороны клиента.&lt;br /&gt;
* '''События''' в стиле '''Admin''' должны подтверждать '''права доступа''' игрока, либо с помощью [https://wiki.multitheftauto.com/wiki/IsObjectInACLGroup isObjectInACLGroup], либо [https://wiki.multitheftauto.com/wiki/HasObjectPermissionTo hasObjectPermissionTo].&lt;br /&gt;
&lt;br /&gt;
----------&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
В этом примере показано, как вы должны создавать события только на стороне сервера.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function onServerSideOnlyEvent()&lt;br /&gt;
	-- делаем какие-то вещи на стороне сервера&lt;br /&gt;
end&lt;br /&gt;
addEvent(&amp;quot;onServerSideOnlyEvent&amp;quot;, false) -- установите второй аргумент (allowRemoteTriger) в false, чтобы его нельзя было вызвать с клиента&lt;br /&gt;
addEventHandler(&amp;quot;onServerSideOnlyEvent&amp;quot;, root, onServerSideOnlyEvent) -- связываем наше событие с функцией onServerSideOnlyEvent&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Защита снарядов и взрывных устройств ==&lt;br /&gt;
Этот раздел (и '''код''' - '''работа продолжается''') - '''используйте на свой страх и риск'''.&lt;br /&gt;
----------&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;false&amp;quot;&amp;gt;&lt;br /&gt;
Устройство для отслеживания боеприпасов к снарядам:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local playerProjectileAmmo = {} -- хранить здесь боезапас оружия игрока&lt;br /&gt;
local playerWeaponsToTrack = { -- отслеживать боезапас для определенных типов оружия игрока, в основном тех, которые создают снаряды; [weaponID] = weaponSlot&lt;br /&gt;
	[16] = 8, -- grenade&lt;br /&gt;
	[17] = 8, -- teargas&lt;br /&gt;
	[18] = 8, -- molotov&lt;br /&gt;
	[35] = 7, -- rocket launcher&lt;br /&gt;
	[36] = 7, -- rocket launcher (heat-seeking)&lt;br /&gt;
	[39] = 8, -- satchel charge&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local function updateProjectileAmmoForPlayer(playerElement)&lt;br /&gt;
	local validElement = isElement(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerDead = isPedDead(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (playerDead) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for weaponID, weaponSlot in pairs(playerWeaponsToTrack) do&lt;br /&gt;
		local weaponInSlot = getPedWeapon(playerElement, weaponSlot)&lt;br /&gt;
		local weaponTotalAmmo = getPedTotalAmmo(playerElement, weaponSlot)&lt;br /&gt;
		local weaponHasAmmo = (weaponTotalAmmo &amp;gt; 0)&lt;br /&gt;
		local weaponMatching = (weaponInSlot == weaponID)&lt;br /&gt;
		local updateWeaponAmmo = (weaponMatching and weaponHasAmmo)&lt;br /&gt;
&lt;br /&gt;
		if (updateWeaponAmmo) then&lt;br /&gt;
			local storedProjectileAmmo = playerProjectileAmmo[playerElement]&lt;br /&gt;
			local newWeaponAmmo = (updateWeaponAmmo and weaponTotalAmmo or nil)&lt;br /&gt;
&lt;br /&gt;
			if (not storedProjectileAmmo) then&lt;br /&gt;
				playerProjectileAmmo[playerElement] = {}&lt;br /&gt;
				storedProjectileAmmo = playerProjectileAmmo[playerElement]&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			storedProjectileAmmo[weaponID] = newWeaponAmmo&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function hasPlayerProjectileAmmo(playerElement, projectileWeapon)&lt;br /&gt;
	local validElement = isElement(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerDead = isPedDead(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (playerDead) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local projectileData = playerProjectileAmmo[playerElement]&lt;br /&gt;
	local projectileAmmo = (projectileData and projectileData[projectileWeapon])&lt;br /&gt;
&lt;br /&gt;
	return projectileAmmo&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function decreasePlayerProjectileAmmo(playerElement, projectileWeapon)&lt;br /&gt;
	local validElement = isElement(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerDead = isPedDead(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (playerDead) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerProjectileData = playerProjectileAmmo[playerElement]&lt;br /&gt;
&lt;br /&gt;
	if (not playerProjectileData) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local projectileWeaponAmmo = playerProjectileData[projectileWeapon]&lt;br /&gt;
	local tempProjectileAmmo = (projectileWeaponAmmo - 1)&lt;br /&gt;
	local newProjectileAmmo = (tempProjectileAmmo &amp;gt; 0 and tempProjectileAmmo or nil)&lt;br /&gt;
&lt;br /&gt;
	playerProjectileData[projectileWeapon] = newProjectileAmmo&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onPlayerWeaponSwitchAntiCheat(previousWeaponID, currentWeaponID)&lt;br /&gt;
	setTimer(updateProjectileAmmoForPlayer, 50, 1, source)&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onPlayerWeaponSwitch&amp;quot;, root, onPlayerWeaponSwitchAntiCheat)&lt;br /&gt;
&lt;br /&gt;
function onResourceStartAntiCheat()&lt;br /&gt;
	local playersTable = getElementsByType(&amp;quot;player&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for playerID = 1, #playersTable do&lt;br /&gt;
		local playerElement = playersTable[playerID]&lt;br /&gt;
&lt;br /&gt;
		updateProjectileAmmoForPlayer(playerElement)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onResourceStart&amp;quot;, resourceRoot, onResourceStartAntiCheat)&lt;br /&gt;
&lt;br /&gt;
function onPlayerWastedQuitAntiCheat()&lt;br /&gt;
	playerProjectileAmmo[source] = nil&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onPlayerWasted&amp;quot;, root, onPlayerWastedQuitAntiCheat)&lt;br /&gt;
addEventHandler(&amp;quot;onPlayerQuit&amp;quot;, root, onPlayerWastedQuitAntiCheat)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;false&amp;quot;&amp;gt;&lt;br /&gt;
Манипулятор со снарядом:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local playerCreatedProjectiles = {} -- хранить количество легитимно созданных снарядов игрока; [playerElement] = {[projectileType] = activeProjectiles}&lt;br /&gt;
local projectileTypes = {&lt;br /&gt;
	[16] = { -- Grenade&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 2,&lt;br /&gt;
		projectileAllowedWeapons = {&lt;br /&gt;
			[16] = true, -- grenade&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[17] = { -- Teargas&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 2,&lt;br /&gt;
		projectileAllowedWeapons = {&lt;br /&gt;
			[17] = true, -- teargas&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[18] = { -- Molotov&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 2,&lt;br /&gt;
		projectileAllowedWeapons = {&lt;br /&gt;
			[18] = true, -- molotov&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[19] = { -- Rocket&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 5,&lt;br /&gt;
		projectileMaxVelocity = 2,&lt;br /&gt;
		projectileAllowedWeapons = {&lt;br /&gt;
			[35] = true, -- rocket launcher&lt;br /&gt;
		},&lt;br /&gt;
		projectileAllowedVehicles = {&lt;br /&gt;
			[425] = true, -- hunter&lt;br /&gt;
			[520] = true, -- hydra&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[20] = { -- Rocket (heat-seeking)&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 5,&lt;br /&gt;
		projectileMaxVelocity = 2,&lt;br /&gt;
		projectileAllowedWeapons = {&lt;br /&gt;
			[36] = true, -- rocket launcher (heat-seeking)&lt;br /&gt;
		},&lt;br /&gt;
		projectileAllowedVehicles = {&lt;br /&gt;
			[520] = true, -- hydra&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[21] = { -- Airbomb&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileAllowedVehicles = {&lt;br /&gt;
			[520] = true, -- hydra&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[39] = { -- Satchel charge&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 2,&lt;br /&gt;
		projectileAllowedWeapons = {&lt;br /&gt;
			[39] = true, -- satchel charge&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[58] = { -- Hydra flare&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 5,&lt;br /&gt;
		projectileAllowedVehicles = {&lt;br /&gt;
			[520] = true, -- hydra&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local reportAbnormality = true -- сообщать ли о нарушениях в скрипте отладки - по умолчанию&lt;br /&gt;
local punishPlayerOnDetect = false -- должен ли игрок быть наказан при обнаружении; true - да, или false, чтобы ничего не делать (убедитесь, что ресурс, запускающий этот код, имеет права администратора)&lt;br /&gt;
local punishmentBan = true -- актуально только если punishPlayerOnDetect установлен в true; используйте true для бана или false для кика&lt;br /&gt;
local punishmentReason = &amp;quot;Projectile/explosion anti-cheat&amp;quot; -- актуально только если punishPlayerOnDetect установлен в true; причина, которая будет показана наказанному игроку&lt;br /&gt;
local punishedBy = &amp;quot;Console&amp;quot; -- актуально только если punishPlayerOnDetect установлен в true; кто ответственен за наказание, также показывается наказанному игроку&lt;br /&gt;
local banByIP = false -- актуально только если punishPlayerOnDetect и punishmentBan установлены в true; бан по IP в настоящее время не рекомендуется (...)&lt;br /&gt;
local banByUsername = false -- имя пользователя сообщества - устаревшая вещь, поэтому установлено в false и должно оставаться таким&lt;br /&gt;
local banBySerial = true -- актуально только если punishPlayerOnDetect и punishmentBan установлены в true; (...) если есть серийный номер игрока, который можно использовать вместо этого&lt;br /&gt;
local banTime = 0 -- актуально только если punishPlayerOnDetect и punishmentBan установлены в true; время в секундах, 0 навсегда&lt;br /&gt;
local debugMsgLevel = 4 -- этот уровень отладки позволяет скрыть префикс INFO: и использовать пользовательские цвета&lt;br /&gt;
local debugMsgR = 255 -- сообщение отладки - красный цвет&lt;br /&gt;
local debugMsgG = 127 -- сообщение отладки - зеленый цвет&lt;br /&gt;
local debugMsgB = 0 -- сообщение отладки - синий цвет&lt;br /&gt;
&lt;br /&gt;
local function reportProjectileAbnormality(playerElement, projectileType, projectileX, projectileY, projectileZ, projectileForce, projectileTarget, projectileRX, projectileRY, projectileRZ, projectileVX, projectileVY, projectileVZ, detectionCode)&lt;br /&gt;
	local projectileSyncer = inspect(playerElement)&lt;br /&gt;
	local projectilePosition = projectileX..&amp;quot;, &amp;quot;..projectileY..&amp;quot;, &amp;quot;..projectileZ&lt;br /&gt;
	local projectileZoneName = getZoneName(projectileX, projectileY, projectileZ, false)&lt;br /&gt;
	local projectileCityName = getZoneName(projectileX, projectileY, projectileZ, true)&lt;br /&gt;
	local projectileLog =&lt;br /&gt;
		&amp;quot;* Detected projectile abnormality - &amp;quot;..detectionCode..&amp;quot; *\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Projectile syncer: &amp;quot;..projectileSyncer..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Projectile type: &amp;quot;..projectileType..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Projectile position: &amp;quot;..projectilePosition.. &amp;quot; (&amp;quot;..projectileZoneName..&amp;quot;, &amp;quot;..projectileCityName..&amp;quot;)\n&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	outputDebugString(projectileLog, debugMsgLevel, debugMsgR, debugMsgG, debugMsgB)&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function processProjectileChecks(playerElement, projectileType, projectileX, projectileY, projectileZ, projectileForce, projectileTarget, projectileRX, projectileRY, projectileRZ, projectileVX, projectileVY, projectileVZ)&lt;br /&gt;
	local projectileData = projectileTypes[projectileType]&lt;br /&gt;
	local projectileAllowed = projectileData.projectileAllowed&lt;br /&gt;
&lt;br /&gt;
	if (not projectileAllowed) then&lt;br /&gt;
		return false, &amp;quot;Projectile not allowed&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local projectileAllowedWeapons = projectileData.projectileAllowedWeapons&lt;br /&gt;
&lt;br /&gt;
	if (projectileAllowedWeapons) then&lt;br /&gt;
		local playerWeapon = getPedWeapon(playerElement)&lt;br /&gt;
		local allowedWeapon = projectileAllowedWeapons[playerWeapon]&lt;br /&gt;
&lt;br /&gt;
		if (not allowedWeapon) then&lt;br /&gt;
			return false, &amp;quot;Player is not holding correct weapon&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local weaponAmmo = hasPlayerProjectileAmmo(playerElement, playerWeapon)&lt;br /&gt;
		local playerHasAmmo = (weaponAmmo &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
		if (not playerHasAmmo) then&lt;br /&gt;
			return false, &amp;quot;Player doesn't have ammo for weapon&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		decreasePlayerProjectileAmmo(playerElement, playerWeapon)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerVehicle = getPedOccupiedVehicle(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (playerVehicle) then&lt;br /&gt;
		local projectileAllowedVehicles = projectileData.projectileAllowedVehicles&lt;br /&gt;
&lt;br /&gt;
		if (projectileAllowedVehicles) then&lt;br /&gt;
			local vehicleModel = getElementModel(playerVehicle)&lt;br /&gt;
			local allowedVehicle = projectileAllowedVehicles[vehicleModel]&lt;br /&gt;
&lt;br /&gt;
			if (not allowedVehicle) then&lt;br /&gt;
				return false, &amp;quot;Player is not inside allowed vehicles&amp;quot;&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			local vehicleDriver = getVehicleController(playerVehicle)&lt;br /&gt;
			local playerDriver = (playerElement == vehicleDriver)&lt;br /&gt;
&lt;br /&gt;
			if (not playerDriver) then&lt;br /&gt;
				return false, &amp;quot;Player is not vehicle driver&amp;quot;&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return false, &amp;quot;Player in vehicle&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local projectileMaxDistanceFromCreator = projectileData.projectileMaxDistanceFromCreator&lt;br /&gt;
&lt;br /&gt;
	if (projectileMaxDistanceFromCreator) then&lt;br /&gt;
		local playerX, playerY, playerZ = getElementPosition(playerElement)&lt;br /&gt;
		local distanceToProjectile = getDistanceBetweenPoints3D(playerX, playerY, playerZ, projectileX, projectileY, projectileZ)&lt;br /&gt;
		local matchingProjectileDistance = (distanceToProjectile &amp;lt;= projectileMaxDistanceFromCreator)&lt;br /&gt;
&lt;br /&gt;
		if (not matchingProjectileDistance) then&lt;br /&gt;
			return false, &amp;quot;Projectile distance mismatch&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local projectileMaxVelocity = projectileData.projectileMaxVelocity&lt;br /&gt;
&lt;br /&gt;
	if (projectileMaxVelocity) then&lt;br /&gt;
		local projectileVelocity = (projectileVX ^ 2 + projectileVY ^ 2 + projectileVZ ^ 2)&lt;br /&gt;
		local projectileSpeed = math.sqrt(projectileVelocity)&lt;br /&gt;
		local matchingProjectileVelocity = (projectileSpeed &amp;lt;= projectileMaxVelocity)&lt;br /&gt;
&lt;br /&gt;
		if (not matchingProjectileVelocity) then&lt;br /&gt;
			return false, &amp;quot;Projectile velocity mismatch&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function trackPlayerProjectile(playerElement, projectileID)&lt;br /&gt;
	local validElement = isElement(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerProjectiles = playerCreatedProjectiles[playerElement]&lt;br /&gt;
&lt;br /&gt;
	if (not playerProjectiles) then&lt;br /&gt;
		playerCreatedProjectiles[playerElement] = {}&lt;br /&gt;
		playerProjectiles = playerCreatedProjectiles[playerElement]&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local projectilesByType = playerProjectiles[projectileID] or 0&lt;br /&gt;
	local newProjectilesCount = (projectilesByType + 1)&lt;br /&gt;
&lt;br /&gt;
	playerProjectiles[projectileID] = newProjectilesCount&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getProjectileDetectionOverwrittenBehavior(projectileType)&lt;br /&gt;
	local projectileData = projectileTypes[projectileType]&lt;br /&gt;
&lt;br /&gt;
	if (not projectileData) then&lt;br /&gt;
		return reportAbnormality, punishPlayerOnDetect, punishmentBan&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local projectileBehaviour = projectileData.projectileOverwriteBehaviour&lt;br /&gt;
&lt;br /&gt;
	if (not projectileBehaviour) then&lt;br /&gt;
		return reportAbnormality, punishPlayerOnDetect, punishmentBan&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local overwriteReport = projectileBehaviour.reportAbnormality&lt;br /&gt;
	local overwritePunish = projectileBehaviour.punishPlayerOnDetect&lt;br /&gt;
	local overwriteBan = projectileBehaviour.punishmentBan&lt;br /&gt;
&lt;br /&gt;
	return overwriteReport, overwritePunish, overwriteBan&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function decreasePlayerProjectiles(playerElement, projectileID)&lt;br /&gt;
	local validElement = isElement(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerProjectiles = playerCreatedProjectiles[playerElement]&lt;br /&gt;
&lt;br /&gt;
	if (not playerProjectiles) then&lt;br /&gt;
		return false, true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local projectilesByType = playerProjectiles[projectileID]&lt;br /&gt;
&lt;br /&gt;
	if (not projectilesByType) then&lt;br /&gt;
		return false, true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local tempProjectilesCount = (projectilesByType - 1)&lt;br /&gt;
	local newProjectilesCount = (tempProjectilesCount &amp;gt; 0 and tempProjectilesCount or nil)&lt;br /&gt;
&lt;br /&gt;
	playerProjectiles[projectileID] = newProjectilesCount&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onPlayerProjectileCreationAntiCheat(projectileType, projectileX, projectileY, projectileZ, projectileForce, projectileTarget, projectileRX, projectileRY, projectileRZ, projectileVX, projectileVY, projectileVZ)&lt;br /&gt;
	local approvedProjectile, detectionCode = processProjectileChecks(source, projectileType, projectileX, projectileY, projectileZ, projectileForce, projectileTarget, projectileRX, projectileRY, projectileRZ, projectileVX, projectileVY, projectileVZ)&lt;br /&gt;
&lt;br /&gt;
	if (approvedProjectile) then&lt;br /&gt;
		trackPlayerProjectile(source, projectileType)&lt;br /&gt;
&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local reportAbnormality, punishPlayerOnDetect, punishmentBan = getProjectileDetectionOverwrittenBehavior(projectileType)&lt;br /&gt;
&lt;br /&gt;
	if (reportAbnormality) then&lt;br /&gt;
		reportProjectileAbnormality(source, projectileType, projectileX, projectileY, projectileZ, projectileForce, projectileTarget, projectileRX, projectileRY, projectileRZ, projectileVX, projectileVY, projectileVZ, detectionCode)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	cancelEvent()&lt;br /&gt;
&lt;br /&gt;
	if (not punishPlayerOnDetect) then -- мы не хотим наказывать игрока по какой-то причине&lt;br /&gt;
		return false -- так что останавливаемся здесь&lt;br /&gt;
	end&lt;br /&gt;
		&lt;br /&gt;
	if (punishmentBan) then -- если это бан&lt;br /&gt;
		banPlayer(source, banByIP, banByUsername, banBySerial, punishedBy, punishmentReason, banTime) -- удаляем его присутствие с сервера&lt;br /&gt;
	else -- иначе&lt;br /&gt;
		kickPlayer(source, punishedBy, punishmentReason) -- просто кикаем игрока с сервера&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onPlayerProjectileCreation&amp;quot;, root, onPlayerProjectileCreationAntiCheat)&lt;br /&gt;
&lt;br /&gt;
function onPlayerQuitAntiCheat()&lt;br /&gt;
	playerCreatedProjectiles[source] = nil&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onPlayerQuit&amp;quot;, root, onPlayerQuitAntiCheat)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;false&amp;quot;&amp;gt;&lt;br /&gt;
Обработчик взрывов:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local rocketInstantExplosionDistanceThreshold = 1.55 -- дистанция, ниже которой будет создан только взрыв (а не снаряд ракеты, следовательно, не вызывается onPlayerProjectileCreation); не меняйте это&lt;br /&gt;
local explosionTypes = { -- более конкретная информация о взрыве и разрешен ли он&lt;br /&gt;
	[0] = { -- Grenade&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
		explosionAllowedProjectiles = {&lt;br /&gt;
			[16] = true, -- grenade&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[1] = { -- Molotov&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
		explosionAllowedProjectiles = {&lt;br /&gt;
			[18] = true, -- molotov&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[2] = { -- Rocket&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
		explosionAllowedWeapons = {&lt;br /&gt;
			[35] = true, -- rocket launcher&lt;br /&gt;
			[36] = true, -- rocket launcher (heat-seeking)&lt;br /&gt;
		},&lt;br /&gt;
		explosionAllowedProjectiles = {&lt;br /&gt;
			[19] = true, -- rocket&lt;br /&gt;
			[20] = true, -- rocket (heat-seeking)&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[3] = { -- Rocket weak&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
		explosionAllowedProjectiles = {&lt;br /&gt;
			[19] = true, -- rocket&lt;br /&gt;
			[20] = true, -- rocket (heat-seeking)&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[4] = { -- Car&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[5] = { -- Car quick&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[6] = { -- Boat&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[7] = { -- Heli&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[8] = { -- Mine&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[9] = { -- Object&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[10] = { -- Tank grenade&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
		explosionMaxDistanceFromCreator = 80,&lt;br /&gt;
		explosionAllowedVehicles = {&lt;br /&gt;
			[432] = true,&lt;br /&gt;
		}&lt;br /&gt;
	},&lt;br /&gt;
	[11] = { -- Small&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[12] = { -- Tiny&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local reportAbnormality = true -- сообщать ли о нарушениях в скрипте отладки - по умолчанию&lt;br /&gt;
local punishPlayerOnDetect = false -- должен ли игрок быть наказан при обнаружении; true - да, или false, чтобы ничего не делать (убедитесь, что ресурс, запускающий этот код, имеет права администратора)&lt;br /&gt;
local punishmentBan = true -- актуально только если punishPlayerOnDetect установлен в true; используйте true для бана или false для кика&lt;br /&gt;
local punishmentReason = &amp;quot;Projectile/explosion anti-cheat&amp;quot; -- актуально только если punishPlayerOnDetect установлен в true; причина, которая будет показана наказанному игроку&lt;br /&gt;
local punishedBy = &amp;quot;Console&amp;quot; -- актуально только если punishPlayerOnDetect установлен в true; кто ответственен за наказание, также показывается наказанному игроку&lt;br /&gt;
local banByIP = false -- актуально только если punishPlayerOnDetect и punishmentBan установлены в true; бан по IP в настоящее время не рекомендуется (...)&lt;br /&gt;
local banByUsername = false -- имя пользователя сообщества - устаревшая вещь, поэтому установлено в false и должно оставаться таким&lt;br /&gt;
local banBySerial = true -- актуально только если punishPlayerOnDetect и punishmentBan установлены в true; (...) если есть серийный номер игрока, который можно использовать вместо этого&lt;br /&gt;
local banTime = 0 -- актуально только если punishPlayerOnDetect и punishmentBan установлены в true; время в секундах, 0 навсегда&lt;br /&gt;
local debugMsgLevel = 4 -- этот уровень отладки позволяет скрыть префикс INFO: и использовать пользовательские цвета&lt;br /&gt;
local debugMsgR = 255 -- сообщение отладки - красный цвет&lt;br /&gt;
local debugMsgG = 127 -- сообщение отладки - зеленый цвет&lt;br /&gt;
local debugMsgB = 0 -- сообщение отладки - синий цвет&lt;br /&gt;
&lt;br /&gt;
local function reportExplosionAbnormality(playerElement, explosionType, explosionX, explosionY, explosionZ, detectionCode)&lt;br /&gt;
	local explosionSyncer = inspect(playerElement)&lt;br /&gt;
	local explosionType = explosionType&lt;br /&gt;
	local explosionPosition = explosionX..&amp;quot;, &amp;quot;..explosionY..&amp;quot;, &amp;quot;..explosionZ&lt;br /&gt;
	local explosionZoneName = getZoneName(explosionX, explosionY, explosionZ, false)&lt;br /&gt;
	local explosionCityName = getZoneName(explosionX, explosionY, explosionZ, true)&lt;br /&gt;
	local explosionLog =&lt;br /&gt;
		&amp;quot;* Detected explosion abnormality - &amp;quot;..detectionCode..&amp;quot; *\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Explosion syncer: &amp;quot;..explosionSyncer..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Explosion type: &amp;quot;..explosionType..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Explosion position: &amp;quot;..explosionPosition.. &amp;quot; (&amp;quot;..explosionZoneName..&amp;quot;, &amp;quot;..explosionCityName..&amp;quot;)\n&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	outputDebugString(explosionLog, debugMsgLevel, debugMsgR, debugMsgG, debugMsgB)&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function processExplosionChecks(playerElement, explosionType, explosionX, explosionY, explosionZ)&lt;br /&gt;
	local explosionData = explosionTypes[explosionType]&lt;br /&gt;
	local explosionAllowed = explosionData.explosionAllowed&lt;br /&gt;
&lt;br /&gt;
	if (not explosionAllowed) then&lt;br /&gt;
		return false, &amp;quot;Explosion type not allowed&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local rocketExplosion = (explosionType == 2)&lt;br /&gt;
&lt;br /&gt;
	if (rocketExplosion) then&lt;br /&gt;
		local playerX, playerY, playerZ = getElementPosition(playerElement)&lt;br /&gt;
		local distanceToExplosion = getDistanceBetweenPoints3D(playerX, playerY, playerZ, explosionX, explosionY, explosionZ)&lt;br /&gt;
		local instantExplosion = (distanceToExplosion &amp;lt; rocketInstantExplosionDistanceThreshold)&lt;br /&gt;
&lt;br /&gt;
		if (instantExplosion) then&lt;br /&gt;
			local explosionAllowedWeapons = explosionData.explosionAllowedWeapons&lt;br /&gt;
			local playerWeapon = getPedWeapon(playerElement)&lt;br /&gt;
			local allowedWeapon = explosionAllowedWeapons[playerWeapon]&lt;br /&gt;
&lt;br /&gt;
			if (not allowedWeapon) then&lt;br /&gt;
				return false, &amp;quot;Player is not holding rocket launcher&amp;quot;&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			local weaponAmmo = hasPlayerProjectileAmmo(playerElement, playerWeapon)&lt;br /&gt;
			local playerHasAmmo = (weaponAmmo &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
			if (not playerHasAmmo) then&lt;br /&gt;
				return false, &amp;quot;Player doesn't have ammo for rocket launcher&amp;quot;&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			decreasePlayerProjectileAmmo(playerElement, playerWeapon)&lt;br /&gt;
&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local explosionAllowedProjectiles = explosionData.explosionAllowedProjectiles&lt;br /&gt;
&lt;br /&gt;
	if (explosionAllowedProjectiles) then&lt;br /&gt;
&lt;br /&gt;
		for projectileID, _ in pairs(explosionAllowedProjectiles) do&lt;br /&gt;
			local atleastOneProjectile = decreasePlayerProjectiles(playerElement, projectileID)&lt;br /&gt;
&lt;br /&gt;
			if (atleastOneProjectile) then&lt;br /&gt;
				return true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return false, &amp;quot;Explosion created without respective projectile&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local explosionAllowedVehicles = explosionData.explosionAllowedVehicles&lt;br /&gt;
&lt;br /&gt;
	if (explosionAllowedVehicles) then&lt;br /&gt;
		local playerVehicle = getPedOccupiedVehicle(playerElement)&lt;br /&gt;
&lt;br /&gt;
		if (not playerVehicle) then&lt;br /&gt;
			return false, &amp;quot;Player is not in vehicle&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local vehicleModel = getElementModel(playerVehicle)&lt;br /&gt;
		local allowedVehicle = explosionAllowedVehicles[vehicleModel]&lt;br /&gt;
&lt;br /&gt;
		if (not allowedVehicle) then&lt;br /&gt;
			return false, &amp;quot;Player is inside not allowed vehicles&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local vehicleDriver = getVehicleController(playerVehicle)&lt;br /&gt;
		local playerDriver = (playerElement == vehicleDriver)&lt;br /&gt;
&lt;br /&gt;
		if (not playerDriver) then&lt;br /&gt;
			return false, &amp;quot;Player is not vehicle driver&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local explosionMaxDistanceFromCreator = explosionData.explosionMaxDistanceFromCreator&lt;br /&gt;
&lt;br /&gt;
	if (explosionMaxDistanceFromCreator) then&lt;br /&gt;
		local playerX, playerY, playerZ = getElementPosition(playerElement)&lt;br /&gt;
		local distanceToExplosion = getDistanceBetweenPoints3D(playerX, playerY, playerZ, explosionX, explosionY, explosionZ)&lt;br /&gt;
		local matchingExplosionDistance = (distanceToExplosion &amp;lt; explosionMaxDistanceFromCreator)&lt;br /&gt;
&lt;br /&gt;
		if (not matchingExplosionDistance) then&lt;br /&gt;
			return false, &amp;quot;Explosion distance mismatch&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getExplosionDetectionOverwrittenBehavior(explosionType)&lt;br /&gt;
	local explosionData = explosionTypes[explosionType]&lt;br /&gt;
&lt;br /&gt;
	if (not explosionData) then&lt;br /&gt;
		return reportAbnormality, punishPlayerOnDetect, punishmentBan&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local explosionBehaviour = explosionData.explosionOverwriteBehaviour&lt;br /&gt;
&lt;br /&gt;
	if (not explosionBehaviour) then&lt;br /&gt;
		return reportAbnormality, punishPlayerOnDetect, punishmentBan&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local overwriteReport = explosionBehaviour.reportAbnormality&lt;br /&gt;
	local overwritePunish = explosionBehaviour.punishPlayerOnDetect&lt;br /&gt;
	local overwriteBan = explosionBehaviour.punishmentBan&lt;br /&gt;
&lt;br /&gt;
	return overwriteReport, overwritePunish, overwriteBan&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onExplosionAntiCheat(explosionX, explosionY, explosionZ, explosionType)&lt;br /&gt;
	local serverSyncExplosion = (source == root)&lt;br /&gt;
&lt;br /&gt;
	if (serverSyncExplosion) then&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local approvedExplosion, detectionCode = processExplosionChecks(source, explosionType, explosionX, explosionY, explosionZ)&lt;br /&gt;
&lt;br /&gt;
	if (approvedExplosion) then&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local reportAbnormality, punishPlayerOnDetect, punishmentBan = getExplosionDetectionOverwrittenBehavior(explosionType)&lt;br /&gt;
&lt;br /&gt;
	if (reportAbnormality) then&lt;br /&gt;
		reportExplosionAbnormality(source, explosionType, explosionX, explosionY, explosionZ, detectionCode)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	cancelEvent()&lt;br /&gt;
&lt;br /&gt;
	if (not punishPlayerOnDetect) then -- мы не хотим наказывать игрока по какой-то причине&lt;br /&gt;
		return false -- так что останавливаемся здесь&lt;br /&gt;
	end&lt;br /&gt;
		&lt;br /&gt;
	if (punishmentBan) then -- если это бан&lt;br /&gt;
		banPlayer(source, banByIP, banByUsername, banBySerial, punishedBy, punishmentReason, banTime) -- удаляем его присутствие с сервера&lt;br /&gt;
	else -- иначе&lt;br /&gt;
		kickPlayer(source, punishedBy, punishmentReason) -- просто кикаем игрока с сервера&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onExplosion&amp;quot;, root, onExplosionAntiCheat)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Обработка незарегистрированных событий==&lt;br /&gt;
Смотрите: [[onPlayerTriggerInvalidEvent]]&lt;br /&gt;
&lt;br /&gt;
==Обработка нежелательных событий==&lt;br /&gt;
Смотрите: [[onPlayerTriggerEventThreshold]]&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
[[ru:Script security]]&lt;br /&gt;
[[en:Script security]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Script_security&amp;diff=82697</id>
		<title>Script security</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Script_security&amp;diff=82697"/>
		<updated>2026-01-08T19:12:19Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Awareness of client memory==&lt;br /&gt;
&lt;br /&gt;
Starting from very basics:&lt;br /&gt;
* You should be aware that everything you store on client-side is at risk, this includes .lua files as well. Any confidential (and/or) important data which is stored, or travels through client-side (player PC) could be accessed by malicious clients.&lt;br /&gt;
* To keep sensitive data (and/or) Lua logic safe - use server-side.&lt;br /&gt;
* Do note that scripts marked as '''shared''' act also as '''client code''', which means that everything above applies to them. For example defining:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;script.lua&amp;quot; type=&amp;quot;shared&amp;quot;/&amp;gt; &amp;lt;!-- this script will run separately both on client and server --&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Is same as doing:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;script.lua&amp;quot; type=&amp;quot;client&amp;quot;/&amp;gt; &amp;lt;!-- define it separately on client --&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;script.lua&amp;quot; type=&amp;quot;server&amp;quot;/&amp;gt; &amp;lt;!-- do the same, but on server --&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Additional protection layer==&lt;br /&gt;
&lt;br /&gt;
In order to make things ''slightly harder*'' for those having bad intentions towards your server, you can make use of cache attribute (and/or [https://luac.mtasa.com/ Lua compile (also known as Luac) with extra obfuscation set to level '''3'''] - [https://wiki.multitheftauto.com/wiki/Lua_compilation_API API]) available in [https://wiki.multitheftauto.com/wiki/Meta.xml meta.xml], along with configuring MTA's built-in AC by toggling SD (Special detections), see: [https://wiki.multitheftauto.com/wiki/Anti-cheat_guide Anti-cheat guide].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;shared.lua&amp;quot; type=&amp;quot;shared&amp;quot; cache=&amp;quot;false&amp;quot;/&amp;gt; &amp;lt;!-- cache=&amp;quot;false&amp;quot; indicates that this Lua file won't be saved on player's PC --&amp;gt;&lt;br /&gt;
&amp;lt;script src=&amp;quot;client.lua&amp;quot; type=&amp;quot;client&amp;quot; cache=&amp;quot;false&amp;quot;/&amp;gt; &amp;lt;!-- cache=&amp;quot;false&amp;quot; indicates that this Lua file won't be saved on player's PC --&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* ''Slightly harder'' '''but not impossible''' for some to obtain client code, yet does good job at keeping '''most''' people away from inspecting your .lua files - those looking for possible logic flaws (bugs) or missing/incorrect security based checks.&lt;br /&gt;
* Can be used on both '''client''' and '''shared''' script type (has no effect on server-sided Lua).&lt;br /&gt;
* It doesn't remove Lua files which were previously downloaded.&lt;br /&gt;
&lt;br /&gt;
==Detecting and dealing with backdoors and cheats==&lt;br /&gt;
'''To ensure minimum (or no) damage resulting from Lua scripts:'''&lt;br /&gt;
* Keep your server up-to-date, you can [https://nightly.multitheftauto.com/ download latest server builds from MTA:SA nightly site.] Information on specific builds can be [https://buildinfo.multitheftauto.com/ found here.]&lt;br /&gt;
* Keep your resources up-to-date, you can [https://github.com/multitheftauto/mtasa-resources download latest (default) resources from GitHub repository.] Those often contain latest security fixes, which could mean difference between having your server resist from attack or not.&lt;br /&gt;
* Make sure to properly configure [https://wiki.multitheftauto.com/wiki/Access%20Control%20List ACL (Access Control List)] - which will block resources from using certain, potentially dangerous functions.&lt;br /&gt;
* Zero-trust with giving away admin rights for resources (including maps) coming from unknown sources.&lt;br /&gt;
* Before running any resource you don't trust, analyze:&lt;br /&gt;
** [https://wiki.multitheftauto.com/wiki/Meta.xml meta.xml] of it, for possible hidden scripts lurking beneath other file extensions.&lt;br /&gt;
** It's source code, for malicious logic.&lt;br /&gt;
* Do not run/keep using compiled resources (scripts) of which legitimacy you aren't sure.&lt;br /&gt;
&lt;br /&gt;
'''To ensure minimum damage when a cheater connects to your server:'''&lt;br /&gt;
* When making scripts, remember to never trust data coming from a client.&lt;br /&gt;
* While reviewing scripts for possible security holes. Look at any data coming from the client that is being trusted.&lt;br /&gt;
* Any kind of data could be sent, hence server scripts which communicate with client by receiving data sent by players should validate it, before further use in latter parts of code. Mostly, it will be done either by [[setElementData]] or [[triggerServerEvent]].&lt;br /&gt;
* You shouldn't rely only on player [https://wiki.multitheftauto.com/wiki/Serial serial], when it comes to processing crucial operations (auto-login/admin actions). '''Serials aren't guaranted to be unique or non-fakable'''. This is why you should '''put it behind''' account system, as '''important authentication factor''' (e.g: '''login &amp;amp; password''').&lt;br /&gt;
* Server-side logic '''can not be bypassed''' or '''tampered''' with (unless server is breached or when there is a bug in code, but that's whole different scenario) - '''use it to your advantage'''. In majority of cases, you will be able to perform security validations with no participation of client-side.&lt;br /&gt;
* Using concept of '''''“All parameters including source can be faked and should not be trusted. Global variable client can be trusted.”''''' - gives you reliable assurance that player to which you refer (via '''client''') '''is''' in fact, '''the one which really called event'''. This approach will protect you from situations where cheater can call &amp;amp; process for instance: admin events (e.g kick/ban player) by passing the actual admin ('''2nd''' argument in '''[[triggerServerEvent]]'''), or trigger events for other players (as if they were the ones who called them, but in reality it was forcefully done by cheater) - as a consequence of using wrong variable. To make sure you fully understood it, take a look at examples below:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
--[[&lt;br /&gt;
	DON'T EVER DO THAT - THAT IS COMPLETELY WRONG AND INSECURE&lt;br /&gt;
	THE ISSUE: BY USING 'source' IN hasObjectPermissionTo YOU ARE LEAVING DOOR STRAIGHT OPEN FOR CHEATERS&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
function onServerWrongAdminEvent(playerToBan)&lt;br /&gt;
	if (not client) then -- 'client' points to the player who triggered the event, and should be used as security measure (in order to prevent player faking)&lt;br /&gt;
		return false -- if this variable doesn't exists at the moment (for unknown reason, or it was the server who triggered this event), stop code execution&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local defaultPermission = false -- do not allow action by default, see (defaultPermission): https://wiki.multitheftauto.com/wiki/HasObjectPermissionTo&lt;br /&gt;
	local canAdminBanPlayer = hasObjectPermissionTo(source, &amp;quot;function.banPlayer&amp;quot;, defaultPermission) -- the vulnerability lies here...&lt;br /&gt;
&lt;br /&gt;
	if (not canAdminBanPlayer) then -- if player doesn't have permissions&lt;br /&gt;
		return false -- don't do it&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local validElement = isElement(playerToBan) -- check whether argument passed from client is an element&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then -- it is not&lt;br /&gt;
		return false -- stop code processing&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local elementType = getElementType(playerToBan) -- it's an element, so get it's type&lt;br /&gt;
	local playerType = (elementType == &amp;quot;player&amp;quot;) -- make sure that it's a player&lt;br /&gt;
&lt;br /&gt;
	if (not playerType) then -- it's not a player&lt;br /&gt;
		return false -- stop here&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- banPlayer(...) -- do what needs to be done&lt;br /&gt;
end&lt;br /&gt;
addEvent(&amp;quot;onServerWrongAdminEvent&amp;quot;, true)&lt;br /&gt;
addEventHandler(&amp;quot;onServerWrongAdminEvent&amp;quot;, root, onServerWrongAdminEvent)&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
	onServerCorrectAdminEvent IS PERFECTLY SECURED, AS IT SHOULD BE&lt;br /&gt;
	NO ISSUE HERE: WE'VE USED 'client' IN hasObjectPermissionTo WHICH MAKES IT SAFE FROM FAKING PLAYER WHO CALLED EVENT&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
function onServerCorrectAdminEvent(playerToBan)&lt;br /&gt;
	if (not client) then -- 'client' points to the player who triggered the event, and should be used as security measure (in order to prevent player faking)&lt;br /&gt;
		return false -- if this variable doesn't exists at the moment (for unknown reason, or it was the server who triggered this event), stop code execution&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local defaultPermission = false -- do not allow action by default, see (defaultPermission): https://wiki.multitheftauto.com/wiki/HasObjectPermissionTo&lt;br /&gt;
	local canAdminBanPlayer = hasObjectPermissionTo(client, &amp;quot;function.banPlayer&amp;quot;, defaultPermission) -- is player allowed to do that?&lt;br /&gt;
&lt;br /&gt;
	if (not canAdminBanPlayer) then -- if player doesn't have permissions&lt;br /&gt;
		return false -- don't do it&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local validElement = isElement(playerToBan) -- check whether argument passed from client is an element&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then -- it is not&lt;br /&gt;
		return false -- stop code processing&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local elementType = getElementType(playerToBan) -- it's an element, so get it's type&lt;br /&gt;
	local playerType = (elementType == &amp;quot;player&amp;quot;) -- make sure that it's a player&lt;br /&gt;
&lt;br /&gt;
	if (not playerType) then -- it's not a player&lt;br /&gt;
		return false -- stop here&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- banPlayer(...) -- do what needs to be done&lt;br /&gt;
end&lt;br /&gt;
addEvent(&amp;quot;onServerCorrectAdminEvent&amp;quot;, true)&lt;br /&gt;
addEventHandler(&amp;quot;onServerCorrectAdminEvent&amp;quot;, root, onServerCorrectAdminEvent)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Securing setElementData==&lt;br /&gt;
&lt;br /&gt;
* You should refrain from using [[element data]] everywhere, it should be only used when really necessary. It is advised to replace it with [[triggerClientEvent]] instead.&lt;br /&gt;
* If you still insist on using it, it is recommended to set '''4th''' argument in [[setElementData]] to '''false''' (disabling sync for this, certain data) and use subscriber mode - [[addElementDataSubscriber]], for both security &amp;amp; performance reasons described in [https://wiki.multitheftauto.com/wiki/Script_security#Securing_triggerServerEvent event section.]&lt;br /&gt;
{{Important Note|Disabling sync however, doesn't fully protect data key. It would be still vulnerable by default, but in this case you are not leaving it in plain sight. Using [[getAllElementData]] or digging in RAM wouldn't expose it, since it won't be synced to client in first place. Therefore, it needs to be added to anti-cheat as well.}} &lt;br /&gt;
* All parameters including '''source''' can be faked and should not be trusted.&lt;br /&gt;
* Global variable '''client''' can be trusted.&lt;br /&gt;
&lt;br /&gt;
----------&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
Example of basic element data anti-cheat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local function reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue) -- helper function to log and revert changes&lt;br /&gt;
	local logClient = inspect(clientElement) -- in-depth view of player which forced element data sync&lt;br /&gt;
	local logSerial = getPlayerSerial(clientElement) or &amp;quot;N/A&amp;quot; -- client serial, or &amp;quot;N/A&amp;quot; if not possible, for some reason&lt;br /&gt;
	local logSource = tostring(sourceElement) -- element which received data&lt;br /&gt;
	local logOldValue = tostring(oldValue) -- old value&lt;br /&gt;
	local logNewValue = tostring(newValue) -- new value&lt;br /&gt;
	local logText = -- fill our report with data&lt;br /&gt;
		&amp;quot;=======================================\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Detected element data abnormality:\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Client: &amp;quot;..logClient..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Client serial: &amp;quot;..logSerial..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Source: &amp;quot;..logSource..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Data key: &amp;quot;..dataKey..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Old data value: &amp;quot;..logOldValue..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;New data value: &amp;quot;..logNewValue..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;=======================================&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	local logVisibleTo = root -- specify who will see this log in console, in this case each player connected to server&lt;br /&gt;
	local hadData = (oldValue ~= nil) -- check if element had such data before&lt;br /&gt;
&lt;br /&gt;
	if (hadData) then -- if element had such data before&lt;br /&gt;
		setElementData(sourceElement, dataKey, oldValue, true) -- revert changes, it will call onElementDataChange event, but will fail (stop) on first condition - because server (not client) forced change&lt;br /&gt;
	else&lt;br /&gt;
		removeElementData(sourceElement, dataKey) -- remove it completely&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	outputConsole(logText, logVisibleTo) -- print it to console&lt;br /&gt;
&lt;br /&gt;
	return true -- all success&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onElementDataChangeBasicAC(dataKey, oldValue, newValue) -- the heart of our anti-cheat, which does all the magic security measurements&lt;br /&gt;
	if (not client) then -- check if data is coming from client&lt;br /&gt;
		return false -- if it's not, do not go further&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local checkSpecialThing = (dataKey == &amp;quot;special_thing&amp;quot;) -- compare whether dataKey matches &amp;quot;special_thing&amp;quot;&lt;br /&gt;
	local checkFlagWaving = (dataKey == &amp;quot;flag_waving&amp;quot;) -- compare whether dataKey matches &amp;quot;flag_waving&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	if (checkSpecialThing) then -- if it does, do our security checks&lt;br /&gt;
		local invalidElement = (client ~= source) -- verify whether source element is different from player which changed data&lt;br /&gt;
&lt;br /&gt;
		if (invalidElement) then -- if it's so&lt;br /&gt;
			reportAndRevertDataChange(client, source, dataKey, oldValue, newValue) -- revert data change, because &amp;quot;special_thing&amp;quot; can only be set for player himself&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (checkFlagWaving) then -- if it does, do our security checks&lt;br /&gt;
		local playerVehicle = getPedOccupiedVehicle(client) -- get player's current vehicle&lt;br /&gt;
		local invalidVehicle = (playerVehicle ~= source) -- verify whether source element is different from player's vehicle&lt;br /&gt;
&lt;br /&gt;
		if (invalidVehicle) then -- if it's so&lt;br /&gt;
			reportAndRevertDataChange(client, source, dataKey, oldValue, newValue) -- revert data change, because &amp;quot;flag_waving&amp;quot; can only be set for player's own vehicle&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onElementDataChange&amp;quot;, root, onElementDataChangeBasicAC)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
Example of advanced element data anti-cheat.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
--[[&lt;br /&gt;
	For maximum security set punishPlayerOnDetect, punishmentBan, allowOnlyProtectedKeys to true (as per default configuration)&lt;br /&gt;
	If allowOnlyProtectedKeys is enabled, do not forget to add every client-side element data key to protectedKeys table - otherwise you will face false-positives&lt;br /&gt;
&lt;br /&gt;
	Anti-cheat (handleDataChange) table structure and it's options:&lt;br /&gt;
&lt;br /&gt;
	[&amp;quot;keyName&amp;quot;] = { -- name of key which would be protected&lt;br /&gt;
		onlyForPlayerHimself = true, -- enabling this (true) will make sure that this element data key can only be set on player who synced it (ignores onlyForOwnPlayerVeh and allowForElements), use false/nil to disable this&lt;br /&gt;
		onlyForOwnPlayerVeh = false, -- enabling this (true) will make sure that this element data key can only be set on player's current vehicle who synced it (ignores allowForElements), use false/nil to disable this&lt;br /&gt;
		allowForElements = { -- restrict this key for certain element type(s), set to false/nil or leave it empty to not check this (full list of element types: https://wiki.multitheftauto.com/wiki/GetElementsByType)&lt;br /&gt;
			[&amp;quot;player&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;ped&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;vehicle&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;object&amp;quot;] = true,&lt;br /&gt;
		},&lt;br /&gt;
		allowedDataTypes = { -- restrict this key for certain value type(s), set to false/nil or leave it empty to not check this&lt;br /&gt;
			[&amp;quot;string&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;number&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;table&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;boolean&amp;quot;] = true,&lt;br /&gt;
			[&amp;quot;nil&amp;quot;] = true,&lt;br /&gt;
		},&lt;br /&gt;
		allowedStringLength = {1, 32}, -- if value is a string, then it's length must be in between (min-max), set it to false/nil to not check string length - do note that allowedDataTypes must contain [&amp;quot;string&amp;quot;] = true&lt;br /&gt;
		allowedTableLength = {1, 64}, -- if value is a table, then it's length must be in between (min-max), set it to false/nil to not check table length - do note that allowedDataTypes must contain [&amp;quot;table&amp;quot;] = true&lt;br /&gt;
		allowedNumberRange = {1, 128}, -- if value is a number, then it must be in between (min-max), set it to false/nil to not check number range - do note that allowedDataTypes must contain [&amp;quot;number&amp;quot;] = true&lt;br /&gt;
	}&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local punishPlayerOnDetect = true -- should player be punished upon detection (make sure that resource which runs this code has admin rights)&lt;br /&gt;
local punishmentBan = true -- only relevant if punishPlayerOnDetect is set to true; use true for ban or false for kick&lt;br /&gt;
local punishmentReason = &amp;quot;Altering element data&amp;quot; -- only relevant if punishPlayerOnDetect is set to true; reason which would be shown to punished player&lt;br /&gt;
local punishedBy = &amp;quot;Console&amp;quot; -- only relevant if punishPlayerOnDetect is set to true; who was responsible for punishing, as well shown to punished player&lt;br /&gt;
local banByIP = false -- only relevant if punishPlayerOnDetect and punishmentBan is set to true; banning by IP nowadays is not recommended (...)&lt;br /&gt;
local banByUsername = false -- community username - legacy thing, hence is set to false and should stay like that&lt;br /&gt;
local banBySerial = true -- only relevant if punishPlayerOnDetect and punishmentBan is set to true; (...) if there is a player serial to use instead&lt;br /&gt;
local banTime = 0 -- only relevant if punishPlayerOnDetect and punishmentBan is set to true; time in seconds, 0 for permanent&lt;br /&gt;
local allowOnlyProtectedKeys = true -- disallow (remove by using removeElementData) every element data besides those given in protectedKeys table; in case someone wanted to flood server with garbage keys, which would be kept in memory until server restart or manual remove - setElementData(source, key, nil) won't remove it; it has to be removeElementData&lt;br /&gt;
local debugLevel = 4 -- this debug level allows to hide INFO: prefix, and use custom colors&lt;br /&gt;
local debugR = 255 -- debug message - red color&lt;br /&gt;
local debugG = 127 -- debug message - green color&lt;br /&gt;
local debugB = 0 -- debug message - blue color&lt;br /&gt;
local protectedKeys = {&lt;br /&gt;
	[&amp;quot;vehicleNumber&amp;quot;] = { -- we want vehicleNumber to be set only on vehicles, with stricte numbers in range of 1-100&lt;br /&gt;
		allowForElements = {&lt;br /&gt;
			[&amp;quot;vehicle&amp;quot;] = true,&lt;br /&gt;
		},&lt;br /&gt;
		allowedDataTypes = {&lt;br /&gt;
			[&amp;quot;number&amp;quot;] = true,&lt;br /&gt;
		},&lt;br /&gt;
		allowedNumberRange = {1, 100},&lt;br /&gt;
	},&lt;br /&gt;
	[&amp;quot;personalVehData&amp;quot;] = { -- we want be able to set personalVehData only on current vehicle, also it should be a string with length between 1-24&lt;br /&gt;
		onlyForOwnPlayerVeh = true,&lt;br /&gt;
		allowedDataTypes = {&lt;br /&gt;
			[&amp;quot;string&amp;quot;] = true,&lt;br /&gt;
		},&lt;br /&gt;
		allowedStringLength = {1, 24},&lt;br /&gt;
	},&lt;br /&gt;
	-- perform security checks on keys stored in this table, in a convenient way&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local function reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- helper function to log and revert changes&lt;br /&gt;
	local logClient = inspect(clientElement) -- in-depth view of player which forced element data sync&lt;br /&gt;
	local logSerial = getPlayerSerial(clientElement) or &amp;quot;N/A&amp;quot; -- client serial, or &amp;quot;N/A&amp;quot; if not possible, for some reason&lt;br /&gt;
	local logSource = inspect(sourceElement) -- in-depth view of element which received data&lt;br /&gt;
	local logOldValue = inspect(oldValue) -- in-depth view of old value&lt;br /&gt;
	local logNewValue = inspect(newValue) -- in-depth view of new value&lt;br /&gt;
	local logText = -- fill our report with data&lt;br /&gt;
		&amp;quot;*\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Detected element data abnormality:\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Client: &amp;quot;..logClient..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Client serial: &amp;quot;..logSerial..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Source: &amp;quot;..logSource..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Data key: &amp;quot;..dataKey..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Old data value: &amp;quot;..logOldValue..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;New data value: &amp;quot;..logNewValue..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Fail reason: &amp;quot;..failReason..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;*&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	outputDebugString(logText, debugLevel, debugR, debugG, debugB) -- print it to debug&lt;br /&gt;
&lt;br /&gt;
	if (forceRemove) then -- we don't want this element data key to exist at all&lt;br /&gt;
		removeElementData(sourceElement, dataKey) -- remove it&lt;br /&gt;
&lt;br /&gt;
		return true -- return success and stop here, we don't need further checks&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	setElementData(sourceElement, dataKey, oldValue, true) -- revert changes, it will call onElementDataChange event, but will fail (stop) on first condition - because server (not client) forced change&lt;br /&gt;
&lt;br /&gt;
	return true -- return success&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function handleDataChange(clientElement, sourceElement, dataKey, oldValue, newValue) -- the heart of our anti-cheat, which does all the magic security measurements, returns true if there was no altering from client (based on data from protectedKeys), false otherwise&lt;br /&gt;
	local protectedKey = protectedKeys[dataKey] -- look up whether key changed is stored in protectedKeys table&lt;br /&gt;
&lt;br /&gt;
	if (not protectedKey) then -- if it's not&lt;br /&gt;
&lt;br /&gt;
		if (allowOnlyProtectedKeys) then -- if we don't want garbage keys&lt;br /&gt;
			local failReason = &amp;quot;Key isn't present in protectedKeys&amp;quot; -- reason shown in report&lt;br /&gt;
			local forceRemove = true -- should key be completely removed&lt;br /&gt;
&lt;br /&gt;
			reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
			return false -- return failure&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return true -- this key isn't protected, let it through&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local onlyForPlayerHimself = protectedKey.onlyForPlayerHimself -- if key has &amp;quot;self-set&amp;quot; lock&lt;br /&gt;
	local onlyForOwnPlayerVeh = protectedKey.onlyForOwnPlayerVeh -- if key has &amp;quot;self-vehicle&amp;quot; lock&lt;br /&gt;
	local allowForElements = protectedKey.allowForElements -- if key has element type check&lt;br /&gt;
	local allowedDataTypes = protectedKey.allowedDataTypes -- if key has allowed data type check&lt;br /&gt;
&lt;br /&gt;
	if (onlyForPlayerHimself) then -- if &amp;quot;self-set&amp;quot; lock is active&lt;br /&gt;
		local matchingElement = (clientElement == sourceElement) -- verify whether player who set data is equal to element which received data&lt;br /&gt;
&lt;br /&gt;
		if (not matchingElement) then -- if it's not matching&lt;br /&gt;
			local failReason = &amp;quot;Can only set on player himself&amp;quot; -- reason shown in report&lt;br /&gt;
			local forceRemove = false -- should key be completely removed&lt;br /&gt;
&lt;br /&gt;
			reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
			return false -- return failure&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (onlyForOwnPlayerVeh) then -- if &amp;quot;self-vehicle&amp;quot; lock is active&lt;br /&gt;
		local playerVehicle = getPedOccupiedVehicle(clientElement) -- get current vehicle of player which set data&lt;br /&gt;
		local matchingVehicle = (playerVehicle == sourceElement) -- check whether it matches the one which received data&lt;br /&gt;
&lt;br /&gt;
		if (not matchingVehicle) then -- if it doesn't match&lt;br /&gt;
			local failReason = &amp;quot;Can only set on player's own vehicle&amp;quot; -- reason shown in report&lt;br /&gt;
			local forceRemove = false -- should key be completely removed&lt;br /&gt;
&lt;br /&gt;
			reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
			return false -- return failure&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (allowForElements) then -- check if it's one of them&lt;br /&gt;
		local elementType = getElementType(sourceElement) -- get type of element whose data changed&lt;br /&gt;
		local matchingElementType = allowForElements[elementType] -- verify whether it's allowed&lt;br /&gt;
&lt;br /&gt;
		if (not matchingElementType) then -- this isn't matching&lt;br /&gt;
			local failReason = &amp;quot;Invalid element type&amp;quot; -- reason shown in report&lt;br /&gt;
			local forceRemove = false -- should key be completely removed&lt;br /&gt;
&lt;br /&gt;
			reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
			return false -- return failure&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (allowedDataTypes) then -- if there's allowed data types&lt;br /&gt;
		local valueType = type(newValue) -- get data type of value&lt;br /&gt;
		local matchingType = allowedDataTypes[valueType] -- check if it's one of allowed&lt;br /&gt;
&lt;br /&gt;
		if (not matchingType) then -- if it's not then&lt;br /&gt;
			local failReason = &amp;quot;Invalid data type&amp;quot; -- reason shown in report&lt;br /&gt;
			local forceRemove = false -- should key be completely removed&lt;br /&gt;
&lt;br /&gt;
			reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
			return false -- return failure&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local allowedStringLength = protectedKey.allowedStringLength -- if key has specified string length check&lt;br /&gt;
		local dataString = (valueType == &amp;quot;string&amp;quot;) -- make sure it's a string&lt;br /&gt;
&lt;br /&gt;
		if (allowedStringLength and dataString) then -- if we should check string length&lt;br /&gt;
			local minLength = allowedStringLength[1] -- retrieve min length&lt;br /&gt;
			local maxLength = allowedStringLength[2] -- retrieve max length&lt;br /&gt;
			local stringLength = utf8.len(newValue) -- get length of data string&lt;br /&gt;
			local matchingLength = (stringLength &amp;gt;= minLength) and (stringLength &amp;lt;= maxLength) -- compare whether value fits in between&lt;br /&gt;
&lt;br /&gt;
			if (not matchingLength) then -- if it doesn't&lt;br /&gt;
				local failReason = &amp;quot;Invalid string length (must be between &amp;quot;..minLength..&amp;quot;-&amp;quot;..maxLength..&amp;quot;)&amp;quot; -- reason shown in report&lt;br /&gt;
				local forceRemove = false -- should key be completely removed&lt;br /&gt;
&lt;br /&gt;
				reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
				return false -- return failure&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local allowedTableLength = protectedKey.allowedTableLength -- if key has table length check&lt;br /&gt;
		local dataTable = (valueType == &amp;quot;table&amp;quot;) -- make sure it's a table&lt;br /&gt;
&lt;br /&gt;
		if (allowedTableLength and dataTable) then -- if we should check table length&lt;br /&gt;
			local minLength = allowedTableLength[1] -- retrieve min length&lt;br /&gt;
			local maxLength = allowedTableLength[2] -- retrieve max length&lt;br /&gt;
			local minLengthAchieved = false -- variable which checks 'does minimum length was achieved'&lt;br /&gt;
			local maxLengthExceeded = false -- variable which checks 'does length has exceeds more than allowed maximum'&lt;br /&gt;
			local tableLength = 0 -- store initial table length&lt;br /&gt;
&lt;br /&gt;
			for _, _ in pairs(newValue) do -- loop through whole table&lt;br /&gt;
				tableLength = (tableLength + 1) -- add + 1 on each table entry&lt;br /&gt;
				minLengthAchieved = (tableLength &amp;gt;= minLength) -- is length bigger or at very minimum we require&lt;br /&gt;
				maxLengthExceeded = (tableLength &amp;gt; maxLength) -- does table exceeded more than max length?&lt;br /&gt;
&lt;br /&gt;
				if (maxLengthExceeded) then -- it is bigger than it should be&lt;br /&gt;
					break -- break the loop (due of condition above being worthy, it makes no point to count further and waste CPU, on a table which potentially could have huge amount of entries)&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			local matchingLength = (minLengthAchieved and not maxLengthExceeded) -- check if min length has been achieved, and make sure that it doesn't go beyond max length&lt;br /&gt;
&lt;br /&gt;
			if (not matchingLength) then -- this table doesn't match requirements&lt;br /&gt;
				local failReason = &amp;quot;Invalid table length (must be between &amp;quot;..minLength..&amp;quot;-&amp;quot;..maxLength..&amp;quot;)&amp;quot; -- reason shown in report&lt;br /&gt;
				local forceRemove = false -- should key be completely removed&lt;br /&gt;
&lt;br /&gt;
				reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
				return false -- return failure&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local allowedNumberRange = protectedKey.allowedNumberRange -- if key has allowed number range check&lt;br /&gt;
		local dataNumber = (valueType == &amp;quot;number&amp;quot;) -- make sure it's a number&lt;br /&gt;
&lt;br /&gt;
		if (allowedNumberRange and dataNumber) then -- if we should check number range&lt;br /&gt;
			local minRange = allowedNumberRange[1] -- retrieve min number range&lt;br /&gt;
			local maxRange = allowedNumberRange[2] -- retrieve max number range&lt;br /&gt;
			local matchingRange = (newValue &amp;gt;= minRange) and (newValue &amp;lt;= maxRange) -- compare whether value fits in between&lt;br /&gt;
&lt;br /&gt;
			if (not matchingRange) then -- if it doesn't&lt;br /&gt;
				local failReason = &amp;quot;Invalid number range (must be between &amp;quot;..minRange..&amp;quot;-&amp;quot;..maxRange..&amp;quot;)&amp;quot; -- reason shown in report&lt;br /&gt;
				local forceRemove = false -- should key be completely removed&lt;br /&gt;
&lt;br /&gt;
				reportAndRevertDataChange(clientElement, sourceElement, dataKey, oldValue, newValue, failReason, forceRemove) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
				return false -- return failure&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return true -- security checks passed, we are all clear with this data key&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onElementDataChangeAdvancedAC(dataKey, oldValue, newValue) -- this event makes use of handleDataChange, the code was split for better readability&lt;br /&gt;
	if (not client) then -- check if data is coming from client&lt;br /&gt;
		return false -- if it's not, do not continue&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local approvedChange = handleDataChange(client, source, dataKey, oldValue, newValue) -- run our security checks&lt;br /&gt;
&lt;br /&gt;
	if (approvedChange) then -- it's all cool and good&lt;br /&gt;
		return false -- we don't need further action&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (not punishPlayerOnDetect) then -- we don't want to punish player for some reason&lt;br /&gt;
		return false -- so stop here&lt;br /&gt;
	end&lt;br /&gt;
		&lt;br /&gt;
	if (punishmentBan) then -- if it's ban&lt;br /&gt;
		banPlayer(client, banByIP, banByUsername, banBySerial, punishedBy, punishmentReason, banTime) -- remove his presence from server&lt;br /&gt;
	else -- otherwise&lt;br /&gt;
		kickPlayer(client, punishedBy, punishmentReason) -- simply kick player out of server&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onElementDataChange&amp;quot;, root, onElementDataChangeAdvancedAC)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Securing triggerServerEvent==&lt;br /&gt;
&lt;br /&gt;
* All parameters including '''source''' can be faked and should not be trusted.&lt;br /&gt;
* Global variable '''client''' can be trusted.&lt;br /&gt;
* '''Admin''' styled '''events''' should be verifying player (client) '''ACL rights''', either by [https://wiki.multitheftauto.com/wiki/IsObjectInACLGroup isObjectInACLGroup] or [https://wiki.multitheftauto.com/wiki/HasObjectPermissionTo hasObjectPermissionTo].&lt;br /&gt;
* Do '''not''' use the same name for your custom event as MTA native server events (which aren't remotely triggerable by default), e.g: '''onPlayerLogin'''; doing so would open door for cheaters manipulations.&lt;br /&gt;
* Be aware to which players event is sent via [[triggerClientEvent]]. For both security &amp;amp; performance reasons, admin like events should be received by admins only (to prevent confidential data being accessed), in the same time you shouldn't send each event to everyone on server (e.g: login success event which hides login panel for certain player). [[triggerClientEvent]] allows you to specify the event receiver as first (optional) argument. It defaults to [[root]], meaning if you don't specify it, it will be sent to everyone connected to server - even those who are still downloading server cache (which results in ''Server triggered clientside event eventName, but event is not added clientside.''). You can either pass player element or table with receivers:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local playersToReceiveEvent = {player1, player2, player3} -- each playerX is player element&lt;br /&gt;
&lt;br /&gt;
triggerClientEvent(playersToReceiveEvent, ...) -- do not forget to fill the latter part of arguments&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----------&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
Example of anti-cheat function designed for events, used for data validation for both normal, and admin events which are called from client-side.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
--[[&lt;br /&gt;
	For maximum security set punishPlayerOnDetect, punishmentBan to true (as per default configuration)&lt;br /&gt;
&lt;br /&gt;
	Anti-cheat (processServerEventData) table structure and it's options:&lt;br /&gt;
&lt;br /&gt;
	checkACLGroup = { -- check whether player who called event belongs to at least one group below, set to false/nil to not check this&lt;br /&gt;
		&amp;quot;Admin&amp;quot;,&lt;br /&gt;
	},&lt;br /&gt;
	checkPermissions = { -- check whether player who called event has permission to at least one thing below, set to false/nil to not check this&lt;br /&gt;
		&amp;quot;function.kickPlayer&amp;quot;,&lt;br /&gt;
	},&lt;br /&gt;
	checkEventData = {&lt;br /&gt;
		{&lt;br /&gt;
			debugData = &amp;quot;source&amp;quot;, -- optional details for report shown in debug message&lt;br /&gt;
			eventData = source, -- data we want to verify&lt;br /&gt;
			equalTo = client, -- compare whether eventData == equalTo&lt;br /&gt;
			allowedElements = { -- restrict eventData to be certain element type(s), set to false/nil or leave it empty to not check this (full list of element types: https://wiki.multitheftauto.com/wiki/GetElementsByType)&lt;br /&gt;
				[&amp;quot;player&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;ped&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;vehicle&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;object&amp;quot;] = true,&lt;br /&gt;
			},&lt;br /&gt;
			allowedDataTypes = { -- restrict eventData to be certain value type(s), set to false/nil or leave it empty to not check this&lt;br /&gt;
				[&amp;quot;string&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;number&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;table&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;boolean&amp;quot;] = true,&lt;br /&gt;
				[&amp;quot;nil&amp;quot;] = true,&lt;br /&gt;
			},&lt;br /&gt;
			allowedStringLength = {1, 32}, -- if eventData is a string, then it's length must be in between (min-max), set it to false/nil to not check string length - do note that allowedDataTypes must contain [&amp;quot;string&amp;quot;] = true&lt;br /&gt;
			allowedTableLength = {1, 64}, -- if eventData is a table, then it's length must be in between (min-max), set it to false/nil to not check table length - do note that allowedDataTypes must contain [&amp;quot;table&amp;quot;] = true&lt;br /&gt;
			allowedNumberRange = {1, 128}, -- if eventData is a number, then it must be in between (min-max), set it to false/nil to not check number range - do note that allowedDataTypes must contain [&amp;quot;number&amp;quot;] = true&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
]]&lt;br /&gt;
&lt;br /&gt;
local punishPlayerOnDetect = true -- should player be punished upon detection (make sure that resource which runs this code has admin rights)&lt;br /&gt;
local punishmentBan = true -- only relevant if punishPlayerOnDetect is set to true; use true for ban or false for kick&lt;br /&gt;
local punishmentReason = &amp;quot;Altering server event data&amp;quot; -- only relevant if punishPlayerOnDetect is set to true; reason which would be shown to punished player&lt;br /&gt;
local punishedBy = &amp;quot;Console&amp;quot; -- only relevant if punishPlayerOnDetect is set to true; who was responsible for punishing, as well shown to punished player&lt;br /&gt;
local banByIP = false -- only relevant if punishPlayerOnDetect and punishmentBan is set to true; banning by IP nowadays is not recommended (...)&lt;br /&gt;
local banByUsername = false -- community username - legacy thing, hence is set to false and should stay like that&lt;br /&gt;
local banBySerial = true -- only relevant if punishPlayerOnDetect and punishmentBan is set to true; (...) if there is a player serial to use instead&lt;br /&gt;
local banTime = 0 -- only relevant if punishPlayerOnDetect and punishmentBan is set to true; time in seconds, 0 for permanent&lt;br /&gt;
local debugLevel = 4 -- this debug level allows to hide INFO: prefix, and use custom colors&lt;br /&gt;
local debugR = 255 -- debug message - red color&lt;br /&gt;
local debugG = 127 -- debug message - green color&lt;br /&gt;
local debugB = 0 -- debug message - blue color&lt;br /&gt;
&lt;br /&gt;
function processServerEventData(clientElement, sourceElement, serverEvent, securityChecks) -- the heart of our anti-cheat, which does all the magic security measurements, returns true if there was no altering from client (based on data from securityChecks), false otherwise&lt;br /&gt;
	if (not securityChecks) then -- if we haven't passed any security checks&lt;br /&gt;
		return true -- nothing to check, let code go further&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	if (not clientElement) then -- if client variable isn't available for some reason (although it should never happen)&lt;br /&gt;
		local failReason = &amp;quot;Client variable not present&amp;quot; -- reason shown in report&lt;br /&gt;
		local skipPunishment = true -- should server skip punishment&lt;br /&gt;
&lt;br /&gt;
		reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
		return false -- return failure&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local checkACLGroup = securityChecks.checkACLGroup -- if there's any ACL groups to check&lt;br /&gt;
	local checkPermissions = securityChecks.checkPermissions -- if there's any permissions to check&lt;br /&gt;
	local checkEventData = securityChecks.checkEventData -- if there's any data checks&lt;br /&gt;
&lt;br /&gt;
	if (checkACLGroup) then -- let's check player ACL groups&lt;br /&gt;
		local playerAccount = getPlayerAccount(clientElement) -- get current account of player&lt;br /&gt;
		local guestAccount = isGuestAccount(playerAccount) -- if account is guest (meaning player is not logged in)&lt;br /&gt;
&lt;br /&gt;
		if (guestAccount) then -- it's the case&lt;br /&gt;
			local failReason = &amp;quot;Can't retrieve player login - guest account&amp;quot; -- reason shown in report&lt;br /&gt;
			local skipPunishment = true -- should server skip punishment&lt;br /&gt;
&lt;br /&gt;
			reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
			return false -- return failure&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local accountName = getAccountName(playerAccount) -- get name of player's current account&lt;br /&gt;
		local aclString = &amp;quot;user.&amp;quot;..accountName -- format it for further use in isObjectInACLGroup function&lt;br /&gt;
&lt;br /&gt;
		for groupID = 1, #checkACLGroup do -- iterate over table of given groups&lt;br /&gt;
			local groupName = checkACLGroup[groupID] -- get each group name&lt;br /&gt;
			local aclGroup = aclGetGroup(groupName) -- check if such group exists&lt;br /&gt;
&lt;br /&gt;
			if (not aclGroup) then -- it doesn't&lt;br /&gt;
				local failReason = &amp;quot;ACL group '&amp;quot;..groupName..&amp;quot;' is missing&amp;quot; -- reason shown in report&lt;br /&gt;
				local skipPunishment = true -- should server skip punishment&lt;br /&gt;
&lt;br /&gt;
				reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
				return false -- return failure&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			local playerInACLGroup = isObjectInACLGroup(aclString, aclGroup) -- check if player belong to the group&lt;br /&gt;
&lt;br /&gt;
			if (playerInACLGroup) then -- yep, it's the case&lt;br /&gt;
				return true -- so it's a success&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local failReason = &amp;quot;Player doesn't belong to any given ACL group&amp;quot; -- reason shown in report&lt;br /&gt;
		local skipPunishment = true -- should server skip punishment&lt;br /&gt;
&lt;br /&gt;
		reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
		return false -- return failure&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (checkPermissions) then -- check if player has at least one desired permission&lt;br /&gt;
		local allowedByDefault = false -- does he have access by default&lt;br /&gt;
&lt;br /&gt;
		for permissionID = 1, #checkPermissions do -- iterate over all permissions&lt;br /&gt;
			local permissionName = checkPermissions[permissionID] -- get permission name&lt;br /&gt;
			local hasPermission = hasObjectPermissionTo(clientElement, permissionName, allowedByDefault) -- check whether player is allowed to perform certain action&lt;br /&gt;
&lt;br /&gt;
			if (hasPermission) then -- if player has access&lt;br /&gt;
				return true -- one is available (and enough), server won't bother to check others (as return keywords also breaks loop)&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local failReason = &amp;quot;Not enough permissions&amp;quot; -- reason shown in report&lt;br /&gt;
		local skipPunishment = true -- should server skip punishment&lt;br /&gt;
&lt;br /&gt;
		reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
		return false -- return failure&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	if (checkEventData) then -- if there is some data to verify&lt;br /&gt;
&lt;br /&gt;
		for dataID = 1, #checkEventData do -- iterate over each of data&lt;br /&gt;
			local dataToCheck = checkEventData[dataID] -- get each data set&lt;br /&gt;
			local eventData = dataToCheck.eventData -- this is the one we'll be verifying&lt;br /&gt;
			local equalTo = dataToCheck.equalTo -- we want to compare whether eventData == equalTo&lt;br /&gt;
			local allowedElements = dataToCheck.allowedElements -- check whether is element, and whether belongs to certain element types&lt;br /&gt;
			local allowedDataTypes = dataToCheck.allowedDataTypes -- do we restrict data to be certain type?&lt;br /&gt;
			local debugData = dataToCheck.debugData -- additional helper data&lt;br /&gt;
			local debugText = debugData and &amp;quot; (&amp;quot;..debugData..&amp;quot;)&amp;quot; or &amp;quot;&amp;quot; -- if it's present, format it nicely&lt;br /&gt;
&lt;br /&gt;
			if (equalTo) then -- equal check exists&lt;br /&gt;
				local matchingData = (eventData == equalTo) -- compare whether those two values are equal&lt;br /&gt;
&lt;br /&gt;
				if (not matchingData) then -- they aren't&lt;br /&gt;
					local failReason = &amp;quot;Data isn't equal @ argument &amp;quot;..dataID..debugText -- reason shown in report&lt;br /&gt;
					local skipPunishment = false -- should server skip punishment&lt;br /&gt;
&lt;br /&gt;
					reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
					return false -- return failure&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			if (allowedElements) then -- we do check whether is an element, and belongs to at least one given in the list&lt;br /&gt;
				local validElement = isElement(eventData) -- check if it's actual element&lt;br /&gt;
&lt;br /&gt;
				if (not validElement) then -- it's not&lt;br /&gt;
					local failReason = &amp;quot;Data isn't element @ argument &amp;quot;..dataID..debugText -- reason shown in report&lt;br /&gt;
					local skipPunishment = false -- should server skip punishment&lt;br /&gt;
&lt;br /&gt;
					reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
					return false -- return failure&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local elementType = getElementType(eventData) -- it's element, so we want to know it's type&lt;br /&gt;
				local matchingElementType = allowedElements[elementType] -- verify whether it's allowed&lt;br /&gt;
&lt;br /&gt;
				if (not matchingElementType) then -- it's not allowed&lt;br /&gt;
					local failReason = &amp;quot;Invalid element type @ argument &amp;quot;..dataID..debugText -- reason shown in report&lt;br /&gt;
					local skipPunishment = false -- should server skip punishment&lt;br /&gt;
&lt;br /&gt;
					reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
					return false -- return failure&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			if (allowedDataTypes) then -- let's check allowed data types&lt;br /&gt;
				local dataType = type(eventData) -- get data type&lt;br /&gt;
				local matchingType = allowedDataTypes[dataType] -- verify whether it's allowed&lt;br /&gt;
&lt;br /&gt;
				if (not matchingType) then -- it isn't&lt;br /&gt;
					local failReason = &amp;quot;Invalid data type @ argument &amp;quot;..dataID..debugText -- reason shown in report&lt;br /&gt;
					local skipPunishment = false -- should server skip punishment&lt;br /&gt;
&lt;br /&gt;
					reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
					return false -- return failure&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local allowedStringLength = dataToCheck.allowedStringLength -- if data has string length check&lt;br /&gt;
				local dataString = (dataType == &amp;quot;string&amp;quot;) -- make sure it's a string&lt;br /&gt;
&lt;br /&gt;
				if (allowedStringLength and dataString) then -- if we should check string length&lt;br /&gt;
					local minLength = allowedStringLength[1] -- retrieve min length&lt;br /&gt;
					local maxLength = allowedStringLength[2] -- retrieve max length&lt;br /&gt;
					local stringLength = utf8.len(eventData) -- get length of data string&lt;br /&gt;
					local matchingLength = (stringLength &amp;gt;= minLength) and (stringLength &amp;lt;= maxLength) -- compare whether value fits in between&lt;br /&gt;
&lt;br /&gt;
					if (not matchingLength) then -- if it doesn't&lt;br /&gt;
						local failReason = &amp;quot;Invalid string length (must be between &amp;quot;..minLength..&amp;quot;-&amp;quot;..maxLength..&amp;quot;) @ argument &amp;quot;..dataID..debugText -- reason shown in report&lt;br /&gt;
						local skipPunishment = false -- should server skip punishment&lt;br /&gt;
&lt;br /&gt;
						reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
						return false -- return failure&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local allowedTableLength = dataToCheck.allowedTableLength -- if data has table length check&lt;br /&gt;
				local dataTable = (dataType == &amp;quot;table&amp;quot;) -- make sure it's a table&lt;br /&gt;
&lt;br /&gt;
				if (allowedTableLength and dataTable) then -- if we should check table length&lt;br /&gt;
					local minLength = allowedTableLength[1] -- retrieve min length&lt;br /&gt;
					local maxLength = allowedTableLength[2] -- retrieve max length&lt;br /&gt;
					local minLengthAchieved = false -- variable which checks 'does minimum length was achieved'&lt;br /&gt;
					local maxLengthExceeded = false -- variable which checks 'does length has exceeds more than allowed maximum'&lt;br /&gt;
					local tableLength = 0 -- store initial table length&lt;br /&gt;
&lt;br /&gt;
					for _, _ in pairs(eventData) do -- loop through whole table&lt;br /&gt;
						tableLength = (tableLength + 1) -- add + 1 on each table entry&lt;br /&gt;
						minLengthAchieved = (tableLength &amp;gt;= minLength) -- is length bigger or at very minimum we require&lt;br /&gt;
						maxLengthExceeded = (tableLength &amp;gt; maxLength) -- does table exceeded more than max length?&lt;br /&gt;
&lt;br /&gt;
						if (maxLengthExceeded) then -- it is bigger than it should be&lt;br /&gt;
							break -- break the loop (due of condition above being worthy, it makes no point to count further and waste CPU, on a table which potentially could have huge amount of entries)&lt;br /&gt;
						end&lt;br /&gt;
					end&lt;br /&gt;
&lt;br /&gt;
					local matchingLength = (minLengthAchieved and not maxLengthExceeded) -- check if min length has been achieved, and make sure that it doesn't go beyond max length&lt;br /&gt;
&lt;br /&gt;
					if (not matchingLength) then -- this table doesn't match requirements&lt;br /&gt;
						local failReason = &amp;quot;Invalid table length (must be between &amp;quot;..minLength..&amp;quot;-&amp;quot;..maxLength..&amp;quot;) @ argument &amp;quot;..dataID..debugText -- reason shown in report&lt;br /&gt;
						local skipPunishment = false -- should server skip punishment&lt;br /&gt;
&lt;br /&gt;
						reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
						return false -- return failure&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
&lt;br /&gt;
				local allowedNumberRange = dataToCheck.allowedNumberRange -- if data has number range check&lt;br /&gt;
				local dataNumber = (dataType == &amp;quot;number&amp;quot;) -- make sure it's a number&lt;br /&gt;
&lt;br /&gt;
				if (allowedNumberRange and dataNumber) then -- if we should check number range&lt;br /&gt;
					local minRange = allowedNumberRange[1] -- retrieve min number range&lt;br /&gt;
					local maxRange = allowedNumberRange[2] -- retrieve max number range&lt;br /&gt;
					local matchingRange = (eventData &amp;gt;= minRange) and (eventData &amp;lt;= maxRange) -- compare whether value fits in between&lt;br /&gt;
&lt;br /&gt;
					if (not matchingRange) then -- if it doesn't&lt;br /&gt;
						local failReason = &amp;quot;Invalid number range (must be between &amp;quot;..minRange..&amp;quot;-&amp;quot;..maxRange..&amp;quot;) @ argument &amp;quot;..dataID..debugText -- reason shown in report&lt;br /&gt;
						local skipPunishment = false -- should server skip punishment&lt;br /&gt;
&lt;br /&gt;
						reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- report accident, and handle (or not) this player&lt;br /&gt;
&lt;br /&gt;
						return false -- return failure&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return true -- security checks passed, we are all clear with this event call&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function reportAndHandleEventAbnormality(clientElement, sourceElement, serverEvent, failReason, skipPunishment) -- helper function to log and handle accidents&lt;br /&gt;
	local logClient = inspect(clientElement) -- in-depth view player which called event&lt;br /&gt;
	local logSerial = getPlayerSerial(clientElement) or &amp;quot;N/A&amp;quot; -- client serial, or &amp;quot;N/A&amp;quot; if not possible, for some reason&lt;br /&gt;
	local logSource = inspect(sourceElement) -- in-depth view of source element&lt;br /&gt;
	local logText = -- fill our report with data&lt;br /&gt;
		&amp;quot;*\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Detected event abnormality:\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Client: &amp;quot;..logClient..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Client serial: &amp;quot;..logSerial..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Source: &amp;quot;..logSource..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Event: &amp;quot;..serverEvent..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Reason: &amp;quot;..failReason..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;*&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	outputDebugString(logText, debugLevel, debugR, debugG, debugB) -- print it to debug&lt;br /&gt;
&lt;br /&gt;
	if (not punishPlayerOnDetect or skipPunishment) then -- we don't want to punish player for some reason&lt;br /&gt;
		return true -- stop here&lt;br /&gt;
	end&lt;br /&gt;
		&lt;br /&gt;
	if (punishmentBan) then -- if it's ban&lt;br /&gt;
		banPlayer(clientElement, banByIP, banByUsername, banBySerial, punishedBy, punishmentReason, banTime) -- remove his presence from server&lt;br /&gt;
	else -- otherwise&lt;br /&gt;
		kickPlayer(clientElement, punishedBy, punishmentReason) -- simply kick player out of server&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return true -- all done, report success&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onServerEvent(clientData)&lt;br /&gt;
	--[[&lt;br /&gt;
		Assume this server event (function) is called in such way:&lt;br /&gt;
&lt;br /&gt;
		local dataToPass = 10&lt;br /&gt;
&lt;br /&gt;
		triggerServerEvent(&amp;quot;onServerEvent&amp;quot;, localPlayer, dataToPass)&lt;br /&gt;
	]]&lt;br /&gt;
&lt;br /&gt;
	local shouldProcessServerCode = processServerEventData(&lt;br /&gt;
		client, -- client element - responsible for calling event&lt;br /&gt;
		source, -- source element - passed in triggerServerEvent (as 2nd argument)&lt;br /&gt;
		eventName, -- name of event - in this case 'onServerEvent'&lt;br /&gt;
		{&lt;br /&gt;
			checkEventData = { -- we want to verify everything what comes from client&lt;br /&gt;
				{&lt;br /&gt;
					eventData = source, -- first to check, source variable&lt;br /&gt;
					equalTo = client, -- we want to check whether it matches player who called event&lt;br /&gt;
					debugData = &amp;quot;source&amp;quot;, -- helper details which would be shown in report&lt;br /&gt;
				},&lt;br /&gt;
				{&lt;br /&gt;
					eventData = clientData, -- let's check the data which client sent to us&lt;br /&gt;
					allowedDataTypes = {&lt;br /&gt;
						[&amp;quot;number&amp;quot;] = true, -- we want it to be only number&lt;br /&gt;
					},&lt;br /&gt;
					allowedNumberRange = {1, 100}, -- in range of 1 to 100&lt;br /&gt;
					debugData = &amp;quot;clientData&amp;quot;, -- if something goes wrong, let server know where (it will appear in debug report)&lt;br /&gt;
				},&lt;br /&gt;
			},&lt;br /&gt;
		}&lt;br /&gt;
	)&lt;br /&gt;
&lt;br /&gt;
	if (not shouldProcessServerCode) then -- something isn't right, no green light for processing code behind this scope&lt;br /&gt;
		return false -- stop code execution&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- do code as usual&lt;br /&gt;
end&lt;br /&gt;
addEvent(&amp;quot;onServerEvent&amp;quot;, true)&lt;br /&gt;
addEventHandler(&amp;quot;onServerEvent&amp;quot;, root, onServerEvent)&lt;br /&gt;
&lt;br /&gt;
function onServerAdminEvent(playerToBan)&lt;br /&gt;
	--[[&lt;br /&gt;
		Assume this server admin event (function) is called in such way:&lt;br /&gt;
&lt;br /&gt;
		local playerToBan = getPlayerFromName(&amp;quot;playerToBan&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
		triggerServerEvent(&amp;quot;onServerAdminEvent&amp;quot;, localPlayer, playerToBan)&lt;br /&gt;
	]]&lt;br /&gt;
&lt;br /&gt;
	local shouldProcessServerCode = processServerEventData(&lt;br /&gt;
		client, -- client element - responsible for calling event&lt;br /&gt;
		source, -- source element - passed in triggerServerEvent (as 2nd argument)&lt;br /&gt;
		eventName, -- name of event - in this case 'onServerAdminEvent'&lt;br /&gt;
		{&lt;br /&gt;
			checkACLGroup = { -- we need to check whether player who called event belongs to ACL groups&lt;br /&gt;
				&amp;quot;Admin&amp;quot;, -- in this case admin group&lt;br /&gt;
			},&lt;br /&gt;
			checkEventData = { -- we want to verify everything what comes from client&lt;br /&gt;
				{&lt;br /&gt;
					eventData = source, -- first to check, source variable&lt;br /&gt;
					equalTo = client, -- we want to check whether it matches player who called event&lt;br /&gt;
					debugData = &amp;quot;source&amp;quot;, -- helper details which would be shown in report&lt;br /&gt;
				},&lt;br /&gt;
				{&lt;br /&gt;
					eventData = playerToBan, -- let's check the data which client sent to us&lt;br /&gt;
					allowedDataTypes = {&lt;br /&gt;
						[&amp;quot;player&amp;quot;] = true, -- we want it to be player&lt;br /&gt;
					},&lt;br /&gt;
					debugData = &amp;quot;playerToBan&amp;quot;, -- if something goes wrong, let server know where (it will appear in debug report)&lt;br /&gt;
				},&lt;br /&gt;
			},&lt;br /&gt;
		}&lt;br /&gt;
	)&lt;br /&gt;
&lt;br /&gt;
	if (not shouldProcessServerCode) then -- something isn't right, no green light for processing code behind this scope&lt;br /&gt;
		return false -- stop code execution&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	-- do code as usual&lt;br /&gt;
end&lt;br /&gt;
addEvent(&amp;quot;onServerAdminEvent&amp;quot;, true)&lt;br /&gt;
addEventHandler(&amp;quot;onServerAdminEvent&amp;quot;, root, onServerAdminEvent)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Securing server-only events==&lt;br /&gt;
* It is very important to '''disable remote triggering''' ability in [https://wiki.multitheftauto.com/wiki/AddEvent addEvent], to prevent calling server-side only events from client-side.&lt;br /&gt;
* '''Admin''' styled '''events''' should be verifying player '''ACL rights''', either by [https://wiki.multitheftauto.com/wiki/IsObjectInACLGroup isObjectInACLGroup] or [https://wiki.multitheftauto.com/wiki/HasObjectPermissionTo hasObjectPermissionTo].&lt;br /&gt;
&lt;br /&gt;
----------&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
This example shows how you should make event server-side only.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
function onServerSideOnlyEvent()&lt;br /&gt;
	-- do some server-side stuff&lt;br /&gt;
end&lt;br /&gt;
addEvent(&amp;quot;onServerSideOnlyEvent&amp;quot;, false) -- set second argument (allowRemoteTriger) to false, so it can't be called from client&lt;br /&gt;
addEventHandler(&amp;quot;onServerSideOnlyEvent&amp;quot;, root, onServerSideOnlyEvent) -- associate our event with function onServerSideOnlyEvent&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Securing projectiles &amp;amp; explosions==&lt;br /&gt;
This section (and '''code''' is '''work in progress''') - '''use at your own risk'''.&lt;br /&gt;
&lt;br /&gt;
----------&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;false&amp;quot;&amp;gt;&lt;br /&gt;
Projectile ammo tracker:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local playerProjectileAmmo = {} -- store player-held weapons ammo here&lt;br /&gt;
local playerWeaponsToTrack = { -- keep track of ammo for certain player-held weapon types, basically those which create projectile; [weaponID] = weaponSlot&lt;br /&gt;
	[16] = 8, -- grenade&lt;br /&gt;
	[17] = 8, -- teargas&lt;br /&gt;
	[18] = 8, -- molotov&lt;br /&gt;
	[35] = 7, -- rocket launcher&lt;br /&gt;
	[36] = 7, -- rocket launcher (heat-seeking)&lt;br /&gt;
	[39] = 8, -- satchel charge&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local function updateProjectileAmmoForPlayer(playerElement)&lt;br /&gt;
	local validElement = isElement(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerDead = isPedDead(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (playerDead) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	for weaponID, weaponSlot in pairs(playerWeaponsToTrack) do&lt;br /&gt;
		local weaponInSlot = getPedWeapon(playerElement, weaponSlot)&lt;br /&gt;
		local weaponTotalAmmo = getPedTotalAmmo(playerElement, weaponSlot)&lt;br /&gt;
		local weaponHasAmmo = (weaponTotalAmmo &amp;gt; 0)&lt;br /&gt;
		local weaponMatching = (weaponInSlot == weaponID)&lt;br /&gt;
		local updateWeaponAmmo = (weaponMatching and weaponHasAmmo)&lt;br /&gt;
&lt;br /&gt;
		if (updateWeaponAmmo) then&lt;br /&gt;
			local storedProjectileAmmo = playerProjectileAmmo[playerElement]&lt;br /&gt;
			local newWeaponAmmo = (updateWeaponAmmo and weaponTotalAmmo or nil)&lt;br /&gt;
&lt;br /&gt;
			if (not storedProjectileAmmo) then&lt;br /&gt;
				playerProjectileAmmo[playerElement] = {}&lt;br /&gt;
				storedProjectileAmmo = playerProjectileAmmo[playerElement]&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			storedProjectileAmmo[weaponID] = newWeaponAmmo&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function hasPlayerProjectileAmmo(playerElement, projectileWeapon)&lt;br /&gt;
	local validElement = isElement(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerDead = isPedDead(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (playerDead) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local projectileData = playerProjectileAmmo[playerElement]&lt;br /&gt;
	local projectileAmmo = (projectileData and projectileData[projectileWeapon])&lt;br /&gt;
&lt;br /&gt;
	return projectileAmmo&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function decreasePlayerProjectileAmmo(playerElement, projectileWeapon)&lt;br /&gt;
	local validElement = isElement(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerDead = isPedDead(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (playerDead) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerProjectileData = playerProjectileAmmo[playerElement]&lt;br /&gt;
&lt;br /&gt;
	if (not playerProjectileData) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local projectileWeaponAmmo = playerProjectileData[projectileWeapon]&lt;br /&gt;
	local tempProjectileAmmo = (projectileWeaponAmmo - 1)&lt;br /&gt;
	local newProjectileAmmo = (tempProjectileAmmo &amp;gt; 0 and tempProjectileAmmo or nil)&lt;br /&gt;
&lt;br /&gt;
	playerProjectileData[projectileWeapon] = newProjectileAmmo&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onPlayerWeaponSwitchAntiCheat(previousWeaponID, currentWeaponID)&lt;br /&gt;
	setTimer(updateProjectileAmmoForPlayer, 50, 1, source)&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onPlayerWeaponSwitch&amp;quot;, root, onPlayerWeaponSwitchAntiCheat)&lt;br /&gt;
&lt;br /&gt;
function onResourceStartAntiCheat()&lt;br /&gt;
	local playersTable = getElementsByType(&amp;quot;player&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
	for playerID = 1, #playersTable do&lt;br /&gt;
		local playerElement = playersTable[playerID]&lt;br /&gt;
&lt;br /&gt;
		updateProjectileAmmoForPlayer(playerElement)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onResourceStart&amp;quot;, resourceRoot, onResourceStartAntiCheat)&lt;br /&gt;
&lt;br /&gt;
function onPlayerWastedQuitAntiCheat()&lt;br /&gt;
	playerProjectileAmmo[source] = nil&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onPlayerWasted&amp;quot;, root, onPlayerWastedQuitAntiCheat)&lt;br /&gt;
addEventHandler(&amp;quot;onPlayerQuit&amp;quot;, root, onPlayerWastedQuitAntiCheat)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;false&amp;quot;&amp;gt;&lt;br /&gt;
Projectile handler:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local playerCreatedProjectiles = {} -- store count of legitimately created player projectiles; [playerElement] = {[projectileType] = activeProjectiles}&lt;br /&gt;
local projectileTypes = {&lt;br /&gt;
	[16] = { -- Grenade&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 2,&lt;br /&gt;
		projectileAllowedWeapons = {&lt;br /&gt;
			[16] = true, -- grenade&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[17] = { -- Teargas&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 2,&lt;br /&gt;
		projectileAllowedWeapons = {&lt;br /&gt;
			[17] = true, -- teargas&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[18] = { -- Molotov&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 2,&lt;br /&gt;
		projectileAllowedWeapons = {&lt;br /&gt;
			[18] = true, -- molotov&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[19] = { -- Rocket&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 5,&lt;br /&gt;
		projectileMaxVelocity = 2,&lt;br /&gt;
		projectileAllowedWeapons = {&lt;br /&gt;
			[35] = true, -- rocket launcher&lt;br /&gt;
		},&lt;br /&gt;
		projectileAllowedVehicles = {&lt;br /&gt;
			[425] = true, -- hunter&lt;br /&gt;
			[520] = true, -- hydra&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[20] = { -- Rocket (heat-seeking)&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 5,&lt;br /&gt;
		projectileMaxVelocity = 2,&lt;br /&gt;
		projectileAllowedWeapons = {&lt;br /&gt;
			[36] = true, -- rocket launcher (heat-seeking)&lt;br /&gt;
		},&lt;br /&gt;
		projectileAllowedVehicles = {&lt;br /&gt;
			[520] = true, -- hydra&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[21] = { -- Airbomb&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileAllowedVehicles = {&lt;br /&gt;
			[520] = true, -- hydra&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[39] = { -- Satchel charge&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 2,&lt;br /&gt;
		projectileAllowedWeapons = {&lt;br /&gt;
			[39] = true, -- satchel charge&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[58] = { -- Hydra flare&lt;br /&gt;
		projectileAllowed = true,&lt;br /&gt;
		projectileMaxDistanceFromCreator = 5,&lt;br /&gt;
		projectileAllowedVehicles = {&lt;br /&gt;
			[520] = true, -- hydra&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local reportAbnormality = true -- whether to report about abnormality in debug script - by default&lt;br /&gt;
local punishPlayerOnDetect = false -- should player be punished upon detection; true - yes, or false to not do anything (make sure that resource which runs this code has admin rights)&lt;br /&gt;
local punishmentBan = true -- only relevant if punishPlayerOnDetect is set to true; use true for ban or false for kick&lt;br /&gt;
local punishmentReason = &amp;quot;Projectile/explosion anti-cheat&amp;quot; -- only relevant if punishPlayerOnDetect is set to true; reason which would be shown to punished player&lt;br /&gt;
local punishedBy = &amp;quot;Console&amp;quot; -- only relevant if punishPlayerOnDetect is set to true; who was responsible for punishing, as well shown to punished player&lt;br /&gt;
local banByIP = false -- only relevant if punishPlayerOnDetect and punishmentBan is set to true; banning by IP nowadays is not recommended (...)&lt;br /&gt;
local banByUsername = false -- community username - legacy thing, hence is set to false and should stay like that&lt;br /&gt;
local banBySerial = true -- only relevant if punishPlayerOnDetect and punishmentBan is set to true; (...) if there is a player serial to use instead&lt;br /&gt;
local banTime = 0 -- only relevant if punishPlayerOnDetect and punishmentBan is set to true; time in seconds, 0 for permanent&lt;br /&gt;
local debugMsgLevel = 4 -- this debug level allows to hide INFO: prefix, and use custom colors&lt;br /&gt;
local debugMsgR = 255 -- debug message - red color&lt;br /&gt;
local debugMsgG = 127 -- debug message - green color&lt;br /&gt;
local debugMsgB = 0 -- debug message - blue color&lt;br /&gt;
&lt;br /&gt;
local function reportProjectileAbnormality(playerElement, projectileType, projectileX, projectileY, projectileZ, projectileForce, projectileTarget, projectileRX, projectileRY, projectileRZ, projectileVX, projectileVY, projectileVZ, detectionCode)&lt;br /&gt;
	local projectileSyncer = inspect(playerElement)&lt;br /&gt;
	local projectilePosition = projectileX..&amp;quot;, &amp;quot;..projectileY..&amp;quot;, &amp;quot;..projectileZ&lt;br /&gt;
	local projectileZoneName = getZoneName(projectileX, projectileY, projectileZ, false)&lt;br /&gt;
	local projectileCityName = getZoneName(projectileX, projectileY, projectileZ, true)&lt;br /&gt;
	local projectileLog =&lt;br /&gt;
		&amp;quot;* Detected projectile abnormality - &amp;quot;..detectionCode..&amp;quot; *\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Projectile syncer: &amp;quot;..projectileSyncer..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Projectile type: &amp;quot;..projectileType..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Projectile position: &amp;quot;..projectilePosition.. &amp;quot; (&amp;quot;..projectileZoneName..&amp;quot;, &amp;quot;..projectileCityName..&amp;quot;)\n&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	outputDebugString(projectileLog, debugMsgLevel, debugMsgR, debugMsgG, debugMsgB)&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function processProjectileChecks(playerElement, projectileType, projectileX, projectileY, projectileZ, projectileForce, projectileTarget, projectileRX, projectileRY, projectileRZ, projectileVX, projectileVY, projectileVZ)&lt;br /&gt;
	local projectileData = projectileTypes[projectileType]&lt;br /&gt;
	local projectileAllowed = projectileData.projectileAllowed&lt;br /&gt;
&lt;br /&gt;
	if (not projectileAllowed) then&lt;br /&gt;
		return false, &amp;quot;Projectile not allowed&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local projectileAllowedWeapons = projectileData.projectileAllowedWeapons&lt;br /&gt;
&lt;br /&gt;
	if (projectileAllowedWeapons) then&lt;br /&gt;
		local playerWeapon = getPedWeapon(playerElement)&lt;br /&gt;
		local allowedWeapon = projectileAllowedWeapons[playerWeapon]&lt;br /&gt;
&lt;br /&gt;
		if (not allowedWeapon) then&lt;br /&gt;
			return false, &amp;quot;Player is not holding correct weapon&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local weaponAmmo = hasPlayerProjectileAmmo(playerElement, playerWeapon)&lt;br /&gt;
		local playerHasAmmo = (weaponAmmo &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
		if (not playerHasAmmo) then&lt;br /&gt;
			return false, &amp;quot;Player doesn't have ammo for weapon&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		decreasePlayerProjectileAmmo(playerElement, playerWeapon)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerVehicle = getPedOccupiedVehicle(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (playerVehicle) then&lt;br /&gt;
		local projectileAllowedVehicles = projectileData.projectileAllowedVehicles&lt;br /&gt;
&lt;br /&gt;
		if (projectileAllowedVehicles) then&lt;br /&gt;
			local vehicleModel = getElementModel(playerVehicle)&lt;br /&gt;
			local allowedVehicle = projectileAllowedVehicles[vehicleModel]&lt;br /&gt;
&lt;br /&gt;
			if (not allowedVehicle) then&lt;br /&gt;
				return false, &amp;quot;Player is not inside allowed vehicles&amp;quot;&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			local vehicleDriver = getVehicleController(playerVehicle)&lt;br /&gt;
			local playerDriver = (playerElement == vehicleDriver)&lt;br /&gt;
&lt;br /&gt;
			if (not playerDriver) then&lt;br /&gt;
				return false, &amp;quot;Player is not vehicle driver&amp;quot;&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return false, &amp;quot;Player in vehicle&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local projectileMaxDistanceFromCreator = projectileData.projectileMaxDistanceFromCreator&lt;br /&gt;
&lt;br /&gt;
	if (projectileMaxDistanceFromCreator) then&lt;br /&gt;
		local playerX, playerY, playerZ = getElementPosition(playerElement)&lt;br /&gt;
		local distanceToProjectile = getDistanceBetweenPoints3D(playerX, playerY, playerZ, projectileX, projectileY, projectileZ)&lt;br /&gt;
		local matchingProjectileDistance = (distanceToProjectile &amp;lt;= projectileMaxDistanceFromCreator)&lt;br /&gt;
&lt;br /&gt;
		if (not matchingProjectileDistance) then&lt;br /&gt;
			return false, &amp;quot;Projectile distance mismatch&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local projectileMaxVelocity = projectileData.projectileMaxVelocity&lt;br /&gt;
&lt;br /&gt;
	if (projectileMaxVelocity) then&lt;br /&gt;
		local projectileVelocity = (projectileVX ^ 2 + projectileVY ^ 2 + projectileVZ ^ 2)&lt;br /&gt;
		local projectileSpeed = math.sqrt(projectileVelocity)&lt;br /&gt;
		local matchingProjectileVelocity = (projectileSpeed &amp;lt;= projectileMaxVelocity)&lt;br /&gt;
&lt;br /&gt;
		if (not matchingProjectileVelocity) then&lt;br /&gt;
			return false, &amp;quot;Projectile velocity mismatch&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function trackPlayerProjectile(playerElement, projectileID)&lt;br /&gt;
	local validElement = isElement(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerProjectiles = playerCreatedProjectiles[playerElement]&lt;br /&gt;
&lt;br /&gt;
	if (not playerProjectiles) then&lt;br /&gt;
		playerCreatedProjectiles[playerElement] = {}&lt;br /&gt;
		playerProjectiles = playerCreatedProjectiles[playerElement]&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local projectilesByType = playerProjectiles[projectileID] or 0&lt;br /&gt;
	local newProjectilesCount = (projectilesByType + 1)&lt;br /&gt;
&lt;br /&gt;
	playerProjectiles[projectileID] = newProjectilesCount&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getProjectileDetectionOverwrittenBehavior(projectileType)&lt;br /&gt;
	local projectileData = projectileTypes[projectileType]&lt;br /&gt;
&lt;br /&gt;
	if (not projectileData) then&lt;br /&gt;
		return reportAbnormality, punishPlayerOnDetect, punishmentBan&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local projectileBehaviour = projectileData.projectileOverwriteBehaviour&lt;br /&gt;
&lt;br /&gt;
	if (not projectileBehaviour) then&lt;br /&gt;
		return reportAbnormality, punishPlayerOnDetect, punishmentBan&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local overwriteReport = projectileBehaviour.reportAbnormality&lt;br /&gt;
	local overwritePunish = projectileBehaviour.punishPlayerOnDetect&lt;br /&gt;
	local overwriteBan = projectileBehaviour.punishmentBan&lt;br /&gt;
&lt;br /&gt;
	return overwriteReport, overwritePunish, overwriteBan&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function decreasePlayerProjectiles(playerElement, projectileID)&lt;br /&gt;
	local validElement = isElement(playerElement)&lt;br /&gt;
&lt;br /&gt;
	if (not validElement) then&lt;br /&gt;
		return false&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local playerProjectiles = playerCreatedProjectiles[playerElement]&lt;br /&gt;
&lt;br /&gt;
	if (not playerProjectiles) then&lt;br /&gt;
		return false, true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local projectilesByType = playerProjectiles[projectileID]&lt;br /&gt;
&lt;br /&gt;
	if (not projectilesByType) then&lt;br /&gt;
		return false, true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local tempProjectilesCount = (projectilesByType - 1)&lt;br /&gt;
	local newProjectilesCount = (tempProjectilesCount &amp;gt; 0 and tempProjectilesCount or nil)&lt;br /&gt;
&lt;br /&gt;
	playerProjectiles[projectileID] = newProjectilesCount&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onPlayerProjectileCreationAntiCheat(projectileType, projectileX, projectileY, projectileZ, projectileForce, projectileTarget, projectileRX, projectileRY, projectileRZ, projectileVX, projectileVY, projectileVZ)&lt;br /&gt;
	local approvedProjectile, detectionCode = processProjectileChecks(source, projectileType, projectileX, projectileY, projectileZ, projectileForce, projectileTarget, projectileRX, projectileRY, projectileRZ, projectileVX, projectileVY, projectileVZ)&lt;br /&gt;
&lt;br /&gt;
	if (approvedProjectile) then&lt;br /&gt;
		trackPlayerProjectile(source, projectileType)&lt;br /&gt;
&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local reportAbnormality, punishPlayerOnDetect, punishmentBan = getProjectileDetectionOverwrittenBehavior(projectileType)&lt;br /&gt;
&lt;br /&gt;
	if (reportAbnormality) then&lt;br /&gt;
		reportProjectileAbnormality(source, projectileType, projectileX, projectileY, projectileZ, projectileForce, projectileTarget, projectileRX, projectileRY, projectileRZ, projectileVX, projectileVY, projectileVZ, detectionCode)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	cancelEvent()&lt;br /&gt;
&lt;br /&gt;
	if (not punishPlayerOnDetect) then -- we don't want to punish player for some reason&lt;br /&gt;
		return false -- so stop here&lt;br /&gt;
	end&lt;br /&gt;
		&lt;br /&gt;
	if (punishmentBan) then -- if it's ban&lt;br /&gt;
		banPlayer(source, banByIP, banByUsername, banBySerial, punishedBy, punishmentReason, banTime) -- remove his presence from server&lt;br /&gt;
	else -- otherwise&lt;br /&gt;
		kickPlayer(source, punishedBy, punishmentReason) -- simply kick player out of server&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onPlayerProjectileCreation&amp;quot;, root, onPlayerProjectileCreationAntiCheat)&lt;br /&gt;
&lt;br /&gt;
function onPlayerQuitAntiCheat()&lt;br /&gt;
	playerCreatedProjectiles[source] = nil&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onPlayerQuit&amp;quot;, root, onPlayerQuitAntiCheat)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;section name=&amp;quot;Server&amp;quot; class=&amp;quot;server&amp;quot; show=&amp;quot;false&amp;quot;&amp;gt;&lt;br /&gt;
Explosions handler:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
local rocketInstantExplosionDistanceThreshold = 1.55 -- distance below which only explosion will be created (and not rocket projectile, hence not calling onPlayerProjectileCreation); do not change it&lt;br /&gt;
local explosionTypes = { -- more specific info on explosion, and whether it is allowed&lt;br /&gt;
	[0] = { -- Grenade&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
		explosionAllowedProjectiles = {&lt;br /&gt;
			[16] = true, -- grenade&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[1] = { -- Molotov&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
		explosionAllowedProjectiles = {&lt;br /&gt;
			[18] = true, -- molotov&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[2] = { -- Rocket&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
		explosionAllowedWeapons = {&lt;br /&gt;
			[35] = true, -- rocket launcher&lt;br /&gt;
			[36] = true, -- rocket launcher (heat-seeking)&lt;br /&gt;
		},&lt;br /&gt;
		explosionAllowedProjectiles = {&lt;br /&gt;
			[19] = true, -- rocket&lt;br /&gt;
			[20] = true, -- rocket (heat-seeking)&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[3] = { -- Rocket weak&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
		explosionAllowedProjectiles = {&lt;br /&gt;
			[19] = true, -- rocket&lt;br /&gt;
			[20] = true, -- rocket (heat-seeking)&lt;br /&gt;
		},&lt;br /&gt;
	},&lt;br /&gt;
	[4] = { -- Car&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[5] = { -- Car quick&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[6] = { -- Boat&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[7] = { -- Heli&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[8] = { -- Mine&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[9] = { -- Object&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[10] = { -- Tank grenade&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
		explosionMaxDistanceFromCreator = 80,&lt;br /&gt;
		explosionAllowedVehicles = {&lt;br /&gt;
			[432] = true,&lt;br /&gt;
		}&lt;br /&gt;
	},&lt;br /&gt;
	[11] = { -- Small&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
	[12] = { -- Tiny&lt;br /&gt;
		explosionAllowed = true,&lt;br /&gt;
	},&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
local reportAbnormality = true -- whether to report about abnormality in debug script - by default&lt;br /&gt;
local punishPlayerOnDetect = false -- should player be punished upon detection; true - yes, or false to not do anything (make sure that resource which runs this code has admin rights)&lt;br /&gt;
local punishmentBan = true -- only relevant if punishPlayerOnDetect is set to true; use true for ban or false for kick&lt;br /&gt;
local punishmentReason = &amp;quot;Projectile/explosion anti-cheat&amp;quot; -- only relevant if punishPlayerOnDetect is set to true; reason which would be shown to punished player&lt;br /&gt;
local punishedBy = &amp;quot;Console&amp;quot; -- only relevant if punishPlayerOnDetect is set to true; who was responsible for punishing, as well shown to punished player&lt;br /&gt;
local banByIP = false -- only relevant if punishPlayerOnDetect and punishmentBan is set to true; banning by IP nowadays is not recommended (...)&lt;br /&gt;
local banByUsername = false -- community username - legacy thing, hence is set to false and should stay like that&lt;br /&gt;
local banBySerial = true -- only relevant if punishPlayerOnDetect and punishmentBan is set to true; (...) if there is a player serial to use instead&lt;br /&gt;
local banTime = 0 -- only relevant if punishPlayerOnDetect and punishmentBan is set to true; time in seconds, 0 for permanent&lt;br /&gt;
local debugMsgLevel = 4 -- this debug level allows to hide INFO: prefix, and use custom colors&lt;br /&gt;
local debugMsgR = 255 -- debug message - red color&lt;br /&gt;
local debugMsgG = 127 -- debug message - green color&lt;br /&gt;
local debugMsgB = 0 -- debug message - blue color&lt;br /&gt;
&lt;br /&gt;
local function reportExplosionAbnormality(playerElement, explosionType, explosionX, explosionY, explosionZ, detectionCode)&lt;br /&gt;
	local explosionSyncer = inspect(playerElement)&lt;br /&gt;
	local explosionType = explosionType&lt;br /&gt;
	local explosionPosition = explosionX..&amp;quot;, &amp;quot;..explosionY..&amp;quot;, &amp;quot;..explosionZ&lt;br /&gt;
	local explosionZoneName = getZoneName(explosionX, explosionY, explosionZ, false)&lt;br /&gt;
	local explosionCityName = getZoneName(explosionX, explosionY, explosionZ, true)&lt;br /&gt;
	local explosionLog =&lt;br /&gt;
		&amp;quot;* Detected explosion abnormality - &amp;quot;..detectionCode..&amp;quot; *\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Explosion syncer: &amp;quot;..explosionSyncer..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Explosion type: &amp;quot;..explosionType..&amp;quot;\n&amp;quot;..&lt;br /&gt;
		&amp;quot;Explosion position: &amp;quot;..explosionPosition.. &amp;quot; (&amp;quot;..explosionZoneName..&amp;quot;, &amp;quot;..explosionCityName..&amp;quot;)\n&amp;quot;&lt;br /&gt;
&lt;br /&gt;
	outputDebugString(explosionLog, debugMsgLevel, debugMsgR, debugMsgG, debugMsgB)&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function processExplosionChecks(playerElement, explosionType, explosionX, explosionY, explosionZ)&lt;br /&gt;
	local explosionData = explosionTypes[explosionType]&lt;br /&gt;
	local explosionAllowed = explosionData.explosionAllowed&lt;br /&gt;
&lt;br /&gt;
	if (not explosionAllowed) then&lt;br /&gt;
		return false, &amp;quot;Explosion type not allowed&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local rocketExplosion = (explosionType == 2)&lt;br /&gt;
&lt;br /&gt;
	if (rocketExplosion) then&lt;br /&gt;
		local playerX, playerY, playerZ = getElementPosition(playerElement)&lt;br /&gt;
		local distanceToExplosion = getDistanceBetweenPoints3D(playerX, playerY, playerZ, explosionX, explosionY, explosionZ)&lt;br /&gt;
		local instantExplosion = (distanceToExplosion &amp;lt; rocketInstantExplosionDistanceThreshold)&lt;br /&gt;
&lt;br /&gt;
		if (instantExplosion) then&lt;br /&gt;
			local explosionAllowedWeapons = explosionData.explosionAllowedWeapons&lt;br /&gt;
			local playerWeapon = getPedWeapon(playerElement)&lt;br /&gt;
			local allowedWeapon = explosionAllowedWeapons[playerWeapon]&lt;br /&gt;
&lt;br /&gt;
			if (not allowedWeapon) then&lt;br /&gt;
				return false, &amp;quot;Player is not holding rocket launcher&amp;quot;&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			local weaponAmmo = hasPlayerProjectileAmmo(playerElement, playerWeapon)&lt;br /&gt;
			local playerHasAmmo = (weaponAmmo &amp;gt; 0)&lt;br /&gt;
&lt;br /&gt;
			if (not playerHasAmmo) then&lt;br /&gt;
				return false, &amp;quot;Player doesn't have ammo for rocket launcher&amp;quot;&lt;br /&gt;
			end&lt;br /&gt;
&lt;br /&gt;
			decreasePlayerProjectileAmmo(playerElement, playerWeapon)&lt;br /&gt;
&lt;br /&gt;
			return true&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local explosionAllowedProjectiles = explosionData.explosionAllowedProjectiles&lt;br /&gt;
&lt;br /&gt;
	if (explosionAllowedProjectiles) then&lt;br /&gt;
&lt;br /&gt;
		for projectileID, _ in pairs(explosionAllowedProjectiles) do&lt;br /&gt;
			local atleastOneProjectile = decreasePlayerProjectiles(playerElement, projectileID)&lt;br /&gt;
&lt;br /&gt;
			if (atleastOneProjectile) then&lt;br /&gt;
				return true&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		return false, &amp;quot;Explosion created without respective projectile&amp;quot;&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local explosionAllowedVehicles = explosionData.explosionAllowedVehicles&lt;br /&gt;
&lt;br /&gt;
	if (explosionAllowedVehicles) then&lt;br /&gt;
		local playerVehicle = getPedOccupiedVehicle(playerElement)&lt;br /&gt;
&lt;br /&gt;
		if (not playerVehicle) then&lt;br /&gt;
			return false, &amp;quot;Player is not in vehicle&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local vehicleModel = getElementModel(playerVehicle)&lt;br /&gt;
		local allowedVehicle = explosionAllowedVehicles[vehicleModel]&lt;br /&gt;
&lt;br /&gt;
		if (not allowedVehicle) then&lt;br /&gt;
			return false, &amp;quot;Player is inside not allowed vehicles&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		local vehicleDriver = getVehicleController(playerVehicle)&lt;br /&gt;
		local playerDriver = (playerElement == vehicleDriver)&lt;br /&gt;
&lt;br /&gt;
		if (not playerDriver) then&lt;br /&gt;
			return false, &amp;quot;Player is not vehicle driver&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local explosionMaxDistanceFromCreator = explosionData.explosionMaxDistanceFromCreator&lt;br /&gt;
&lt;br /&gt;
	if (explosionMaxDistanceFromCreator) then&lt;br /&gt;
		local playerX, playerY, playerZ = getElementPosition(playerElement)&lt;br /&gt;
		local distanceToExplosion = getDistanceBetweenPoints3D(playerX, playerY, playerZ, explosionX, explosionY, explosionZ)&lt;br /&gt;
		local matchingExplosionDistance = (distanceToExplosion &amp;lt; explosionMaxDistanceFromCreator)&lt;br /&gt;
&lt;br /&gt;
		if (not matchingExplosionDistance) then&lt;br /&gt;
			return false, &amp;quot;Explosion distance mismatch&amp;quot;&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	return true&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function getExplosionDetectionOverwrittenBehavior(explosionType)&lt;br /&gt;
	local explosionData = explosionTypes[explosionType]&lt;br /&gt;
&lt;br /&gt;
	if (not explosionData) then&lt;br /&gt;
		return reportAbnormality, punishPlayerOnDetect, punishmentBan&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local explosionBehaviour = explosionData.explosionOverwriteBehaviour&lt;br /&gt;
&lt;br /&gt;
	if (not explosionBehaviour) then&lt;br /&gt;
		return reportAbnormality, punishPlayerOnDetect, punishmentBan&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local overwriteReport = explosionBehaviour.reportAbnormality&lt;br /&gt;
	local overwritePunish = explosionBehaviour.punishPlayerOnDetect&lt;br /&gt;
	local overwriteBan = explosionBehaviour.punishmentBan&lt;br /&gt;
&lt;br /&gt;
	return overwriteReport, overwritePunish, overwriteBan&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function onExplosionAntiCheat(explosionX, explosionY, explosionZ, explosionType)&lt;br /&gt;
	local serverSyncExplosion = (source == root)&lt;br /&gt;
&lt;br /&gt;
	if (serverSyncExplosion) then&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local approvedExplosion, detectionCode = processExplosionChecks(source, explosionType, explosionX, explosionY, explosionZ)&lt;br /&gt;
&lt;br /&gt;
	if (approvedExplosion) then&lt;br /&gt;
		return true&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	local reportAbnormality, punishPlayerOnDetect, punishmentBan = getExplosionDetectionOverwrittenBehavior(explosionType)&lt;br /&gt;
&lt;br /&gt;
	if (reportAbnormality) then&lt;br /&gt;
		reportExplosionAbnormality(source, explosionType, explosionX, explosionY, explosionZ, detectionCode)&lt;br /&gt;
	end&lt;br /&gt;
&lt;br /&gt;
	cancelEvent()&lt;br /&gt;
&lt;br /&gt;
	if (not punishPlayerOnDetect) then -- we don't want to punish player for some reason&lt;br /&gt;
		return false -- so stop here&lt;br /&gt;
	end&lt;br /&gt;
		&lt;br /&gt;
	if (punishmentBan) then -- if it's ban&lt;br /&gt;
		banPlayer(source, banByIP, banByUsername, banBySerial, punishedBy, punishmentReason, banTime) -- remove his presence from server&lt;br /&gt;
	else -- otherwise&lt;br /&gt;
		kickPlayer(source, punishedBy, punishmentReason) -- simply kick player out of server&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
addEventHandler(&amp;quot;onExplosion&amp;quot;, root, onExplosionAntiCheat)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;/section&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Handling non-registered events==&lt;br /&gt;
&lt;br /&gt;
See: [[onPlayerTriggerInvalidEvent]]&lt;br /&gt;
&lt;br /&gt;
==Handling events spam==&lt;br /&gt;
See: [[onPlayerTriggerEventThreshold]]&lt;br /&gt;
&lt;br /&gt;
__NOTOC__&lt;br /&gt;
__NOEDITSECTION__&lt;br /&gt;
[[ru:Script security]]&lt;br /&gt;
[[en:Script security]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Forks&amp;diff=82687</id>
		<title>RU/Forks</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Forks&amp;diff=82687"/>
		<updated>2026-01-02T20:15:14Z</updated>

		<summary type="html">&lt;p&gt;Flox: Created page with &amp;quot;__NOTOC__ {{Note|Information on this page does not apply to the official builds of MTA.}}  Multi Theft Auto - Это программное обеспечение с открытым исходным кодом, доступное бесплатно на [https://github.com/multitheftauto/mtasa-blue GitHub multitheftauto/mtasa-blue]. Любой может создать форк проекта, если будет соблюдать условия нашей лиценз...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__ {{Note|Information on this page does not apply to the official builds of MTA.}}&lt;br /&gt;
&lt;br /&gt;
Multi Theft Auto - Это программное обеспечение с открытым исходным кодом, доступное бесплатно на [https://github.com/multitheftauto/mtasa-blue GitHub multitheftauto/mtasa-blue].&lt;br /&gt;
Любой может создать форк проекта, если будет соблюдать условия нашей лицензии — Стандартной общественной лицензии GNU версии 3.&lt;br /&gt;
&lt;br /&gt;
Вы можете ознакомиться с пояснениями к GNU GPL v3 здесь: [https://choosealicense.com/licenses/gpl-3.0/ choosealicense.com] и [https://tldrlegal.com/license/gnu-general-public-license-v3-(gpl-3) tldrlegal.com]. Приоритет [https://github.com/multitheftauto/mtasa-blue/blob/master/LICENSE license] отдается нашей лицензии, но обычно это означает, что вы должны:&lt;br /&gt;
&lt;br /&gt;
* указать существенные изменения, внесенные в программное обеспечение&lt;br /&gt;
* раскрыть исходный код &lt;br /&gt;
* поделиться своим кодом под той же лицензией&lt;br /&gt;
* включить оригинальное уведомление об авторских правах&lt;br /&gt;
&lt;br /&gt;
Если вы работаете над форком, мы просим вас указать ссылку на вашу домашнюю страницу и указать, где мы можем найти исходный код. Это позволяет нам быть в курсе событий, связанных с проектами, и даже вносить улучшения для подавляющего большинства игроков в MTA. Указывать имя в Discord не обязательно, но если вы обратитесь за помощью в разработке на наш GitHub, форум или в Discord, это поможет нам понять, из какого вы проекта и соблюдаете ли вы условия лицензии.&lt;br /&gt;
&lt;br /&gt;
== Forks and anti-cheat==&lt;br /&gt;
&lt;br /&gt;
(from https://wiki.multitheftauto.com/wiki/Anti-cheat_support_for_custom_builds)&lt;br /&gt;
&lt;br /&gt;
=== '''// UPDATE (December 2022)''' ===&lt;br /&gt;
Теперь вы также можете использовать «полный античит для форков». Для получения дополнительной информации прочтите эту статью: '''[[Forks Full AC]]'''&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
.. But otherwise&lt;br /&gt;
&lt;br /&gt;
Пользовательские сборки MTA и форки столкнутся с некоторыми проблемами, связанными с античитом (AC). Из-за того, что многие форки и пользовательские сборки работают не так, как ожидает модуль античита, мы были вынуждены удалить множество расширенных средств обнаружения и защиты от античита, чтобы создать и предоставить отдельный модуль (тот, что с https://mirror-cdn.multitheftauto.com/bdata/netc.dll), который, проще говоря, является гораздо более слабым античитом, чем «настоящий» MTA. Таким образом, если вы не примете меры, ваш форк-проект может (и будет) легко заражён мошенниками. Этого можно избежать с помощью [[Forks Full AC]] (нажмите, чтобы прочитать статью). Но в стандартном сценарии вам поможет информация, представленная ниже.&lt;br /&gt;
&lt;br /&gt;
Компоненты античита и неткода (netc.dll, net.dll, FairplayKD.sys), в отличие от самого MTA, имеют закрытый исходный код, поэтому без дополнительной информации вам будет сложно справиться с трудностями.&lt;br /&gt;
&lt;br /&gt;
AC, как правило, не поддерживается в форках и в будущем может быть полностью исключён. Это означает, что вы, как правило, ''не можете'' полагаться на античит MTA в своём форке. '''Мы настоятельно рекомендуем вам написать и внедрить собственный античит.'''&lt;br /&gt;
&lt;br /&gt;
Если вы не можете написать свой собственный AC, вот несколько шагов, которые помогут вам максимально эффективно использовать наш (не поддерживаемый) AC:&lt;br /&gt;
&lt;br /&gt;
* Всегда используйте версию наших сетевых модулей (например, [https://mirror-cdn.multitheftauto.com/bdata/netc.dll netc.dll] и [https://mirror-cdn.multitheftauto.com/bdata/net.dll net.dll]), которая соответствует нашему коммиту в основной ветке, на которой основан ваш форк&lt;br /&gt;
** Если говорить конкретно, вы можете использовать последнюю версию модуля, совместимую с битовым потоком&lt;br /&gt;
** Вы можете загрузить эти модули, выполнив команду https://github.com/multitheftauto/mtasa-blue/blob/master/win-build.bat&lt;br /&gt;
* Никогда не блокируйте трафик MTA (клиент и сервер взаимодействуют с официальными серверами MTAHQ) в своём проекте&lt;br /&gt;
'''* Обязательно используйте тип сборки «нестабильный», а не «пользовательский», иначе 15 % функций AC для «bdata forks netc» снизятся до 1 %. Подробную информацию и правильную конфигурацию см. в документации по типу сборки по адресу [https://github.com/multitheftauto/mtasa-blue/blob/master/Shared/sdk/version.h mtasa-blue/Shared/sdk/version.h] '''&lt;br /&gt;
&lt;br /&gt;
=== Функции AC отсутствуют в пользовательских сборках === &lt;br /&gt;
* Не обнаруживаются изменения в разделе кода gta_sa&lt;br /&gt;
* Не обнаруживаются изменения в некоторых переменных gta_sa&lt;br /&gt;
* Не обнаруживаются изменения в памяти&lt;br /&gt;
* Не обнаруживаются различные методы внедрения Lua&lt;br /&gt;
* SetElementData не защищён от внешних изменений с помощью хаков&lt;br /&gt;
* Гораздо меньше эвристических методов защиты от читов и внутренних средств защиты&lt;br /&gt;
* Не гарантируется постоянное обновление всех исправленных методов и уязвимостей, на основе которых можно писать читы (иногда они выбираются случайным образом; это одна из причин, по которой рекомендуется обновлять netc.dll до последней доступной версии). Это самая большая (и самая важная) часть оригинального античита.&lt;br /&gt;
* Модули MTA не проверяются на предмет модификаций или удалённого перехвата/манипулирования&lt;br /&gt;
* и многое другое&lt;br /&gt;
&lt;br /&gt;
Как правило, лучше всего работают системы обнаружения на основе сигнатур. Никаких эвристических методов, исправленных методов и исправленных уязвимостей. Системы обнаружения на основе сигнатур — самые слабые, и основная античит-система решает реальную проблему, а не полагается на сигнатуры. Обратите внимание, что в некоторых форках (например, в российской «MTA Province») античит-система MTA поддерживается ещё хуже, чем в большинстве других форков. Это связано с тем, что разработчики форков имеют возможность полностью блокировать или прерывать коммуникационный трафик клиента &amp;gt; MTAHQ (на что мы в значительной степени полагаемся, чтобы помочь форкам противодействовать мошенничеству, поскольку большинство обычных функций AC недоступны), или выполнять и изменять другие действия, которые с технической точки зрения приведут к тому, что функции AC не будут работать. работайте по назначению или немедленно выйдите из строя. Если вы не хотите, чтобы ваш форк был заражен читерами так же сильно, как &amp;quot;провинция MTA&amp;quot; и как они ее называют, &amp;quot;их клоны&amp;quot; (из провинции).. в дополнение к тому, что вы установили тип сборки «custom», тогда как он должен быть «unstable». Теперь, надеюсь, вы знаете, на что следует обратить внимание как разработчику форка. Кроме того, было бы неплохо, если бы это сообщение дошло до разработчиков форков с большим количеством читеров, таких как Province.&lt;br /&gt;
&lt;br /&gt;
 Кроме того, команда по борьбе с мошенничеством в MTA выполняет дополнительную работу вручную, чтобы пресекать мошенничество на форках, например, время от времени блокируя читеров из известных форков с помощью слишком простых методов обнаружения, прилагая все усилия (без каких-либо гарантий). Это всего лишь любезность со стороны MTA, которую мы проявляем, когда нам этого хочется, или, может быть, когда вы обращаетесь к нам... и на это нельзя полагаться.&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Известно, что вышеупомянутые волны банов приводят к банам по причинам, которые выглядят одинаково и известны читерам как «БАН: RPBOX / NEXTRP / PROVINCE CHEAT» (в зависимости от названий форков, затронутых определенным читом). Поэтому, пожалуйста, не направляйте этих пользователей в MTA для обжалования банов.&lt;br /&gt;
&lt;br /&gt;
[[Category:Development]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82686</id>
		<title>RU/Where to buy GTASA</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82686"/>
		<updated>2026-01-02T20:00:24Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;На этой странице описывается общая совместимость версий Grand Theft Auto: San Andreas с MTA:SA, а также где их можно приобрести.&lt;br /&gt;
&lt;br /&gt;
=== Совместимость ===&lt;br /&gt;
&lt;br /&gt;
Если версия Grand Theft Auto: San Andreas, отмеченная ниже как совместимая, не работает, попробуйте переустановить MTA:SA. Если это не сработает, следуйте [https://forum.mtasa.com/topic/11757-patching-your-101-or-200-version-of-gta_saexe/ этим инструкциям]. Если это по-прежнему не сработает, пожалуйста, свяжитесь с нами на форуме [https://forum.mtasa.com/forum/83-client/] или присоединяйтесь к [https://mtasa.com/discord MTA Discord #help-support channel].&lt;br /&gt;
&lt;br /&gt;
{{Important Note|Grand Theft Auto: San Andreas как часть '''Grand Theft Auto: The Trilogy – The Definitive Edition''' ''(2021)'' это совершенно новая версия игры. Данная версия является '''несовместимой''' с MTA:SA.}}&lt;br /&gt;
&lt;br /&gt;
=== Получение совместимых и бывших в употреблении копий ===&lt;br /&gt;
&lt;br /&gt;
Официально единственный способ приобрести совместимую копию Grand Theft Auto: San Andreas от Rockstar Games и Take-Two — это приобрести коллекцию classic collection [https://store.rockstargames.com/en/game/buy/grand-theft-auto-the-trilogy &amp;quot;Grand Theft Auto: Trilogy&amp;quot; (2005) в магазине Rockstar Store].&lt;br /&gt;
&lt;br /&gt;
Есть только два других варианта: либо приобрести подержанную физическую копию через блошиные рынки и частных посредников, либо приобрести ключ для совместимой цифровой версии у посредника по продаже ключей.&lt;br /&gt;
&lt;br /&gt;
Ярким примером покупки подержанной физической копии на сайтах, указанных ниже. Введя в поле поиска «gta san andreas pc» или «gta san andreas», вы сможете найти множество людей, которые все еще продают совместимую игру. Однако будьте осторожны, поскольку покупка у ненадежных реселлеров, таких как неизвестные люди, не занимающиеся бизнесом, сопряжена с риском (например, подделки или поврежденные копии).&lt;br /&gt;
&lt;br /&gt;
Чтобы найти продавца цифровых ключей, воспользуйтесь поисковой системой, чтобы найти «Grand Theft Auto: San Andreas key» или что-то подобное.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Прежде чем рассматривать возможность покупки, оцените, какие источники являются надежными, и убедитесь, что ключ будет работать в вашем регионе. ===&lt;br /&gt;
&lt;br /&gt;
На этой странице перечислены некоторые веб-сайты, на которых можно купить Grand Theft Auto San Andreas в цифровом виде и играть в MTA:SA (иногда с автоматическим понижением версии игры). Не все из них были проверены, но все должно работать без проблем. Если нет, пожалуйста, обратитесь в службу поддержки.&lt;br /&gt;
&lt;br /&gt;
Известно, что все версии (DVD) GTA:SA для Windows функционируют нормально. Если вы планируете покупать DVD-диск GTA:SA, вам следует попытаться получить &amp;quot;Standard&amp;quot; версию, а не &amp;quot;Second Edition&amp;quot; или &amp;quot;Greatest Hits&amp;quot; издания, хотя они будут работать нормально.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 900px; text-align: center; table-layout: fixed;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Ритейлер&lt;br /&gt;
!Примечания&lt;br /&gt;
!Работает с MTA: SA?&lt;br /&gt;
|-&lt;br /&gt;
|[http://store.steampowered.com/app/12120/ Steam]&lt;br /&gt;
|Внимание: Grand Theft Auto: San Andreas больше не доступна в магазине Steam.Специализированная Steam-версия игры. Установщик MTA произведет даунгрейд (понижение) версии игры. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |[http://www.amazon.com/Grand-Theft-Auto-Andreas-Download/dp/B006YVXGJQ Amazon]&lt;br /&gt;
| Для '''Standard''' издания игры, если MTA несовместима, попробуйте найти GTA SA 1.00 No CD - любой релиз от HOODLUM будет функционировать без проблем.&lt;br /&gt;
| {{Partial|Не подтверждено (Standard)}}&lt;br /&gt;
|-&lt;br /&gt;
| Steam-версия и копии дисков GTASA будут функционировать нормально&lt;br /&gt;
| {{Yes| Да (Steam/DVD-бокс)}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamersgate.co.uk/DD-GTASAS/grand-theft-auto-san-andreas GamersGate]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.game.co.uk/en/grand-theft-auto-san-andreas-301403 Game UK]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://digital.gamefly.co.uk/#!/download-grand-theft-auto-san-andreas/5006365 GameFly Digital]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.greenmangaming.com/s/gb/en/pc/games/action/grand-theft-auto-san-andreas/ GreenManGaming]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamestop.com/pc/games/grand-theft-auto-san-andreas/37409 GameStop]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.walmart.com/ip/Take-Two-GTASAESD-Grand-Theft-Auto-San-Andreas-PC/36754297 Walmart]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ebay.com/sch/i.html?_from=R40&amp;amp;_trksid=p4432023.m570.l1313&amp;amp;_nkw=GTA%3ASA&amp;amp;_sacat=0 Ebay]&lt;br /&gt;
|Доступна к покупке (Нужна версия ПК).&lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ozon.ru/category/gta-san-andreas-na-pk/?__rr=1&amp;amp;abt_att=1 Ozon MarketPlace]&lt;br /&gt;
|Доступна к покупке. Не проверено при работе с MTA:SA.&lt;br /&gt;
| {{Partial|Не проверено}}&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.wildberries.ru/catalog/0/search.aspx?search=gta%20san%20andreas%20диск%20на%20пк Wildberries MarketPlace]&lt;br /&gt;
|Доступна к покупке. Не проверено при работе с MTA:SA.&lt;br /&gt;
| {{Partial|Не проверено}}&lt;br /&gt;
|-&lt;br /&gt;
|Windows App Store&lt;br /&gt;
|Мобильная версия игры, перенесенная на ПК. '''Никогда не будет работать с MTA'''.&lt;br /&gt;
|{{No|Нет}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
[[en:Where to buy GTASA]]&lt;br /&gt;
[[es:Dónde comprar GTA: SA]]&lt;br /&gt;
[[uk:Where to buy GTASA]]&lt;br /&gt;
[[pl:Where to buy GTASA]]&lt;br /&gt;
[[tr:GTA:SA Nerden Alınır]]&lt;br /&gt;
[[zh-cn:在那里可以购买GTASA]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82453</id>
		<title>RU/Where to buy GTASA</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82453"/>
		<updated>2025-09-06T13:37:05Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* Прежде чем рассматривать возможность покупки, оцените, какие источники являются надежными, и убедитесь, что ключ будет работать в вашем регионе. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;На этой странице описывается общая совместимость версий Grand Theft Auto: San Andreas с MTA:SA, а также где их можно приобрести.&lt;br /&gt;
&lt;br /&gt;
=== Совместимость ===&lt;br /&gt;
&lt;br /&gt;
Если версия Grand Theft Auto: San Andreas, отмеченная ниже как совместимая, не работает, попробуйте переустановить MTA:SA. Если это не сработает, следуйте [https://forum.mtasa.com/topic/11757-patching-your-101-or-200-version-of-gta_saexe/ этим инструкциям]. Если это по-прежнему не сработает, пожалуйста, свяжитесь с нами на форуме [https://forum.mtasa.com/forum/83-client/] или присоединяйтесь к [https://mtasa.com/discord MTA Discord #help-support channel].&lt;br /&gt;
&lt;br /&gt;
{{Important Note|Grand Theft Auto: San Andreas как часть '''Grand Theft Auto: The Trilogy – The Definitive Edition''' ''(2021)'' это совершенно новая версия игры. Данная версия является '''несовместимой''' с MTA:SA.}}&lt;br /&gt;
&lt;br /&gt;
=== Получение совместимых и бывших в употреблении копий ===&lt;br /&gt;
&lt;br /&gt;
Официально единственный способ приобрести совместимую копию Grand Theft Auto: San Andreas от Rockstar Games и Take-Two — это приобрести коллекцию classic collection [https://store.rockstargames.com/en/game/buy/grand-theft-auto-the-trilogy &amp;quot;Grand Theft Auto: Trilogy&amp;quot; (2005) в магазине Rockstar Store].&lt;br /&gt;
&lt;br /&gt;
Есть только два других варианта: либо приобрести подержанную физическую копию через блошиные рынки и частных посредников, либо приобрести ключ для совместимой цифровой версии у посредника по продаже ключей.&lt;br /&gt;
&lt;br /&gt;
Ярким примером покупки подержанной физической копии на сайтах, указанных ниже. Введя в поле поиска «gta san andreas pc» или «gta san andreas», вы сможете найти множество людей, которые все еще продают совместимую игру. Однако будьте осторожны, поскольку покупка у ненадежных реселлеров, таких как неизвестные люди, не занимающиеся бизнесом, сопряжена с риском (например, подделки или поврежденные копии).&lt;br /&gt;
&lt;br /&gt;
Чтобы найти продавца цифровых ключей, воспользуйтесь поисковой системой, чтобы найти «Grand Theft Auto: San Andreas key» или что-то подобное.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Прежде чем рассматривать возможность покупки, оцените, какие источники являются надежными, и убедитесь, что ключ будет работать в вашем регионе. ===&lt;br /&gt;
&lt;br /&gt;
На этой странице перечислены некоторые веб-сайты, на которых можно купить Grand Theft Auto San Andreas в цифровом виде и играть в MTA:SA (иногда с автоматическим понижением версии игры). Не все из них были проверены, но все должно работать без проблем. Если нет, пожалуйста, обратитесь в службу поддержки.&lt;br /&gt;
&lt;br /&gt;
Известно, что все версии (DVD) GTA:SA для Windows функционируют нормально. Если вы планируете покупать DVD-диск GTA:SA, вам следует попытаться получить &amp;quot;Standard&amp;quot; версию, а не &amp;quot;Second Edition&amp;quot; или &amp;quot;Greatest Hits&amp;quot; издания, хотя они будут работать нормально.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 900px; text-align: center; table-layout: fixed;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Ритейлер&lt;br /&gt;
!Примечания&lt;br /&gt;
!Работает с MTA: SA?&lt;br /&gt;
|-&lt;br /&gt;
|[http://store.steampowered.com/app/12120/ Steam]&lt;br /&gt;
|Внимание: Grand Theft Auto: San Andreas больше не доступна в магазине Steam.Специализированная Steam-версия игры. Установщик MTA произведет даунгрейд (понижение) версии игры. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |[http://www.amazon.com/Grand-Theft-Auto-Andreas-Download/dp/B006YVXGJQ Amazon]&lt;br /&gt;
| Для '''Standard''' издания игры, если MTA несовместима, попробуйте найти GTA SA 1.00 No CD - любой релиз от HOODLUM будет функционировать без проблем.&lt;br /&gt;
| {{Partial|Не подтверждено (Standard)}}&lt;br /&gt;
|-&lt;br /&gt;
| Steam-версия и копии дисков GTASA будут функционировать нормально&lt;br /&gt;
| {{Yes| Да (Steam/DVD-бокс)}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamersgate.co.uk/DD-GTASAS/grand-theft-auto-san-andreas GamersGate]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.game.co.uk/en/grand-theft-auto-san-andreas-301403 Game UK]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://digital.gamefly.co.uk/#!/download-grand-theft-auto-san-andreas/5006365 GameFly Digital]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.greenmangaming.com/s/gb/en/pc/games/action/grand-theft-auto-san-andreas/ GreenManGaming]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamestop.com/pc/games/grand-theft-auto-san-andreas/37409 GameStop]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.walmart.com/ip/Take-Two-GTASAESD-Grand-Theft-Auto-San-Andreas-PC/36754297 Walmart]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ebay.com/sch/i.html?_from=R40&amp;amp;_trksid=p4432023.m570.l1313&amp;amp;_nkw=GTA%3ASA&amp;amp;_sacat=0 Ebay]&lt;br /&gt;
|Доступна к покупке (Нужна версия ПК).&lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ozon.ru/category/gta-san-andreas-na-pk/?__rr=1&amp;amp;abt_att=1 Ozon MarketPlace]&lt;br /&gt;
|Доступна к покупке. Не проверено при работе с MTA:SA.&lt;br /&gt;
| {{Partial|Не проверено}}&lt;br /&gt;
|-&lt;br /&gt;
|Windows App Store&lt;br /&gt;
|Мобильная версия игры, перенесенная на ПК. '''Никогда не будет работать с MTA'''.&lt;br /&gt;
|{{No|Нет}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
[[en:Where to buy GTASA]]&lt;br /&gt;
[[es:Dónde comprar GTA: SA]]&lt;br /&gt;
[[uk:Where to buy GTASA]]&lt;br /&gt;
[[pl:Where to buy GTASA]]&lt;br /&gt;
[[tr:GTA:SA Nerden Alınır]]&lt;br /&gt;
[[zh-cn:在那里可以购买GTASA]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82452</id>
		<title>RU/Where to buy GTASA</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82452"/>
		<updated>2025-09-06T13:36:39Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* Прежде чем рассматривать возможность покупки, оцените, какие источники являются надежными, и убедитесь, что ключ будет работать в вашем регионе. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;На этой странице описывается общая совместимость версий Grand Theft Auto: San Andreas с MTA:SA, а также где их можно приобрести.&lt;br /&gt;
&lt;br /&gt;
=== Совместимость ===&lt;br /&gt;
&lt;br /&gt;
Если версия Grand Theft Auto: San Andreas, отмеченная ниже как совместимая, не работает, попробуйте переустановить MTA:SA. Если это не сработает, следуйте [https://forum.mtasa.com/topic/11757-patching-your-101-or-200-version-of-gta_saexe/ этим инструкциям]. Если это по-прежнему не сработает, пожалуйста, свяжитесь с нами на форуме [https://forum.mtasa.com/forum/83-client/] или присоединяйтесь к [https://mtasa.com/discord MTA Discord #help-support channel].&lt;br /&gt;
&lt;br /&gt;
{{Important Note|Grand Theft Auto: San Andreas как часть '''Grand Theft Auto: The Trilogy – The Definitive Edition''' ''(2021)'' это совершенно новая версия игры. Данная версия является '''несовместимой''' с MTA:SA.}}&lt;br /&gt;
&lt;br /&gt;
=== Получение совместимых и бывших в употреблении копий ===&lt;br /&gt;
&lt;br /&gt;
Официально единственный способ приобрести совместимую копию Grand Theft Auto: San Andreas от Rockstar Games и Take-Two — это приобрести коллекцию classic collection [https://store.rockstargames.com/en/game/buy/grand-theft-auto-the-trilogy &amp;quot;Grand Theft Auto: Trilogy&amp;quot; (2005) в магазине Rockstar Store].&lt;br /&gt;
&lt;br /&gt;
Есть только два других варианта: либо приобрести подержанную физическую копию через блошиные рынки и частных посредников, либо приобрести ключ для совместимой цифровой версии у посредника по продаже ключей.&lt;br /&gt;
&lt;br /&gt;
Ярким примером покупки подержанной физической копии на сайтах, указанных ниже. Введя в поле поиска «gta san andreas pc» или «gta san andreas», вы сможете найти множество людей, которые все еще продают совместимую игру. Однако будьте осторожны, поскольку покупка у ненадежных реселлеров, таких как неизвестные люди, не занимающиеся бизнесом, сопряжена с риском (например, подделки или поврежденные копии).&lt;br /&gt;
&lt;br /&gt;
Чтобы найти продавца цифровых ключей, воспользуйтесь поисковой системой, чтобы найти «Grand Theft Auto: San Andreas key» или что-то подобное.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Прежде чем рассматривать возможность покупки, оцените, какие источники являются надежными, и убедитесь, что ключ будет работать в вашем регионе. ===&lt;br /&gt;
&lt;br /&gt;
На этой странице перечислены некоторые веб-сайты, на которых можно купить Grand Theft Auto San Andreas в цифровом виде и играть в MTA:SA (иногда с автоматическим понижением версии игры). Не все из них были проверены, но все должно работать без проблем. Если нет, пожалуйста, обратитесь в службу поддержки.&lt;br /&gt;
&lt;br /&gt;
Известно, что все версии (DVD) GTA:SA для Windows функционируют нормально. Если вы планируете покупать DVD-диск GTA:SA, вам следует попытаться получить &amp;quot;Standard&amp;quot; версию, а не &amp;quot;Second Edition&amp;quot; или &amp;quot;Greatest Hits&amp;quot; издания, хотя они будут работать нормально.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 900px; text-align: center; table-layout: fixed;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Ритейлер&lt;br /&gt;
!Примечания&lt;br /&gt;
!Работает с MTA: SA?&lt;br /&gt;
|-&lt;br /&gt;
|[http://store.steampowered.com/app/12120/ Steam]&lt;br /&gt;
|Внимание: Grand Theft Auto: San Andreas больше не доступна в магазине Steam.Специализированная Steam-версия игры. Установщик MTA произведет даунгрейд (понижение) версии игры. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |[http://www.amazon.com/Grand-Theft-Auto-Andreas-Download/dp/B006YVXGJQ Amazon]&lt;br /&gt;
| Для '''Standard''' издания игры, если MTA несовместима, попробуйте найти GTA SA 1.00 No CD - любой релиз от HOODLUM будет функционировать без проблем.&lt;br /&gt;
| {{Partial|Не подтверждено (Standard)}}&lt;br /&gt;
|-&lt;br /&gt;
| Steam-версия и копии дисков GTASA будут функционировать нормально&lt;br /&gt;
| {{Yes| Да (Steam/DVD-бокс)}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamersgate.co.uk/DD-GTASAS/grand-theft-auto-san-andreas GamersGate]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.game.co.uk/en/grand-theft-auto-san-andreas-301403 Game UK]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://digital.gamefly.co.uk/#!/download-grand-theft-auto-san-andreas/5006365 GameFly Digital]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.greenmangaming.com/s/gb/en/pc/games/action/grand-theft-auto-san-andreas/ GreenManGaming]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamestop.com/pc/games/grand-theft-auto-san-andreas/37409 GameStop]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.walmart.com/ip/Take-Two-GTASAESD-Grand-Theft-Auto-San-Andreas-PC/36754297 Walmart]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ebay.com/sch/i.html?_from=R40&amp;amp;_trksid=p4432023.m570.l1313&amp;amp;_nkw=GTA%3ASA&amp;amp;_sacat=0 Ebay]&lt;br /&gt;
|Доступна к покупке (Нужна версия ПК).&lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ozon.ru/category/gta-san-andreas-na-pk/?__rr=1&amp;amp;abt_att=1 Ozon MarketPlace]&lt;br /&gt;
|Доступна к покупке. Не проверено при работе с MTA:SA.&lt;br /&gt;
| {{Partial|Не подтверждено (Standard)}}&lt;br /&gt;
|-&lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|Windows App Store&lt;br /&gt;
|Мобильная версия игры, перенесенная на ПК. '''Никогда не будет работать с MTA'''.&lt;br /&gt;
|{{No|Нет}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
[[en:Where to buy GTASA]]&lt;br /&gt;
[[es:Dónde comprar GTA: SA]]&lt;br /&gt;
[[uk:Where to buy GTASA]]&lt;br /&gt;
[[pl:Where to buy GTASA]]&lt;br /&gt;
[[tr:GTA:SA Nerden Alınır]]&lt;br /&gt;
[[zh-cn:在那里可以购买GTASA]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82451</id>
		<title>RU/Where to buy GTASA</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82451"/>
		<updated>2025-09-06T13:36:09Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;На этой странице описывается общая совместимость версий Grand Theft Auto: San Andreas с MTA:SA, а также где их можно приобрести.&lt;br /&gt;
&lt;br /&gt;
=== Совместимость ===&lt;br /&gt;
&lt;br /&gt;
Если версия Grand Theft Auto: San Andreas, отмеченная ниже как совместимая, не работает, попробуйте переустановить MTA:SA. Если это не сработает, следуйте [https://forum.mtasa.com/topic/11757-patching-your-101-or-200-version-of-gta_saexe/ этим инструкциям]. Если это по-прежнему не сработает, пожалуйста, свяжитесь с нами на форуме [https://forum.mtasa.com/forum/83-client/] или присоединяйтесь к [https://mtasa.com/discord MTA Discord #help-support channel].&lt;br /&gt;
&lt;br /&gt;
{{Important Note|Grand Theft Auto: San Andreas как часть '''Grand Theft Auto: The Trilogy – The Definitive Edition''' ''(2021)'' это совершенно новая версия игры. Данная версия является '''несовместимой''' с MTA:SA.}}&lt;br /&gt;
&lt;br /&gt;
=== Получение совместимых и бывших в употреблении копий ===&lt;br /&gt;
&lt;br /&gt;
Официально единственный способ приобрести совместимую копию Grand Theft Auto: San Andreas от Rockstar Games и Take-Two — это приобрести коллекцию classic collection [https://store.rockstargames.com/en/game/buy/grand-theft-auto-the-trilogy &amp;quot;Grand Theft Auto: Trilogy&amp;quot; (2005) в магазине Rockstar Store].&lt;br /&gt;
&lt;br /&gt;
Есть только два других варианта: либо приобрести подержанную физическую копию через блошиные рынки и частных посредников, либо приобрести ключ для совместимой цифровой версии у посредника по продаже ключей.&lt;br /&gt;
&lt;br /&gt;
Ярким примером покупки подержанной физической копии на сайтах, указанных ниже. Введя в поле поиска «gta san andreas pc» или «gta san andreas», вы сможете найти множество людей, которые все еще продают совместимую игру. Однако будьте осторожны, поскольку покупка у ненадежных реселлеров, таких как неизвестные люди, не занимающиеся бизнесом, сопряжена с риском (например, подделки или поврежденные копии).&lt;br /&gt;
&lt;br /&gt;
Чтобы найти продавца цифровых ключей, воспользуйтесь поисковой системой, чтобы найти «Grand Theft Auto: San Andreas key» или что-то подобное.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Прежде чем рассматривать возможность покупки, оцените, какие источники являются надежными, и убедитесь, что ключ будет работать в вашем регионе. ===&lt;br /&gt;
&lt;br /&gt;
На этой странице перечислены некоторые веб-сайты, на которых можно купить Grand Theft Auto San Andreas в цифровом виде и играть в MTA:SA (иногда с автоматическим понижением версии игры). Не все из них были проверены, но все должно работать без проблем. Если нет, пожалуйста, обратитесь в службу поддержки.&lt;br /&gt;
&lt;br /&gt;
Известно, что все версии (DVD) GTA:SA для Windows функционируют нормально. Если вы планируете покупать DVD-диск GTA:SA, вам следует попытаться получить &amp;quot;Standard&amp;quot; версию, а не &amp;quot;Second Edition&amp;quot; или &amp;quot;Greatest Hits&amp;quot; издания, хотя они будут работать нормально.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 900px; text-align: center; table-layout: fixed;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Ритейлер&lt;br /&gt;
!Примечания&lt;br /&gt;
!Работает с MTA: SA?&lt;br /&gt;
|-&lt;br /&gt;
|[http://store.steampowered.com/app/12120/ Steam]&lt;br /&gt;
|Внимание: Grand Theft Auto: San Andreas больше не доступна в магазине Steam.Специализированная Steam-версия игры. Установщик MTA произведет даунгрейд (понижение) версии игры. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |[http://www.amazon.com/Grand-Theft-Auto-Andreas-Download/dp/B006YVXGJQ Amazon]&lt;br /&gt;
| Для '''Standard''' издания игры, если MTA несовместима, попробуйте найти GTA SA 1.00 No CD - любой релиз от HOODLUM будет функционировать без проблем.&lt;br /&gt;
| {{Partial|Не подтверждено (Standard)}}&lt;br /&gt;
|-&lt;br /&gt;
| Steam-версия и копии дисков GTASA будут функционировать нормально&lt;br /&gt;
| {{Yes| Да (Steam/DVD-бокс)}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamersgate.co.uk/DD-GTASAS/grand-theft-auto-san-andreas GamersGate]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.game.co.uk/en/grand-theft-auto-san-andreas-301403 Game UK]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://digital.gamefly.co.uk/#!/download-grand-theft-auto-san-andreas/5006365 GameFly Digital]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.greenmangaming.com/s/gb/en/pc/games/action/grand-theft-auto-san-andreas/ GreenManGaming]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamestop.com/pc/games/grand-theft-auto-san-andreas/37409 GameStop]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.walmart.com/ip/Take-Two-GTASAESD-Grand-Theft-Auto-San-Andreas-PC/36754297 Walmart]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ebay.com/sch/i.html?_from=R40&amp;amp;_trksid=p4432023.m570.l1313&amp;amp;_nkw=GTA%3ASA&amp;amp;_sacat=0 Ebay]&lt;br /&gt;
|Доступна к покупке (Нужна версия ПК).&lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ozon.ru/category/gta-san-andreas-na-pk/?__rr=1&amp;amp;abt_att=1 Ozon MarketPlace]&lt;br /&gt;
|Доступна к покупке. Не проверено при работе с MTA:SA.&lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|Windows App Store&lt;br /&gt;
|Мобильная версия игры, перенесенная на ПК. '''Никогда не будет работать с MTA'''.&lt;br /&gt;
|{{No|Нет}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
[[en:Where to buy GTASA]]&lt;br /&gt;
[[es:Dónde comprar GTA: SA]]&lt;br /&gt;
[[uk:Where to buy GTASA]]&lt;br /&gt;
[[pl:Where to buy GTASA]]&lt;br /&gt;
[[tr:GTA:SA Nerden Alınır]]&lt;br /&gt;
[[zh-cn:在那里可以购买GTASA]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82450</id>
		<title>RU/Where to buy GTASA</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82450"/>
		<updated>2025-09-06T13:29:03Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;На этой странице описывается общая совместимость версий Grand Theft Auto: San Andreas с MTA:SA, а также где их можно приобрести.&lt;br /&gt;
&lt;br /&gt;
=== Совместимость ===&lt;br /&gt;
&lt;br /&gt;
Если версия Grand Theft Auto: San Andreas, отмеченная ниже как совместимая, не работает, попробуйте переустановить MTA:SA. Если это не сработает, следуйте [https://forum.mtasa.com/topic/11757-patching-your-101-or-200-version-of-gta_saexe/ этим инструкциям]. Если это по-прежнему не сработает, пожалуйста, свяжитесь с нами на форуме [https://forum.mtasa.com/forum/83-client/] или присоединяйтесь к [https://mtasa.com/discord MTA Discord #help-support channel].&lt;br /&gt;
&lt;br /&gt;
{{Important Note|Grand Theft Auto: San Andreas как часть '''Grand Theft Auto: The Trilogy – The Definitive Edition''' ''(2021)'' это совершенно новая версия игры. Данная версия является '''несовместимой''' с MTA:SA.}}&lt;br /&gt;
&lt;br /&gt;
=== Получение совместимых и бывших в употреблении копий ===&lt;br /&gt;
&lt;br /&gt;
Официально единственный способ приобрести совместимую копию Grand Theft Auto: San Andreas от Rockstar Games и Take-Two — это приобрести коллекцию classic collection [https://store.rockstargames.com/en/game/buy/grand-theft-auto-the-trilogy &amp;quot;Grand Theft Auto: Trilogy&amp;quot; (2005) в магазине Rockstar Store].&lt;br /&gt;
&lt;br /&gt;
Есть только два других варианта: либо приобрести подержанную физическую копию через блошиные рынки и частных посредников, либо приобрести ключ для совместимой цифровой версии у посредника по продаже ключей.&lt;br /&gt;
&lt;br /&gt;
Ярким примером покупки подержанной физической копии на сайтах, указанных ниже. Введя в поле поиска «gta san andreas pc» или «gta san andreas», вы сможете найти множество людей, которые все еще продают совместимую игру. Однако будьте осторожны, поскольку покупка у ненадежных реселлеров, таких как неизвестные люди, не занимающиеся бизнесом, сопряжена с риском (например, подделки или поврежденные копии).&lt;br /&gt;
&lt;br /&gt;
Чтобы найти продавца цифровых ключей, воспользуйтесь поисковой системой, чтобы найти «Grand Theft Auto: San Andreas key» или что-то подобное.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Прежде чем рассматривать возможность покупки, оцените, какие источники являются надежными, и убедитесь, что ключ будет работать в вашем регионе. ===&lt;br /&gt;
&lt;br /&gt;
На этой странице перечислены некоторые веб-сайты, на которых можно купить Grand Theft Auto San Andreas в цифровом виде и играть в MTA:SA (иногда с автоматическим понижением версии игры). Не все из них были проверены, но все должно работать без проблем. Если нет, пожалуйста, обратитесь в службу поддержки.&lt;br /&gt;
&lt;br /&gt;
Известно, что все версии (DVD) GTA:SA для Windows функционируют нормально. Если вы планируете покупать DVD-диск GTA:SA, вам следует попытаться получить &amp;quot;Standard&amp;quot; версию, а не &amp;quot;Second Edition&amp;quot; или &amp;quot;Greatest Hits&amp;quot; издания, хотя они будут работать нормально.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 900px; text-align: center; table-layout: fixed;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Ритейлер&lt;br /&gt;
!Примечания&lt;br /&gt;
!Работает с MTA: SA?&lt;br /&gt;
|-&lt;br /&gt;
|[http://store.steampowered.com/app/12120/ Steam]&lt;br /&gt;
|Внимание: Grand Theft Auto: San Andreas больше не доступна в магазине Steam.Специализированная Steam-версия игры. Установщик MTA произведет даунгрейд (понижение) версии игры. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |[http://www.amazon.com/Grand-Theft-Auto-Andreas-Download/dp/B006YVXGJQ Amazon]&lt;br /&gt;
| Для '''Standard''' издания игры, если MTA несовместима, попробуйте найти GTA SA 1.00 No CD - любой релиз от HOODLUM будет функционировать без проблем.&lt;br /&gt;
| {{Partial|Не подтверждено (Standard)}}&lt;br /&gt;
|-&lt;br /&gt;
| Steam-версия и копии дисков GTASA будут функционировать нормально&lt;br /&gt;
| {{Yes| Да (Steam/DVD-бокс)}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamersgate.co.uk/DD-GTASAS/grand-theft-auto-san-andreas GamersGate]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.game.co.uk/en/grand-theft-auto-san-andreas-301403 Game UK]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://digital.gamefly.co.uk/#!/download-grand-theft-auto-san-andreas/5006365 GameFly Digital]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.greenmangaming.com/s/gb/en/pc/games/action/grand-theft-auto-san-andreas/ GreenManGaming]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamestop.com/pc/games/grand-theft-auto-san-andreas/37409 GameStop]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.walmart.com/ip/Take-Two-GTASAESD-Grand-Theft-Auto-San-Andreas-PC/36754297 Walmart]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ebay.com/sch/i.html?_from=R40&amp;amp;_trksid=p4432023.m570.l1313&amp;amp;_nkw=GTA%3ASA&amp;amp;_sacat=0 Ebay]&lt;br /&gt;
|Доступна к покупке (Нужна версия ПК).&lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|Windows App Store&lt;br /&gt;
|Мобильная версия игры, перенесенная на ПК. '''Никогда не будет работать с MTA'''.&lt;br /&gt;
|{{No|Нет}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
[[en:Where to buy GTASA]]&lt;br /&gt;
[[es:Dónde comprar GTA: SA]]&lt;br /&gt;
[[uk:Where to buy GTASA]]&lt;br /&gt;
[[pl:Where to buy GTASA]]&lt;br /&gt;
[[tr:GTA:SA Nerden Alınır]]&lt;br /&gt;
[[zh-cn:在那里可以购买GTASA]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82449</id>
		<title>RU/Where to buy GTASA</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82449"/>
		<updated>2025-09-06T13:28:38Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;На этой странице описывается общая совместимость версий Grand Theft Auto: San Andreas с MTA:SA, а также где их можно приобрести.&lt;br /&gt;
&lt;br /&gt;
=== Совместимость ===&lt;br /&gt;
&lt;br /&gt;
Если версия Grand Theft Auto: San Andreas, отмеченная ниже как совместимая, не работает, попробуйте переустановить MTA:SA. Если это не сработает, следуйте [https://forum.mtasa.com/topic/11757-patching-your-101-or-200-version-of-gta_saexe/ этим инструкциям]. Если это по-прежнему не сработает, пожалуйста, свяжитесь с нами на форуме [https://forum.mtasa.com/forum/83-client/] или присоединяйтесь к [https://mtasa.com/discord MTA Discord #help-support channel].&lt;br /&gt;
&lt;br /&gt;
{{Важное замечание|Grand Theft Auto: San Andreas как часть '''Grand Theft Auto: The Trilogy – The Definitive Edition''' ''(2021)'' — это совершенно новая версия игры. Данная версия является '''несовместимой''' с MTA:SA.}}&lt;br /&gt;
{{Important Note|Grand Theft Auto: San Andreas как часть '''Grand Theft Auto: The Trilogy – The Definitive Edition''' ''(2021)'' это совершенно новая версия игры. Данная версия является '''not compatible''' with MTA:SA.}}&lt;br /&gt;
&lt;br /&gt;
=== Получение совместимых и бывших в употреблении копий ===&lt;br /&gt;
&lt;br /&gt;
Официально единственный способ приобрести совместимую копию Grand Theft Auto: San Andreas от Rockstar Games и Take-Two — это приобрести коллекцию classic collection [https://store.rockstargames.com/en/game/buy/grand-theft-auto-the-trilogy &amp;quot;Grand Theft Auto: Trilogy&amp;quot; (2005) в магазине Rockstar Store].&lt;br /&gt;
&lt;br /&gt;
Есть только два других варианта: либо приобрести подержанную физическую копию через блошиные рынки и частных посредников, либо приобрести ключ для совместимой цифровой версии у посредника по продаже ключей.&lt;br /&gt;
&lt;br /&gt;
Ярким примером покупки подержанной физической копии на сайтах, указанных ниже. Введя в поле поиска «gta san andreas pc» или «gta san andreas», вы сможете найти множество людей, которые все еще продают совместимую игру. Однако будьте осторожны, поскольку покупка у ненадежных реселлеров, таких как неизвестные люди, не занимающиеся бизнесом, сопряжена с риском (например, подделки или поврежденные копии).&lt;br /&gt;
&lt;br /&gt;
Чтобы найти продавца цифровых ключей, воспользуйтесь поисковой системой, чтобы найти «Grand Theft Auto: San Andreas key» или что-то подобное.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Прежде чем рассматривать возможность покупки, оцените, какие источники являются надежными, и убедитесь, что ключ будет работать в вашем регионе. ===&lt;br /&gt;
&lt;br /&gt;
На этой странице перечислены некоторые веб-сайты, на которых можно купить Grand Theft Auto San Andreas в цифровом виде и играть в MTA:SA (иногда с автоматическим понижением версии игры). Не все из них были проверены, но все должно работать без проблем. Если нет, пожалуйста, обратитесь в службу поддержки.&lt;br /&gt;
&lt;br /&gt;
Известно, что все версии (DVD) GTA:SA для Windows функционируют нормально. Если вы планируете покупать DVD-диск GTA:SA, вам следует попытаться получить &amp;quot;Standard&amp;quot; версию, а не &amp;quot;Second Edition&amp;quot; или &amp;quot;Greatest Hits&amp;quot; издания, хотя они будут работать нормально.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 900px; text-align: center; table-layout: fixed;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Ритейлер&lt;br /&gt;
!Примечания&lt;br /&gt;
!Работает с MTA: SA?&lt;br /&gt;
|-&lt;br /&gt;
|[http://store.steampowered.com/app/12120/ Steam]&lt;br /&gt;
|Внимание: Grand Theft Auto: San Andreas больше не доступна в магазине Steam.Специализированная Steam-версия игры. Установщик MTA произведет даунгрейд (понижение) версии игры. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |[http://www.amazon.com/Grand-Theft-Auto-Andreas-Download/dp/B006YVXGJQ Amazon]&lt;br /&gt;
| Для '''Standard''' издания игры, если MTA несовместима, попробуйте найти GTA SA 1.00 No CD - любой релиз от HOODLUM будет функционировать без проблем.&lt;br /&gt;
| {{Partial|Не подтверждено (Standard)}}&lt;br /&gt;
|-&lt;br /&gt;
| Steam-версия и копии дисков GTASA будут функционировать нормально&lt;br /&gt;
| {{Yes| Да (Steam/DVD-бокс)}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamersgate.co.uk/DD-GTASAS/grand-theft-auto-san-andreas GamersGate]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.game.co.uk/en/grand-theft-auto-san-andreas-301403 Game UK]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://digital.gamefly.co.uk/#!/download-grand-theft-auto-san-andreas/5006365 GameFly Digital]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.greenmangaming.com/s/gb/en/pc/games/action/grand-theft-auto-san-andreas/ GreenManGaming]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamestop.com/pc/games/grand-theft-auto-san-andreas/37409 GameStop]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.walmart.com/ip/Take-Two-GTASAESD-Grand-Theft-Auto-San-Andreas-PC/36754297 Walmart]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ebay.com/sch/i.html?_from=R40&amp;amp;_trksid=p4432023.m570.l1313&amp;amp;_nkw=GTA%3ASA&amp;amp;_sacat=0 Ebay]&lt;br /&gt;
|Доступна к покупке (Нужна версия ПК).&lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|Windows App Store&lt;br /&gt;
|Мобильная версия игры, перенесенная на ПК. '''Никогда не будет работать с MTA'''.&lt;br /&gt;
|{{No|Нет}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
[[en:Where to buy GTASA]]&lt;br /&gt;
[[es:Dónde comprar GTA: SA]]&lt;br /&gt;
[[uk:Where to buy GTASA]]&lt;br /&gt;
[[pl:Where to buy GTASA]]&lt;br /&gt;
[[tr:GTA:SA Nerden Alınır]]&lt;br /&gt;
[[zh-cn:在那里可以购买GTASA]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82448</id>
		<title>RU/Where to buy GTASA</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82448"/>
		<updated>2025-09-06T13:28:12Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;На этой странице описывается общая совместимость версий Grand Theft Auto: San Andreas с MTA:SA, а также где их можно приобрести.&lt;br /&gt;
&lt;br /&gt;
=== Совместимость ===&lt;br /&gt;
&lt;br /&gt;
Если версия Grand Theft Auto: San Andreas, отмеченная ниже как совместимая, не работает, попробуйте переустановить MTA:SA. Если это не сработает, следуйте [https://forum.mtasa.com/topic/11757-patching-your-101-or-200-version-of-gta_saexe/ этим инструкциям]. Если это по-прежнему не сработает, пожалуйста, свяжитесь с нами на форуме [https://forum.mtasa.com/forum/83-client/] или присоединяйтесь к [https://mtasa.com/discord MTA Discord #help-support channel].&lt;br /&gt;
&lt;br /&gt;
{{Важное замечание|Grand Theft Auto: San Andreas как часть '''Grand Theft Auto: The Trilogy – The Definitive Edition''' ''(2021)'' — это совершенно новая версия игры. Данная версия является '''несовместимой''' с MTA:SA.}}&lt;br /&gt;
{{Важное замечание|Grand Theft Auto: San Andreas как часть '''Grand Theft Auto: The Trilogy – The Definitive Edition''' ''(2021)'' — это совершенно новая версия игры. Данная версия является '''несовместимой''' c MTA:SA.}}&lt;br /&gt;
&lt;br /&gt;
=== Получение совместимых и бывших в употреблении копий ===&lt;br /&gt;
&lt;br /&gt;
Официально единственный способ приобрести совместимую копию Grand Theft Auto: San Andreas от Rockstar Games и Take-Two — это приобрести коллекцию classic collection [https://store.rockstargames.com/en/game/buy/grand-theft-auto-the-trilogy &amp;quot;Grand Theft Auto: Trilogy&amp;quot; (2005) в магазине Rockstar Store].&lt;br /&gt;
&lt;br /&gt;
Есть только два других варианта: либо приобрести подержанную физическую копию через блошиные рынки и частных посредников, либо приобрести ключ для совместимой цифровой версии у посредника по продаже ключей.&lt;br /&gt;
&lt;br /&gt;
Ярким примером покупки подержанной физической копии на сайтах, указанных ниже. Введя в поле поиска «gta san andreas pc» или «gta san andreas», вы сможете найти множество людей, которые все еще продают совместимую игру. Однако будьте осторожны, поскольку покупка у ненадежных реселлеров, таких как неизвестные люди, не занимающиеся бизнесом, сопряжена с риском (например, подделки или поврежденные копии).&lt;br /&gt;
&lt;br /&gt;
Чтобы найти продавца цифровых ключей, воспользуйтесь поисковой системой, чтобы найти «Grand Theft Auto: San Andreas key» или что-то подобное.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Прежде чем рассматривать возможность покупки, оцените, какие источники являются надежными, и убедитесь, что ключ будет работать в вашем регионе. ===&lt;br /&gt;
&lt;br /&gt;
На этой странице перечислены некоторые веб-сайты, на которых можно купить Grand Theft Auto San Andreas в цифровом виде и играть в MTA:SA (иногда с автоматическим понижением версии игры). Не все из них были проверены, но все должно работать без проблем. Если нет, пожалуйста, обратитесь в службу поддержки.&lt;br /&gt;
&lt;br /&gt;
Известно, что все версии (DVD) GTA:SA для Windows функционируют нормально. Если вы планируете покупать DVD-диск GTA:SA, вам следует попытаться получить &amp;quot;Standard&amp;quot; версию, а не &amp;quot;Second Edition&amp;quot; или &amp;quot;Greatest Hits&amp;quot; издания, хотя они будут работать нормально.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 900px; text-align: center; table-layout: fixed;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Ритейлер&lt;br /&gt;
!Примечания&lt;br /&gt;
!Работает с MTA: SA?&lt;br /&gt;
|-&lt;br /&gt;
|[http://store.steampowered.com/app/12120/ Steam]&lt;br /&gt;
|Внимание: Grand Theft Auto: San Andreas больше не доступна в магазине Steam.Специализированная Steam-версия игры. Установщик MTA произведет даунгрейд (понижение) версии игры. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |[http://www.amazon.com/Grand-Theft-Auto-Andreas-Download/dp/B006YVXGJQ Amazon]&lt;br /&gt;
| Для '''Standard''' издания игры, если MTA несовместима, попробуйте найти GTA SA 1.00 No CD - любой релиз от HOODLUM будет функционировать без проблем.&lt;br /&gt;
| {{Partial|Не подтверждено (Standard)}}&lt;br /&gt;
|-&lt;br /&gt;
| Steam-версия и копии дисков GTASA будут функционировать нормально&lt;br /&gt;
| {{Yes| Да (Steam/DVD-бокс)}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamersgate.co.uk/DD-GTASAS/grand-theft-auto-san-andreas GamersGate]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.game.co.uk/en/grand-theft-auto-san-andreas-301403 Game UK]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://digital.gamefly.co.uk/#!/download-grand-theft-auto-san-andreas/5006365 GameFly Digital]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.greenmangaming.com/s/gb/en/pc/games/action/grand-theft-auto-san-andreas/ GreenManGaming]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamestop.com/pc/games/grand-theft-auto-san-andreas/37409 GameStop]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.walmart.com/ip/Take-Two-GTASAESD-Grand-Theft-Auto-San-Andreas-PC/36754297 Walmart]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ebay.com/sch/i.html?_from=R40&amp;amp;_trksid=p4432023.m570.l1313&amp;amp;_nkw=GTA%3ASA&amp;amp;_sacat=0 Ebay]&lt;br /&gt;
|Доступна к покупке (Нужна версия ПК).&lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|Windows App Store&lt;br /&gt;
|Мобильная версия игры, перенесенная на ПК. '''Никогда не будет работать с MTA'''.&lt;br /&gt;
|{{No|Нет}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
[[en:Where to buy GTASA]]&lt;br /&gt;
[[es:Dónde comprar GTA: SA]]&lt;br /&gt;
[[uk:Where to buy GTASA]]&lt;br /&gt;
[[pl:Where to buy GTASA]]&lt;br /&gt;
[[tr:GTA:SA Nerden Alınır]]&lt;br /&gt;
[[zh-cn:在那里可以购买GTASA]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82447</id>
		<title>RU/Where to buy GTASA</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82447"/>
		<updated>2025-09-06T13:27:41Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;На этой странице описывается общая совместимость версий Grand Theft Auto: San Andreas с MTA:SA, а также где их можно приобрести.&lt;br /&gt;
&lt;br /&gt;
=== Совместимость ===&lt;br /&gt;
&lt;br /&gt;
Если версия Grand Theft Auto: San Andreas, отмеченная ниже как совместимая, не работает, попробуйте переустановить MTA:SA. Если это не сработает, следуйте [https://forum.mtasa.com/topic/11757-patching-your-101-or-200-version-of-gta_saexe/ этим инструкциям]. Если это по-прежнему не сработает, пожалуйста, свяжитесь с нами на форуме [https://forum.mtasa.com/forum/83-client/] или присоединяйтесь к [https://mtasa.com/discord MTA Discord #help-support channel].&lt;br /&gt;
&lt;br /&gt;
{{Важное замечание|Grand Theft Auto: San Andreas как часть '''Grand Theft Auto: The Trilogy – The Definitive Edition''' ''(2021)'' — это совершенно новая версия игры. Данная версия является '''несовместимой''' с MTA:SA.}}&lt;br /&gt;
{{Important Note|Grand Theft Auto: San Andreas as part of '''Grand Theft Auto: The Trilogy – The Definitive Edition''' ''(2021)'' is an entirely new release of the game. This version is '''not compatible''' with MTA:SA.}}&lt;br /&gt;
&lt;br /&gt;
=== Получение совместимых и бывших в употреблении копий ===&lt;br /&gt;
&lt;br /&gt;
Официально единственный способ приобрести совместимую копию Grand Theft Auto: San Andreas от Rockstar Games и Take-Two — это приобрести коллекцию classic collection [https://store.rockstargames.com/en/game/buy/grand-theft-auto-the-trilogy &amp;quot;Grand Theft Auto: Trilogy&amp;quot; (2005) в магазине Rockstar Store].&lt;br /&gt;
&lt;br /&gt;
Есть только два других варианта: либо приобрести подержанную физическую копию через блошиные рынки и частных посредников, либо приобрести ключ для совместимой цифровой версии у посредника по продаже ключей.&lt;br /&gt;
&lt;br /&gt;
Ярким примером покупки подержанной физической копии на сайтах, указанных ниже. Введя в поле поиска «gta san andreas pc» или «gta san andreas», вы сможете найти множество людей, которые все еще продают совместимую игру. Однако будьте осторожны, поскольку покупка у ненадежных реселлеров, таких как неизвестные люди, не занимающиеся бизнесом, сопряжена с риском (например, подделки или поврежденные копии).&lt;br /&gt;
&lt;br /&gt;
Чтобы найти продавца цифровых ключей, воспользуйтесь поисковой системой, чтобы найти «Grand Theft Auto: San Andreas key» или что-то подобное.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Прежде чем рассматривать возможность покупки, оцените, какие источники являются надежными, и убедитесь, что ключ будет работать в вашем регионе. ===&lt;br /&gt;
&lt;br /&gt;
На этой странице перечислены некоторые веб-сайты, на которых можно купить Grand Theft Auto San Andreas в цифровом виде и играть в MTA:SA (иногда с автоматическим понижением версии игры). Не все из них были проверены, но все должно работать без проблем. Если нет, пожалуйста, обратитесь в службу поддержки.&lt;br /&gt;
&lt;br /&gt;
Известно, что все версии (DVD) GTA:SA для Windows функционируют нормально. Если вы планируете покупать DVD-диск GTA:SA, вам следует попытаться получить &amp;quot;Standard&amp;quot; версию, а не &amp;quot;Second Edition&amp;quot; или &amp;quot;Greatest Hits&amp;quot; издания, хотя они будут работать нормально.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 900px; text-align: center; table-layout: fixed;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Ритейлер&lt;br /&gt;
!Примечания&lt;br /&gt;
!Работает с MTA: SA?&lt;br /&gt;
|-&lt;br /&gt;
|[http://store.steampowered.com/app/12120/ Steam]&lt;br /&gt;
|Внимание: Grand Theft Auto: San Andreas больше не доступна в магазине Steam.Специализированная Steam-версия игры. Установщик MTA произведет даунгрейд (понижение) версии игры. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |[http://www.amazon.com/Grand-Theft-Auto-Andreas-Download/dp/B006YVXGJQ Amazon]&lt;br /&gt;
| Для '''Standard''' издания игры, если MTA несовместима, попробуйте найти GTA SA 1.00 No CD - любой релиз от HOODLUM будет функционировать без проблем.&lt;br /&gt;
| {{Partial|Не подтверждено (Standard)}}&lt;br /&gt;
|-&lt;br /&gt;
| Steam-версия и копии дисков GTASA будут функционировать нормально&lt;br /&gt;
| {{Yes| Да (Steam/DVD-бокс)}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamersgate.co.uk/DD-GTASAS/grand-theft-auto-san-andreas GamersGate]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.game.co.uk/en/grand-theft-auto-san-andreas-301403 Game UK]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://digital.gamefly.co.uk/#!/download-grand-theft-auto-san-andreas/5006365 GameFly Digital]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.greenmangaming.com/s/gb/en/pc/games/action/grand-theft-auto-san-andreas/ GreenManGaming]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamestop.com/pc/games/grand-theft-auto-san-andreas/37409 GameStop]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.walmart.com/ip/Take-Two-GTASAESD-Grand-Theft-Auto-San-Andreas-PC/36754297 Walmart]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ebay.com/sch/i.html?_from=R40&amp;amp;_trksid=p4432023.m570.l1313&amp;amp;_nkw=GTA%3ASA&amp;amp;_sacat=0 Ebay]&lt;br /&gt;
|Доступна к покупке (Нужна версия ПК).&lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|Windows App Store&lt;br /&gt;
|Мобильная версия игры, перенесенная на ПК. '''Никогда не будет работать с MTA'''.&lt;br /&gt;
|{{No|Нет}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
[[en:Where to buy GTASA]]&lt;br /&gt;
[[es:Dónde comprar GTA: SA]]&lt;br /&gt;
[[uk:Where to buy GTASA]]&lt;br /&gt;
[[pl:Where to buy GTASA]]&lt;br /&gt;
[[tr:GTA:SA Nerden Alınır]]&lt;br /&gt;
[[zh-cn:在那里可以购买GTASA]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82446</id>
		<title>RU/Where to buy GTASA</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=82446"/>
		<updated>2025-09-06T13:26:24Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;На этой странице описывается общая совместимость версий Grand Theft Auto: San Andreas с MTA:SA, а также где их можно приобрести.&lt;br /&gt;
&lt;br /&gt;
=== Совместимость ===&lt;br /&gt;
&lt;br /&gt;
Если версия Grand Theft Auto: San Andreas, отмеченная ниже как совместимая, не работает, попробуйте переустановить MTA:SA. Если это не сработает, следуйте [https://forum.mtasa.com/topic/11757-patching-your-101-or-200-version-of-gta_saexe/ этим инструкциям]. Если это по-прежнему не сработает, пожалуйста, свяжитесь с нами на форуме [https://forum.mtasa.com/forum/83-client/] или присоединяйтесь к [https://mtasa.com/discord MTA Discord #help-support channel].&lt;br /&gt;
&lt;br /&gt;
{{Важное замечание|Grand Theft Auto: San Andreas как часть '''Grand Theft Auto: The Trilogy – The Definitive Edition''' ''(2021)'' — это совершенно новая версия игры. Данная версия является '''несовместимой''' с MTA:SA.}}&lt;br /&gt;
&lt;br /&gt;
=== Получение совместимых и бывших в употреблении копий ===&lt;br /&gt;
&lt;br /&gt;
Официально единственный способ приобрести совместимую копию Grand Theft Auto: San Andreas от Rockstar Games и Take-Two — это приобрести коллекцию classic collection [https://store.rockstargames.com/en/game/buy/grand-theft-auto-the-trilogy &amp;quot;Grand Theft Auto: Trilogy&amp;quot; (2005) в магазине Rockstar Store].&lt;br /&gt;
&lt;br /&gt;
Есть только два других варианта: либо приобрести подержанную физическую копию через блошиные рынки и частных посредников, либо приобрести ключ для совместимой цифровой версии у посредника по продаже ключей.&lt;br /&gt;
&lt;br /&gt;
Ярким примером покупки подержанной физической копии на сайтах, указанных ниже. Введя в поле поиска «gta san andreas pc» или «gta san andreas», вы сможете найти множество людей, которые все еще продают совместимую игру. Однако будьте осторожны, поскольку покупка у ненадежных реселлеров, таких как неизвестные люди, не занимающиеся бизнесом, сопряжена с риском (например, подделки или поврежденные копии).&lt;br /&gt;
&lt;br /&gt;
Чтобы найти продавца цифровых ключей, воспользуйтесь поисковой системой, чтобы найти «Grand Theft Auto: San Andreas key» или что-то подобное.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Прежде чем рассматривать возможность покупки, оцените, какие источники являются надежными, и убедитесь, что ключ будет работать в вашем регионе. ===&lt;br /&gt;
&lt;br /&gt;
На этой странице перечислены некоторые веб-сайты, на которых можно купить Grand Theft Auto San Andreas в цифровом виде и играть в MTA:SA (иногда с автоматическим понижением версии игры). Не все из них были проверены, но все должно работать без проблем. Если нет, пожалуйста, обратитесь в службу поддержки.&lt;br /&gt;
&lt;br /&gt;
Известно, что все версии (DVD) GTA:SA для Windows функционируют нормально. Если вы планируете покупать DVD-диск GTA:SA, вам следует попытаться получить &amp;quot;Standard&amp;quot; версию, а не &amp;quot;Second Edition&amp;quot; или &amp;quot;Greatest Hits&amp;quot; издания, хотя они будут работать нормально.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 900px; text-align: center; table-layout: fixed;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Ритейлер&lt;br /&gt;
!Примечания&lt;br /&gt;
!Работает с MTA: SA?&lt;br /&gt;
|-&lt;br /&gt;
|[http://store.steampowered.com/app/12120/ Steam]&lt;br /&gt;
|Внимание: Grand Theft Auto: San Andreas больше не доступна в магазине Steam.Специализированная Steam-версия игры. Установщик MTA произведет даунгрейд (понижение) версии игры. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |[http://www.amazon.com/Grand-Theft-Auto-Andreas-Download/dp/B006YVXGJQ Amazon]&lt;br /&gt;
| Для '''Standard''' издания игры, если MTA несовместима, попробуйте найти GTA SA 1.00 No CD - любой релиз от HOODLUM будет функционировать без проблем.&lt;br /&gt;
| {{Partial|Не подтверждено (Standard)}}&lt;br /&gt;
|-&lt;br /&gt;
| Steam-версия и копии дисков GTASA будут функционировать нормально&lt;br /&gt;
| {{Yes| Да (Steam/DVD-бокс)}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamersgate.co.uk/DD-GTASAS/grand-theft-auto-san-andreas GamersGate]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.game.co.uk/en/grand-theft-auto-san-andreas-301403 Game UK]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://digital.gamefly.co.uk/#!/download-grand-theft-auto-san-andreas/5006365 GameFly Digital]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.greenmangaming.com/s/gb/en/pc/games/action/grand-theft-auto-san-andreas/ GreenManGaming]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamestop.com/pc/games/grand-theft-auto-san-andreas/37409 GameStop]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.walmart.com/ip/Take-Two-GTASAESD-Grand-Theft-Auto-San-Andreas-PC/36754297 Walmart]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ebay.com/sch/i.html?_from=R40&amp;amp;_trksid=p4432023.m570.l1313&amp;amp;_nkw=GTA%3ASA&amp;amp;_sacat=0 Ebay]&lt;br /&gt;
|Доступна к покупке (Нужна версия ПК).&lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|Windows App Store&lt;br /&gt;
|Мобильная версия игры, перенесенная на ПК. '''Никогда не будет работать с MTA'''.&lt;br /&gt;
|{{No|Нет}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
[[en:Where to buy GTASA]]&lt;br /&gt;
[[es:Dónde comprar GTA: SA]]&lt;br /&gt;
[[uk:Where to buy GTASA]]&lt;br /&gt;
[[pl:Where to buy GTASA]]&lt;br /&gt;
[[tr:GTA:SA Nerden Alınır]]&lt;br /&gt;
[[zh-cn:在那里可以购买GTASA]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Resource:Hedit&amp;diff=82190</id>
		<title>Resource:Hedit</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Resource:Hedit&amp;diff=82190"/>
		<updated>2025-07-01T20:58:31Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Resource page}}&lt;br /&gt;
The MTA Ingame Handling Editor (known as 'hedit') is an open source resource that was created in 2010 and has been included in the official MTA resources package since 2021.&lt;br /&gt;
&lt;br /&gt;
You can see and download the latest version on the Hedit page of [https://github.com/multitheftauto/mtasa-resources/tree/master/%5Bgameplay%5D/hedit official resources '''GitHub repository'''] or download it directly from the latest package at https://mirror-cdn.multitheftauto.com/mtasa/resources/mtasa-resources-latest.zip. &amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''[https://forum.mtasa.com/topic/25539-hedit-mta-ingame-handling-editor-v214/ Be sure to see the Hedit forum topic for all information!]'''&lt;br /&gt;
&lt;br /&gt;
[https://github.com/multitheftauto/mtasa-resources/tree/master/%5Bgameplay%5D/hedit GitHub repository] - See and get the latest changes here.&amp;lt;br&amp;gt;&lt;br /&gt;
[https://forum.mtasa.com/topic/25539-hedit-mta-ingame-handling-editor-v214/ Official Forum Topic] - The place for discussing this project.&amp;lt;br&amp;gt;&lt;br /&gt;
[http://www.youtube.com/user/SilentStrikeMTA?feature=mhsn#p/p Youtube playlist] - Full playlist of several development video's of the handling editor.&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=79372</id>
		<title>RU/Where to buy GTASA</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Where_to_buy_GTASA&amp;diff=79372"/>
		<updated>2024-05-22T18:40:59Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;На этой странице перечислены некоторые веб-сайты, на которых можно купить Grand Theft Auto San Andreas в цифровом виде и играть в MTASA (иногда с автоматическим понижением версии игры). Не все из них были проверены, но все должно работать без проблем. Если нет, пожалуйста, обратитесь в службу поддержки.&lt;br /&gt;
&lt;br /&gt;
Известно, что все версии (DVD) GTASA для Windows функционируют нормально. Если вы планируете покупать DVD-диск GTASA, вам следует попытаться получить &amp;quot;Standard&amp;quot; версию, а не &amp;quot;Second Edition&amp;quot; или &amp;quot;Greatest Hits&amp;quot; издания, хотя они будут работать нормально.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width: 900px; text-align: center; table-layout: fixed;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Ритейлер&lt;br /&gt;
!Примечания&lt;br /&gt;
!Работает с MTA: SA?&lt;br /&gt;
|-&lt;br /&gt;
|[http://store.steampowered.com/app/12120/ Steam]&lt;br /&gt;
|Внимание: Grand Theft Auto: San Andreas больше не доступна в магазине Steam.Специализированная Steam-версия игры. Установщик MTA произведет даунгрейд (понижение) версии игры. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
| rowspan=&amp;quot;2&amp;quot; |[http://www.amazon.com/Grand-Theft-Auto-Andreas-Download/dp/B006YVXGJQ Amazon]&lt;br /&gt;
| Для '''Standard''' издания игры, если MTA несовместима, попробуйте найти GTA SA 1.00 No CD - любой релиз от HOODLUM будет функционировать без проблем.&lt;br /&gt;
| {{Partial|Не подтверждено (Standard)}}&lt;br /&gt;
|-&lt;br /&gt;
| Steam-версия и копии дисков GTASA будут функционировать нормально&lt;br /&gt;
| {{Yes| Да (Steam/DVD-бокс)}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamersgate.co.uk/DD-GTASAS/grand-theft-auto-san-andreas GamersGate]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.game.co.uk/en/grand-theft-auto-san-andreas-301403 Game UK]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://digital.gamefly.co.uk/#!/download-grand-theft-auto-san-andreas/5006365 GameFly Digital]&lt;br /&gt;
|К сожалению, данная страница больше не доступна. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.greenmangaming.com/s/gb/en/pc/games/action/grand-theft-auto-san-andreas/ GreenManGaming]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.gamestop.com/pc/games/grand-theft-auto-san-andreas/37409 GameStop]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.walmart.com/ip/Take-Two-GTASAESD-Grand-Theft-Auto-San-Andreas-PC/36754297 Walmart]&lt;br /&gt;
|К сожалению, этот сайт недоступен в вашем регионе. &lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|[https://www.ebay.com/sch/i.html?_from=R40&amp;amp;_trksid=p4432023.m570.l1313&amp;amp;_nkw=GTA%3ASA&amp;amp;_sacat=0 Ebay]&lt;br /&gt;
|Доступна к покупке (Нужна версия ПК).&lt;br /&gt;
|{{Yes|Да}}&lt;br /&gt;
|-&lt;br /&gt;
|Windows App Store&lt;br /&gt;
|Мобильная версия игры, перенесенная на ПК. '''Никогда не будет работать с MTA'''.&lt;br /&gt;
|{{No|Нет}}&lt;br /&gt;
|-&lt;br /&gt;
&lt;br /&gt;
[[en:Where to buy GTASA]]&lt;br /&gt;
[[es:Dónde comprar GTA: SA]]&lt;br /&gt;
[[uk:Where to buy GTASA]]&lt;br /&gt;
[[pl:Where to buy GTASA]]&lt;br /&gt;
[[tr:GTA:SA Nerden Alınır]]&lt;br /&gt;
[[zh-cn:在那里可以购买GTASA]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=OOP&amp;diff=79364</id>
		<title>OOP</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=OOP&amp;diff=79364"/>
		<updated>2024-05-21T15:54:35Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Object Orientated Programming was introduced in MTA:SA 1.4 and comes with special utility classes like [[Vector]] and [[Matrix]]. This page contains general information about the OOP functions and provides useful links.&lt;br /&gt;
&lt;br /&gt;
== Turning it on ==&lt;br /&gt;
By default, OOP is disabled (however, vectors and matrices are always available) - this is mainly because the vast majority of servers will prefer to stick to what they know - procedural programming. In fact, functions are still available even when OOP is enabled. Enabling OOP is as simple as adding the following line to the resource meta file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;lt;oop&amp;gt;true&amp;lt;/oop&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vectors and Matrices ==&lt;br /&gt;
[[Vector|Vectors]] and [[Matrix|Matrices]] make it easier to drop the complex maths and go straight ahead with fun part of maths. As mentioned above, OOP does not have to be enabled in the server config for this to be enabled.&lt;br /&gt;
&lt;br /&gt;
==ADVANCED: OOP Metatable Structure==&lt;br /&gt;
You will understand this if you're proficient with Lua and have a decent understanding of metatables. Understanding this section is not necessary to use OOP.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- Exposed to global environment&lt;br /&gt;
Element = {&lt;br /&gt;
    Element = createElement,&lt;br /&gt;
    setPosition = setElementPosition,&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Vehicle = {&lt;br /&gt;
    Vehicle = createVehicle,&lt;br /&gt;
    setColor = setVehicleColor,&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Hidden in lua registry, applied to userdata&lt;br /&gt;
ElementMT = {&lt;br /&gt;
    __index = CLuaClassDefs::Index,&lt;br /&gt;
    __newindex = CLuaClassDefs::NewIndex,&lt;br /&gt;
    __class = Element,&lt;br /&gt;
    __call = __class.create,&lt;br /&gt;
    __set = {&lt;br /&gt;
        type = CLuaClassDefs::ReadOnly,&lt;br /&gt;
        health = setElementHealth,&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
    __get = {&lt;br /&gt;
        type = getElementType,&lt;br /&gt;
        health = getElementHealth,&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
VehicleMT = {&lt;br /&gt;
    __index = CLuaClassDefs::Index,&lt;br /&gt;
    __newindex = CLuaClassDefs::NewIndex,&lt;br /&gt;
    __class = Vehicle,&lt;br /&gt;
    __parent = ElementMT,&lt;br /&gt;
    __call = __class.create,&lt;br /&gt;
    __set = {&lt;br /&gt;
        damageProof = setVehicleDamageProof&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
    __get = {&lt;br /&gt;
        damageProof = isVehicleDamageProof&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Useful Links ==&lt;br /&gt;
* '''[[OOP Introduction]]''' - teaches you about the basics of OOP&lt;br /&gt;
* '''[[OOP_client|Function list (client)]]''' and '''[[OOP_server|Function list (server)]]''' - a list of functions implemented&lt;br /&gt;
&lt;br /&gt;
[[Category:OOP]]&lt;br /&gt;
[[Category:Incomplete]]&lt;br /&gt;
[[Category:Tutorials]]&lt;br /&gt;
&lt;br /&gt;
[[Ru/OOP]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=OOP&amp;diff=79363</id>
		<title>OOP</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=OOP&amp;diff=79363"/>
		<updated>2024-05-21T15:54:14Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Object Orientated Programming was introduced in MTA:SA 1.4 and comes with special utility classes like [[Vector]] and [[Matrix]]. This page contains general information about the OOP functions and provides useful links.&lt;br /&gt;
&lt;br /&gt;
== Turning it on ==&lt;br /&gt;
By default, OOP is disabled (however, vectors and matrices are always available) - this is mainly because the vast majority of servers will prefer to stick to what they know - procedural programming. In fact, functions are still available even when OOP is enabled. Enabling OOP is as simple as adding the following line to the resource meta file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;lt;oop&amp;gt;true&amp;lt;/oop&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vectors and Matrices ==&lt;br /&gt;
[[Vector|Vectors]] and [[Matrix|Matrices]] make it easier to drop the complex maths and go straight ahead with fun part of maths. As mentioned above, OOP does not have to be enabled in the server config for this to be enabled.&lt;br /&gt;
&lt;br /&gt;
==ADVANCED: OOP Metatable Structure==&lt;br /&gt;
You will understand this if you're proficient with Lua and have a decent understanding of metatables. Understanding this section is not necessary to use OOP.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- Exposed to global environment&lt;br /&gt;
Element = {&lt;br /&gt;
    Element = createElement,&lt;br /&gt;
    setPosition = setElementPosition,&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Vehicle = {&lt;br /&gt;
    Vehicle = createVehicle,&lt;br /&gt;
    setColor = setVehicleColor,&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Hidden in lua registry, applied to userdata&lt;br /&gt;
ElementMT = {&lt;br /&gt;
    __index = CLuaClassDefs::Index,&lt;br /&gt;
    __newindex = CLuaClassDefs::NewIndex,&lt;br /&gt;
    __class = Element,&lt;br /&gt;
    __call = __class.create,&lt;br /&gt;
    __set = {&lt;br /&gt;
        type = CLuaClassDefs::ReadOnly,&lt;br /&gt;
        health = setElementHealth,&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
    __get = {&lt;br /&gt;
        type = getElementType,&lt;br /&gt;
        health = getElementHealth,&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
VehicleMT = {&lt;br /&gt;
    __index = CLuaClassDefs::Index,&lt;br /&gt;
    __newindex = CLuaClassDefs::NewIndex,&lt;br /&gt;
    __class = Vehicle,&lt;br /&gt;
    __parent = ElementMT,&lt;br /&gt;
    __call = __class.create,&lt;br /&gt;
    __set = {&lt;br /&gt;
        damageProof = setVehicleDamageProof&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
    __get = {&lt;br /&gt;
        damageProof = isVehicleDamageProof&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Useful Links ==&lt;br /&gt;
* '''[[OOP Introduction]]''' - teaches you about the basics of OOP&lt;br /&gt;
* '''[[OOP_client|Function list (client)]]''' and '''[[OOP_server|Function list (server)]]''' - a list of functions implemented&lt;br /&gt;
&lt;br /&gt;
[[Category:OOP]]&lt;br /&gt;
[[Category:Incomplete]]&lt;br /&gt;
[[Category:Tutorials]]&lt;br /&gt;
&lt;br /&gt;
[[ru:OOP]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=OOP&amp;diff=79362</id>
		<title>OOP</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=OOP&amp;diff=79362"/>
		<updated>2024-05-21T15:54:02Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Object Orientated Programming was introduced in MTA:SA 1.4 and comes with special utility classes like [[Vector]] and [[Matrix]]. This page contains general information about the OOP functions and provides useful links.&lt;br /&gt;
&lt;br /&gt;
== Turning it on ==&lt;br /&gt;
By default, OOP is disabled (however, vectors and matrices are always available) - this is mainly because the vast majority of servers will prefer to stick to what they know - procedural programming. In fact, functions are still available even when OOP is enabled. Enabling OOP is as simple as adding the following line to the resource meta file:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;lt;oop&amp;gt;true&amp;lt;/oop&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Vectors and Matrices ==&lt;br /&gt;
[[Vector|Vectors]] and [[Matrix|Matrices]] make it easier to drop the complex maths and go straight ahead with fun part of maths. As mentioned above, OOP does not have to be enabled in the server config for this to be enabled.&lt;br /&gt;
&lt;br /&gt;
==ADVANCED: OOP Metatable Structure==&lt;br /&gt;
You will understand this if you're proficient with Lua and have a decent understanding of metatables. Understanding this section is not necessary to use OOP.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- Exposed to global environment&lt;br /&gt;
Element = {&lt;br /&gt;
    Element = createElement,&lt;br /&gt;
    setPosition = setElementPosition,&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Vehicle = {&lt;br /&gt;
    Vehicle = createVehicle,&lt;br /&gt;
    setColor = setVehicleColor,&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Hidden in lua registry, applied to userdata&lt;br /&gt;
ElementMT = {&lt;br /&gt;
    __index = CLuaClassDefs::Index,&lt;br /&gt;
    __newindex = CLuaClassDefs::NewIndex,&lt;br /&gt;
    __class = Element,&lt;br /&gt;
    __call = __class.create,&lt;br /&gt;
    __set = {&lt;br /&gt;
        type = CLuaClassDefs::ReadOnly,&lt;br /&gt;
        health = setElementHealth,&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
    __get = {&lt;br /&gt;
        type = getElementType,&lt;br /&gt;
        health = getElementHealth,&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
VehicleMT = {&lt;br /&gt;
    __index = CLuaClassDefs::Index,&lt;br /&gt;
    __newindex = CLuaClassDefs::NewIndex,&lt;br /&gt;
    __class = Vehicle,&lt;br /&gt;
    __parent = ElementMT,&lt;br /&gt;
    __call = __class.create,&lt;br /&gt;
    __set = {&lt;br /&gt;
        damageProof = setVehicleDamageProof&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
    __get = {&lt;br /&gt;
        damageProof = isVehicleDamageProof&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Useful Links ==&lt;br /&gt;
* '''[[OOP Introduction]]''' - teaches you about the basics of OOP&lt;br /&gt;
* '''[[OOP_client|Function list (client)]]''' and '''[[OOP_server|Function list (server)]]''' - a list of functions implemented&lt;br /&gt;
&lt;br /&gt;
[[Category:OOP]]&lt;br /&gt;
[[Category:Incomplete]]&lt;br /&gt;
[[Category:Tutorials]]&lt;br /&gt;
&lt;br /&gt;
[[ru:OOP Russian]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Ru/OOP&amp;diff=79361</id>
		<title>Ru/OOP</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Ru/OOP&amp;diff=79361"/>
		<updated>2024-05-21T15:50:47Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Объектно-ориентированное программирование было введено в MTA:SA 1.4 и поставляется со специальными служебными классами, такими как [[Vector]] и [[Matrix]]. Эта страница содержит общую информацию о функциях OOP и содержит полезные ссылки.&lt;br /&gt;
&lt;br /&gt;
== Включение ==&lt;br /&gt;
По умолчанию ООП отключено (однако векторы и матрицы доступны всегда) - это происходит главным образом потому, что подавляющее большинство серверов предпочитают придерживаться того, что они знают, - процедурного программирования. На самом деле, функции по-прежнему доступны, даже если ООП включено. Включить ООП так же просто, как добавить следующую строку в мета-файл ресурса:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;lt;oop&amp;gt;true&amp;lt;/oop&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Векторы и матрицы ==&lt;br /&gt;
[[Vector|Vectors]] и [[Matrix|Matrices]] так будет проще отказаться от сложной математики и сразу перейти к увлекательной ее части. Как упоминалось выше, для этого необязательно включать OOP в конфигурации сервера.&lt;br /&gt;
&lt;br /&gt;
==ДОПОЛНИТЕЛЬНО: Метастабильная структура OOP ==&lt;br /&gt;
Вы поймете это, если хорошо владеете Lua и хорошо разбираетесь в метатаблях. Понимание этого раздела не обязательно для использования OOP.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- Подвержен воздействию глобальной окружающей среды&lt;br /&gt;
Element = {&lt;br /&gt;
    Element = createElement,&lt;br /&gt;
    setPosition = setElementPosition,&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Vehicle = {&lt;br /&gt;
    Vehicle = createVehicle,&lt;br /&gt;
    setColor = setVehicleColor,&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Скрыто в реестре lua, применяется к пользовательским данным&lt;br /&gt;
ElementMT = {&lt;br /&gt;
    __index = CLuaClassDefs::Index,&lt;br /&gt;
    __newindex = CLuaClassDefs::NewIndex,&lt;br /&gt;
    __class = Element,&lt;br /&gt;
    __call = __class.create,&lt;br /&gt;
    __set = {&lt;br /&gt;
        type = CLuaClassDefs::ReadOnly,&lt;br /&gt;
        health = setElementHealth,&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
    __get = {&lt;br /&gt;
        type = getElementType,&lt;br /&gt;
        health = getElementHealth,&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
VehicleMT = {&lt;br /&gt;
    __index = CLuaClassDefs::Index,&lt;br /&gt;
    __newindex = CLuaClassDefs::NewIndex,&lt;br /&gt;
    __class = Vehicle,&lt;br /&gt;
    __parent = ElementMT,&lt;br /&gt;
    __call = __class.create,&lt;br /&gt;
    __set = {&lt;br /&gt;
        damageProof = setVehicleDamageProof&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
    __get = {&lt;br /&gt;
        damageProof = isVehicleDamageProof&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Полезные ссылки ==&lt;br /&gt;
* '''[[OOP Introduction]]''' - познакомит вас с основами OOP&lt;br /&gt;
* '''[[OOP_client|Function list (client)]]''' и '''[[OOP_server|Function list (server)]]''' - список реализованных функций&lt;br /&gt;
&lt;br /&gt;
== Выше предоставлены страницы с полезными ссылками на английском языке. ==&lt;br /&gt;
&lt;br /&gt;
[[Category:OOP]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Ru/OOP&amp;diff=79360</id>
		<title>Ru/OOP</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Ru/OOP&amp;diff=79360"/>
		<updated>2024-05-21T15:50:34Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Объектно-ориентированное программирование было введено в MTA:SA 1.4 и поставляется со специальными служебными классами, такими как [[Vector]] и [[Matrix]]. Эта страница содержит общую информацию о функциях OOP и содержит полезные ссылки.&lt;br /&gt;
&lt;br /&gt;
== Включение ==&lt;br /&gt;
По умолчанию ООП отключено (однако векторы и матрицы доступны всегда) - это происходит главным образом потому, что подавляющее большинство серверов предпочитают придерживаться того, что они знают, - процедурного программирования. На самом деле, функции по-прежнему доступны, даже если ООП включено. Включить ООП так же просто, как добавить следующую строку в мета-файл ресурса:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;lt;oop&amp;gt;true&amp;lt;/oop&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Векторы и матрицы ==&lt;br /&gt;
[[Vector|Vectors]] и [[Matrix|Matrices]] так будет проще отказаться от сложной математики и сразу перейти к увлекательной ее части. Как упоминалось выше, для этого необязательно включать OOP в конфигурации сервера.&lt;br /&gt;
&lt;br /&gt;
==ДОПОЛНИТЕЛЬНО: Метастабильная структура OOP ==&lt;br /&gt;
Вы поймете это, если хорошо владеете Lua и хорошо разбираетесь в метатаблях. Понимание этого раздела не обязательно для использования OOP.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- Подвержен воздействию глобальной окружающей среды&lt;br /&gt;
Element = {&lt;br /&gt;
    Element = createElement,&lt;br /&gt;
    setPosition = setElementPosition,&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Vehicle = {&lt;br /&gt;
    Vehicle = createVehicle,&lt;br /&gt;
    setColor = setVehicleColor,&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Скрыто в реестре lua, применяется к пользовательским данным&lt;br /&gt;
ElementMT = {&lt;br /&gt;
    __index = CLuaClassDefs::Index,&lt;br /&gt;
    __newindex = CLuaClassDefs::NewIndex,&lt;br /&gt;
    __class = Element,&lt;br /&gt;
    __call = __class.create,&lt;br /&gt;
    __set = {&lt;br /&gt;
        type = CLuaClassDefs::ReadOnly,&lt;br /&gt;
        health = setElementHealth,&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
    __get = {&lt;br /&gt;
        type = getElementType,&lt;br /&gt;
        health = getElementHealth,&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
VehicleMT = {&lt;br /&gt;
    __index = CLuaClassDefs::Index,&lt;br /&gt;
    __newindex = CLuaClassDefs::NewIndex,&lt;br /&gt;
    __class = Vehicle,&lt;br /&gt;
    __parent = ElementMT,&lt;br /&gt;
    __call = __class.create,&lt;br /&gt;
    __set = {&lt;br /&gt;
        damageProof = setVehicleDamageProof&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
    __get = {&lt;br /&gt;
        damageProof = isVehicleDamageProof&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Полезные ссылки ==&lt;br /&gt;
* '''[[OOP Introduction]]''' - познакомит вас с основами OOP&lt;br /&gt;
* '''[[OOP_client|Function list (client)]]''' и '''[[OOP_server|Function list (server)]]''' - список реализованных функций&lt;br /&gt;
&lt;br /&gt;
== Выше предоставлены страницы с полезными ссылками на английском языке. ==&lt;br /&gt;
&lt;br /&gt;
[[Category:OOP]]&lt;br /&gt;
&lt;br /&gt;
[[OOP English]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=Ru/OOP&amp;diff=79359</id>
		<title>Ru/OOP</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=Ru/OOP&amp;diff=79359"/>
		<updated>2024-05-21T15:49:28Z</updated>

		<summary type="html">&lt;p&gt;Flox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Объектно-ориентированное программирование было введено в MTA:SA 1.4 и поставляется со специальными служебными классами, такими как [[Vector]] и [[Matrix]]. Эта страница содержит общую информацию о функциях OOP и содержит полезные ссылки.&lt;br /&gt;
&lt;br /&gt;
== Включение ==&lt;br /&gt;
По умолчанию ООП отключено (однако векторы и матрицы доступны всегда) - это происходит главным образом потому, что подавляющее большинство серверов предпочитают придерживаться того, что они знают, - процедурного программирования. На самом деле, функции по-прежнему доступны, даже если ООП включено. Включить ООП так же просто, как добавить следующую строку в мета-файл ресурса:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&amp;lt;oop&amp;gt;true&amp;lt;/oop&amp;gt;&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Векторы и матрицы ==&lt;br /&gt;
[[Vector|Vectors]] и [[Matrix|Matrices]] так будет проще отказаться от сложной математики и сразу перейти к увлекательной ее части. Как упоминалось выше, для этого необязательно включать OOP в конфигурации сервера.&lt;br /&gt;
&lt;br /&gt;
==ДОПОЛНИТЕЛЬНО: Метастабильная структура OOP ==&lt;br /&gt;
Вы поймете это, если хорошо владеете Lua и хорошо разбираетесь в метатаблях. Понимание этого раздела не обязательно для использования OOP.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;lua&amp;quot;&amp;gt;&lt;br /&gt;
-- Подвержен воздействию глобальной окружающей среды&lt;br /&gt;
Element = {&lt;br /&gt;
    Element = createElement,&lt;br /&gt;
    setPosition = setElementPosition,&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
Vehicle = {&lt;br /&gt;
    Vehicle = createVehicle,&lt;br /&gt;
    setColor = setVehicleColor,&lt;br /&gt;
    ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
-- Скрыто в реестре lua, применяется к пользовательским данным&lt;br /&gt;
ElementMT = {&lt;br /&gt;
    __index = CLuaClassDefs::Index,&lt;br /&gt;
    __newindex = CLuaClassDefs::NewIndex,&lt;br /&gt;
    __class = Element,&lt;br /&gt;
    __call = __class.create,&lt;br /&gt;
    __set = {&lt;br /&gt;
        type = CLuaClassDefs::ReadOnly,&lt;br /&gt;
        health = setElementHealth,&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
    __get = {&lt;br /&gt;
        type = getElementType,&lt;br /&gt;
        health = getElementHealth,&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
VehicleMT = {&lt;br /&gt;
    __index = CLuaClassDefs::Index,&lt;br /&gt;
    __newindex = CLuaClassDefs::NewIndex,&lt;br /&gt;
    __class = Vehicle,&lt;br /&gt;
    __parent = ElementMT,&lt;br /&gt;
    __call = __class.create,&lt;br /&gt;
    __set = {&lt;br /&gt;
        damageProof = setVehicleDamageProof&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
    __get = {&lt;br /&gt;
        damageProof = isVehicleDamageProof&lt;br /&gt;
        ...&lt;br /&gt;
    },&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Полезные ссылки ==&lt;br /&gt;
* '''[[OOP Introduction]]''' - познакомит вас с основами OOP&lt;br /&gt;
* '''[[OOP_client|Function list (client)]]''' и '''[[OOP_server|Function list (server)]]''' - список реализованных функций&lt;br /&gt;
&lt;br /&gt;
== Выше предоставлены страницы с полезными ссылками на английском языке. ==&lt;br /&gt;
&lt;br /&gt;
[[Category:OOP]]&lt;br /&gt;
&lt;br /&gt;
[[https://wiki.multitheftauto.com/wiki/OOP|en:OOP English]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
	<entry>
		<id>https://wiki.multitheftauto.com/index.php?title=RU/Meta.xml&amp;diff=79358</id>
		<title>RU/Meta.xml</title>
		<link rel="alternate" type="text/html" href="https://wiki.multitheftauto.com/index.php?title=RU/Meta.xml&amp;diff=79358"/>
		<updated>2024-05-21T15:47:18Z</updated>

		<summary type="html">&lt;p&gt;Flox: /* Тэги */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Файл ''meta.xml'' представляет MTA набор метаданных, таких как название ресурса, включенные в него скрипты и какие файлы предварительно кэшировать для отправки клиенту, это лишь часть. В нем также объявляются &amp;quot;элементы&amp;quot; для дальнейшей работы с ними. Он написан в XML, который базируется на HTML, и является родителем XHTML.&lt;br /&gt;
&lt;br /&gt;
=Тэги=&lt;br /&gt;
XML - текстовый формат данных, широко используемый для представления данных. MTA использует базирующийся на XML язык для описания метаданных ресурсов с использованием тегов ниже:&lt;br /&gt;
&lt;br /&gt;
*'''&amp;lt;info /&amp;gt;''' Информация об этом ресурсе, возможные для включения параметры (любые произвольные параметры могут быть использованы и прочитаны с помощью [[getResourceInfo]]):&lt;br /&gt;
** '''author:''' Автор данного ресурса&lt;br /&gt;
** '''version:''' Версия ресурса&lt;br /&gt;
** '''name:''' Название ресурса&lt;br /&gt;
** '''description:''' Краткое описание ресурса&lt;br /&gt;
** '''type:''' Тип ресурса, может быть &amp;quot;gamemode&amp;quot; (игровой режим, мод), &amp;quot;script&amp;quot; (сценарий, скрипт), &amp;quot;map&amp;quot; (карта) или &amp;quot;misc&amp;quot; (разное).&lt;br /&gt;
*'''&amp;lt;script /&amp;gt;''' Исходный код ресурса, возможные параметры:&lt;br /&gt;
** '''src:''' Название файла с исходным кодом (скрипта)&lt;br /&gt;
** '''type:''' Тип исходного кода: &amp;quot;client&amp;quot;, &amp;quot;server&amp;quot; или &amp;quot;shared&amp;quot;&lt;br /&gt;
** '''validate:''' Если установлено значение &amp;quot;false&amp;quot;, то актуальность скрипта проверяться не будет.&lt;br /&gt;
** '''cache:''' Кеширование для клиентского скрипта, если установлено &amp;quot;false&amp;quot;, то скрипт не будет сохраняться на диске клиента.&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
** '''protected:''' Для клиентских скриптов, должен ли данный скрипт сохраняться на жестком диске клиента или нет: &amp;quot;true&amp;quot; (да) или &amp;quot;false&amp;quot; (нет). &lt;br /&gt;
--&amp;gt;&lt;br /&gt;
*'''&amp;lt;map /&amp;gt;''' Карта для мода, возможные параметры:&lt;br /&gt;
**'''src:''' название .map-файла (может быть в т.ч. и путь, напр. &amp;quot;maps/filename.map&amp;quot;)&lt;br /&gt;
**'''dimension:''' Измерение, в котором карта будет загружена (опционально)&lt;br /&gt;
*'''&amp;lt;file /&amp;gt;''' Клиентский файл. В основном, это картинки, .txd, .col, .dff или .xml файлы. Они будут скачаны клиентами при старте ресурса (или при заходе)&lt;br /&gt;
**'''src:''' название клиентского файла (может быть в т.ч. и путь, напр. &amp;quot;images/image.png&amp;quot;)&lt;br /&gt;
**'''download:''' Должен ли файл быть послан клиенту автоматически или нет (опционально). По умолчанию &amp;quot;true&amp;quot;, использование &amp;quot;no&amp;quot; или &amp;quot;false&amp;quot; будет значить, что файл не будет послан при старте ресурса, но сможет быть задействован позже через [[downloadFile]] (с версии 1.4)&lt;br /&gt;
*'''&amp;lt;include /&amp;gt;''' Включение других ресурсов, которые будет использовать данный ресурс&lt;br /&gt;
**'''resource:''' Название ресурса, который вы хотите чтоб стартовал с данным ресурсом&lt;br /&gt;
**'''minversion:''' Минимальная версия, которая должна быть у '''ресурса''' (опционально)&lt;br /&gt;
**'''maxversion:''' Максимальная версия, которая должна быть у '''ресурса''' (опционально)&lt;br /&gt;
*'''&amp;lt;config /&amp;gt;''' Конфигурационный файл (.xml), к которому будет иметь доступ ресурс, допустимые параметры:&lt;br /&gt;
**'''src:''' Название конфигурационного файла&lt;br /&gt;
**'''type:''' Тип конфигурационного файла: &amp;quot;client&amp;quot; или &amp;quot;server&amp;quot;&lt;br /&gt;
*'''&amp;lt;export /&amp;gt;''' Это экспортирует функции из данного ресурса, чтобы другие ресурсы могли ими пользоваться через [[call]]&lt;br /&gt;
**'''function:''' Название функции&lt;br /&gt;
**'''type''' Является ли экспортированная функция серверной или клиентской (допустимые значения: &amp;quot;client&amp;quot;, &amp;quot;server&amp;quot; и &amp;quot;shared&amp;quot;)&lt;br /&gt;
**'''http:''' Может ли функция быть вызвана через HTTP (true/false)&lt;br /&gt;
*'''&amp;lt;html /&amp;gt;'''&lt;br /&gt;
**'''src:''' Название HTTP-файла (может быть и путем)&lt;br /&gt;
**'''default:''' Является ли html-файл тем, который будет показан по умолчанию при заходе в /имяРесурса/ на сервере. Только один html может быть по умолчанию, все остальные игнорируются. (true/false)&lt;br /&gt;
**'''raw:''' Html-файл не анализируется Lua-интерпретатором и рассматривается как двоичные данные. Обязательно должно использоваться для двоичных файлов (в основном картинок) (true/false)&lt;br /&gt;
*'''&amp;lt;settings&amp;gt; &amp;lt;setting name=&amp;quot;&amp;quot; value=&amp;quot;&amp;quot;/&amp;gt; &amp;lt;/settings&amp;gt;:''' Большинство модов использует [[settings system]], чтобы позволить администраторам серверов настраивать его по их желанию. Например, вы можете установить время раунда, а затем воспользоваться [[get]] и [[set]] для получения или изменения значений соответственно.&lt;br /&gt;
*'''&amp;lt;min_mta_version /&amp;gt;''' Минимальная требуемая версия для правильной работы данного ресурса. При авторинге ресурсов, обычно минимальная версия должна быть установлена на в данный момент зарелиженную версию MTA:SA (на данный момент это &amp;quot;{{Current Version|full}}&amp;quot;).&lt;br /&gt;
**'''client:''' Минимальная версия клиента&lt;br /&gt;
**'''server:''' Минимальная версия сервера&lt;br /&gt;
*'''&amp;lt;aclrequest /&amp;gt;''' Лист [[Access_Control_List|ACL]]-прав, которые понадобятся ресурсу.&lt;br /&gt;
*'''&amp;lt;oop&amp;gt;true/false&amp;lt;/oop&amp;gt;''' Пожалуйста, обратитесь к [[Ru/OOP|ООП]] за документацией&lt;br /&gt;
{{New items|3.0139|1.3.1 r4141|&lt;br /&gt;
*'''&amp;lt;sync_map_element_data /&amp;gt;''' Контролирует, пересылаются ли [[Element_data|данные элементов]] карты, такие как &amp;quot;PosX&amp;quot; и &amp;quot;DoubleSided&amp;quot; клиенту. Эти данные зачастую не требуются большинству модов или ресурсов. (Но следует отметить значимое исключения - map editor). При установке параметра в meta.xml мода, настройка применится ко всем картам, загруженным данным ресурсом.&lt;br /&gt;
**'''false:''' Отключить пересылку данных элементов карты. Это может значительно уменьшить время закачки карты.&lt;br /&gt;
**'''true:''' Включить пересылку данных элементов карты (по умолчанию).&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Пример ==&lt;br /&gt;
Вот и пример meta-файла, использующего некоторые из упомянутых тегов:&lt;br /&gt;
{{#tag:syntaxhighlight |&lt;br /&gt;
&amp;lt;meta&amp;gt;&lt;br /&gt;
    &amp;lt;info author=&amp;quot;Slothman&amp;quot; type=&amp;quot;gamemode&amp;quot; name=&amp;quot;Stealth&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;config src=&amp;quot;help.xml&amp;quot; type=&amp;quot;client&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;min_mta_version client=&amp;quot;{{Current Version|full}}&amp;quot; server=&amp;quot;{{Current Version|full}}&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;script src=&amp;quot;stealthmain_server.lua&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;script src=&amp;quot;noiseblip.lua&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;script src=&amp;quot;mission_timer.lua&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;script src=&amp;quot;gadgets_server.lua&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;script src=&amp;quot;gadgets_client.lua&amp;quot; type=&amp;quot;client&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;script src=&amp;quot;stealthmain_client.lua&amp;quot; type=&amp;quot;client&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;script src=&amp;quot;noisebar.lua&amp;quot; type=&amp;quot;client&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;script src=&amp;quot;spycam.lua&amp;quot; type=&amp;quot;client&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;script src=&amp;quot;riemann_z_demonstration.lua&amp;quot; type=&amp;quot;client&amp;quot; cache=&amp;quot;false&amp;quot;/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;file src=&amp;quot;riot_shield.txd&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;file src=&amp;quot;riot_shield.dff&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;file src=&amp;quot;riot_shield.col&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;file src=&amp;quot;armor.png&amp;quot; download=&amp;quot;true&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;file src=&amp;quot;camera.png&amp;quot; download=&amp;quot;false&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;file src=&amp;quot;cloak.png&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;file src=&amp;quot;goggles.png&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;file src=&amp;quot;mine.png&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;file src=&amp;quot;radar.png&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;file src=&amp;quot;shield.png&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;include resource=&amp;quot;scoreboard&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;include resource=&amp;quot;killmessages&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;include resource=&amp;quot;maplimits&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;export function=&amp;quot;exampleExport1&amp;quot; type=&amp;quot;server&amp;quot; /&amp;gt; &amp;lt;!-- Название ваших функций сервера --&amp;gt;&lt;br /&gt;
    &amp;lt;export function=&amp;quot;exampleExport2&amp;quot; type=&amp;quot;client&amp;quot; /&amp;gt; &amp;lt;!-- Название ваших функций клиента --&amp;gt;&lt;br /&gt;
    &amp;lt;export function=&amp;quot;exampleExport3&amp;quot; type=&amp;quot;shared&amp;quot; /&amp;gt; &amp;lt;!-- Название ваших функций конфига --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;settings&amp;gt;&lt;br /&gt;
         &amp;lt;setting name=&amp;quot;roundlimit&amp;quot; value=&amp;quot;[6]&amp;quot; /&amp;gt; &amp;lt;!-- длина раунда в минутах --&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;teamdamage&amp;quot; value=&amp;quot;[1]&amp;quot; /&amp;gt; &amp;lt;!-- 0 для выключения командной защиты, 1 для включения --&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;teambalance&amp;quot; value=&amp;quot;[1]&amp;quot; /&amp;gt; &amp;lt;!--  максимум разницы игроков между командами --&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;spazammo&amp;quot; value=&amp;quot;[25]&amp;quot; /&amp;gt; &amp;lt;!-- количество патронов --&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;m4ammo&amp;quot; value=&amp;quot;[100]&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;shotgunammo&amp;quot; value=&amp;quot;[25]&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;sniperammo&amp;quot; value=&amp;quot;[20]&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;ak47ammo&amp;quot; value=&amp;quot;[120]&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;rifleammo&amp;quot; value=&amp;quot;[40]&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;deserteagleammo&amp;quot; value=&amp;quot;[45]&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;pistolammo&amp;quot; value=&amp;quot;[132]&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;uziammo&amp;quot; value=&amp;quot;[150]&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;tec9ammo&amp;quot; value=&amp;quot;[150]&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;silencedammo&amp;quot; value=&amp;quot;[65]&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;grenadeammo&amp;quot; value=&amp;quot;[4]&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;satchelammo&amp;quot; value=&amp;quot;[4]&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;teargasammo&amp;quot; value=&amp;quot;[4]&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;setting name=&amp;quot;molatovammo&amp;quot; value=&amp;quot;[4]&amp;quot; /&amp;gt;&lt;br /&gt;
     &amp;lt;/settings&amp;gt;&lt;br /&gt;
&lt;br /&gt;
     &amp;lt;aclrequest&amp;gt;&lt;br /&gt;
	 &amp;lt;right name=&amp;quot;function.startResource&amp;quot; access=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;right name=&amp;quot;function.stopResource&amp;quot; access=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;
	 &amp;lt;right name=&amp;quot;function.setPlayerMuted&amp;quot; access=&amp;quot;true&amp;quot; /&amp;gt;&lt;br /&gt;
     &amp;lt;/aclrequest&amp;gt;&lt;br /&gt;
     &lt;br /&gt;
     &amp;lt;sync_map_element_data&amp;gt;false&amp;lt;/sync_map_element_data&amp;gt;&lt;br /&gt;
&lt;br /&gt;
     &amp;lt;oop&amp;gt;false&amp;lt;/oop&amp;gt;&lt;br /&gt;
&lt;br /&gt;
     &amp;lt;download_priority_group&amp;gt;0&amp;lt;/download_priority_group&amp;gt;&lt;br /&gt;
&amp;lt;/meta&amp;gt;&lt;br /&gt;
|lang=&amp;quot;xml&amp;quot;}}&lt;br /&gt;
[[Category:Понятия скриптинга]]&lt;br /&gt;
[[cs:Meta.xml]]&lt;br /&gt;
[[de:Meta.xml]]&lt;br /&gt;
[[en:Meta.xml]]&lt;br /&gt;
[[es:Sobre el archivo &amp;quot;meta.xml&amp;quot;]]&lt;br /&gt;
[[it:Meta.xml]]&lt;br /&gt;
[[pl:Meta.xml]]&lt;/div&gt;</summary>
		<author><name>Flox</name></author>
	</entry>
</feed>