Skip to content

multitheftauto/amx

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

amx - MTA AMX compatibility layer

Introduction

amx is a software package that allows the execution of unmodified San Andreas: Multiplayer 0.3.7 gamemodes, filterscripts and plugins on Multi Theft Auto: San Andreas 1.6 and higher servers. It is open source, and a prebuilt binary for Windows is available for testing purposes right now.

License

amx is free and open source. You are allowed to use and modify it free of charge in any way you please.

You are allowed to redistribute (modified) versions of amx, provided that you:

  • do not charge for them,
  • keep the original credits and licence intact,
  • clearly list any modifications you made, and
  • do not present them as an official version.

Compatibility

Compatibility is quite high:

  • Almost all SA-MP scripting functions and callbacks are implemented.
  • Database functions (db_*) are implemented.
  • HTTP function is implemented and properly works with HTTPS requests.
  • SA-MP server plugins work unmodified, if they don't use memory hacking.
  • SA-MP style rcon commands are available from the server console and the ingame console.

See Limitations for a list of features that are currently missing.

Extra features

Apart from being compatible, amx also offers a number of extra features:

  • New scripting features (include a_amx.inc to use these):

  • In addition to the new native functions, gamemodes run in amx can also call Lua functions. Lua scripts can in turn call public Pawn functions.

    Using Lua not only gives you access to the wide range of MTA functions that offer a lot of functionality that SA-MP doesn't have, but also allows you to write code in a much more comfortable and efficient fashion than Pawn. For example, while Pawn is a subset of C and requires you to create a temporary buffer and call one or more functions to concatenate strings, you can simply do str1 = str2 .. str3 in Lua.

  • You can load plugins dynamically, while the server is running. Use the loadplugin console command for this.

  • There is no hard-coded max filterscript count, the number of running filterscripts is unlimited.

Installation

amx consists of a binary server module (.dll/.so) and a Lua resource. It will only run on MTA:SA 1.6 and later. Installation steps are lined out below.

Extracting

  • All needed binary files are in the archive provided on Releases page. Unpack amx.zip and extract the mods folder into your MTA server directory.

  • amx folder located in mods/deathmatch/resources is a place for the mentioned Lua resources. It will be empty at this point, so you need to copy all the latest files of amx folder from this repository into your amx folder.

Configuration

  • Open server/mods/deathmatch/mtaserver.conf in a text editor. Add the following line within the <config> node:

    <module src="king.dll"/>

    (Use "king.so" on Linux systems). This will instruct the MTA server to load the module on startup.

  • At this point you can add the amx resource to the autostart list if you want. Doing this will allow you to use SA-MP style rcon commands in the server console as soon as the server is started.

    <resource src="amx" startup="1" protected="0"/>

    Save and close mtaserver.conf.

  • After starting the MTA server you should see the following output:

    Resource ‘amx’ requests some acl rights. Use the command ‘aclrequest list amx’

    Run aclrequest list amx to see what ACL rights are needed, and if you are happy with the request, type aclrequest allow amx all.

    The following rights are used for the following purposes:

    • general.ModifyOtherObjects:
      • to access files of amx-* resources
    • function.startResource
      function.stopResource
      function.restartResource:
      • to automatically (re)start filterscripts when amx starts
      • for rcon
    • function.getServerPassword
      function.setServerPassword:
      • for rcon

Migrating gamemodes, filterscripts, plugins from an SA-MP server

If you have an SA-MP server with a number of modes and scripts that you would like to host on your MTA server, you can easily migrate these with an automated tool. For Windows, a graphical click-through wizard is provided: amxdeploy.exe (.NET Framework 2.0 required). For Linux there is an interactive Perl script: amxdeploy.pl. Simply run the tool appropriate for your operating system and follow the instructions. The tool will:

  • install the selected SA-MP gamemodes and filterscripts as MTA resources,
  • copy the selected plugins to MTA,
  • copy all scriptfiles to MTA,
  • set up the MTA mapcycler resource according to the gamemode cycling configuration in SA-MP's server.cfg, and
  • set up the autostart filterscripts and plugins according to SA-MP's server.cfg.

Special note for Linux users infamiliar with Perl

amxdeploy.pl uses some modules that are not part of a standard Perl installation. These are:

  • File::Copy::Recursive
  • XML::Twig

If you don't have these yet, you need to install them before you can run the script. To do this, open a terminal, switch to root and start cpan. If this is the first time you start cpan, it will walk you through some configuration (selection of download mirrors etc.). After it's set up, type install <modname> for each module to download and install it, for example: install XML::Twig.

Once the modules are installed you should be able to run the script without problems: perl amxdeploy.pl.

Maintenance of your MTA server

The migration tool is mainly meant for moving over files from an SA-MP server to a fresh amx install. To add SA-MP content to your MTA server at a later point, you probably want to take the manual route. Information about this is lined out below.

  • In SA-MP, there is one folder that contains all gamemodes and another that contains all filterscripts. In MTA, it is the convention to create a separate resource (i.e. folder) for each gamemode. amx follows the MTA convention for better integration, which means that a resource needs to be created for each gamemode and filterscript. The naming convention for these is amx-name for gamemodes and amx-fs-name for filterscripts.

    So, to add a new gamemode or filterscript, you create a folder in server/mods/deathmatch/resources/, place one or more .amx files in it, and add an appropriate meta.xml. Additionally you need to copy all the content from your scriptfiles folder in server/mods/deathmatch/resources/amx/scriptfiles.

    The meta.xml files of gamemodes and filterscripts are slightly different. Two resources, amx-test and amx-fs-test, are included in the amx repository as examples. Most times you can simply copy-paste these to a new resource and adjust the names in it.

  • To specify what filterscripts to autostart when amx loads, open server/mods/deathmatch/resources/amx/meta.xml and edit the "filterscripts" setting. Its value is a list of filterscript names separated by spaces. For example:

    <setting name="filterscripts" value="adminspec vactions"/>

    This will start the resources amx-fs-adminspec and amx-fs-vactions.

  • Plugins go in server/mods/deathmatch/resources/amx/plugins. Additionally you need to specify what plugins to load when amx starts: open server/mods/deathmatch/resources/amx/meta.xml and edit the "plugins" setting. Its value consists of the names of the plugins to start, separated by spaces. For example:

    <setting name="plugins" value="crashdetect mysql"/>

    This will load crashdetect.dll and mysql.dll on Windows, or .so on Linux.

  • jbeta's mapcycler resource (shipped with the MTA server) is used for automatic map cycling. The cycling is configured in server/mods/deathmatch/resources/mapcycler/mapcycle.xml. For each gamemode, add a line like this:

    <game mode="amx" map="amx-name" rounds="1"/>

    By default, the gamemodes are run in the order in which they appear in the list; you can also opt to randomly select the next mode from the list by setting the type attribute of the root <cycle> node to "shuffle".

    Automatic cycling will only happen when the mapcycler resource is started. You can start it manually (start mapcycler) or add it to the autostart list of your server (mtaserver.conf). If mapcycler is not started, amx will let players vote on the next mode instead.

Finishing up

  • If you are planning to compile Pawn scripts that use the new native functions provided by amx, place a_amx.inc in your Pawno "include" directory.

  • You are done!

Running gamemodes and filterscripts

Before you can run SA-MP modes or filterscripts, you need to start the amx resource. Type this command in the server console or as admin in the ingame console:

start amx

Alternatively you can add it to the autostart list of your server, in mtaserver.conf. Once amx is started you can use the following commands to start and stop gamemodes and filterscripts:

start amx-name
stop amx-name
start amx-fs-name
stop amx-fs-name

Alternatively, you can use the SA-MP style changemode and (un)loadfs commands. At most one gamemode can be running at any time, the number of running filterscripts is unlimited.

Go ahead and try starting the example gamemode (amx-test) and filterscript (amx-fs-test).

New scripting features

Here follows a quick reference for the new features amx introduces. To use them, #include <a_amx> in Pawno.

CJ clothes

native AddPlayerClothes(playerid, type, index);
native GetPlayerClothes(playerid, type);
native RemovePlayerClothes(playerid, type);

Changes the specified clothing on a player. See the clothes page for a list of valid type and index ID's. Note: these functions only have a visible effect on players with the CJ skin.

Walking style

native GetPlayerWalkingStyle(playerid);
native SetPlayerWalkingStyle(playerid, style);

Changes the walking style of a player. See the walking style page for a list of valid styles. Note: UsePlayerPedAnims may affect the behavior of these functions.

Player stats

native GetPlayerStat(playerid, statid);
native SetPlayerStat(playerid, statid, Float:value);

Changes the value of a specific statistic for a player. See the stats page for a list of valid stat ID's. Note: Visual stats (FAT and BODY_MUSCLE) can only be used on the CJ skin.

Vehicle variants

native GetVehicleVariant(vehicleid, &var1, &var2);
native SetVehicleVariant(vehicleid, var1, var2);

Changes the variant of a vehicle. Vehicle variants can be anything from different adverts to additional parts of the model. See the vehicle variants page for a list of default vehicle variants.

Garages

native IsGarageOpen(garageid);
native SetGarageOpen(garageid, bool:open);

Opens or closes the specified garage door in the world. See the garages page for a list of valid garage ID's. Note: SetGarageOpen does not work with ID 32, since this garage has been disabled by Rockstar Games due to floor collision issues.

Traffic light state

native GetTrafficLightState();
native SetTrafficLightState(lightState);

Sets the current traffic light state. This state controls the traffic light colors. See the traffic lights state page for a list of possible combinations.

Control state

native SetPlayerControlState(playerid, const control[], bool:controlState);

Sets state of a specified player's control, as if they pressed or released it. See the control names for a list of possible control names.

Glitches

native IsGlitchEnabled(const name[]);
native SetGlitchEnabled(const name[], bool:enable);

Enables or disables glitches which were found in the original game and which can be used to gain an advantage in multiplayer. See the glitch names for a list of possible game glitches.

New Pawn scripting functions

Here follows a quick reference for the new Pawn native functions amx introduces. To use them, #include <a_amx> in Pawno.

lua

native lua(const fnName[], {Float,_}:...);

Calls a Lua function. The function must be defined in a .lua file in the same resource as the calling .amx, and must have been registered earlier with amxRegisterLuaPrototypes. See also Pawn-Lua interaction.

Example:

new playerid = lua("luaTestfn1", 1.3, "Test string");

amxRegisterPawnPrototypes

native amxRegisterPawnPrototypes(const prototype[][]);

Registers prototypes for public functions that can be subsequently called from Lua scripts with pawn. The prototype list must be terminated with an empty string. See also Pawn-Lua interaction.

This example code registers two functions. The first one takes a float and a string argument and returns a player ID, the second takes a player ID and returns nothing:

new prototypes[][] = {
    "p:pawnTestfn1", { "f", "s" },
    "pawnTestfn2", { "p" },
    ""
};
amxRegisterPawnPrototypes(prototypes);

amxVersion

native amxVersion(&Float:ver);

Retrieves the amx version as a floating point number, e.g. 1.3.

amxVersionString

native amxVersionString(buffer[], size);

Retrieves the complete amx version string.

New Lua scripting functions

A number of new Lua functions were also introduced.

pawn

variant pawn(string fnName, ...)

Calls a Pawn function. The function must be public, must be defined in an .amx file in the same resource as the calling .lua, and must have been registered earlier with amxRegisterPawnPrototypes.

Example:

local player = pawn('pawnTestfn1', 0.5, 'Test string')

amxIsPluginLoaded

bool amxIsPluginLoaded(string pluginName)

Checks if a specific SA-MP server plugin is currently loaded. pluginName is the name of the plugin without a file extension.

amxRegisterLuaPrototypes

bool amxRegisterLuaPrototypes(table prototypes)

Registers prototypes of Lua functions that can subsequently be called from a Pawn script with lua. See also Pawn-Lua interaction.

The following example code registers two functions - the first one takes a float and a string argument and returns a player element, the second takes a player element and returns nothing:

amxRegisterLuaPrototypes(
    {
        ['p:luaTestfn1'] = { 'f', 's' },
        ['luaTestfn2']   = { 'p' }
    }
)

amxVersion

float amxVersion()

Returns the amx version as a floating point number, for example 1.3.

amxVersionString

string amxVersionString()

Returns the complete amx version string.

New MTA events

amx also provides events for detecting when .amx files are loaded and unloaded.

onAMXStart

onAMXStart(resource res, string amxName)

Triggered when an .amx file has just finished loading and initializing. The source of this event is the root element of the resource containing the .amx file. res is the resource pointer to this resource. amxName is the name of the .amx file minus the extension.

You should only call pawn after this event has triggered; if you call it in the main body of a Lua script, .amx files won't have registered their functions yet.

onAMXStop

onAMXStop(resource res, string amxName)

Triggered when an .amx file was unloaded. The source of this event is the root element of the resource containing the .amx file. res is the resource pointer to this resource. amxName is the name of the .amx file minus the extension.

Pawn-Lua interaction

amx allows developers to enrich their gamemodes and other scripts with Lua code, which is easier and more efficient to write than Pawn. To make this possible, a new Pawn function, lua was added to call Lua functions, and a Lua function called pawn correspondingly calls public Pawn functions.

A resource that uses the interaction functions will contain both one or more .amx files (<amx/> in meta.xml) and serverside MTA scripts (<script/>). Both Pawn and Lua scripts can only call other-language scripts that are in the same resource.

Registering prototypes

Before you can call a function with lua or pawn you need to define its prototype, which consists of the types of its arguments and return value. Each type corresponds to a single letter:

Letter Type Letter Type Letter Type
b boolean p player m menu
i integer v vehicle g gang zone
f floating point o object a 3D text label
s string u pickup k native marker
c color y actor z bot
t team x textdraw

Pawn functions are registered with amxRegisterPawnPrototypes, Lua functions with amxRegisterLuaPrototypes. Both functions associate a number of function names with their argument types and (optionally) return type. To specify a return type, prepend the function name with the type letter followed by a colon (:), for example: f:testfn. If you do not specify a return type (i.e. only specify the name, testfn), "i" will be assumed.

See the syntax sections of the two registration functions for the precise syntax to use.

Calling other-language functions

Use lua to call a Lua function from Pawn, and pawn to call a Pawn function from Lua. The functions have the same syntax: a string containing the name of the function, followed by the arguments to the function. amx takes care of any necessary argument and return value conversions: for example an .amx vehicle ID passed to lua will arrive in the Lua function as an MTA vehicle element, and vice versa (provided the correct prototype was registered for the Lua function).

Passing arguments by reference

It is possible to pass arguments by-reference from Pawn to Lua - however this is not possible in the opposite direction.

To make an argument be passed by reference, modifications in both the Lua function's prototype and body are necessary. In the prototype, prepend the type letter with a &. In the function's code, write _[argname] instead of argname for reading and writing the argument (argname holds the memory address in the .amx of the argument).

Cross-language calling limitations

Some limitations apply to cross-language calling.

  • Only scalar values (numbers, players, vehicles...) and strings can be passed as arguments; Pawn arrays and Lua tables are not supported.
  • Functions can only return scalar values (no strings or other arrays).
  • As stated in the previous section, by-reference arguments can only be passed from Pawn to Lua, not from Lua to Pawn.

Example

This example code demonstrates registering prototypes and calling other-language functions, with arguments passed by value and by reference.

test.pwn
#include <a_samp>
#include <a_amx>

main()
{
    new prototypes[][] =
    {
       "p:testfn", { "p", "f", "s" },
       ""
    };
    amxRegisterPawnPrototypes(prototypes);
}

public testfn(playerid, Float:f, str[])
{
    printf("pawn> testfn: %d %.1f %s", playerid, f, str);
    return playerid;
}

public OnGameModeInit()
{
    new
        vehicleid = CreateVehicle(415, 0.0, 0.0, 3.0, -90.0, 0, 1, 5000),
        vehicletype;

    // vehicletype is passed by reference
    new success = lua("getVehicleType", vehicleid, vehicletype, "Test text from Pawn");
    if (success) printf("pawn> Vehicle type: %d", vehicletype);

    SetGameModeText("Blank Script");
    AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
    return 1;
}

public OnPlayerRequestClass(playerid, classid)
{
    SetPlayerPos(playerid, 1958.3783, 1343.1572, 15.3746);
    SetPlayerCameraPos(playerid, 1958.3783, 1343.1572, 15.3746);
    SetPlayerCameraLookAt(playerid, 1958.3783, 1343.1572, 15.3746);
    return 1;
}
test.lua
function getVehicleType(vehicle, pVehicleType, str)
    print('lua> ' .. str)
    print('lua> ' .. _[pVehicleType])
    local model = getElementModel(vehicle)
    if model then
        _[pVehicleType] = model
        return true
    else
        return false
    end
end

addEventHandler('onAMXStart', root,
    function()
        -- Note that we are calling pawn() from the onAMXStart event instead of in the main script body
        -- Calling it from the main body would fail as the Pawn functions haven't yet been registered at that point
        local player = pawn('testfn', getRandomPlayer(), 0.8, 'Test string from Lua')
        if player then
            print('lua> ' .. getClientName(player))
        else
            print('lua> No random player')
        end
    end
)

amxRegisterLuaPrototypes({
    ['b:getVehicleType'] = { 'v', '&i', 's' }
})
Sample output of this code
lua> Test text from Pawn
lua> 0
pawn> Vehicle type: 415
pawn> testfn: 1 0.8 Test string from Lua
lua> arc_

Limitations

Even though amx offers a high level of compatibility, not everything is perfect. Below is a list of limitations that may or may not be addressed in later versions of amx and Multi Theft Auto.

The following functions will require certain resources installed to have effect when called:

  • DisableInteriorEnterExits
    • disable enex markers implemented by "interiors" resource, otherwise they are always disabled
  • SendDeathMessage
    • invoke graphical death messages from "killmessages" resource

The following features are currently not implemented and will have no effect when used:

  • Custom SA-MP objects
  • NPC related functions (StartRecordingPlayerData, StopRecordingPlayerData)
  • Object material and text (SetObjectMaterial, SetObjectMaterialText)
  • TextDraw preview and sprites (TextDrawSetPreviewModel, TextDrawSetPreviewRot, TextDrawSetPreviewVehCol)
  • Camera target functions (EnablePlayerCameraTarget)

Credits

amx was developed by arc_. Special thanks go out to:

  • Everyone who tested or participated in group tests during development, especially MeKorea who quite literally tried out every mode and filterscript he could find.

  • The MTA team, for providing such a tremendous platform to develop on.

About

MTA AMX compatibility layer.

Topics

Resources

License

Stars

Watchers

Forks

Contributors 12