AMX Mod X 1.9 API Changes

From AlliedModders Wiki
Revision as of 13:21, 30 September 2021 by Shooting King (talk | contribs) (Assign an Amxmodx category)
Jump to: navigation, search
Ambox content soft.svg  This version is not yet released. The release notes are not final.


Note:These are just the API changes from AMX Mod X 1.8.2 to AMX Mod X 1.9. Click here for the full AMX Mod X 1.9 Release Notes.
Hint:This page includes hidden examples or API reference that you can toggle with .
🙌 Congratulations for understanding the hint!

Documentation

A large part of the scripting documentation has been improved and an online version with searching capability can be found at https://amxmodx.org/api/.

Gamedata

As stated in the Release Notes, we have now gamedata files to avoid to hard code data related to the game or engine. Such files located in the amxmodx/data/gamedata/ directory.

Gamedata files shipped with AMX Mod X can and will be updated at any time, therefore it is strongly discouraged to edit them manually.
To make custom gamedata changes, please use the custom folder under the gamedata directory. All files under this directory are parsed (in an undefined order) after the main files are loaded. They will never be overwritten.

The files structure is currently arranged this way:

├─ common.games │ ├─ entities.games │ │ └─ $mod │ │ ├─ offsets-$class.txt │ │ ├─ ... │ ├─ gamerules.games │ │ └─ $mod │ │ ├─ offsets-$class.txt │ │ ├─ ... │ ├─ hostages.games │ │ └─ $mod │ │ ├─ offsets-$class.txt │ │ ├─ ... │ ├─ others.games │ │ └─ $mod │ │ ├─ offsets-$class.txt │ │ ├─ ... │ ├─ functions.engine.txt │ ├─ globalvars.engine.txt │ └─ master.games.txt ├─ modules.games │ ├─ master.games.txt │ └─ game.cstrike.txt

The main directories are:

  • common.games contains the shared data.
  • modules.games contains the data per module.

In those directories, you will find:

  • master.games.txt which references all the files to be loaded by the core/modules.

Inside common.games directory:

  • entities.games, entities.games, entities.games and others.games directories contains the $class member's offset per-$mod. Related to gamerules object but also player, hostage, item and weapons entities.
  • functions.engine.txt contains the symbols/signatures of functions in the engine.
  • globalvars.engine.txt contains the symbols/signatures of global variables in the engine.

Inside modules.games directory:

  • game.cstrike.txt contains CS-specific data such as the symbol/signatures of functions and others static datas.
Note:More details about the file format can be found in the Quick Guide in #Game_Config_Parser.

Compiler

Along a bunch of fixed issues, there are some improvements/features worth to be noted.

Emscripten support

The AMX Mod X Compiler can now be compiled with Emscripten allowing it to run inside of a web browser.

A good example is Spider, a web-based, entirely client-side, editor and compiler for [Source]Pawn development (by asherkin).

Increased Limits

Name/function and input line maximum length (in characters) have been increased.

Description Old value New value
Name/Function 31 63
Input Line 511 4095

Predefined Constants

Global Description
__BINARY__ Name of the compiled plugin. Example: admin.amxx
__FILE__ Name of the source plugin. Custom includes is supported. Example: admin.sma, myinclude/myfile.inc
__LINE__ Current line from the plugin's source code.
Note:Values are populated at compile time.

Pragma

A new #pragma deprecated has been added to tell the compiler that this specific native/stock is deprecated.
This will issue a warning upon the compilation.

Example:
#pragma deprecated  Some comment here.
native foo();

At compilation:

[...] warning 233: symbol "foo" is marked as deprecated: Some comment here.

String Literal Contatenation

This basically allows you to concatenate literal strings and stringizing a parameter in macro substitution only (so possible breakage is very limited).

Description Symbol
To concatenate +
To Stringize #
Example:
#define PROJECT_AUTHOR    "AMX Mod X"
#define PROJECT_COPYRIGHT "Copyright (C) 2017  " + PROJECT_AUTHOR
 
#define VERSION_MAJOR      "1"
#define VERSION_MINOR      "9"
#define VERSION_RELEASE    "0"
#define VERSION            VERSION_MAJOR + "." + VERSION_MINOR + "." + VERSION_RELEASE
 
#define log(%1)  "logging: " + #%1 + "\n"
 
foo()
{
    server_print(log(hello));
}

Internal Core Changes

String Buffer

The buffer size AMX Mod X uses internally to retrieve strings has been increased from 3k to 16k.

Note:A MAX_STRING_LENGTH define has been added in amxconst.inc.
Note:By default plugins don't have enough memory available to allocate an array of this size.
You probably should not use this define to actually declare a buffer unless you absolutely have to.
Look at #pragma dynamic to increase a plugins available memory.

New Core APIs

Automatic Config File

This provides a system for plugins to automatically generate config files with plugin's cvars which get executed on load.
This is done via the AutoExecConfig native.

Once all configuration files are executed, OnConfigsExecuted is called. This forward will always be called, even if your plugin had no configs or if it was loaded late.

Native Description
AutoExecConfig  Specifies that the given config file should be executed after plugin load.
/**
 * Specifies that the given config file should be executed after plugin load.
 *
 * @note OnConfigsExecuted() will not be called until the config file has executed,
 *       but it will be called if the execution fails.
 * @note The name parameter should not contain dots, otherwise file will not be executed.
 *
 * @param autoCreate    If true, and the config file does not exist, such a config
 *                      file will be automatically created and populated with
 *                      information from the plugin's registered cvars.
 * @param name          Name of the config file, excluding the .cfg extension.
 *                      If empty, <plugin.filename.cfg> is assumed.
 * @param folder        Folder under plugins/ to use.
 *
 * @noreturn
 */
native AutoExecConfig(bool:autoCreate = true, const name[] = "", const folder[] = "");
Forward Description
OnConfigsExecuted  Called when the map has loaded, and all configs are done executing.
/**
 * Called when the map has loaded, and all configs are done executing.
 * This includes servercfgfile (server.cfg), amxx.cfg, plugin's config, and
 * per-map config.
 *
 * @note This is best place to initialize plugin functions which are based on cvar data.
 * @note This will always be called once and only once per map.  It will be
 *       called few seconds after plugin_cfg().
 *
 * @noreturn
 */
forward OnConfigsExecuted();
OnAutoConfigsBuffered  Called when the map has loaded, right after plugin_cfg but any time before OnConfigsExecuted.
/**
 * Called when the map has loaded, right after plugin_cfg() but any time
 * before OnConfigsExecuted.  It's called after amxx.cfg and  all
 * AutoExecConfig() exec commands have been added to the server command buffer.
 *
 * @note This will always be called once and only once per map.
 *
 * @noreturn
 */
forward OnAutoConfigsBuffered();
Example:
#include <amxmodx>
 
public plugin_init()
{
    register_plugin("Hat", "User", "1.0");
 
    create_cvar("mysqlk_database", "", .description = "MySQL database");
    create_cvar("mysqlk_host", "localhost", .description = "MySQL host, use this to configure various^nthings for your server.");
 
    AutoExecConfig();
}

That would export a config file that looks like this:

// This file was auto-generated by AMX Mod X (v1.9)
// Cvars for plugin "Hat" by "User" (hat.amxx, v1.0)
 
 
// MySQL database
// -
// Default: ""
mysqlk_database ""
 
// MySQL host, use this to configure various
// things for your server.
// -
// Default: "localhost"
mysqlk_host "localhost"

DataPack

This offers you a way to dynamically store and move around various types of data.

Datapacks provide a way to store and move around arbitrary amounts (and types) of data in AMX Mox X, available from datapack.inc.
Data is packed into a single cell value - the DataPack handle. This handle can be passed around more easily, can be returned by functions and can simulate advanced concepts like string consummation.

Native Description
Creating & Disposing
CreateDataPack  Creates a new datapack.
/**
 * Creates a new datapack.
 *
 * @return  New datapack handle, which must be freed via DestroyDataPack().
 */
native DataPack:CreateDataPack();
DestroyDataPack  Destroys the datapack and frees its memory.
/**
 * Destroys the datapack and frees its memory.
 *
 * @param pack      Datapack handle
 *
 * @return          True if disposed, false otherwise
 */
native DestroyDataPack(&DataPack:pack);
Resetting
ResetPack  Resets the datapack read/write position to the start.
/**
 * Resets the datapack read/write position to the start.
 *
 * @param pack      Datapack handle
 * @param clear     If true, clears the contained data
 *
 * @noreturn
 * @error           If an invalid handle is provided, an error will be thrown.
 */
native ResetPack(DataPack:pack, bool:clear = false);
Writing data
WritePackCell  Packs a cell value into a datapack.
/**
 * Packs a cell value into a datapack.
 *
 * @param pack      Datapack handle
 * @param cell      Cell value to pack
 *
 * @noreturn
 * @error           If an invalid handle is provided, an error will be thrown.
 */
native WritePackCell(DataPack:pack, any:cell);
WritePackFloat  Packs a float value into a datapack.
/**
 * Packs a float value into a datapack.
 *
 * @param pack      Datapack handle
 * @param val       Float value to pack
 *
 * @noreturn
 * @error           If an invalid handle is provided, an error will be thrown.
 */
native WritePackFloat(DataPack:pack, Float:val);
WritePackString  Packs a string into a datapack.
/**
 * Packs a string into a datapack.
 *
 * @param pack      Datapack handle
 * @param str       String to pack
 *
 * @return          Length of copied string
 * @error           If an invalid handle is provided, an error will be thrown.
 */
native WritePackString(DataPack:pack, const str[]);
Reading data
ReadPackCell  Reads a cell from a Datapack.
/**
 * Reads a cell from a Datapack.
 *
 * @param pack      Datapack handle
 *
 * @return          Cell value
 * @error           If an invalid handle is provided, or not enough data is left
 *                  in the datapack, an error will be thrown.
 */
native any:ReadPackCell(DataPack:pack);
ReadPackFloat  Reads a float from a Datapack.
/**
 * Reads a float from a datapack.
 *
 * @param pack      Datapack handle
 *
 * @return          Float value
 * @error           If an invalid handle is provided, or not enough data is left
 *                  in the datapack, an error will be thrown.
 */
native Float:ReadPackFloat(DataPack:pack);
ReadPackString  Reads a string from a Datapack.
/**
 * Reads a string from a Datapack.
 *
 * @param pack      Datapack handle
 * @param buffer    Buffer to copy string to
 * @param maxlen    Maximum size of buffer
 *
 * @return          Number of cells written to buffer
 * @error           If an invalid handle is provided, or not enough data is left
 *                  in the datapack, an error will be thrown.
 */
native ReadPackString(DataPack:pack, buffer[], maxlen);
Managing position
GetPackPosition  Returns the datapack read/write position.
/**
 * Returns the datapack read/write position.
 *
 * @param pack      Datapack handle
 *
 * @return          Position in the datapack, only usable with calls to SetPackPosition
 * @error           If an invalid handle is provided, an error will be thrown.
 */
native DataPackPos:GetPackPosition(DataPack:pack);
SetPackPosition  Sets the datapack read/write position.
/**
 * Sets the datapack read/write position.
 *
 * @note This should only ever be used with (known to be valid) positions
 *       returned by GetPackPosition(). It is not possible for plugins to safely
 *       compute datapack positions.
 *
 * @param pack      Datapack handle
 * @param position  New position to set
 *
 * @noreturn
 * @error           If an invalid handle is provided, or the new position is
 *                  out of datapack bounds, an error will be thrown.
 */
native SetPackPosition(DataPack:pack, DataPackPos:position);
Example:
#include <amxmodx>
 
public plugin_init()
{
    // Creating
    new const DataPack:pack = CreateDataPack();
 
    // Writing
    WritePackCell(pack, refCell);
    WritePackFloat(pack, refFloat);
    WritePackString(pack, refString);
 
    // Reset before reading
    ResetPack(pack);
    server_print("Datapack is readable: %s", !IsPackEnded(pack) ? "yes" : "no");
 
    // Reading
    new cellValue = ReadPackCell(pack);
    new Float:floatValue = ReadPackFloat(pack);
    new buffer[32];
    ReadPackString(pack, buffer, charsmax(buffer));
    server_print("cellValue = %d, floatValue = %f, buffer = %s", cellValue, floatValue, buffer)
    server_print("Datapack is no more readable: %s", IsPackEnded(pack) ? "yes" : "no");
 
    // Clear all data
    ResetPack(pack, .clear = true);
    server_print("Datapack is empty: %s", IsPackEnded(pack) ? "yes" : "no");
 
    // Disposing
    DestroyDataPack(pack);
}

Game Config Parser

Now we have gamedata files, we strongly encourage any plugins which hardcode static game datas to use the following API.

Native Description
Loading & Closing file
LoadGameConfigFile  Loads a game config file.
/**
 * Loads a game config file.
 *
 * @note The file path must be relative to the 'gamedata' folder under the data folder
 *       and the extension should be omitted.
 *
 * @param file          File to load
 *
 * @return              A handle to the game config file
 */
native GameConfig:LoadGameConfigFile(const file[]);
CloseGameConfigFile  Destroys a game config and frees its memory.
/**
 * Destroys a game config and frees its memory.
 *
 * @note The function automatically sets the variable passed to it to 0 to aid
 *       in preventing accidental usage after destroy.
 *
 * @param handle        Game config handle
 *
 * @return              1 on success, 0 if an invalid handle was passed in
 */
native CloseGameConfigFile(&GameConfig:handle);
Getting value
GameConfGetOffset  Returns an offset value.
/**
 *
 *
 * @param handle        Game config handle
 * @param key           Key to retrieve from the offset section
 *
 * @return              An offset, or -1 on failure
 * @error               Invalid game config handle
 */
native GameConfGetOffset(GameConfig:handle, const key[]);
GameConfGetClassOffset  Returns an offset value given a classname.
/**
 * Returns an offset value given a classname.
 *
 * @param handle        Game config handle
 * @param classname     Class name to match from the offset section
 * @param key           Key to retrieve from the offset section
 *
 * @return              An offset, or -1 on failure
 * @error               Invalid game config handle
 */
native GameConfGetClassOffset(GameConfig:handle, const classname[], const key[]);
GameConfGetKeyValue  Gets the value of a key from the "Keys" section.
/**
 * Gets the value of a key from the "Keys" section.
 *
 * @param handle        Game config handle
 * @param key           Key to retrieve from the Keys section
 * @param buffer        Destination string buffer
 * @param maxlen        Maximum length of output string buffer
 *
 * @return              True if key existed, false otherwise
 * @error               Invalid game config handle
 */
native bool:GameConfGetKeyValue(GameConfig:handle, const key[], buffer[], maxlen);
GameConfGetAddress  Finds an address calculation in a GameConfig file.
/**
 * Finds an address calculation in a GameConfig file.
 *
 * @param handle        Game config handle
 * @param name          Name of the property to find
 *
 * @return              An address calculated on success, otherwise 0 on failure.
 * @error               Invalid game config handle
 */
native GameConfGetAddress(GameConfig:handle, const name[]);
Quick guide:
Config location

Any default and new gamedata files must be located in /amxmodx/data/gamedata/ directory.
You can create your own directories inside as well.

Filename format

The file name must end with .txt extension, e.g. myfile.txt

Loading a specific file

The right way to load a file is to provide the filename without .txt extension.
E.g. LoadGameConfigFile("myfile") will try to load /data/gamedata/myfile.txt.

Loading multiple files

You are able to load several at once via a master file, named master.game.txt.
A master file is basically a way to tell the parser to load any files listed inside and nothing else.
You can also specify whether a file should be loaded depending the mod name (such as cstrike) or engine (dedicated server: engine_ds or listen server: engine_ls).

For example:

├─ gamedata
│  └─ myfolder
│	  ├─ myfile1.txt
│	  ├─ myfile2.txt
│	  ├─ myfile3.txt
│	  └─ master.game.txt

master.game.txt:

"Game Master"           // Must start with this.
{
    "myfile1.txt"       // No option, will be loaded all the time
    {
    }
 
    "myfile2.txt"       // Will be loaded for both servers
    {
        "engine"  "engine_ds"
        "engine"  "engine_ls"
    }
 
    "myfile3.txt"       // Will be loaded only if the mod is Counter-Strike.
    {
        "game"  "cstrike"
    }
}

Then to load, you only need to provide your directory, e.g. LoadGameConfigFile("myfolder").
This will looks at the /gamedata/myfolder/master.game.txt file and will load the listed files from there.

Config file format

The config file has a specific format as well. This must to start with:

"Games"
{
 
}

Then, you need to tell on what game the date will be loaded.
There are different values:

  • "<game name>", such as cstrike
  • "*" or "#default" to match any game
"Games"
{
    "cstrike"
    {
        // Counter-Strike only
    }
 
    "#default"
    {
        // Any game
        // Note you can create multiple game blocks.
    }
}

If you need to create a block which inherit multiple games or engine, you can achieve it with #supported key.

"Games"
{
    "#default"	// Must start with this
    {
        "#supported"
        {
            "game"   "cstrike"
            "game"   "czero"
 
            "engine"  "engine_ds"  // you can specify the engine as well.
         }
 
        // Data
    }
}

Data Type

There are 5 different types of datas that you are allowed to store:

  • Signature:
Retrieves an address from either a symbol or bytes. E.g. @g_pGameRules or \xDC\x2A\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x56
Symbol must start with @.
For use with GameConfGetAddress native.
  • Address:
Reads a value from a given address (usually from signature reference)
For use with GameConfGetAddress native.
  • Offset:
A platform-dependent value (windows, linux or mac)
For use with GameConfGetOffset native.
  • Class Offset:
Same as Offset but can be grouped into a classname
For use with GameConfGetClassOffset native.
  • Keyvalue:
simple key associated to a value.
For use with GameConfGetKeyValue native.
"Games"
{
    "#default"
    {
        "Signatures"
        {
            "SV_DropClient"
            {
                "library"   "engine" // This can be either "server" (mod), "engine_ds" (dedicated server) or "engine_ls' (listen server)
                "windows"   "\x55\x8B\x2A\x81\x2A\x2A\x2A\x2A\x2A\x8B\x2A\x2A\x53\x56\x8D"
                "linux"     "@SV_DropClient"
                "mac"       "@SV_DropClient" // Note: A symbol must start always with '@'
            }
 
            "g_pGameRules"
            {
                "library"   "server"
                "windows"   "\x8B\x2A\x2A\x2A\x2A\x2A\x85\x2A\x74\x2A\x8B\x2A\xFF\x2A\x2A\xA1" // StartFrame()
                "linux"     "@g_pGameRules"
                "mac"       "@g_pGameRules"
            }
        }
 
        "Offsets"
        {
            "something"
            {
                "windows"   "4"
                "linux"     "2"
                "mac"       "0"
            }
        }
 
        "Classes"
        {
            "CSomething"
            {
                "Offsets"
                {
                    "windows"   "4"
                    "linux"     "2"
                    "mac"       "0"
                }
            }
        }
 
        "Addresses"
        {
            "GameRulesPointer" // Gets the address of "g_pGameRules", adds 2 bytes on windows and 0 byte on linux/mac.
            {
                "signature"  "g_pGameRules"
 
                "windows"
                {
                    "read"   "2"
                }
 
                "read"  "0"
            }
 
            "Something" // Gets the address of "SV_DropClient" and adds 5 bytes, on linux platform only.
            {
                "linux"
                {
                    signature "SV_DropClient"
                    "read"    "5"
                }
            }
        }
 
        "Keys"
        {
            "key1"   "value1"
            "Key2"   "value2"
        }
    }
}

Hasher

Supports several new hash types: CRC32, MD5, SHA*, Keccak*.

Note:The following API deprecates md5 and md5_file natives.
Native Description
hash_string  Generates a hash value (message digest).
/**
 * Generates a hash value (message digest)
 *
 * @param string        String to be hashed.
 * @param type          Type of selected hashing algorithm. See Hash_* constants in amxconst.inc file.
 * @param output        Output string to store hash in.
 * @param outputSize    The maximum size of the output string to store hash in.
 *
 * @return              Number of written bytes.
 */
native hash_string(const string[], const HashType:type, output[], const outputSize);
hash_file  Generates a hash value using the contents of a given file.
/**
 * Generates a hash value using the contents of a given file
 *
 * @param fileName      Path of file to be hashed.
 * @param type          Type of selected hashing algorithm. See Hash_* constants in amxconst.inc file.
 * @param output        Output string to store hash in.
 * @param outputSize    The maximum size of the output string to store hash in.
 *
 * @return              Number of written bytes.
 * @error               If the file couldn't be opened, an error is thrown.
 */
native hash_file(const fileName[], const HashType:type, output[], const outputSize);

The available HashType constants are:

  • Hash_Crc32
  • Hash_Md5
  • Hash_Sha1
  • Hash_Sha256
  • Hash_Sha3_224
  • Hash_Sha3_256
  • Hash_Sha3_384
  • Hash_Sha3_512
  • Hash_Keccak_224
  • Hash_Keccak_256
  • Hash_Keccak_384
  • Hash_Keccak_512
Example:
#include <amxmodx>
 
public plugin_init()
{
    new hash1[32];
    new const message[] = "Hello World!";
    new const length = hash_string(message, Hash_Md5, hash1, charsmax(hash1));
 
    server_print("hash1 = %s", hash1);
 
    new hash2[32];
    new const fileName[] = "server.cfg";
    new const length = hash_file(message, Hash_Md5, hash2, charsmax(hash2));
 
    server_print("hash2 = %s", hash2);
}

Stack Structure

A stack is a LIFO (last in, first out) dynamic vector of of items.

Stacks provide only two operations:

  • Push, adding an item to the top.
  • Pop, removing an item from the top, in reverse-push order.
Note:An example is available in the testsuite directory, see stacktest.sma.
Native Description
Creating & Destroying
CreateStack  Creates a stack structure.
/**
 * Creates a stack structure. A stack is a LIFO (last in, first out) vector of
 * of items. It has O(1) insertion and O(1) removal.
 *
 * @note Stacks provide only two operations: Push (adding an item to the top)
 * 		 and Pop (remove an item from the top, in reverse-push order).
 * @note The contents of the stack are uniform; i.e. storing a string and then
 *       retrieving it as an integer is NOT the same as str_to_num()!
 * @note The "blocksize" determines how many cells each stack slot has, it can
 *       not be changed after creation.
 *
 * @param blocksize     The number of cells each entry in the stack can hold
 *
 * @return              New stack Handle, which must be freed via DestroyStack()
 * @error               If an invalid blocksize is provided an error will be
 *                      thrown.
 */
native Stack:CreateStack(blocksize = 1);
DestroyStack  Destroys a stack and frees its memory.
/**
 * Destroys a stack and frees its memory.
 *
 * @note The function automatically sets the variable passed to it to 0 to aid
 *       in preventing accidental usage after destroy.
 *
 * @param handle    Stack to destroy
 *
 * @return          1 if the Stack was destroyed, 0 if nothing had to be
 *                  destroyed (invalid handle)
 */
native DestroyStack(&Stack:handle);
Pushing Data
PushStackCell  Pushes a value onto the end of the stack, adding a new index.
/**
 * Pushes a value onto the end of the stack, adding a new index.
 *
 * @note This may safely be used even if the stack has a blocksize greater than
 *       1.
 *
 * @param handle    Stack handle
 * @param value     Value to push
 *
 * @noreturn
 * @error           If an invalid handle is provided or the resizing
 *                  operation runs out of memory, an error will be thrown.
 */
native PushStackCell(Stack:handle, any:value);
PushStackString  Pushes a string onto the end of a stack, truncating it if it is too long.
/**
 * Pushes a string onto the end of a stack, truncating it if it is too long.
 *
 * @param handle    Stack handle
 * @param value     String to push
 *
 * @noreturn
 * @error           If an invalid handle is provided or the resizing
 *                  operation runs out of memory, an error will be thrown.
 */
native PushStackString(Stack:handle, const value[]);
PushStackArray  Pushes an array of cells onto the end of a stack.
/**
 * Pushes an array of cells onto the end of a stack. The cells are pushed as a
 * block (i.e. the entire array takes up one stack slot), rather than pushing
 * each cell individually.
 *
 * @param handle    Stack handle
 * @param values    Block of values to copy
 * @param size      If not set, the number of elements copied from the array
 *                  will be equal to the blocksize, if set higher than the
 *                  blocksize, the operation will be truncated,
 *
 * @noreturn
 * @error           If an invalid handle is provided or the resizing
 *                  operation runs out of memory, an error will be thrown.
 */
native PushStackArray(Stack:handle, const any:values[], size= -1);
Poping Data
PopStackCell  Pops a cell value from a stack.
/**
 * Pops a cell value from a stack.
 *
 * @param handle    Stack handle
 * @param value     Variable to store the value in
 * @param block     Optionally specify which block to read from (useful if the
 *                  blocksize is > 0)
 * @param asChar    Optionally read as a byte instead of a cell
 *
 * @return          True on success, false if the stack is empty.
 * @error           If an invalid handle, invalid block or invalid byte is
 *                  provided, an error will be thrown.
 */
native bool:PopStackCell(Stack:handle, &any:value, block = 0, bool:asChar = false);
PopStackString  Pops a string value from a stack.
/**
 * Pops a string value from a stack.
 *
 * @param handle        Stack handle
 * @param buffer        Buffer to copy string to
 * @param maxlength     Maximum size of the buffer
 * @param written       Variable to store number of characters copied to
 *
 * @return              True on success, false if the stack is empty
 * @error               If an invalid handle is provided an error will be thrown.
 */
native bool:PopStackString(Stack:handle, buffer[], maxlength, &written = 0);
PopStackArray  Pops an array of cells from a stack.
/**
 * Pops an array of cells from a stack.
 *
 * @param handle    Stack handle
 * @param buffer    Array to copy value to
 * @param size      Size of buffer, if not set (-1) assumes the size is equal to
 *                  the stack blocksize
 *
 * @return          True on success, false if the stack is empty
 * @error           If an invalid handle is provided an error will be thrown.
 */
native bool:PopStackArray(Stack:handle, any:buffer[], size = -1);
Others
IsStackEmpty  Returns if a stack is empty.
/**
 * Returns if a stack is empty.
 *
 * @param handle    Stack handle
 *
 * @return          True if empty, false if not empty
 * @error           If an invalid handle is provided an error will be thrown.
 */
native bool:IsStackEmpty(Stack:handle);
Stock Description
PopStack  Pops a value off a stack, ignoring it completely.
/**
 * Pops a value off a stack, ignoring it completely.
 *
 * @param handle    Stack handle
 *
 * @return          True if a value was popped, false if stack is empty
 * @error           If an invalid handle is provided an error will be thrown.
 */
stock PopStack(Stack:handle)
{
    new value;
    return PopStackCell(handle, value);
}

Text Parser INI/SMC

Event-based text parser to read data in an unified way. It supports INI and SMC (similar to VTF) formats.

Note:An example is available in the testsuite directory, see textparse.sma.

SMC Format

Technical format detail:
/**
 * The SMC file format is defined as:
 *    WHITESPACE: 0x20, \n, \t, \r
 *    IDENTIFIER: Any ASCII character EXCLUDING ", {, }, ;, //, / *, or WHITESPACE.
 *    STRING    : Any set of symbols enclosed in quotes.
 *
 *    Note: if a STRING does not have quotes, it is parsed as an IDENTIFIER.
 *
 * Basic syntax is comprised of SECTIONBLOCKs.
 *    A SECTIONBLOCK defined as:
 *
 *    SECTIONNAME
 *    {
 *        OPTION
 *    }
 *
 * OPTION can be repeated any number of times inside a SECTIONBLOCK.
 * A new line will terminate an OPTION, but there can be more than one OPTION per line.
 * OPTION is defined any of:
 *    "KEY"  "VALUE"
 *    SECTIONBLOCK
 *
 * SECTIONNAME, KEY, VALUE, and SINGLEKEY are strings
 * SECTIONNAME cannot have trailing characters if quoted, but the quotes can be optionally removed.
 * If SECTIONNAME is not enclosed in quotes, the entire sectionname string is used (minus surrounding whitespace).
 * If KEY is not enclosed in quotes, the key is terminated at first whitespace.
 * If VALUE is not properly enclosed in quotes, the entire value string is used (minus surrounding whitespace).
 * The VALUE may have inner quotes, but the key string may not.
 *
 * WHITESPACE should be ignored.
 * Comments are text occurring inside the following tokens, and should be stripped
 * unless they are inside literal strings:
 *    ;<TEXT>
 *    //<TEXT>
 *    / *<TEXT> * /
 *
 * Example file below:
 *   "SomeSection"
 *   {
 *	      /**
 *	       * Some comment
 *         */
 *	      "Key"		"value"
 *   }
 */
Native Description
SMC_CreateParser  Creates a new SMC parser.
/**
 * Parser invalid code.
 */
enum SMCParser
{
    Invalid_SMCParser = 0
};
 
/**
 * Parse result directive.
 */
enum SMCResult
{
    SMCParse_Continue,          /* Continue parsing */
    SMCParse_Halt,              /* Stop parsing here */
    SMCParse_HaltFail           /* Stop parsing and return failure */
};
 
/**
 * Creates a new SMC parser.
 * This is used to set parse hooks.
 *
 * @return              A new handle to an SMC Parse structure.
 */
native SMCParser:SMC_CreateParser();
SMC_DestroyParser  Disposes of an SMC parser.
/**
 * Disposes of an SMC parser.
 *
 * @param handle        Handle to an SMC Parse structure.
 *
 * @return              True if disposed, false otherwise.
 */
native SMC_DestroyParser(&SMCParser:handle);
SMC_ParseFile  Parses a config file.
/**
 * Parses a config file.
 *
 * @param handle        A handle to an SMC Parse structure.
 * @param file          A string containing the file path.
 * @param line          An optional by reference cell to store the last line number read.
 * @param col           An optional by reference cell to store the last column number read.
 * @param data          An optional handle or value to pass through to callback functions
 *
 * @return              An SMCParseError result.
 * @error               Invalid or corrupt handle.
 */
native SMCError:SMC_ParseFile(SMCParser:handle, const file[], &line = 0, &col = 0, any:data = 0);
/**
 * Parse error codes.
 */
enum SMCError
{
    SMCError_Okay = 0,          /* No error */
    SMCError_StreamOpen,        /* Stream failed to open */
    SMCError_StreamError,       /* The stream died... somehow */
    SMCError_Custom,            /* A custom handler threw an error */
    SMCError_InvalidSection1,   /* A section was declared without quotes, and had extra tokens */
    SMCError_InvalidSection2,   /* A section was declared without any header */
    SMCError_InvalidSection3,   /* A section ending was declared with too many unknown tokens */
    SMCError_InvalidSection4,   /* A section ending has no matching beginning */
    SMCError_InvalidSection5,   /* A section beginning has no matching ending */
    SMCError_InvalidTokens,     /* There were too many unidentifiable strings on one line */
    SMCError_TokenOverflow,     /* The token buffer overflowed */
    SMCError_InvalidProperty1,  /* A property was declared outside of any section */
};
SMC_SetParseStart  Sets the SMC_ParseStart function of a parse handle.
/**
 * Sets the SMC_ParseStart function of a parse handle.
 *
 * @note  Below is the prototype of callback:
 *        -
 *          Called when parsing is started.
 *
 *          @param handle        Handle to an SMC Parse structure.
 *          @param data          Handle or value passed in SMC_ParseFile
 *
 *          @noreturn
 *
 *          public OnParseStart(SMCParser:handle, any:data)
 *        -
 * @param handle        Handle to an SMC Parse structure.
 * @param func          A ParseStart callback.
 *
 * @noreturn
 * @error               Invalid or corrupt handle.
 */
native SMC_SetParseStart(SMCParser:handle, const func[]);
SMC_SetParseEnd  Sets the SMC_ParseEnd function of a parse handle.
/**
 * Sets the SMC_ParseEnd function of a parse handle.
 *
 * @note  Below is the prototype of callback:
 *        -
 *          Called when parsing is halted.
 *
 *          @param handle        Handle to an SMC Parse structure.
 *          @param halted        True if abnormally halted, false otherwise.
 *          @param failed        True if parsing failed, false otherwise.
 *          @param data          Handle or value passed in SMC_ParseFile
 *
 *          @noreturn
 *
 *          public OnParseEnd(SMCParser:handle, bool:halted, bool:failed, any:data)
 *        -
 * @param handle        Handle to an SMC Parse structure.
 * @param func          A ParseEnd callback.
 *
 * @noreturn
 * @error               Invalid or corrupt handle.
 */
native SMC_SetParseEnd(SMCParser:handle, const func[]);
SMC_SetReaders  Sets the three main reader functions.
/**
 * Sets the three main reader functions.
 *
 * @note  Enclosing quotes are always stripped.
 * @note  Below is the prototype of callbacks:
 *        -
 *          NewSection:
 *              Called when the parser finds a new section or sub-section.
 *
 *              @param handle           Handle to an SMC Parse structure.
 *              @param name             String containing section name.
 *              @param data             Handle or value passed in SMC_ParseFile
 *
 *              @return                 An SMCResult action to take.
 *
 *              public SMCResult:OnNewSection(SMCParser:handle, const name[], any:data)
 *
 *          KeyValue:
 *              Called when the parser finds a new key/value pair.
 *
 *              @param handle        Handle to an SMC Parse structure.
 *              @param key           String containing key name.
 *              @param value         String containing value name.
 *              @param data          Handle or value passed in SMC_ParseFile
 *
 *              @return              An SMCResult action to take.
 *
 *              public SMCResult:OnKeyValue(SMCParser:handle, const key[], const value[], any:data)
 *
 *          EndSection:
 *              Called when the parser finds the end of the current section.
 *
 *              @param handle        Handle to an SMC Parse structure.
 *              @param data          Handle or value passed in SMC_ParseFile
 *
 *              @return              An SMCResult action to take.
 *
 *              public SMCResult:OnEndSection(SMCParser:handle, any:data)
 * -
 * @param handle        Handle to an SMC Parse structure.
 * @param kv            A KeyValue callback.
 * @param ns            An optional NewSection callback.
 * @param es            An optional EndSection callback.
 *
 * @noreturn
 */
native SMC_SetReaders(SMCParser:smc, const kvFunc[], const nsFunc[] = "", const esFunc[] = "");
SMC_SetRawLine  Sets a raw line reader on an text parser handle.
/**
 * Sets a raw line reader on an text parser handle.
 *
 * @note  Below is the prototype of callbacks:
 *        -
 *          Called whenever a raw line is read.
 *
 *          @param handle        Handle to an SMC Parse structure.
 *          @param line          A string containing the raw line from the file.
 *          @param lineno        The line number it occurs on.
 *          @param data          Handle or value passed in SMC_ParseFile
 *
 *          @return              An SMCResult action to take.
 *
 *          public SMCResult:SMC_RawLine(SMCParser:handle, const line[], lineno, any:data)
 *        -
 * @param handle        Handle to an SMC Parse structure.
 * @param func          A RawLine callback.
 *
 * @noreturn
 */
native SMC_SetRawLine(SMCParser:handle, const func[]);
SMC_GetErrorString  Gets an error string for an SMCError code.
/**
 * Gets an error string for an SMCError code.
 *
 * @note  SMCError_Okay returns false.
 * @note  SMCError_Custom (which is thrown on SMCParse_HaltFail) returns false.
 *
 * @param error         The SMCParseError code.
 * @param buffer        A string buffer for the error (contents undefined on failure).
 * @param buf_max       The maximum size of the buffer.
 *
 * @return              True on success, false otherwise.
 */
native bool:SMC_GetErrorString(SMCError:error, buffer[], buf_max);

INI Format

Technical format detail:
/**
 * The INI file format is defined as:
 *    WHITESPACE: 0x20, \n, \t, \r
 *    IDENTIFIER: A-Z a-z 0-9 _ - , + . $ ? /
 *    STRING    : Any set of symbols
 *
 * Basic syntax is comprised of SECTIONs.
 *    A SECTION is defined as:
 *    [SECTIONNAME]
 *    OPTION
 *    OPTION
 *    OPTION...
 *
 * SECTIONNAME is an IDENTIFIER.
 *    OPTION can be repeated any number of times, once per line.
 *    OPTION is defined as one of:
 *      KEY = "VALUE"
 *      KEY = VALUE
 *      KEY
 *    Where KEY is an IDENTIFIER and VALUE is a STRING.
 *
 * WHITESPACE should always be omitted.
 *    COMMENTS should be stripped, and are defined as text occurring in:
 *    ;<TEXT>
 *
 * Example file below.  Note that the second line is technically invalid.
 * The event handler must decide whether this should be allowed.
 *    --FILE BELOW--
 *    [gaben]
 *    hi = clams
 *    bye = "NO CLAMS"
 *
 *    [valve]
 *    cannot
 *    maintain
 *    products
 */
Native Description
INI_CreateParser  Creates a new SMC parser.
/**
 * Parser invalid code.
 */
enum INIParser
{
    Invalid_INIParser = 0
};
 
/**
 * Creates a new INI parser.
 * This is used to set parse hooks.
 *
 * @return              A new handle to an INI Parse structure.
 */
native INIParser:INI_CreateParser();
INI_DestroyParser  Disposes of an INI parser.
/**
 * Disposes of an INI parser.
 *
 * @param handle        Handle to an INI Parse structure.
 *
 * @return              True if disposed, false otherwise.
 */
native INI_DestroyParser(&INIParser:handle);
INI_ParseFile  Parses an INI config file.
/**
 * Parses an INI config file.
 *
 * @param handle        A handle to an INI Parse structure.
 * @param file          A string containing the file path.
 * @param line          An optional by reference cell to store the last line number read.
 * @param col           An optional by reference cell to store the last column number read.
 * @param data          An optional handle or value to pass through to callback functions
 *
 * @return              An SMCParseError result.
 * @error               Invalid or corrupt handle.
 */
native bool:INI_ParseFile(INIParser:handle, const file[], &line = 0, &col = 0, any:data = 0);
INI_ParseStart  Sets the INI_ParseStart function of a parse handle.
/**
 * Sets the INI_ParseStart function of a parse handle.
 *
 * @note  Below is the prototype of callback:
 *        -
 *          Called when parsing is started.
 *
 *          @param handle        A handle to an INI Parse structure.
 *          @param data          Handle or value passed in INI_ParseFile
 *
 *          @noreturn
 *
 *          public OnParseStart(INIParser:handle, any:data)
 *        -
 * @param handle        Handle to an INI Parse structure.
 * @param func          A ParseStart callback.
 *
 * @noreturn
 * @error               Invalid or corrupt handle.
 */
native INI_SetParseStart(INIParser:handle, const func[]);
INI_SetParseEnd  Sets the INI_ParseEnd function of a parse handle.
/**
 * Sets the INI_ParseEnd function of a parse handle.
 *
 * @note  Below is the prototype of callback:
 *        -
 *          Called when parsing is halted.
 *
 *          @param handle        A handle to an INI Parse structure.
 *          @param halted        True if abnormally halted, false otherwise.
 *          @param data          Handle or value passed in INI_ParseFile
 *
 *          @noreturn
 *
 *          public OnParseEnd(INIParser:handle, bool:halted, any:data)
 *        -
 * @param handle        Handle to an INI Parse structure.
 * @param func          A ParseEnd callback.
 *
 * @noreturn
 * @error               Invalid or corrupt handle.
 */
native INI_SetParseEnd(INIParser:handle, const func[]);
INI_SetReaders  Sets the two main reader functions.
/**
 * Sets the two main reader functions.
 *
 * @note  Below is the prototype of callback:
 *        -
 *          NewSection:
 *              Called when the parser finds a new section.
 *
 *              @param handle           Handle to an INI Parse structure.
 *              @param section          Name of section in between the [ and ] characters.
 *              @param invalid_tokens   True if invalid tokens were detected in the name.
 *              @param close_bracket    True if a closing bracket was detected, false otherwise.
 *              @param extra_tokens     True if extra tokens were detected on the line.
 *              @param curtok           Contains current token in the line where the section name starts.
 *                                      You can add to this offset when failing to point to a token.
 *              @param data             Handle or value passed in INI_ParseFile
 *
 *              @return                 True to keep parsing, false otherwise.
 *
 *              public bool:OnNewSection(INIParser:handle, const section[], bool:invalid_tokens, bool:close_bracket, bool:extra_tokens, curtok, any:data)
 *
 *          KeyValue:
 *              Called when the parser finds a new key/value pair.
 *
 *              @param handle           Handle to an INI Parse structure.
 *              @param key              Name of key.
 *              @param value            String containing value (with quotes stripped, if any).
 *              @param invalid_tokens   Whether or not the key contained invalid tokens.
 *              @param equal_token      There was an '=' sign present (in case the value is missing).
 *              @param quotes           Whether value was enclosed in quotes.
 *              @param curtok           Contains the token index of the start of the value string.
 *                                      This can be changed when returning false.
 *              @param data             Handle or value passed in INI_ParseFile
 *
 *              @return                 True to keep parsing, false otherwise.
 *
 *              public bool:OnKeyValue(INIParser:handle, const key[], const value[], bool:invalid_tokens, bool:equal_token, bool:quotes, curtok, any:data)
 *        -
 * @param handle        Handle to an INI Parse structure.
 * @param kv            A KeyValue callback.
 * @param ns            An optional NewSection callback.
 *
 * @noreturn
 */
native INI_SetReaders(INIParser:smc, const kvFunc[], const nsFunc[] = "" );
INI_SetRawLine  Sets a raw line reader on an INI parser handle.
/**
 * Sets a raw line reader on an INI parser handle.
 *
 * @note  Below is the prototype of callback:
 *        -
 *          Called whenever a raw line is read.
 *
 *          @param handle       The INI Parse handle.
 *          @param line         Contents of line.
 *          @param lineno       The line number it occurs on.
 *          @param curtok       Pointer to optionally store failed position in string.
 *          @param data         Handle or value passed in INI_ParseFile
 *
 *          @return             True to keep parsing, false otherwise.
 *
 *          public bool:OnRawLine(INIParser:smc, const line[], lineno, curtok, any:data)
 *
 * @param handle        Handle to an INI Parse structure.
 * @param func          A RawLine callback.
 *
 * @noreturn
 */
native INI_SetRawLine(INIParser:handle, const func[]);

Existing core APIs additions

Client

Behavior changes

  • The following natives can now be used on connecting players: find_player, get_players and engclient_print (console only).
  • set_user_rendering default color and amount are now set to 0 to follow game behavior.

(Dis)connection

Note:The client_disconnect forward is deprecated in favor of client_disconnected.
This will be called in some additional cases that client_disconnect doesn't cover, most notably when a client aborts the connection process.
It is guaranteed to pair with the client_connect forward.
Forward Description
client_connectex  Called when a client is connecting.
/**
 * Called when a client is connecting.
 *
 * @note This forward is called too early to do anything that directly affects
 *       the client.
 *
 * @param id        Client index
 * @param name      Client name
 * @param ip        Client ip address with port
 * @param reason    A reason that will be displayed when player gets rejected (can be overwritten)
 *
 * @return          PLUGIN_CONTINUE to let a client join to the server
 *                  PLUGIN_HANDLED or higher to prevent a client to join
 */
forward client_connectex(id, const name[], const ip[], reason[128]);
client_disconnected  Called when a client is disconnected from the server.
/**
 * Called when a client is disconnected from the server.
 *
 * @note This will be called in some additional cases that client_disconnect doesn't cover,
 *       most notably when a client aborts the connection process. It is guaranteed to pair
 *       with the client_connect() forward.
 * @note When this fires the player entity is still valid (e.g. is_user_connected(id) will
 *       return true), but no networked commands will reach the client.
 *
 * @param id         Client index
 * @param drop       If true, the game has explicitly dropped the client
 * @param message    If drop is true, a writable buffer containing the disconnect info message
 * @param maxlen     Maximum size of buffer
 *
 * @noreturn
 */
forward client_disconnected(id, bool:drop, message[], maxlen);
client_remove  Called when a client entity has been removed from the server.
/**
 * Called when a client entity has been removed from the server.
 *
 * @note This fires after the client_disconnected() forward, when the player entity has been
 *       removed (e.g. is_user_connected(id) will return false).
 *
 * @param id         Client index
 * @param drop       If true, the game has explicitly dropped the client
 * @param message    If drop is true, contains the disconnect info message
 *
 * @noreturn
 */
forward client_remove(id, bool:drop, const message[]);

New Natives & Stocks

For the sake of better understanding and readability, find_player and get_players have now their counterparts which use the flags as name constants instead of letter. It is encouraged to use them instead.

/**
 * FindPlayerFlags constants for find_player_ex()
 */
enum FindPlayerFlags (<<= 1)
{
	FindPlayer_None = 0,           // None
	FindPlayer_MatchName = 1,      // Match with name
	FindPlayer_MatchNameSubstring, // Match with name substring
	FindPlayer_MatchAuthId,        // Match with authid
	FindPlayer_MatchIP,            // Match with ip
	FindPlayer_MatchTeam,          // Match with team name
	FindPlayer_ExcludeDead,        // Do not include dead clients
	FindPlayer_ExcludeAlive,       // Do not include alive clients
	FindPlayer_ExcludeBots,        // Do not include bots
	FindPlayer_ExcludeHuman,       // Do not include human clients
	FindPlayer_LastMatched,        // Return last matched client instead of the first
	FindPlayer_MatchUserId,        // Match with userid
	FindPlayer_CaseInsensitive,    // Match case insensitively
	FindPlayer_IncludeConnecting   // Include connecting clients
}
Native & Stock Description
find_player_ex  Finds a player given a filter.
/**
 * Find a player given a filter.
 *
 * @note If matching by userid, do not also specify FindPlayer_MatchName, FindPlayer_MatchNameSubstring
 *       or FindPlayer_MatchAuthId, or the function may not return a correct result.
 *
 * @param flags     Filtering flags (enum FindPlayerFlags); valid flags are:
 *                    FindPlayer_MatchName - match with name
 *                    FindPlayer_MatchNameSubstring - match with name substring
 *                    FindPlayer_MatchAuthId - match with authid
 *                    FindPlayer_MatchIP - match with ip
 *                    FindPlayer_MatchTeam - match with team name
 *                    FindPlayer_ExcludeDead - do not include dead clients
 *                    FindPlayer_ExcludeAlive - do not include alive clients
 *                    FindPlayer_ExcludeBots - do not include bots
 *                    FindPlayer_ExcludeHuman - do not include human clients
 *                    FindPlayer_LastMatched - return last matched client instead of the first
 *                    FindPlayer_MatchUserId - match with userid
 *                    FindPlayer_CaseInsensitive - match case insensitively
 *                    FindPlayer_IncludeConnecting - include connecting clients
 * @param ...       String to match against (integer if FindPlayer_MatchUserId is specified)
 *
 * @return          Client index, or 0 if no client was found
 */
native find_player_ex(FindPlayerFlags:flags, ...);
get_players_ex  Stores a filtered list of client indexes to an array.
/**
 * Stores a filtered list of client indexes to an array.
 *
 * @note Example retrieving all alive CTs:
 *       get_players_ex(players, num, GetPlayers_ExcludeDead | GetPlayers_MatchTeam, "CT")
 *
 * @param players   Array to store indexes to
 * @param num       Variable to store number of indexes to
 * @param flags     Optional filtering flags (enum GetPlayersFlags); valid flags are:
 *                    GetPlayers_None - No filter (Default)
 *                    GetPlayers_ExcludeDead - do not include dead clients
 *                    GetPlayers_ExcludeAlive - do not include alive clients
 *                    GetPlayers_ExcludeBots - do not include bots
 *                    GetPlayers_ExcludeHuman - do not include human clients
 *                    GetPlayers_MatchTeam - match with team
 *                    GetPlayers_MatchNameSubstring - match with part of name
 *                    GetPlayers_CaseInsensitive - match case insensitive
 *                    GetPlayers_ExcludeHLTV - do not include HLTV proxies
 *                    GetPlayers_IncludeConnecting - include connecting clients
 * @param team      String to match against if the "e" or "f" flag is specified
 *
 * @noreturn
 */
stock get_players_ex(players[MAX_PLAYERS], &num, GetPlayersFlags:flags = GetPlayers_None, const team[] = "")
{
    new strFlags[10];
    get_flags(_:flags, strFlags, charsmax(strFlags));
    get_players(players, num, strFlags, team);
}
get_playersnum_ex  Returns the number of clients on the server that match the specified flags.
/**
 * Returns the number of clients on the server that match the specified flags.
 *
 * @note Example retrieving all alive CTs:
 *       new AliveCt = get_playersnum_ex(GetPlayers_ExcludeDead | GetPlayers_MatchTeam, "CT")
 *
 * @param flags     Optional filtering flags (enum GetPlayersFlags); valid flags are:
 *                    GetPlayers_None - No filter (Default)
 *                    GetPlayers_ExcludeDead - do not include dead clients
 *                    GetPlayers_ExcludeAlive - do not include alive clients
 *                    GetPlayers_ExcludeBots - do not include bots
 *                    GetPlayers_ExcludeHuman - do not include human clients
 *                    GetPlayers_MatchTeam - match with team
 *                    GetPlayers_MatchNameSubstring - match with part of name
 *                    GetPlayers_CaseInsensitive - match case insensitive
 *                    GetPlayers_ExcludeHLTV - do not include HLTV proxies
 *                    GetPlayers_IncludeConnecting - include connecting clients
 * @param team      String to match against if the GetPlayers_MatchTeam or GetPlayers_MatchNameSubstring flag is specified
 *
 * @return          Number of clients on the server that match the specified flags
 */
stock get_playersnum_ex(GetPlayersFlags:flags = GetPlayers_None, const team[] = "")
{
	new PlayersNum;
	get_players_ex(_, PlayersNum, flags, team);
	return PlayersNum;
}
Example:
findPlayer()
{
    new const dead_player = find_player_ex(FindPlayer_MatchName | FindPlayer_ExcludeAlive, "egg");
}
 
getPlayer()
{
    new playersList[MAX_PLAYERS], playersCount;
    get_players_ex(playersList, playersCount, GetPlayers_ExcludeDead | GetPlayers_MatchTeam, "CT");
 
    // ...
 
    new const aliveCTsCount = get_playersnum_ex(GetPlayers_ExcludeDead | GetPlayers_MatchTeam, "CT");
}

New params

Native parameter Description
user_silentkill flag  If nonzero, the death will not affect the client's score.
stock user_silentkill(index, flag = 1)
{
    static msgid = 0;
    new msgblock;
    if (!msgid)
    {
        msgid = get_user_msgid("DeathMsg");
    }
    msgblock = get_msg_block(msgid);
    set_msg_block(msgid, BLOCK_ONCE);
    user_kill(index, flag);
    set_msg_block(msgid, msgblock);
 
    return 1;
}
Forward parameter Description
client_authorized authid  Client auth
forward client_authorized(id, const authid[]);

Command

Callback

Native Description
amxclient_cmd  Executes a command from the client without actually sending it to the client's DLL.
Similar to engclient_cmd with the difference this triggers plugin command hooks.
/**
 * Execute a command from the client without actually sending it to the client's
 * DLL. This triggers plugin command hooks.
 *
 * @note This emulates a client command on the server side, and is an excellent
 *       tool to force a client to do certain actions related to the game.
 * @note The command has to stand alone in the command parameter, only add
 *       arguments using the designated parameters.
 * @note Commands emulated using this function will trigger other plugin's
 *       command hooks. For an alternative that doesn't, see engclient_cmd()
 *
 * @param index         Client index, use 0 to execute from all clients
 * @param command       Client command to execute on
 * @param arg1          Optional command arguments
 * @param arg2          Optional command arguments
 *
 * @noreturn
 * @error           If a single client is specified and the index is not within
 *                  the range of 1 to MaxClients, an error will be thrown.
 */
native amxclient_cmd(index, const command[], const arg1[] = "", const arg2[] = "");

Arguments conversion

New natives to retrieve a command's argument directly as an integer or float instead of as a string (read_argv()).

Native Description
read_argv_int  Retrieves argument of client command as integer value.
/**
 * Retrieves argument of client command as integer value.
 *
 * @note Should only be used inside of the client_command() forward.
 *
 * @param id        Argument index starting from 1
 *
 * @return          Integer value
 */
native read_argv_int(id);
read_argv_float  Retrieves argument of client command as float value.
/**
 * Retrieves argument of client command as float value.
 *
 * @note Should only be used inside of the client_command() forward.
 *
 * @param id        Argument index starting from 1
 *
 * @return          Float value
 */
native Float:read_argv_float(id);
Example:
#include <amxmodx>
 
public plugin_init()
{
    register_clcmd("set_level", "@OnSetLevel", .info = "<value> - Sets a custom level");
}
 
@OnSetLevel(const client, const command_level, const command_id)
{
    new const value = read_argv_int(1);
}

Translatable description

In order to encourage the translations of command's description, a new parameter is available.
This is useful for use with the amx_help client command for example.

Native parameter Description
register_clcmd
register_concmd
register_srvcmd
info_ml  If true, the parameter info will be looked up as multilingual key.
/**
 * Registers a callback to be called when the client executes a command from the
 * console.
 *
 * @note For a list of possible access flags, see the ADMIN_* constants in
 *       amxconst.inc
 * @note Opting in to FlagManager enables the admin privileges to be overwritten
 *       by the end user via the cmdaccess.ini config file.
 * @note Automatic detection for FlagManager will only include a command if it
 *       has required privileges (flags is not -1) and it is not a command
 *       starting with "say".
 *
 * @param client_cmd    Command to register
 * @param function      Callback function
 * @param flags         Admin privilege flags required
 * @param info          Command description
 * @param FlagManager   0 opts out of flag manager, 1 opts in, -1 selects
 *                      automatically
 * @param info_ml       If true, the parameter "info" will be looked up as multilingual key
 *
 * @return              Command id, 0 on failure
 * @error               If an invalid callback function is specified, an error
 *                      will be thrown.
 */
native register_clcmd(const client_cmd[], const function[], flags = -1, const info[] = "", FlagManager = -1, bool:info_ml = false);
 
/**
 * Registers a callback to be called when the client or server executes a
 * command from the console.
 *
 * @note For a list of possible access flags, see the ADMIN_* constants in
 *       amxconst.inc
 * @note Opting in to FlagManager enables the admin privileges to be overwritten
 *       by the end user via the cmdaccess.ini config file.
 * @note Automatic detection for FlagManager will only include a command if it
 *       has required privileges (flags is not -1) and it is not a command
 *       starting with "say".
 *
 * @param client_cmd    Command to register
 * @param function      Callback function
 * @param flags         Admin privilege flags required
 * @param info          Command description
 * @param FlagManager   0 opts out of flag manager, 1 opts in, -1 selects
 *                      automatically
 * @param info_ml       If true, the parameter "info" will be looked up as multilingual key
 *
 * @return              Command id, 0 on failure
 * @error               If an invalid callback function is specified, an error
 *                      will be thrown.
 */
native register_concmd(const cmd[], const function[], flags = -1, const info[] = "", FlagManager = -1, bool:info_ml = false);
 
/**
 * Registers a callback to be called when the server executes a command from the
 * console.
 *
 * @note For a list of possible access flags, see the ADMIN_* constants in
 *       amxconst.inc
 *
 * @param client_cmd    Command to register
 * @param function      Callback function
 * @param flags         Admin privilege flags required
 * @param info          Command description
 * @param info_ml       If true, the parameter "info" will be looked up as multilingual key
 *
 * @return              Command id, 0 on failure
 * @error               If an invalid callback function is specified, an error
 *                      will be thrown.
 */
native register_srvcmd(const server_cmd[], const function[], flags = -1, const info[] = "", bool:info_ml = false);
Example:
[en]
MY_KEY = Hello world!
#include <amxmodx>
 
public plugin_init()
{
    register_clcmd("my_command", "OnMyCommand", ADMIN_CFG, "MY_KEY", .info_ml = true);
}

Cvar

In order to manage cvars more easily, several new cvar features have been added.

Note:A cvar managed at least once is now cached internally, for faster lookup, that's it.
Note:The cvar API is now moved to its own cvars.inc include file.

Hooking

You can now hook when a cvar value has changed. This allows plugins to react to cases where other plugins or clients change a cvar's value.

Native Description
hook_cvar_change  To create a hook
/**
 * Creates a hook for when a cvar's value is changed.
 *
 * @note Changing the cvar value from within this forward can lead to infinite
 *       recursion and should be avoided.
 * @note The callback will be called in the following manner:
 *
 * public cvar_change_callback(pcvar, const old_value[], const new_value[])
 *
 *   pcvar         - Pointer to cvar that was changed
 *   old_value     - Buffer containing the previous value of the cvar
 *   new_value     - Buffer containing the new value of the cvar
 *
 * The return value is ignored
 *
 * @param pcvar     Pointer to cvar
 * @param callback  Name of callback function
 *
 * @return          Callback handle that can be used with
 *                  [disable|enable]_cvar_hook
 * @error           If an invalid cvar pointer or callback function is provided,
 *                  an error will be thrown.
 */
native cvarhook:hook_cvar_change(pcvar, const callback[]);
disable_cvar_hook  To disable a hook
/**
 * Disables a cvar hook, stopping it from being called.
 *
 * @note Use the handle returned by hook_cvar_change as the parameter here.
 *
 * @param handle    Forward to disable
 * @error           If an invalid hook handle is provided, an error will be
 *                  thrown.
 */
native disable_cvar_hook(cvarhook:handle);
enable_cvar_hook  To enable a hook
/**
 * Enables a cvar hook, restoring it to being called.
 *
 * @note Use the handle returned by hook_cvar_change as the parameter here.
 *
 * @param handle    Forward to enable
 * @error           If an invalid hook handle is provided, an error will be
 *                  thrown.
 */
native enable_cvar_hook(cvarhook:handle);
Example:
#include <amxmodx>
 
new cvarhook:CvarHandle;
 
public plugin_init()
{
    CvarHandle = hook_cvar_change(get_cvar_pointer("mp_timelimit"), "@OnTimelimitChange");
 
    register_concmd("enable_hook" , "@OnConsoleCommand_EnableHook");
    register_concmd("disable_hook", "@OnConsoleCommand_DisableHook");
}
 
@OnTimelimitChange(const pointer, const old_value[], const new_value[])
{
    server_print("mp_timelimit: %s -> %s", old_value, new_value);
}
 
@OnClientCommand_EnableHook()
{
    enable_cvar_hook(CvarHandle);
}
 
@OnClientCommand_DisableHook()
{
    disable_cvar_hook(CvarHandle);
}

Binding

There are situations where you don't need to hook/manage a cvar value and you would wish to not deal with cvar pointers.
You can now bind a cvar's value to a global variable. This means that variable value will be always up to date.

Native Description
bind_pcvar_num  To bind an integer
/**
 * Binds a cvar's integer value to a global variable. The variable will then
 * always contain the current cvar value as it is automatically kept up to date.
 *
 * @note The variable *has* to be a global or a static variable. Local variables
 *       created within functions can not be used for technical reasons.
 * @note Variables can not be bound to multiple cvars.
 *
 * @param pcvar     Pointer to cvar
 * @param var       Global variable to keep updated
 *
 * @noreturn
 * @error           If an invalid cvar pointer or variable is provided, an error
 *                  will be thrown.
 */
native bind_pcvar_num(pcvar, &any:var);
bind_pcvar_float  To bind a float
/**
 * Binds a cvar's float value to a global variable. The variable will then
 * always contain the current cvar value as it is automatically kept up to date.
 *
 * @note The variable *has* to be a global or a static variable. Local variables
 *       created within functions can not be used for technical reasons.
 * @note Variables can not be bound to multiple cvars.
 *
 * @param pcvar     Pointer to cvar
 * @param var       Global variable to keep updated
 *
 * @noreturn
 * @error           If an invalid cvar pointer or variable is provided, an error
 *                  will be thrown.
 */
native bind_pcvar_float(pcvar, &Float:var);
bind_pcvar_string  To bind a string
/**
 * Binds a cvar's string value to a global array. The array will then
 * always contain the current cvar value as it is automatically kept up to date.
 *
 * @note The array *has* to be a global or a static array. Local arrays
 *       created within functions can not be used for technical reasons.
 * @note Arrays can not be bound to multiple cvars.
 *
 * @param pcvar     Pointer to cvar
 * @param var       Global array to keep updated
 * @param varlen    Maximum length of string array
 *
 * @noreturn
 * @error           If an invalid cvar pointer or variable is provided, an error
 *                  will be thrown.
 */
native bind_pcvar_string(pcvar, any:var[], varlen);
Example:
#include <amxmodx>
 
new CvarTimelimit;
new Float:CvarBuyTime;
new CvarSomething[32];
 
public plugin_init()
{
    bind_pcvar_num(get_cvar_pointer("mp_timelimit"), CvarTimelimit);
    bind_pcvar_float(get_cvar_pointer("mp_buytime"), CvarBuyTime);
    bind_pcvar_string(register_cvar("amx_something", "something"), CvarSomething, charsmax(CvarSomething));
 
    server_print("mp_timelimit  current value: %d", CvarTimelimit);
    server_print("mp_buytime    current value: %f", CvarBuyTime);
    server_print("amx_something current value: %s", CvarSomething);
}

Boundary

Having a better control over a cvar's value, we can enforce the value to be in a defined boundary.

Description Native
get_pcvar_bounds  To get a boundary
/**
 * Retrieves the specified value boundary of a cvar.
 *
 * @param pcvar     Pointer to cvar
 * @param type      Type of boundary to retrieve
 * @param value     Variable to store the specified boundary to
 *
 * @return          True if the cvar has a boundary set, false otherwise
 * @error           If an invalid cvar pointer or boundary type is provided,
 *                  an error will be thrown.
 */
native bool:get_pcvar_bounds(pcvar, CvarBounds:type, &Float:value);
set_pcvar_bounds  To set a boundary
/**
 * Sets the specified boundary of a cvar.
 *
 * @param pcvar     Pointer to cvar
 * @param type      Type of boundary to set
 * @param set       If true the cvar boundary will be set, otherwise it will be
 *                  removed (value is ignored)
 * @param value     Floating point value to use as the boundary
 *
 * @noreturn
 * @error           If an invalid cvar pointer or boundary type is provided, an
 *                  error will be thrown.
 */
native set_pcvar_bounds(pcvar, CvarBounds:type, bool:set, Float:value = 0.0);
Note:CvarBounds has the following values:
  • CvarBound_Upper
  • CvarBound_Lower
Example:
#include <amxmodx>
 
public plugin_init()
{
    new const pointer = register_cvar("amx_leet", "1337");
 
    // Defines min and max value
    set_pcvar_bounds(pointer, CvarBound_Lower, .set = true, 0.0);
    set_pcvar_bounds(pointer, CvarBound_Upper, .set = true, 42.0);
 
    // Current value should be "42".
    server_print("amx_something current value: %f", get_pcvar_float(pointer));
 
    // Removes the lower bound.
    set_pcvar_bounds(pointer, CvarBound_Lower, .set = false);
 
    new Float:value;
 
    if (get_pcvar_bounds(pointer, CvarBound_Upper, value))
    {
        server_print("amx_something should have an upper bound: %f", value);
    }
 
    if (!get_pcvar_bounds(pointer, CvarBound_Upper, value))
    {
        server_print("amx_something should not have an lower bound);
    }
}

Constant

A missing FCVAR_NOEXTRAWHITEPACE flag has been added.
It automatically strips trailing/leading white space from the string value.

Creating

A new create_cvar native has been added, similar to register_cvar but with two new features:

/**
 * Creates a new cvar for the engine.
 *
 * @note This has the same effect as register_cvar() but provides more options.
 * @note For a list of possible cvar flags see FCVAR_* constants above.
 * @note If an already existing cvar is registered it will not be duplicated.
 *       The default value is only set when the cvar is registered for the very
 *       first time since the server was started. Cvar bounds are overwritten
 *       by the create_cvar() call just as if they were re-set using
 *       set_pcvar_bounds().
 * @note The returned cvar pointer should be used with the get_pcvar_* and
 *       set_pcvar_* set of functions.
 *
 * @param name          Cvar name
 * @param string        Default cvar value
 * @param flags         Optional bitsum of flags specifying cvar behavior
 * @param description   Optional description of the cvar
 * @param has_min       Optional boolean that specifies if the cvar has a
 *                      minimum value
 * @param min_val       Minimum floating point value
 * @param has_max       Optional boolean that specifies if the cvar has a
 *                      maximum value
 * @param max_val       Maximum floating point value
 *
 * @return              Unique cvar pointer
 * @error               If invalid bounds are provided (min_val > max_val or
 *                      vice versa), an error will be thrown.
 */
native create_cvar(const name[], const string[], flags = FCVAR_NONE, const description[] = "", bool:has_min = false, Float:min_val = 0.0, bool:has_max = false, Float:max_val = 0.0);
Description Similar to command, you can explain shorlty what does the cvar. The message can be retrieved with get_plugins_cvar and can be read from amxx cvars detailed output.
The description is used with AutoExecConfig for example.
Boudary You can set directly a boudary, either a minimum value, a maximum value or both.
Example:
#include <amxmodx>
 
public plugin_init()
{
    create_cvar("amx_something1", "1", FCVAR_NONE, "My description here", true, 1.0, true, 42.0);
    create_cvar("amx_something2", "2", .description = "My description here", .has_min = true, min_val = 1.0, .has_max = true, .max_val = 42.0);
    create_cvar("amx_something3", "3", .has_min = true, min_val = 1.0);
    create_cvar("amx_something4", "4", .has_max = true, max_val = 42.0);
}

Command

The amxx cvars shows now more informations about a cvar state. Here an example of output:

Managed cvars:
       NAME                     VALUE                    PLUGIN             HOOKED   MIN     MAX
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 [  1] amx_mode                 1                        admin.amxx         no       -       -
 [  2] amx_password_field       _pw                      admin.amxx         no       -       -
 [  3] amx_default_access       z                        admin.amxx         no       -       -
 [  4] amx_vote_ratio           0.02                     admin.amxx         no       -       -
 [  5] amx_something            something                test-hook.amxx     yes      -       -
 [  6] amx_leet                 42                       test-bounds.amxx   no       0.00    42.00
 ...

It can show further details if you specify a cvar or index from the table: amxx cvars <index or cvar name>

amxx cvars 6
 
Cvar details :
 
 Cvar name   : amx_leet
 Value       : 42
 Def. value  : 1337
 Description :
 Flags       : FCVAR_EXTDLL
 
 STATUS        PLUGIN                     INFOS
 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 Registered    test-bounds.amxx           -
 Min value     test-bounds.amxx           0.000000
 Max value     test-bounds.amxx           42.000000

Others

Native Description
get_pcvar_bool  Returns an boolean value from a cvar via direct pointer access.
/**
 * Returns an boolean value from a cvar via direct pointer access.
 *
 * @param pcvar     Pointer to cvar to retrieve value from
 *
 * @return          Cvar value, converted to bool
 * @error           If an invalid cvar pointer is provided, an error will be
 *                  thrown.
 */
native bool:get_pcvar_bool(pcvar);
set_pcvar_bool  Sets a boolean value to a cvar via direct pointer access.
/**
 * Sets a boolean value to a cvar via direct pointer access.
 *
 * @param pcvar     Pointer to cvar to set value of
 * @param num       Value to set cvar to
 *
 * @noreturn
 * @error           If an invalid cvar pointer is provided, an error will be
 *                  thrown.
 */
native set_pcvar_bool(pcvar, bool:num);

CellArray

A bunch of natives have been added to complete the existing API. You are now able to:

  • Clone an array
  • Resize an array
  • Find a value or string inside an array
  • Control more precisely how the data is retrieved/saved
Note:Arrays are heterogeneous. This means you can save different data types into a list.
A good example is the Stack Structure API which is actually based on Array (internal library, that's it).
Note:Initially the reserved parameter in ArrayCreate was intended to create blank entries that would immediately be usable with ArrayGet/Set functions.
This functionality was never working as intended, and can now be achieved using ArrayResize.


Cloning

Native Description
ArrayClone  Clones an array.
/**
 * Clones an array, returning a new handle with the same size and data.
 *
 * @param which         Array handle
 *
 * @return              Handle to the cloned array on success, 0 otherwise
 * @error               If an invalid handle is provided an error will be
 *                      thrown.
 */
native Array:ArrayClone(Array:which);
Example:
#include <amxmodx>
 
public plugin_init()
{
    new Array:list = ArrayCreate();
 
    ArrayPushCell(list, 1);
    ArrayPushCell(list, 2);
    ArrayPushCell(list, 3);
 
    new Array:clone_list = ArrayClone(list);
 
    //
 
    ArrayDestroy(clone_list);
    ArrayDestroy(list);
}

Resizing

Native Description
ArrayResize  Resizes an array.
/**
 * Resizes an array.
 *
 * @note If the size is smaller than the current array size the array is
 *       truncated and data lost.
 *
 * @param which         Array handle
 * @param newsize       New size
 *
 * @noreturn
 * @error               If an invalid handle is provided or the resizing
 *                      operation runs out of memory, an error will be thrown.
 */
native bool:ArrayResize(Array:which, newsize);
Example:
#include <amxmodx>
 
public plugin_init()
{
    new Array:list = ArrayCreate(.cellsize = 1, .reserved = 3);
 
    ArrayPushCell(list, 1);
    ArrayPushCell(list, 2);
    ArrayPushCell(list, 3);
 
    new const count = ArraySize(list);
 
    ArrayResize( list, count + 1); // Add a new allocated and available slot
    ArraySetCell(list, count, 4);  // Notice you can use directly ArraySet
 
    server_print("Last value = %d, Cloned list size = %d", ArrayGetCell(list, count), ArraySize(list)); // Should be 4.
 
    ArrayDestroy(list);
}

Finding a value

Native Description
ArrayFindValue  Searches through the array and returns the index of the first occurence of the specified value.
/**
 * Searches through the array and returns the index of the first occurence of
 * the specified value.
 *
 * @param which         Array handle
 * @param item          Value to search for
 *
 * @return              Array index on success, -1 if the value can't be found
 * @error               If an invalid handle is provided an error will be
 *                      thrown.
 */
native ArrayFindValue(Array:which, any:item);
ArrayFindString  Searches through the array and returns the index of the first occurence of the specified string.
/**
 * Searches through the array and returns the index of the first occurence of
 * the specified string.
 *
 * @param which         Array handle
 * @param item          String to search for
 *
 * @return              Array index on success, -1 if the string can't be found
 * @error               Invalid handle.
 */
native ArrayFindString(Array:which, const item[]);
Example:
#include <amxmodx>
 
public plugin_init()
{
    new Array:list = ArrayCreate(.cellsize = 16);
 
    ArrayPushString(list, "something");
    ArrayPushString(list, "is");
    ArrayPushCell(list, 42);
    ArrayPushString(list, "hidden");
 
    new index = ArrayFindValue(list, 42);
    server_print("Cell index = %d", index); // should be 2
 
    index = ArrayFindString(list, "hidden");
    server_print("String index = %d", index); // should be 3
 
    ArrayDestroy(list);
}


Sorting

Along two new ArraySort and SortADTArray natives, there is also a new Sort_Random method.

Native Description
ArraySortEx  A faster version of ArraySort.
/**
 * A faster version of ArraySort, the sorting algorithm then uses the custom
 * comparison function to sort the data.
 *
 * @note The advantage of this function is that the data of the elements being
 *       compared is directly passed to the function, instead of the item
 *       indexes that are passed by ArraySort. This removes the need for calling
 *       ArrayGet[Cell|String|Array] every time before being able to compare the
 *       elements.
 *
 * @note For Arrays with a cellsize of 1 (used for storing integers and floats),
 *       the function is called in the following manner:
 *
 * public MySortFunc(Array:array, elem1, elem2, const data[], data_size)
 *
 *   array           - Array handle in its current un-sorted state
 *   elem1, elem2    - Current element pair being compared
 *   data[]          - Extra data array passed to the sort func
 *   data_size       - Size of extra data
 *
 * @note For Arrays with a cellsize larger than 1 (used for storing arrays and
 *       strings), the function is called in the following manner:
 *
 * public MySortFunc(Array:array, elem1[], elem2[], const data[], data_size)
 *
 *   array               - Array handle in its current un-sorted state
 *   elem1[], elem2[]    - Current element pair being compared
 *   data[]              - Extra data array passed to the sort func
 *   data_size           - Size of extra data
 *
 *
 * @note The comparison function should return:
 *         -1 if elem1 should go before elem2
 *          0 if elem1 and elem2 are equal
 *          1 if elem1 should go after elem2
 *
 * @note All parameters after item2 are optional and do not need to be specified
 *       and used.
 * @note Unlike the sorting.inc version, the array passed to the callback is not
 *       in mid-sorted state.
 *
 * @param array         Array handle
 * @param comparefunc   Callback function used for comparison
 * @param data          Extra data that is passed through to the callback
 * @param data_size     Size of extra data
 *
 * @noreturn
 * @error               If an invalid handle or an invalid callback is provided
 *                      an error will be thrown.
 */
native ArraySortEx(Array:array, const comparefunc[], data[]="", data_size=0);
SortADTArray  To sort directly with a sort method.
/**
 * Sort an ADT Array. Specify the type as Integer, Float, or String.
 *
 * @param array			Array Handle to sort
 * @param order			Sort order to use, same as other sorts.
 * @param type			Data type stored in the ADT Array
 * @noreturn
 */
native SortADTArray(Array:array, SortMethod:order, SortType:type);
Note:SortMethod has the following values:
  • Sort_Ascending
  • Sort_Descending
  • Sort_Random

New params

Native parameter Description
ArrayGetArray
ArraySetArray
ArrayPushArray
size  Controls the number of elements to use.
/**
 * @param size          If not set, assumes the buffer size is equal to the
 *                      cellsize. Otherwise, the specified size is used.
 */
native ArrayGetArray(Array:which, item, any:output[], size = -1);
native ArraySetArray(Array:which, item, const any:input[], size =-1);
native ArrayPushArray(Array:which, const any:input[], size = -1);
ArrayGetCell
ArraySetCell
achar
block
 Specifies which block and retrieves a value as byte.
/**
 * @param block         If the array has a cellsize >1 this optionally specifies
 *                      which block to read from
 * @param asChar        If true reads the value as a byte instead of a cell
 */
native any:ArrayGetCell(Array:which, item, block = 0, bool:asChar = false);

CellTrie

The word "Trie" in this API is historical. As of AMX Mod X 1.9, tries have been internally replaced with hash tables, which have O(1) insertion time instead of O(n).
As consequence, the API has been completed and you can now:

  • Get a trie size
  • Control more precisely the data on insertion/retrieval
  • Iterate over a trie
Note:Tries are heterogeneous. This means you can save different data types into a list.

Getting size

Native Description
TrieGetSize  Returns the number of entries in a hash map.
/**
 * Returns the number of entries in a hash map.
 *
 * @param handle    Map handle
 *
 * @return          Number of elements in the hash map
 * @error           If an invalid handle is provided an error will be
 *                  thrown.
 */
native TrieGetSize(Trie:handle);

Iterating

There are two ways to iterate over a trie:

  • Snapshots
As the name suggested, it will duplicate the whole set of keys (only) into a separate list. Any changes to the original list will not affect the snapshot.
It's an expensive operation, but can be stored.
Native Description
TrieSnapshotCreate  Creates a snapshot of all keys in a hash map.
/**
 * Creates a snapshot of all keys in a hash map. If the map is changed
 * afterwards,  the changes are not reflected in the snapshot.
 * Keys are not sorted.
 *
 * @param handle    Map handle
 *
 * @return          New map snapshot handle, which must be freed via
 *                  TrieSnapshotDestroy()
 * @error           If an invalid handle is provided an error will be
 *                  thrown.
 */
native Snapshot:TrieSnapshotCreate(Trie:handle);
TrieSnapshotLength  Returns the number of keys in a map snapshot.
/**
 * Returns the number of keys in a map snapshot. Note that this may be
 * different from the size of the map, since the map can change after the
 * snapshot of its keys was taken.
 *
 * @param handle    Map snapshot handle
 *
 * @return          Number of keys
 * @error           If an invalid handle is provided an error will be
 *                  thrown.
 */
native TrieSnapshotLength(Snapshot:handle);
TrieSnapshotGetKey  Retrieves the key string of a given key in a map snapshot.
/**
 * Retrieves the key string of a given key in a map snapshot.
 *
 * @param handle    Map snapshot handle
 * @param index     Key index (starting from 0)
 * @param buffer    String buffer
 * @param maxlength Maximum buffer length
 *
 * @return          Number of bytes written to the buffer
 * @error           If an invalid handle is provided an error will be
 *                  thrown. or index out of range
 */
native TrieSnapshotGetKey(Snapshot:handle, index, buffer[], maxlength);
TrieSnapshotDestroy  Retrieves the key string of a given key in a map snapshot.
/**
 * Destroys a map snapshot and frees its memory.
 *
 * @note The function automatically sets the variable passed to it to 0 to aid
 *       in preventing accidental usage after destroy.
 *
 * @param handle    Map snapshot handle
 *
 * @return          1 on success, 0 if an invalid handle was passed in
 */
native TrieSnapshotDestroy(&Snapshot:handle);
Note:The keys are not sorted.
Example:
#include <amxmodx>
 
public plugin_init()
{
    new Trie:list = TrieCreate();
    {
        TrieSetString(list, "adventure", "time!");
        TrieSetString(list, "butterflies", "bees");
        TrieSetString(list, "egg", "egg");
    }
 
    new Snapshot:keys = TrieSnapshotCreate(list);
    {
        new const length = TrieSnapshotLength(keys);
        new key[32];
 
        for (new const i = 0; i < length; ++i)
        {
            TrieSnapshotGetKey(keys, i, buffer, charmax(buffer));
            server_print("buffer = %s", buffer);
        }
    }
 
    TrieSnapshotDestroy(keys);
}
  • Iterator
A contrario, Iterators are designed to be short-lived and not stored, and creating them is very cheap.
Reading data from an iterator is just as fast as reading directly from the map.
This is useful if you just need to iterate (or eventually updating values of existing keys, which is allowed)
Native Description
TrieIterCreate  Creates an iterator for a map.
/**
 * Creates an iterator for a map. It provides iterative read-only access to the
 * maps contents.
 *
 * @note Removing or adding keys to the underlying map will invalidate all its
 *       iterators. Updating values of existing keys is allowed and the changes
 *       will be immediately reflected in the iterator.
 * @note Iterators are designed to be short-lived and not stored, and creating
 *       them is very cheap. Reading data from an iterator is just as fast as
 *       reading directly from the map.
 * @note Just like in snapshots the keys are not sorted.
 *
 * @return              New iterator handle, which must be freed via TrieIterDestroy().
 * @error               Invalid Handle
 */
native TrieIter:TrieIterCreate(Trie:handle);
TrieIterEnded  Returns if the iterator has reached its end and no more data can be read.
/**
 * Returns if the iterator has reached its end and no more data can be read.
 *
 * @param handle        Iterator handle
 *
 * @return              True if iterator has reached the end, false otherwise
 * @error               Invalid Handle
 *                      Iterator has been closed (underlying map destroyed)
 *                      Iterator is outdated
 */
native bool:TrieIterEnded(TrieIter:handle);
TrieIterNext  Advances the iterator to the next key/value pair if one is available.
/**
 * Advances the iterator to the next key/value pair if one is available.
 *
 * @param handle        Iterator handle
 *
 * @error               Invalid Handle
 *                      Iterator has been closed (underlying map destroyed)
 *                      Iterator is outdated
 */
native TrieIterNext(TrieIter:handle);
TrieIterGetKey  Retrieves the key the iterator currently points to.
/**
 * Retrieves the key the iterator currently points to.
 *
 * @param handle        Iterator handle.
 * @param key           Buffer to store the current key in.
 * @param outputsize    Maximum size of string buffer.
 *
 * @return              Nnumber of bytes written to the buffer
 * @error               Invalid handle
 *                      Iterator has been closed (underlying map destroyed)
 *                      Iterator is outdated
 */
native TrieIterGetKey(TrieIter:handle, key[], outputsize);
TrieIterGetSize  Retrieves the number of elements in the underlying map.
/**
 * Retrieves the number of elements in the underlying map.
 *
 * @note When used on a valid iterator this is exactly the same as calling TrieGetSize on the map directly.
 *
 * @param handle        Iterator handle
 *
 * @return              Number of elements in the map
 * @error               Invalid handle
 *                      Iterator has been closed (underlying map destroyed)
 *                      Iterator is outdated
 */
native TrieIterGetSize(TrieIter:handle);
TrieIterGetCell  Retrieves a value at the current position of the iterator.
/**
 * Retrieves a value at the current position of the iterator.
 *
 * @param handle        Iterator handle
 * @param value         Variable to store value in
 *
 * @return              True on success, false if the iterator is empty or the current
 *                      value is an array or a string.
 * @error               Invalid handle
 *                      Iterator has been closed (underlying map destroyed)
 *                      Iterator is outdated
 */
native bool:TrieIterGetCell(TrieIter:handle, &any:value);
TrieIterGetString  Retrieves a string at the current position of the iterator.
/**
 * Retrieves a string at the current position of the iterator.
 *
 * @param handle        Iterator handle
 * @param buffer        Buffer to store the string in
 * @param outputsize    Maximum size of string buffer
 * @param size          Optional parameter to store the number of bytes written to the buffer.
 *
 * @return              True on success, false if the iterator is empty or the current value
 *                      is not a string.
 * @error               Invalid handle
 *                      Invalid buffer size
 *                      Iterator has been closed (underlying map destroyed)
 *                      Iterator is outdated
 */
native bool:TrieIterGetString(TrieIter:handle, buffer[], outputsize, &size = 0);
TrieIterGetArray  Retrieves an array at the current position of the iterator.
/**
 * Retrieves an array at the current position of the iterator.
 *
 * @param handle        Iterator handle
 * @param buffer        Buffer to store the array
 * @param outputsize    Maximum size of buffer
 * @param size          Optional parameter to store the number of bytes written to the buffer
 *
 * @return              True on success, false if the iterator is empty or the current
 *                      value is not an array.
 * @error               Invalid handle
 *                      Invalid buffer size
 *                      Iterator has been closed (underlying map destroyed)
 *                      Iterator is outdated
 */
native bool:TrieIterGetArray(TrieIter:handle, any:array[], outputsize, &size = 0);
TrieIterDestroy  Destroys an iterator handle.
/**
 * Destroys an iterator handle.
 *
 * @param handle    Iterator handle.
 *
 * @return          True on success, false if the value was never set.
 */
native TrieIterDestroy(&TrieIter:handle);
Note:The keys are not sorted.
Example:
#include <amxmodx>
 
public plugin_init()
{
    new Trie:list = TrieCreate();
    {
        TrieSetString(list, "adventure", "time!");
        TrieSetString(list, "butterflies", "bees");
        TrieSetString(list, "hello", "world!");
    }
 
    new TrieIter:iter = TrieIterCreate(list);
    {
        new key[32], key_length;
        new value[32], value_length;
 
        while (!TrieIterEnded(iter))
        {
            key_length = TrieIterGetKey(iter, key, charsmax(key));
            TrieIterGetString(iter, value, charsmax(value), value_length);
 
            server_print("%s (%d) -> %s (%d)", key, key_length, value, value_length);
 
            // Should throw an error
            // TrieSetString(t, "monkey", "island");
            // TrieDeleteKey(t, "full");
            // TrieClear(t);
 
            TrieIterNext(iter);
        }
    }
    TrieIterDestroy(iter);
 
    TrieDestroy(list);
}

New params

Native parameter Description
TrieSetString
TrieSetArray
replace  Makes operation fail if key already set.
/**
 * @param replace   If false the operation will fail if the key is already set
 */
native TrieSetCell(Trie:handle, const key[], any:value, bool:replace = true);
native TrieSetString(Trie:handle, const key[], const value[], bool:replace = true);
native TrieSetArray(Trie:handle, const key[], const any:buffer[], size, bool:replace = true);
TrieGetString
TrieGetArray
size  Returns the number of bytes written in the buffer.
/**
 * @param size          Optional variable to store the number of cells written
 *                      to the array in
 */
native bool:TrieGetString(Trie:handle, const key[], output[], outputsize, &size = 0);
native bool:TrieGetArray(Trie:handle, const key[], any:output[], outputsize, &size = 0);

Event

New natives

Native Description
register_event_ex  Registers a function to be called on a given game event.
A wrapper of register_event using flags as strings.
/**
 * Registers a function to be called on a given game event.
 *
 * @note Examples for event conditions:
 *       "2=c4" - Second parameter of message must be the string "c4"
 *       "3>10" - Third parameter of message must be greater than 10
 *       "3!4" - Third parameter of message must not be equal to 4
 *       "2&Buy" - Second parameter of message must contain "Buy" substring
 *       "2!Buy" - Second parameter of message must not equal "Buy"
 * @note Due to a long-standing bug that would break compatibility with older
 *       plugins, the client id should be checked for alive/dead state if using
 *       flags "d" or "e".
 * @note If multiple conditions are specified for a single parameter, only one
 *       of them has to hold true for the event function to be called.
 *
 * @param event     Name of event that should be hooked
 * @param function  Name of callback function
 * @param flags     Flags used for filtering events (enum RegisterEventFlags); the valid flags are:
 *                    RegisterEvent_Global - Global event (sent to every client)
 *                    RegisterEvent_Single - Event sent to single client
 *                    RegisterEvent_OnceForMultiple - Call only once when repeated to multiple clients
 *                    RegisterEvent_OnlyDead - Call only if sent to dead client
 *                    RegisterEvent_OnlyAlive - Call only if sent to alive client
 *                    RegisterEvent_OnlyHuman - Call only if sent to human client (RegisterEvent_Single required)
 *                    RegisterEvent_OnlyBots - Call only if sent to bot (RegisterEvent_Single required)
 * @param cond      Condition string used for filtering events, built as:
 *                  "<argument number><comparison operator><value>"
 *                  Argument number is the argument position to be filtered
 *                  The comparison operator may be:
 *                    "=" for equality comparison (all argument types)
 *                    "!" for inequality comparison (all argument types)
 *                    "&" for bitwise and (int argument) or substring
 *                        comparison (string argument)
 *                    "<" for less than comparison (int/float arguments)
 *                    ">" for greater than comparison (int/float arguments)
 *                  The argument is compared to the specified value accordingly
 * @param ...       Any number of additional conditions
 *
 * @return          Event handle
 * @error           If an invalid event name or callback function is provided,
 *                  an error will be thrown.
 */
native register_event_ex(const event[], const function[], RegisterEventFlags:flags, const cond[] = "", ...);
enable_event
disable_event
 Enables a function hook of a game event which has been previously registered with register_event or register_event_ex.
/**
 * Enables a function hook of a game event which has been previously registered with register_event and register_event_ex().
 *
 * @param handle    Value returned from register_event() or register_event_ex()
 *
 * @noreturn
 * @error           If an invalid handle is provided, an error will be thrown.
 */
native enable_event(handle);
 Disables a function hook of a game event which has been previously registered with register_event or register_event_ex.
/**
 * Disables a function hook of a game event which has been previously registered with register_event and register_event_ex().
 *
 * @param handle    Value returned from register_event() or register_event_ex()
 *
 * @noreturn
 * @error           If an invalid handle is provided, an error will be thrown.
 */
native disable_event(handle);
enable_logevent
disable_logevent
 Enables a function hook of a game log event which has been previously registered with register_logevent.
/**
 * Enables a function hook of a game log event which has been previously registered with register_logevent().
 *
 * @param handle    Value returned from register_logevent()
 *
 * @noreturn
 * @error           If an invalid handle is provided, an error will be thrown.
 */
native enable_logevent(handle);
 Disables a function hook of a game log event which has been previously registered with register_logevent.
/**
 * Disables a function hook of a game log event which has been previously registered with register_logevent().
 *
 * @param handle    Value returned from register_logevent()
 *
 * @noreturn
 * @error           If an invalid handle is provided, an error will be thrown.
 */
native disable_logevent(handle);

New flags

Native flags Description
register_event "f"
"g"
 Call only if sent to human client ("b" flag required)
Call only if sent to bot ("b" flag required).
/**
 * Registers a function to be called on a given game event.
 *
 * @note Please consider using register_event_ex() instead which allows you to
 *       use named constants for flags instead of letters.
 * @note Examples for event conditions:
 *       "2=c4" - Second parameter of message must be the string "c4"
 *       "3>10" - Third parameter of message must be greater than 10
 *       "3!4" - Third parameter of message must not be equal to 4
 *       "2&Buy" - Second parameter of message must contain "Buy" substring
 *       "2!Buy" - Second parameter of message must not equal "Buy"
 * @note Due to a long-standing bug that would break compatibility with older
 *       plugins, the client id should be checked for alive/dead state if using
 *       flags "d" or "e".
 * @note If multiple conditions are specified for a single parameter, only one
 *       of them has to hold true for the event function to be called.
 *
 * @param event     Name of event that should be hooked
 * @param function  Name of callback function
 * @param flags     Flags used for filtering events, the valid flags are:
 *                  "a" - Global event (sent to every client)
 *                  "b" - Event sent to single client
 *                  "c" - Call only once when repeated to multiple clients
 *                  "d" - Call only if sent to dead client
 *                  "e" - Call only if sent to alive client
 *                  "f" - Call only if sent to human client ("b" flag required)
 *                  "g" - Call only if sent to bot ("b" flag required)
 * @param cond      Condition string used for filtering events, built as:
 *                  "<argument number><comparison operator><value>"
 *                  Argument number is the argument position to be filtered
 *                  The comparison operator may be:
 *                    - "=" for equality comparison (all argument types)
 *                    - "!" for inequality comparison (all argument types)
 *                    - "&" for bitwise and (int argument) or substring
 *                      comparison (string argument)
 *                    - "<" for less than comparison (int/float arguments)
 *                    - ">" for greater than comparison (int/float arguments)
 *                  The argument is compared to the specified value accordingly
 * @param ...       Any number of additional conditions
 *
 * @return          Event handle
 * @error           If an invalid event name or callback function is provided,
 *                  an error will be thrown.
 */
native register_event(const event[], const function[], const flags[], const cond[] = "", ...);


File

Valve FileSystems

Thanks to the IFileSystem interface from HLSDK, we are now able to make more operations possible with files via Valve File System through Valve search paths (example: download directory).
This is handy when you want to deal with files which are not necessary existing directly in the game directory.

Not all natives are concerned. This features some new natives and enhanced others existing ones with small quality of life changes.

Valve Paths

Path ID Description
GAME All paths related to current mod, including fallback. Depending settings, it includes: <gamedir>_lv/_addon/_language/_hd and <gamedir> itself.
GAMECONFIG The default writable directory: <gamedir>.
GAMEDOWNLOAD The download directory: <gamedir>_download.
GAME_FALLBACK All paths related to fallback game, same as GAME (example: czero has cstrike as fallback. Others mods have usually the default game valve, including cstrike).
DEFAULTGAME All paths related to the default game which is valve, same as GAME.
BASE The base path where server is installed.

Native Support

Some natives supports partially Valve FS, where a path ID can't be provided and this will search in all paths instead.

Native parameter Description
delete_file unlink
file_exists partially
dir_exists partially
file_size
fopen
mkdir
open_dir
use_valve_fs
valve_path_id
 Uses the Valve file system via a search path from gameinfo.
/**
 * @note Registered paths ID are (in priority order) :
 *         GAME           All paths related to current mod, including fallback
 *                        Depending settings, it includes: <gamedir>_lv/_addon/_<language>/_hd
 *                        and <gamedir> itself
 *         GAMECONFIG     The default writable directory (<gamedir>)
 *         GAMEDOWNLOAD   The download directory (<gamedir>_download)
 *         GAME_FALLBACK  All paths related to fallback game, same as GAME
 *         DEFAULTGAME    All paths related to the default game which is "valve", same as GAME
 *         BASE           The base path where server is installed
 *
 *         Note that some paths are non-writable. It includes all <gamedir>_* (expect _download)
 *         and DEFAULTGAME. Any file inside a non-writable path will be ignored if you try to open
 *         it in writing mode.
 *
 * @param use_valve_fs  If true, the Valve file system will be used instead
 *                      This can be used to finred files existing in valve
 *                      search paths, rather than solely files existing directly
 *                      in the gamedir.
 * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths
 */

Some natives are not adjusted because not exposed by Valve FS:

  • rename_file
  • rmdir

New Natives

Native Description
FileReadInt8
FileReadUint8
FileReadInt16
FileReadUint16
FileReadInt32
 Reads a single value from a file.
More sane and better designed natives to read a single value (proper type, unsigned byte/short support and returns 1 or 0).
/**
 * Reads a single int8 (byte) from a file. The returned value is sign-
 * extended to an int32.
 *
 * @param file          Handle to the file
 * @param data          Variable to store the data read
 *
 * @return              True on success, false on failure
 */
native bool:FileReadInt8(file, &any:data);
 
/**
 * Reads a single uint8 (unsigned byte) from a file. The returned value is
 * zero-extended to an int32.
 *
 * @param file          Handle to the file
 * @param data          Variable to store the data read
 *
 * @return              True on success, false on failure
 */
native bool:FileReadUint8(file, &any:data);
 
/**
 * Reads a single int16 (short) from a file. The value is sign-extended to
 * an int32.
 *
 * @param file          Handle to the file
 * @param data          Variable to store the data read
 *
 * @return              True on success, false on failure
 */
native bool:FileReadInt16(file, &any:data);
 
/**
 * Reads a single unt16 (unsigned short) from a file. The value is zero-
 * extended to an int32.
 *
 * @param file          Handle to the file
 * @param data          Variable to store the data read
 *
 * @return              True on success, false on failure
 */
native bool:FileReadUint16(file, &any:data);
 
/**
 * Reads a single int32 (int/cell) from a file.
 *
 * @param file          Handle to the file
 * @param data          Variable to store the data read
 *
 * @return              True on success, false on failure
 */
native bool:FileReadInt32(file, &any:data);
FileWriteInt8
FileWriteInt16
FileWriteInt32
 Writes a single value from a file.
More sane and better designed natives to write a single value (proper type, unsigned byte/short support and returns 1 or 0).
/**
 * Writes a single int8 (byte) to a file.
 *
 * @param file          Handle to the file
 * @param data          Data to write (truncated to an int8)
 *
 * @return              True on success, false on failure
 */
native bool:FileWriteInt8(file, any:data);
 
/**
 * Writes a single int16 (short) to a file.
 *
 * @param file          Handle to the file
 * @param data          Data to write (truncated to an int16)
 *
 * @return              True on success, false on failure
 */
native bool:FileWriteInt16(file, any:data);
 
/**
 * Writes a single int32 (int/cell) to a file.
 *
 * @param file          Handle to the file
 * @param data          Data to write
 *
 * @return              True on success, false on failure
 */
native bool:FileWriteInt32(file, any:data);
GetFileTime  Returns a file timestamp as a unix timestamp.
/**
 * File time modes for use with GetFileTime().
 */
enum FileTimeType
{
    FileTime_LastAccess,    /* Last access (not available on FAT) */
    FileTime_Created,       /* Creation (not available on FAT) */
    FileTime_LastChange,    /* Last modification */
};
 
/**
 * Returns a file timestamp as a unix timestamp.
 *
 * @param file          File name
 * @param tmode         Time mode, see FileTime_* constants
 *
 * @return              Returns a file timestamp as a unix timestamp
 */
native GetFileTime(const file[], FileTimeType:tmode);
SetFilePermissions  Changes a file or directories permissions.
/**
 * Changes a file or directories permissions.
 *
 * @param path          Path to the file
 * @param mode          Permissions to set, see FPERM_* constants
 *
 * @return              True on success, false otherwise
 */
native bool:SetFilePermissions(const path[], mode);

New params

Native parameter Description
fputs null_term  True to append NULL terminator, false otherwise.
/**
 * Writes a line of text to a text file.
 *
 * @param file          Handle to the file
 * @param text          String to write
 * @param null_term     True to append NULL terminator, false otherwise
 *
 * @return              0 on success, -1 otherwise
 */
native fputs(file, const text[], bool:null_term = false);
mkdir mode  Permissions (default is o=rx,g=rx,u=rwx).
Note that folders must have the execute bit set on Linux.
On Windows, the mode is ignored.
/**
 * Creates a directory.
 *
 * @param path          Path to create
 * @param mode          Permissions (default is o=rx,g=rx,u=rwx).  Note that folders must have
 *                      the execute bit set on Linux.  On Windows, the mode is ignored.
 * @param use_valve_fs  If true, the Valve file system will be used instead
 *                      This can be used to create folders in the game's
 *                      Valve search paths, rather than directly in the gamedir.
 * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for default
 *                      In this case, mode is ignored
 *
 * @return              0 on success, -1 otherwise
 */
native mkdir(const dirname[], mode = FPERM_DIR_DEFAULT, bool:use_valve_fs = false, const valve_path_id[] = "GAMECONFIG");
open_dir
next_file
type  Optional variable to store the file type.
/**
 * Opens a directory/folder for contents enumeration.
 *
 * @note Directories are closed with close_dir().
 *
 * @param dir           Path to open.
 * @param firstfile     String buffer to hold first file name
 * @param length        Maximum size of the string buffer
 * @param type          Optional variable to store the file type
 * @param use_valve_fs  If true, the Valve file system will be used instead.
 *                      This can be used to find files existing in any of
 *                      the Valve search paths, rather than solely files
 *                      existing directly in the gamedir.
 * @param valve_path_id If use_valve_fs, a search path from gameinfo or NULL_STRING for all search paths.
 *
 * @return              Handle to the directory, 0 otherwise
 */
native open_dir(dir[], firstfile[], length, &FileType:type = FileType_Unknown, bool:use_valve_fs = false, const valve_path_id[] = "GAME");
 
/**
 * Reads the next directory entry as a local filename.
 *
 * @note Contents of buffers are undefined when returning false.
 * @note Both the '.' and '..' automatic directory entries will be retrieved for Windows and Linux.
 *
 * @param dirh          Handle to a directory
 * @param buffer        String buffer to hold directory name
 * @param length        Maximum size of string buffer
 * @param type          Optional variable to store the file type. FileType_* constants
 *
 * @return              1 on success, 0 if there are no more files to read.
 */
native next_file(dirh, buffer[], length, &FileType:type = FileType_Unknown);

Others

There are as well some minor additions or changes:

  • Added a new define PLATFORM_MAX_PATH to represent a maximum path length.
/**
 * Maximum path length.
 */
#define PLATFORM_MAX_PATH  256
  • Added any: tag to some natives.
  • read_dir: outlen parameter is now optional.
  • read_file: txtlen parameter is now optional. Adjusted as well buffer to 2048 to match buffer size in write_file.
  • file_size: Fixed potential issue with old compiled plugin which doesn't have the flag parameter. Added FSOPT_* constants as well for use with this flag parameter.
/**
 * Options for use with file_size() flag parameter.
 */
#define FSOPT_BYTES_COUNT  0  /* Returns the file size in number of bytes */
#define FSOPT_LINES_COUNT  1  /* Returns how many lines there are in this file */
#define FSOPT_END_WITH_LF  2  /* Returns whether the last line is '\n' */


General

Constant

  • DMG_GRENADE (Counter-Strike only)
  • Three missing SVC_ messages (PR 223)
    • SVC_RESOURCELOCATION
    • SVC_SENDCVARVALUE
    • SVC_SENDCVARVALUE2
  • Client statistics:
    • STATSX_KILLS
    • STATSX_DEATHS
    • STATSX_HEADSHOTS
    • STATSX_TEAMKILLS
    • STATSX_SHOTS
    • STATSX_HITS
    • STATSX_DAMAGE
    • STATSX_RANK
    • STATSX_MAX_STATS
  • Objective based statistics for CS only:
    • STATSX_TOTAL_DEFUSIONS
    • STATSX_BOMBS_DEFUSED
    • STATSX_BOMBS_PLANTED
    • STATSX_BOMB_EXPLOSIONS
    • STATSX_MAX_OBJECTIVE
  • Client statistics for DoD only:
    • DODX_KILLS
    • DODX_DEATHS
    • DODX_HEADSHOTS
    • DODX_TEAMKILLS
    • DODX_SHOTS
    • DODX_HITS
    • DODX_DAMAGE
    • DODX_POINTS
    • DODX_RANK
    • DODX_MAX_STATS

Forward

  • Added FP_VAL_BYREF to pass values by reference in forwards.
  • ExecuteForward can now be called without the need to create variable for returned value.

Others

Native Description
has_map_ent_class  Returns if a map contains at least one entity with the provided class name.
/**
 * Returns if a map contains at least one entity with the provided class name.
 *
 * @param classname     Entity classname to match
 *
 * @return              True if an entity is found, false otherwise
 */
native bool:has_map_ent_class(const classname[]);
engine_changelevel  Changes the map.
Note:This has the same behavior as using the "changelevel" server command, but will also trigger the server_changelevel forward in AMXX plugins.
It will also notify any Metamod plugins that are hooking the pfnChangeLevel function.
/**
 * Changes the map.
 *
 * @note  This calls the pfnChangelLevel engine function.
 * @note  This has the same behavior as using the "changelevel" server command,
 *        but will also trigger the server_changelevel() forward in AMXX
 *        plugins. It will also notify any Metamod plugins that are hooking
 *        the pfnChangeLevel function.
 *
 * @param map   Map name to change to
 *
 * @noreturn
 */
native engine_changelevel(const map[]);
RequestFrame  Creates a single use hook for the next frame.
/**
 * Creates a single use hook for the next frame.
 *
 * @param callback      Function to be executed on the next frame.
 * @param data          Optional data to be passed to the callback function.
 *
 * @note                Callback function prototype:
 *                          public function(data)
 *
 * @noreturn
 */
native RequestFrame(const callback[], any:data = 0);
Stock Description
set_task_ex  Calls a function after a specified time has elapsed.
Note:Similar to set_task but it allows you to use named constants for flags instead of letters.
/**
 * SetTaskFlags constants for set_task_ex()
 */
enum SetTaskFlags (<<= 1)
{
    SetTask_Once = 0,          // None; execute callback after the specified amount of time (Default)
    SetTask_RepeatTimes = 1,   // Repeat timer a set amount of times
    SetTask_Repeat,            // Loop indefinitely until timer is stopped
    SetTask_AfterMapStart,     // Time interval is treated as absolute time after map start
    SetTask_BeforeMapChange    // Time interval is treated as absolute time before map change
};
 
/**
 * Calls a function after a specified time has elapsed.
 *
 * @param time          Time interval to assign
 * @param function      Function to execute
 * @param id            Task id to assign
 * @param parameter     Data to pass through to callback
 * @param len           Size of data
 * @param flags         Optional flags (enum SetTaskFlags); valid flags are:
 *                        SetTask_Once - Execute callback once (Default)
 *                        SetTask_RepeatTimes - repeat timer a set amount of times
 *                        SetTask_Repeat - loop indefinitely until timer is stopped
 *                        SetTask_AfterMapStart - time interval is treated as absolute
 *                            time after map start
 *                        SetTask_BeforeMapChange - time interval is treated as absolute
 *                            time before map change
 * @param repeat        If the SetTask_RepeatTimes flag is set, the task will be repeated this
 *                      many times
 *
 * @noreturn
 * @error               If an invalid callback function is provided, an error is
 *                      thrown.
 */
stock set_task_ex(Float:time, const function[], id = 0, const any:parameter[] = "", len = 0, SetTaskFlags:flags = SetTask_Once, repeat = 0)
{
    new strFlags[2]; // There should never be a need to set more than 1 flag
    get_flags(_:flags, strFlags, charsmax(strFlags));
    set_task(time, function, id, parameter, len, strFlags, repeat);
}

XS

Stock Description
xs_vec_len_2d  Computes the length of a 2D vector.
/**
 * Computes the length of a 2D vector.
 *
 * @param vec           The vector to compute the length of.
 *
 * @return              The length of the input vector.
 */
stock Float:xs_vec_len_2d(const Float:vec[])
{
    return xs_sqrt(vec[0]*vec[0] + vec[1]*vec[1]);
}
xs_vec_distance  Computes the distance between two vectors (points).
/**
 * Computes the distance between two vectors (points).
 *
 * @param vec1          First vector.
 * @param vec2          Second vector.
 *
 * @return              The distance between two vectors.
 */
stock Float:xs_vec_distance(const Float:vec1[], const Float:vec2[])
{
    return xs_sqrt((vec1[0]-vec2[0]) * (vec1[0]-vec2[0]) +
                   (vec1[1]-vec2[1]) * (vec1[1]-vec2[1]) +
                   (vec1[2]-vec2[2]) * (vec1[2]-vec2[2]));
}
xs_vec_distance_2d  Computes the distance between two 2D vectors (points).
/**
 * Computes the distance between two 2D vectors (points).
 * 
 * @param vec1          First vector.
 * @param vec2          Second vector.
 * 
 * @return              The distance between two vectors.
 */
stock Float:xs_vec_distance_2d(const Float:vec1[], const Float:vec2[])
{
    return xs_sqrt((vec1[0]-vec2[0]) * (vec1[0]-vec2[0]) +
                   (vec1[1]-vec2[1]) * (vec1[1]-vec2[1]));
}
xs_vec_add_scaled  Adds the second vector scaled by a scalar to the first.
/**
 * Adds the second vector scaled by a scalar to the first.
 *
 * @param in1           Vector to add to.
 * @param in2           Vector to scale and add.
 * @param scalar        Scalar to scale the second vector with.
 * @param out           The output vector. Can be one of the input vectors.
 *
 * @noreturn
 */
stock xs_vec_add_scaled(const Float:in1[], const Float:in2[], Float:scalar, Float:out[])
{
    out[0] = in1[0] + in2[0] * scalar;
    out[1] = in1[1] + in2[1] * scalar;
    out[2] = in1[2] + in2[2] * scalar;
}
xs_vec_sub_scaled  Subtracts the second vector scaled by a scalar from the first one.
/**
 * Subtracts the second vector scaled by a scalar from the first one.
 *
 * @param in1           Vector to subtract from.
 * @param in2           Vector to scale and subtract.
 * @param scalar        Scalar to scale the second vector with.
 * @param out           The output vector. Can be one of the input vectors.
 *
 * @noreturn
 */
stock xs_vec_sub_scaled(const Float:in1[], const Float:in2[], Float:scalar, Float:out[])
{
    out[0] = in1[0] - in2[0] * scalar;
    out[1] = in1[1] - in2[1] * scalar;
    out[2] = in1[2] - in2[2] * scalar;
}

Menu

Timeout

Timeout is now added to newmenus, working similar to those of show_menu.

When a menu is acted upon after the specified timeout has run out it will pass a new MENU_TIMEOUT status code into the menu handler.
Actions are:

  • player disconnect
  • selecting an item,
  • cancelling/destroying the menu in the plugin,
  • sending a different menu or using get_user_menu on a player with an open menu.

Just like with the old menus timeouts are not actively polled, and MENU_TIMEOUT is not guaranteed to fire directly after the time has run out.
Also get_user_menu will detect timeouts and reset the menu flags, which is why it also has to trigger the callback.

Note:An example is available at PR 21.
Native parameter Description
menu_display time  If >=0 menu will timeout after this many seconds.
/**
 * Displays a menu to one client.  This should never be called from a handler 
 * when the item is less than 0 (i.e. calling this from a cancelled menu will 
 * result in an error).
 *
 * Starting with 1.8.3 this allows to specify a menu timeout similar to the 
 * show_menu native. If the menu exists on the client past the timeout *any* 
 * further action will send the MENU_TIMEOUT status code to the menu handler.
 * That includes actions which would otherwise send MENU_EXIT, such as the
 * client selecting an item or disconnecting and calling menu_cancel or 
 * menu_destroy on a live menu.
 *
 * @param id			Client index.
 * @param menu			Menu resource identifier.
 * @param page			Page to start from (starting from 0).
 * @param time			If >=0 menu will timeout after this many seconds
 * @noreturn
 * @error				Invalid menu resource or client index.
 */
native menu_display(id, menu, page=0, time=-1);

New native & stock

Native Description
menu_addblank2  Adds a blank line to a menu, always shifting the numbering down.
Note:This fixes an unexpected behavior with the original ones when slot param is set to 1
/**
 * Adds a blank line to a menu, always shifting the numbering down.
 * 
 * This will add a special item to create a blank line. It will affect the menu
 * item count and pagination. These items can be modified later but will ignore 
 * access and item callback results.
 * 
 * Only available in 1.8.3 and above.
 * 
 * @param menu          Menu resource identifier.
 * 
 * @return              1 on success, 0 on failure.
 * @error               Invalid menu resource.
 *                      Too many items on non-paginated menu (max is 10)
 */
native menu_addblank2( menu );
Stock Description
reset_menu  Resets the client's menu.
/**
 * Resets the client's menu.
 *
 * @note This is a wrapper around show_menu() for the sake of readability.
 *
 * @param index     Client to reset menu of, 0 to reset all clients
 *
 * @noreturn
 */
stock reset_menu(index)
{
    show_menu(index, 0, "", 0);
}

New properties

Property Description
MEXIT_FORCE Forces a proper exit button on unpaginated menus
MPROP_SHOWPAGE Whether to show the page number in menu title
MEXIT_FORCE Function to be called on Back and Next

Prototype of callback:

Called when parsing is halted.
 
@param id        Playeer's index
@param status    Either MENU_BACK or MENU_MORE
 
public function(id, status);
Note:An example is available in the testsuite directory, see menu_page_callback_test.sma.

Others

  • menu_item_getinfo's arguments are now optional
  • show_menu] native is allowed to send empty text


Message

New natives

The float version of message_begin, write_angle, write_coord_f, emessage_begin, ewrite_coord and ewrite_angle:

Native Description
message_begin_f
write_angle_f
write_coord_f
 Marks the beginning of a client message.
/**
 * Marks the beginning of a client message.
 *
 * @note You may generate menus, smoke, shockwaves, thunderlights,
 *       intermission and many other messages.
 * @note For a list of HL game events, visit https://wiki.alliedmods.net/Half-Life_1_Game_Events
 * @note For a list of HL engine messages, visit https://wiki.alliedmods.net/Half-Life_1_Engine_Messages
 * @note You may also refer to the messages_const.inc file for examples.
 * @note This function is the same as message_begin(), but the origin
 *       argument accepts only float values in this one.
 * @note Each message starts with a message_begin() or message_begin_f() function
 *       and ends with message_end(). The specific message arguments go in between
 *       these two by using the write_*() functions found in messages.inc.
 *
 * @param dest        Destination type (see MSG_* constants in messages_const.inc)
 * @param msg_type    Message id
 * @param origin      Message origin
 * @param player      Client index receiving the message or 0 for all clients
 *
 * @noreturn
 * @error             If an invalid message id is specified or an invalid number
 *                    of parameters is passed, an error will be thrown.
 */
native message_begin_f(dest, msg_type, const Float:origin[3] = {0.0,0.0,0.0}, player = 0);
 Writes an angle entry to a message using a float value.
/**
 * Writes an angle entry to a message using a float value.
 *
 * @note This function should only be used in between a message_begin()
 *       or message_begin_f() and a message_end() function. Trying to use
 *       it outside of these functions will crash the server immediately.
 *
 * @param x           Angle to write
 *
 * @noreturn
 */
native write_angle_f(Float:x);
 Writes a coordinate entry to a message using a float value.
/**
 * Writes a coordinate entry to a message using a float value.
 *
 * @note This function should only be used in between a message_begin()
 *       or message_begin_f() and a message_end() function. Trying to use
 *       it outside of these functions will crash the server immediately.
 *
 * @param x           Coordinate to write
 *
 * @noreturn
 */
native write_coord_f(Float:x);
zmessage_begin_f
ewrite_coord_f
ewrite_angle_f
 Marks the beginning of a client message.
/**
* Marks the beginning of a client message.
*
* @note You may generate menus, smoke, shockwaves, thunderlights,
*       intermission and many other messages.
* @note For a list of HL game events, visit https://wiki.alliedmods.net/Half-Life_1_Game_Events
* @note For a list of HL engine messages, visit https://wiki.alliedmods.net/Half-Life_1_Engine_Messages
* @note You may also refer to the messages_const.inc file for examples.
* @note This function is the same as message_begin_f(), except that the messages
*       sent with this one are also sent to all other AMXX and Metamod plugins.
*       This means that if you send one of these messages, other plugins will
*       be notified of that message, which was previously impossible.
* @note BE CAREFUL! Using this incorrectly, or not for its intended purpose,
*       could cause infinite recursion or something just as bad!
* @note This function is the same as emessage_begin(), but the origin
*       argument accepts only float values in this one.
* @note Each message starts with a emessage_begin() or emessage_begin_f() function
*       and ends with emessage_end(). The specific message arguments go in between
*       these two by using the ewrite_*() functions found in messages.inc.
*
* @param dest        Destination type (see MSG_* constants in messages_const.inc)
* @param msg_type    Message id
* @param origin      Message origin
* @param player      Client index receiving the message or 0 for all clients
*
* @noreturn
* @error             If an invalid message id is specified or an invalid number
*                    of parameters is passed, an error will be thrown.
*/

native emessage_begin_f(dest, msg_type, const Float:origin[3] = {0.0,0.0,0.0}, player = 0);

</pawn>
 Writes a coordinate entry to a message using a float value.
/**
 * Writes a coordinate entry to a message using a float value.
 *
 * @note This function should only be used in between a emessage_begin()
 *       or emessage_begin_f() and a emessage_end() function. Trying to use
 *       it outside of these functions will crash the server immediately.
 *
 * @param x           Coordinate to write
 *
 * @noreturn
 */
native ewrite_coord_f(Float:x);
 Writes an angle entry to a message using a float value.
/**
 * Writes an angle entry to a message using a float value.
 *
 * @note This function should only be used in between a emessage_begin()
 *       or emessage_begin_f() and a emessage_end() function. Trying to use
 *       it outside of these functions will crash the server immediately.
 *
 * @param x           Angle to write
 *
 * @noreturn
 */
native ewrite_angle_f(Float:x);
Native Description
client_print_color  Sends colored chat messages to clients.
Note:Counter-strike only.
/**
 * Sends colored chat messages to clients.
 *
 * @note This only works in Counter-Strike 1.6 and Condition Zero.
 * @note The colors can be modified inside of the format string using special
 *       characters. These characters can be included using the escape character
 *          green           x04   ; use location color from this point forward
 *          red/blue/grey   x03   ; use team color from this point forward
 *          red/blue/grey   x02   ; use team color to the end of the client name
 *                                ; This only works at the start of the string,
 *                                ; and precludes using other control characters
 *          default         x01   ; use default color from this point forward
 * @note The team color is defined by the sender's index. Alternatively, a
 *       specific team color can be enforced using the print_team_* constants in
 *       amxconst.inc
 * @note Usage examples:
 *       client_print_color(id, print_team_red, "^4Green ^3Red ^1Default")
 *       client_print_color(id, id2, "^4Green ^3id2's team color, ^1Default")
 * @note Including colors in ML can be done using the same escaping method:
 *       EXAMPLE_ML_KEY = ^4Green ^3Team color ^1Default
 * @note This functions return value behaves differently depending on what is
 *       used as the client index: If 0 is specified, then the function will
 *       return 0 if nothing has been sent (no client connected). If either a
 *       single client is specified, or there is at least one client connected,
 *       the number of printed characters will refer to the message that is sent
 *       last, to the client with the highest index.
 *
 * @param index     Client index, use 0 to display to all clients
 * @param sender    Client index used as the message sender
 * @param fmt       Formatting rules
 * @param ...       Variable number of formatting parameters
 *
 * @return          Number of printed characters
 * @error           If a single client is specified and the index is not within
 *                  the range of 1 to MaxClients, an error will be thrown.
 */
native client_print_color(index, sender, const message[], any:...);
set_dhudmessage
show_dhudmessage
 Sets display parameters for director hudmessages.
/**
 * Sets display parameters for director hudmessages.
 *
 * @note For the hudmessage coordinates x and y, -1.0 will center the message
 *       on the respective axis.
 * @note These parameters stay until the next call to set_dhudmessage overwrites
 *       them. Multiple calls to show_dhudmessage will therefore re-use the same
 *       parameters. The parameters are not stored per-plugin, so other plugins
 *       can overwrite them.
 *
 * @param red           Red component of hudmessage color
 * @param green         Green component of hudmessage color
 * @param blue          Blue component of hudmessage color
 * @param x             Location of the message on the x axis in percent
 * @param y             Location of the message on the y axis in percent
 * @param effects       Display effect
 * @param fxtime        Duration of the effect
 * @param holdtime      Time the message stays on screen
 * @param fadeintime    Time it takes the message to fully appear (fade-in)
 * @param fadeouttime   Time it takes the message to fully disappear (fade-out)
 *
 * @noreturn
 */
native set_dhudmessage(red = 200, green = 100, blue = 0, Float:x = -1.0, Float:y = 0.35, effects = 0, Float:fxtime = 6.0, Float:holdtime = 12.0, Float:fadeintime = 0.1, Float:fadeouttime = 0.2);
 Displays a director message on the client HUD.
/**
 * Displays a director message on the client HUD.
 *
 * @note Use set_dhudmessage to define how the message should look on screen.
 * @note Unlike the classic HUD message, which is channel-based, director
 *       messages are stack-based. You can have up to 8 messages displaying at
 *       once. If more are added, they will be overwritten in the order they were
 *       sent. There is no way to clear a specific message.
 * @note The message has a maximum length of 128 characters which this function
 *       will automatically enforce.
 * @note This functions return value behaves differently depending on what is
 *       used as the client index: If 0 is specified, then the function will
 *       return 0 if nothing has been sent (no client connected). If either a
 *       single client is specified, or there is at least one client connected,
 *       the number of printed characters will refer to the message that is sent
 *       last, to the client with the highest index.
 *
 * @param index     Client index, use 0 to display to all clients
 * @param message   Formatting rules
 * @param ...       Variable number of formatting parameters
 *
 * @return          Number of printed characters
 * @error           If a single client is specified and the index is not within
 *                  the range of 1 to MaxClients, an error will be thrown.
 */
native show_dhudmessage(index, const message[], any:...);
elog_message  Logs a message hookable by plugins to the current server log file.
/**
 * Logs a message hookable by plugins to the current server log file.
 *
 * @note The log will include a timestamp with the message.
 * @note The message can be hooked using "register_logevent".
 *
 * @param string    Formatting rules
 * @param ...       Variable number of formatting parameters
 *
 * @return          Number of printed characters
 */
native elog_message(const message[], any:...);
Stock Description
client_printex  Sends a predefined text message to player.
/**
 * Sends a predefined text message to player.
 * Predefined texts are default game messages which will be translated
 * to player's game language, e.g. #Game_join_ct.
 *
 * @note Set index to 0 to send text globally.
 *
 * @note There does not necessarily have to be a total of 6 arguments.
 *       It will depend if message takes arguments, e.g.:
 *         client_printex(id, print_chat, "#Game_join_ct", "Pimp Daddy")
 *         client_printex(id, print_chat, "1", "#Game_radio", "Pimp Daddy", "Hello world!")
 *
 * @param index         Index of the player, use 0 to send to all players.
 * @param type          The message destination. See print_* constants.
 * @param msg_name      The custom or predefined message to send.
 * @param msg_param1    Optional message argument.
 * @param msg_param2    Optional message argument.
 * @param msg_param3    Optional message argument.
 * @param msg_param4    Optional message argument.
 *
 * @noreturn
 */
stock client_printex(index, type, const msg_name[], const msg_param1[] = "", const msg_param2[] = "", const msg_param3[] = "", const msg_param4[] = "")
{
    new ch = msg_name[0];
 
    // If not a predefined message, we don't care about it and forward directly to client_print.
    // Special case for radio message. msg_name is an index, msg_param1 #Game_radio*, etc. Checking index should be enough.
    if (ch != '#' && (type != print_radio || !strtol(msg_name)))
    {
        return client_print(index, type, msg_name, msg_param1, msg_param2, msg_param3, msg_param4);
    }
 
    // Even if message starts with '#', we should check its length for safety.
    new length = strlen(msg_name);
 
    // If string is larger than expected, we forward to client_print which will cut message properly.
    // This means also this can't be a predefined game message.
    //   Max console length: 128 = \n (126) + \0 (127)
    //   Max SayText length: 192 = \n (190) + \0 (191)
    if ((length > 126 && (print_notify <= type <= print_console)) 
    || ( length > 190 && (print_chat   <= type <= print_radio)))
    {
        return client_print(index, type, msg_name, msg_param1, msg_param2, msg_param3, msg_param4);
    }
 
    static msgTextMsg; 
    if (!msgTextMsg) 
    { 
        msgTextMsg = get_user_msgid("TextMsg"); 
    }
 
    message_begin(index > 0 ? MSG_ONE_UNRELIABLE : MSG_BROADCAST, msgTextMsg, {0,0,0}, index);
    write_byte(type);
    write_string(msg_name);
    if (msg_param1[0]) { write_string(msg_param1); }
    if (msg_param2[0]) { write_string(msg_param2); }
    if (msg_param3[0]) { write_string(msg_param3); }
    if (msg_param4[0]) { write_string(msg_param4); }
    message_end();
 
    return 1;
}

Others

  • Added MSG_INIT support in message_begin native
  • Set set_hudmessage default channel to -1 to reflect auto-channeling support

String

  • Constants and stocks from string.inc have been moved in their own files string_const.inc and string_stocks.inc.
  • strlen has been moved from core.inc to string.inc.
  • strbreak is now replaced by a backwards compatibility stock.

Conversion

Native Description
strtol  Parses the string interpreting its content as an integral number of the specified base, which is returned as integer value.
The function also sets the value of endPos to point to the position of the first character after the number.
/**
 * Parses the 'string' interpreting its content as an integral number of the specified 'base', 
 * which is returned as integer value. The function also sets the value of 'endPos' to point 
 * to the position of the first character after the number.
 * 
 * This is the same as C++ strtol function with a difference on second param.
 * 
 * The function first discards as many whitespace characters as necessary until the first 
 * non-whitespace character is found. Then, starting from this character, takes as many 
 * characters as possible that are valid following a syntax that depends on the 'base' parameter,
 * and interprets them as a numerical value. Finally, a position of the first character following
 * the integer representation in 'string' is stored in 'endPos'.
 * 
 * If the value of 'base' is zero, the syntax expected is similar to that of integer constants, 
 * which is formed by a succession of :
 *    An optional sign character (+ or -)
 *    An optional prefix indicating octal or hexadecimal base ("0" or "0x"/"0X" respectively)
 *    A sequence of decimal digits (if no base prefix was specified) or either octal or hexadecimal digits if a specific prefix is present
 *
 * If the 'base' value is between 2 and 36, the format expected for the integral number is a succession 
 * of any of the valid digits and/or letters needed to represent integers of the specified radix 
 * (starting from '0' and up to 'z'/'Z' for radix 36). The sequence may optionally be preceded by 
 * a sign (either + or -) and, if base is 16, an optional "0x" or "0X" prefix.
 *
 * If the first sequence of non-whitespace characters in 'string' is not a valid integral number
 * as defined above, or if no such sequence exists because either 'string' is empty or it contains
 * only whitespace characters, no conversion is performed.
 *
 * @param string    The string to parse.
 * @param endPos    The position of the first character following the number.
 *                  On success and when containing only numbers, position is at the end of string, meaning equal to 'string' length.
 *                  On failure, position is sets always to 0.
 * @param base      The numerical base (radix) that determines the valid characters and their interpretation.
 *                  If this is 0, the base used is determined by the format in the sequence.
 * @return          On success, the function returns the converted integral number as integer value.
 *                  If no valid conversion could be performed, a zero value is returned.
 *                  If the value read is out of the range of representable values by a cell, 
 *                  the function returns 'cellmin' or 'cellmax'.
 */
native strtol(const string[], &endPos = 0, base = 0);
strtof  Parses the string interpreting its content as an floating point number and returns its value as a float.
The function also sets the value of endPos to point to the position of the first character after the number.
/**
 * Parses the 'string' interpreting its content as an floating point number and returns its value as a float.
 * The function also sets the value of 'endPos' to point to the position of the first character after the number.
 * 
 * This is the same as C++ strtod function with a difference on second param.
 * 
 * The function first discards as many whitespace characters as necessary until the first 
 * non-whitespace character is found. Then, starting from this character, takes as many 
 * characters as possible that are valid and interprets them as a numerical value. 
 * Finally, a position of the first character following the float representation in 'string' 
 * is stored in 'endPos'.
 * 
 * If the first sequence of non-whitespace characters in 'string' is not a valid float number
 * as defined above, or if no such sequence exists because either 'string' is empty or it contains
 * only whitespace characters, no conversion is performed.
 *
 * @param string    The string to parse.
 * @param endPos    The position of the first character following the number.
 *                  On success and when containing only numbers, position is at the end of string, meaning equal to 'string' length.
 *                  On failure, position is sets always to 0.
 * @return          On success, the function returns the converted floating point number as float value.
 *                  If no valid conversion could be performed, a zero value is returned.
 */
native Float:strtof(const string[], &endPos = 0);

Format specifier

Specifier Description
%b Binary digits in the value
%n Requires a client index. Expands to a string containing the player's name.
If the client index is 0, the string will be: Console
%N Requires a client index. Expands to 1<2><3><4> where 1 is the player's name, 2 is the player's userid, 3 is the player's SteamID, and 4 the player's team name.
If the client index is 0, the string will be: Console<0><Console><Console>
%l Translates a phrase from a key. Similar to %L with the difference it will use the client's index set internally by the function.
This is only allowed in functions which act directly on one or more clients.
Note:To complement this, a new SetGlobalTransTarget native to set the current index has been added.
This is useful to be used before with natives which are not player-oriented", like a bunch of formatex.
/**
 * Sets the global language target.
 *
 * @note This is useful for creating functions
 *       that will be compatible with the %l format specifier. Note that invalid
 *       indexes can be specified but the error will occur during translation,
 *       not during this function call.
 *
 * @param client    Client index or LANG_SERVER
 * @noreturn
 */
native SetGlobalTransTarget(client);
Example:
client_print(index, print_chat, "%L", index, "EGG");

can be now

client_print(index, print_chat, "%l", "EGG");

Formatting

  • set_fail_state has now the ability to format a text.
  • A new native for simple inline formatting:
Native Description
fmt  Formats and returns a string according to the AMX Mod X format rules.
Note:This should only be used for simple inline formatting like in the above example.
Avoid using this function to store strings into variables as an additional copying step is required.
Note:The buffer size is defined by MAX_FMT_LENGTH.
Example:
menu_additem(menu, fmt("My first %s", "item"))
/**
* Formats and returns a string according to the AMX Mod X format rules
* (see documentation).
*
* @note Example: menu_additem(menu, fmt("My first %s", "item")).
* @note This should only be used for simple inline formatting like in the above example.
*       Avoid using this function to store strings into variables as an additional
*       copying step is required.
* @note The buffer size is defined by MAX_FMT_LENGTH.
*
* @param format        Formatting rules.
* @param ...           Variable number of format parameters.
*
* @return              Formatted string
*/
native [MAX_FMT_LENGTH]fmt(const format[], any:...);

Others

Native Description
strtok2  Breaks a string in two by token.
Note:This function has been added due to strtok being buggy in some situations.
Trim flags:
/**
 * Below are the trim flags for strtok2
 *
 * You can specify how the left and right buffers will
 * be trimmed by strtok2. LTRIM trims spaces from the
 * left side. RTRIM trims from the right side.
 *
 * The defines TRIM_INNER, TRIM_OUTER and TRIM_FULL are
 * shorthands for commonly used flag combinations.
 *
 * When the initial string is trimmed, using TRIM_INNER
 * for all subsequent strtok2 calls will ensure that left
 * and right are always trimmed from both sides.
 *
 * Examples:
 * str1[] = "  This is  *  some text  "
 * strtok2(str1, left, 24, right, 24, '*', TRIM_FULL)
 *  left will be "This is", right will be "some text"
 *
 * str2[] = "  Here is  |  an  | example  "
 * trim(str2)
 * strtok2(str2, left, 24, right, 24, '|', TRIM_INNER)
 *  left will be "Here is", right will be "an  | example"
 * strtok2(right, left, 24, right, 24, '|', TRIM_INNER)
 *  left will be "an", right will be "example"
 *
 * str3[] = "  One  -  more  "
 * strtok2(str3, left, 24, right, 24, '-', TRIM_OUTER)
 *  left will be "One  ", right will be "  more"
 *
 * str4[] = "  Final  .  example  "
 * strtok2(str4, left, 24, right, 24, '.', LTRIM_LEFT|LTRIM_RIGHT)
 *  left will be "Final  ", right will be "example  "
*/
#define LTRIM_LEFT (1<<0)
#define RTRIM_LEFT (1<<1)
#define LTRIM_RIGHT (1<<2)
#define RTRIM_RIGHT (1<<3)
 
#define TRIM_INNER RTRIM_LEFT|LTRIM_RIGHT
#define TRIM_OUTER LTRIM_LEFT|RTRIM_RIGHT
#define TRIM_FULL TRIM_OUTER|TRIM_INNER
/**
 * Breaks a string in two by token.
 *
 * @note Only available in 1.8.3 and above.
 *
 * @param text			String to tokenize
 * @param left			Buffer to store left half
 * @param llen			Size of left buffer
 * @param right			Buffer to store right half
 * @param rlen			Size of right buffer
 * @param token			Token to split by
 * @param trim			Flags for trimming behavior, see above
 *
 * @return				Returns position of token in string if found, 
 *						-1 if token was not found
 */
native strtok2(const text[], left[], const llen, right[], const rlen, const token = ' ', const trim = 0);
Stock Description
explode_string  Breaks a string into pieces and stores each piece into an array of buffers.
/**
 * Breaks a string into pieces and stores each piece into an array of buffers.
 *
 * @param text              The string to split.
 * @param split             The string to use as a split delimiter.
 * @param buffers           An array of string buffers (2D array).
 * @param maxStrings        Number of string buffers (first dimension size).
 * @param maxStringLength   Maximum length of each string buffer.
 * @param copyRemainder     False (default) discard excess pieces, true to ignore
 *                          delimiters after last piece.
 * @return                  Number of strings retrieved.
 */
stock explode_string(const text[], const split[], buffers[][], maxStrings, maxStringLength, bool:copyRemainder = false)
{
    new reloc_idx, idx, total;
 
    if (maxStrings < 1 || !split[0])
    {
        return 0;
    }
 
    while ((idx = split_string(text[reloc_idx], split, buffers[total], maxStringLength)) != -1)
    {
        reloc_idx += idx;
        if (++total == maxStrings)
        {
            if (copyRemainder)
            {
                copy(buffers[total-1], maxStringLength, text[reloc_idx-idx]);
            }
            return total;
        }
    }
 
    copy(buffers[total++], maxStringLength, text[reloc_idx]);
 
    return total;
}
implode_strings  Joins an array of strings into one string, with a join string inserted in between each given string.
This function complements explode_string.
/**
 * Joins an array of strings into one string, with a "join" string inserted in
 * between each given string.  This function complements ExplodeString.
 *
 * @param strings       An array of strings.
 * @param numStrings    Number of strings in the array.
 * @param join          The join string to insert between each string.
 * @param buffer        Output buffer to write the joined string to.
 * @param maxLength     Maximum length of the output buffer.
 * @return              Number of bytes written to the output buffer.
 */
stock implode_strings(const strings[][], numStrings, const join[], buffer[], maxLength)
{
    new total, length, part_length;
    new join_length = strlen(join);
 
    for (new i=0; i<numStrings; i++)
    {
        length = copy(buffer[total], maxLength-total, strings[i]);
        total += length;
 
        if (length < part_length)
        {
            break;
        }
 
        if (i != numStrings - 1)
        {
            length = copy(buffer[total], maxLength-total, join);
            total += length;
 
            if (length < join_length)
            {
                break;
            }
        }
    }
 
    return total;
}

UTF-8

An effort has been made to provide UTF-8 safety for formatting-capable functions. This includes precision with %s e.g. %.12s.

Few specific functions have been updated as well:

  • console_print
  • client_print, client_print_color
  • get_user_name
  • get_concmd, get_clcmd, get_srvcmd
  • get_cvar_string, get_pcvar_string
  • format_time
  • read_data
  • get_localinfo
  • read_argv, read_args
  • read_logdata, read_logargv
  • get_module
  • read_file
  • fgets
  • ReadPackString
  • ArrayGetString
  • TrieGetString
  • strtok, strtok2
  • strbreak
  • isdigit, isalnum, isspace, isalpha

UTF-8 support has been added in the following functions:

  • containi
  • strfind (with ignorecase set)
  • strcmp (with ignorecase set)
  • strncmp (with ignorecase set)
  • equali
  • replace_string (with ignorecase set)
  • replace_stringex (with ignorecase set)
  • get_players (with name and ignorecase flags set)
  • find_player (with name and ignorecase flags set)

New natives have been added:

Native Description
is_char_upper
is_char_lower
is_char_mb
 Returns whether an alphabetic character is uppercase.
/**
 * Returns whether an alphabetic character is uppercase.
 *
 * @note Only available in 1.8.3 and above.
 * @note Multi-byte characters will always return false.
 *
 * @param ch			Character to test.
 * @return				True if character is uppercase, otherwise false.
 */
native bool:is_char_upper(ch);
 Returns whether an alphabetic character is lowercase.
/**
 * Returns whether an alphabetic character is lowercase.
 *
 * @note Only available in 1.8.3 and above.
 * @note Multi-byte characters will always return false.
 *
 * @param ch			Character to test.
 * @return				True if character is lowercase, otherwise false.
 */
native bool:is_char_lower(ch);
 Returns if a character is multi-byte or not.
/**
 * Returns if a character is multi-byte or not.
 *
 * @note Only available in 1.8.3 and above.
 *
 * @param ch			Character to test.
 * @return				0 for a normal 7-bit ASCII character,
 *						otherwise number of bytes in multi-byte character.
 */
native is_char_mb(ch);
is_string_category  Checks if the input string conforms to the category specified by the flags.
/**
 * Checks if the input string conforms to the category specified by the flags.
 *
 * @note This function can be used to check if the code points in a string are part
 *       of a category. Valid flags are part of the UTF8C_* list of defines.
 *       The category for a code point is defined as part of the entry in
 *       UnicodeData.txt, the data file for the Unicode code point database.
 * @note Flags parameter must be a combination of UTF8C_* flags or a single UTF8C_IS* flag.
 *       In order to main backwards compatibility with POSIX functions like `isdigit`
 *       and `isspace`, compatibility flags have been provided. Note, however, that
 *       the result is only guaranteed to be correct for code points in the Basic
 *       Latin range, between U+0000 and 0+007F. Combining a compatibility flag with
 *       a regular category flag will result in undefined behavior.
 * @note The function is greedy. This means it will try to match as many code
 *       points with the matching category flags as possible and return the offset in
 *       the input in bytes.
 *
 * @param input         The string to check
 * @param input_size    Size of the string, use 1 to check one character regardless its size
 * @param flags         Requested category, see UTF8C_* flags
 * @param output_size   Number of bytes in the input that conform to the specified
 *                      category flags
 * @return              True if the whole input of `input_size` conforms to the specified
 *                      category flags, false otherwise
 */
native bool:is_string_category(const input[], input_size, flags, &output_size = 0);
get_char_bytes  Returns the number of bytes a character is using.
/** 
 * Returns the number of bytes a character is using.  This is
 * for multi-byte characters (UTF-8).  For normal ASCII characters,
 * this will return 1.
 *
 * @note Only available in 1.8.3 and above.
 *
 * @param source		Source input string.
 * @return				Number of bytes the current character uses.
 */
native get_char_bytes(const source[]);
mb_strotolower
mb_strtoupper
mb_ucfirst
mb_strtotitle
 Performs a multi-byte safe (UTF-8) conversion of all chars in string to lower case.
/**
 * Performs a multi-byte safe (UTF-8) conversion of all chars in string to lower case.
 *
 * @note Although most code points can be converted in-place, there are notable
 *       exceptions and the final length can vary.
 * @note Case mapping is not reversible. That is, toUpper(toLower(x)) != toLower(toUpper(x)).
 *
 * @param string		The string to convert.
 * @param maxlength		Optional size of the buffer. If 0, the length of the original string
 *                      will be used instead.
 *
 * @return				Number of bytes written.
 */
native mb_strtolower(string[], maxlength = 0);
 Performs a multi-byte safe (UTF-8) conversion of all chars in string to upper case.
/**
 * Performs a multi-byte safe (UTF-8) conversion of all chars in string to upper case.
 *
 * @note Although most code points can be converted in-place, there are notable
 *       exceptions and the final length can vary.
 * @note Case mapping is not reversible. That is, toUpper(toLower(x)) != toLower(toUpper(x)).
 *
 * @param string		The string to convert.
 * @param maxlength		Optional size of the buffer. If 0, the length of the original string
 *                      will be used instead.
 *
 * @return				Number of bytes written.
 */
native mb_strtoupper(string[], maxlength = 0);
 Performs a multi-byte safe (UTF-8) conversion of a string's first character to upper case.
/**
 * Performs a multi-byte safe (UTF-8) conversion of a string's first character to upper case.
 *
 * @note Although most code points can be converted in-place, there are notable
 *       exceptions and the final length can vary.
 *
 * @param string		The string to convert.
 * @param maxlength		Optional size of the buffer. If 0, the length of the original string
 *                      will be used instead.
 *
 * @return				Number of bytes written.
 */
native mb_ucfirst(string[], maxlength = 0);
 Performs a multi-byte safe (UTF-8) conversion of all chars in string to title case.
/**
 * Performs a multi-byte safe (UTF-8) conversion of all chars in string to title case.
 *
 * @note Although most code points can be converted in-place, there are notable
 *       exceptions and the final length can vary.
 * @note Any type of punctuation can break up a word, even if this is
 *       not grammatically valid. This happens because the titlecasing algorithm
 *       does not and cannot take grammar rules into account.
 * @note Examples:
 *         The running man                      | The Running Man
 *	       NATO Alliance                        | Nato Alliance
 *	       You're amazing at building libraries | You'Re Amazing At Building Libraries
 *
 * @param string		The string to convert.
 * @param maxlength		Optional size of the buffer. If 0, the length of the original string
 *                      will be used instead.
 *
 * @return				Number of bytes written.
 */
native mb_strtotitle(string[], maxlength = 0);
replace_string
replace_stringex
 Given a string, replaces all occurrences of a search string with a replacement string.
Note:Similar to replace_all stock, but implemented as native and with different algorithm.
This native doesn't error on bad buffer size and will smartly cut off the string in a way that pushes old data out.
/**
 * Given a string, replaces all occurrences of a search string with a 
 * replacement string.
 *
 * @note Similar to replace_all() stock, but implemented as native and 
 *       with different algorithm. This native doesn't error on bad 
 *       buffer size and will smartly cut off the string in a way 
 *       that pushes old data out.
 *	
 * @note Only available in 1.8.3 and above.
 * @note This supports multi-byte characters (UTF-8) on case insensitive comparison.
 *
 * @param text			String to perform search and replacements on.
 * @param maxlength		Maximum length of the string buffer.
 * @param search		String to search for.
 * @param replace		String to replace the search string with.
 * @param caseSensitive	If true (default), search is case sensitive.
 *
 * @return				Number of replacements that were performed.
 */
native replace_string(text[], maxlength, const search[], const replace[], bool:caseSensitive = true);

 Given a string, replaces the first occurrence of a search string with a replacement string.

Note:Similar to replace native, but implemented as native and with different algorithm.
This native doesn't error on bad buffer size and will smartly cut off the string in a way that pushes old data out.
/**
 * Given a string, replaces the first occurrence of a search string with a 
 * replacement string.
 *
 * @note Similar to replace() native, but implemented with more options and 
 *       with different algorithm. This native doesn't error on bad 
 *       buffer size and will smartly cut off the string in a way 
 *       that pushes old data out.
 *	
 * @note Only available in 1.8.3 and above.
 * @note This supports multi-byte characters (UTF-8) on case insensitive comparison.
 *
 * @param text			String to perform search and replacements on.
 * @param maxlength		Maximum length of the string buffer.
 * @param search		String to search for.
 * @param replace		String to replace the search string with.
 * @param searchLen		If higher than -1, its value will be used instead of
 *						a strlen() call on the search parameter.
 * @param replaceLen	If higher than -1, its value will be used instead of
 *						a strlen() call on the replace parameter.
 * @param caseSensitive	If true (default), search is case sensitive.
 *
 * @return				Index into the buffer (relative to the start) from where
 *						the last replacement ended, or -1 if no replacements were
 *						made.
 */
native replace_stringex(text[], maxlength, const search[], const replace[], searchLen = -1, replaceLen = -1, bool:caseSensitive = true);
strncmp  Compares two strings parts lexographically.
/**
 * Compares two strings parts lexographically.
 *
 * @note Only available in 1.8.3 and above.
 * @note This supports multi-byte characters (UTF-8) on case insensitive comparison.
 *
 * @param string1		First string (left).
 * @param string2		Second string (right).
 * @param num			Number of characters to compare.
 * @param ignorecase	If true, comparison is case insensitive.
 *						If false (default), comparison is case sensitive.
 * @return				-1 if string1 < string2
 *						0 if string1 == string2
 *						1 if string1 > string2
 */
native strncmp(const string1[], const string2[], num, bool:ignorecase = false);

New stocks:

Stock Description
char_to_upper  Returns an uppercase character to a lowercase character.
/**
 * Returns an uppercase character to a lowercase character.
 *
 * @note Only available in 1.8.3 and above.
 *
 * @param chr           Characer to convert.
 * @return              Lowercase character on success,
 *                      no change on failure.
 */
stock char_to_upper(chr)
{
    if (is_char_lower(chr))
    {
        return (chr & ~(1<<5));
    }
 
    return chr;
}
char_to_lower  Returns a lowercase character to an uppercase character.
/**
 * Returns a lowercase character to an uppercase character.
 *
 * @note Only available in 1.8.3 and above.
 *
 * @param chr           Characer to convert.
 * @return              Uppercase character on success,
 *                      no change on failure.
 */
stock char_to_lower(chr)
{
    if (is_char_upper(chr))
    {
        return (chr | (1<<5));
    }
 
    return chr;
}

Existing module APIs additions

AMXX SDK

the following functions have been added:

Function Description
MF_SetAmxStringUTF8Char Sets UTF-8 string from char* input
MF_SetAmxStringUTF8Cell Sets UTF-8 string from cell* input
MF_GetAmxStringNull Gets string with NULL_STRING support
MF_GetAmxVectorNull Gets a vector with NULL_VECTOR support
MF_GetConfigManager Gets the config manager for use with gamedata files
MF_LoadAmxScriptEx Saner version of MF_LoadAmxScript which explicits error max length

CStrike

All hardcoded game datas are now moved to its own gamedata file located in data/gamedata/modules.games/game.cstrike.txt.
See AMX_Mod_X_1.9_Release_Notes#Gamedata for more information.

Constant

Numerous constants from the game have added. See the cstrike_const.inc.

Additionally for two natives:

  • CS_NORESET constant for use with cs_set_user_team for skipping the model reset
  • TRAIN_* constants for use with cs_get_user_driving
/**
 * Train status values
 */
#define TRAIN_ACTIVE  0x80
#define TRAIN_NEW     0xc0
 
#define TRAIN_OFF     0x00
#define TRAIN_NEUTRAL 0x01
#define TRAIN_SLOW    0x02
#define TRAIN_MEDIUM  0x03
#define TRAIN_FAST    0x04
#define TRAIN_BACK    0x05


Entity

Native Description
cs_create_entity  Creates an entity using Counter-Strike's custom CreateNamedEntity wrapper.
Note:Unlike other mods CS keeps track of entities using a custom hashtable.

This function adds entities to this hashtable, providing benefits over the default CreateNamedEntity (used by create_entity for example):

  • Storing entities in a hashtable allows CS to improve classname lookup performance compared to functions like FindEntityByString (used by find_ent_by_class for example) that usually have to loop through all entities incrementally.
  • As CS exclusively uses the hashtable for classname lookup, entities created using the default engine functions will not be found by the game.
    For example "weaponbox" entities are supposed to be automatically cleaned up on round restart but are not considered if they have not been added to the hashtable.
/**
 * Creates an entity using Counter-Strike's custom CreateNamedEntity wrapper.
 *
 * @note Unlike other mods CS keeps track of entities using a custom hashtable.
 *       This function adds entities to this hashtable, providing benefits over
 *       the default CreateNamedEntity (used by create_entity() for example):
 *       - Storing entities in a hashtable allows CS to improve classname lookup
 *         performance compared to functions like FindEntityByString (used by
 *         find_ent_by_class() for example) that usually have to loop
 *         through all entities incrementally.
 *       - As CS exclusively uses the hashtable for classname lookup, entities
 *         created using the default engine functions will not be found by the
 *         game. For example "weaponbox" entities are supposed to be
 *         automatically cleaned up on round restart but are not considered if
 *         they have not been added to the hashtable.
 * @note The faster hashtable lookup can be utilized with cs_find_ent_by_class()
 * @note When creating an entity the classname has to be valid in the mod, as
 *       the engine needs to link the entity to an existing class internally.
 *       The classname string that is stored in the entvar struct
 *       (EV_SZ_classname) is separate from this association and can later be
 *       freely changed to serve other purposes.
 *
 * @param classname     Entity class name
 *
 * @return              Index of the created entity (> 0), 0 otherwise
 */
native cs_create_entity(const classname[]);
cs_find_ent_by_class
cs_find_ent_by_owner
 Finds an entity in the world using Counter-Strike's custom FindEntityByString wrapper.
/**
 * Finds an entity in the world using Counter-Strike's custom FindEntityByString
 * wrapper.
 *
 * @note Unlike other mods CS keeps track of entities using a custom hashtable.
 *       This function utilizes the hasthable and allows for considerably faster
 *       classname lookup compared to the default FindEntityByString (used by
 *       find_ent_by_class() for example).
 * @note This exclusively considers entities in the hashtable, created by the
 *       game itself, using cs_create_entity(), or added via cs_set_ent_class().
 *
 * @param start_index   Entity index to start searching from. -1 to start from
 *                      the first entity
 * @param classname     Classname to search for
 *
 * @return              Entity index > 0 if found, 0 otherwise
 */
native cs_find_ent_by_class(start_index, const classname[]);
 Finds an entity in the world using Counter-Strike's custom FindEntityByString wrapper, matching by owner.
/**
 * Finds an entity in the world using Counter-Strike's custom FindEntityByString
 * wrapper, matching by owner.
 *
 * @note Unlike other mods CS keeps track of entities using a custom hashtable.
 *       This function utilizes the hasthable and allows for considerably faster
 *       classname lookup compared to the default FindEntityByString (used by
 *       find_ent_by_owner() for example).
 * @note This exclusively considers entities in the hashtable, created by the
 *       game itself, using cs_create_entity(), or added via cs_set_ent_class().
 *
 * @param start_index   Entity index to start searching from. -1 to start from
 *                      the first entity
 * @param classname     Classname to search for
 * @param owner         Entity index to search for entity's owner
 *
 * @return              Entity index > 0 if found, 0 otherwise
 */
native cs_find_ent_by_owner(start_index, const classname[], owner);
Note:Those functions utilize the hasthable and allows for considerably faster classname lookup compared to the default FindEntityByString (used by find_ent_by_class for example).
This exclusively considers entities in the hashtable, created by the game itself, using cs_create_entity, or added via cs_set_ent_class).
cs_set_ent_class  Sets a custom classname of an entity.
Note:This function adds or updates the classname in the hasthable as well.
This is useful for use with cs_find_ent_by_class and cs_find_ent_by_owner.
/**
 * Sets a custom classname of an entity.
 *
 * @note Unlike other mods CS keeps track of entities using a custom hashtable.
 *       This function adds or updates the classname in the hasthable as well.
 *       This is useful for use with cs_find_ent_by_class() and cs_find_ent_by_owner().
 *
 * @param index         Entity index
 * @param classname     Classname to update for
 *
 * @noreturn
 */
native cs_set_ent_class(index, const classname[]);

Buying

You can now easily detect when an item is being purchased.

Forward Description
CS_OnBuyAttempt  Called when a client attempts to purchase an item.
Note:This is called immediately when the client issues a buy command.
The game has not yet checked if the client can actually buy the weapon.
/**
 * Called when a client attempts to purchase an item.
 *
 * @note This is called immediately when the client issues a buy command. The
 *       game has not yet checked if the client can actually buy the weapon.
 * @note For a list of possible item ids see the CSI_* constants.
 *
 * @param index     Client index
 * @param item      Item id
 *
 * @return          PLUGIN_CONTINUE to let the buy attempt continue
 *                  PLUGIN_HANDLED to block the buy attempt
 */
forward CS_OnBuyAttempt(index, item);
CS_OnBuy  Called when a client purchases an item.
Note:This is called right before the user receives the item and before the money is deducted from their cash reserves.
/**
 * Called when a client purchases an item.
 *
 * @note This is called right before the user receives the item and before the
 *       money is deducted from their cash reserves.
 * @note For a list of possible item ids see the CSI_* constants.
 *
 * @param index     Client index
 * @param item      Item id
 *
 * @return          PLUGIN_CONTINUE to let the buy continue
 *                  PLUGIN_HANDLED to block the buy
 */
forward CS_OnBuy(index, item);
Note:For a list of possible item ids see the CSI_* constants
/**
 * Constants used for the CS_OnBuy() and CS_OnBuyAttempt() forwards.
 *
 * @note While these mostly overlap with the CSW_* constants the CSI_* constants
 *       contain custom AMXX values that do not correspond to any real value in
 *       the game. The CSI_* constants should therefore be used for consistency.
 */
#define CSI_NONE                CSW_NONE
#define CSI_P228                CSW_P228
#define CSI_GLOCK               CSW_GLOCK  // Unused by game, See CSI_GLOCK18.
#define CSI_SCOUT               CSW_SCOUT
#define CSI_HEGRENADE           CSW_HEGRENADE
#define CSI_XM1014              CSW_XM1014
#define CSI_C4                  CSW_C4
#define CSI_MAC10               CSW_MAC10
#define CSI_AUG                 CSW_AUG
#define CSI_SMOKEGRENADE        CSW_SMOKEGRENADE
#define CSI_ELITE               CSW_ELITE
#define CSI_FIVESEVEN           CSW_FIVESEVEN
#define CSI_UMP45               CSW_UMP45
#define CSI_SG550               CSW_SG550
#define CSI_GALIL               CSW_GALIL
#define CSI_FAMAS               CSW_FAMAS
#define CSI_USP                 CSW_USP
#define CSI_GLOCK18             CSW_GLOCK18
#define CSI_P228                 CSW_AWP
#define CSI_MP5NAVY             CSW_MP5NAVY
#define CSI_M249                CSW_M249
#define CSI_M3                  CSW_M3
#define CSI_M4A1                CSW_M4A1
#define CSI_TMP                 CSW_TMP
#define CSI_G3SG1               CSW_G3SG1
#define CSI_FLASHBANG           CSW_FLASHBANG
#define CSI_DEAGLE              CSW_DEAGLE
#define CSI_SG552               CSW_SG552
#define CSI_AK47                CSW_AK47
#define CSI_KNIFE               CSW_KNIFE
#define CSI_P90                 CSW_P90
#define CSI_SHIELDGUN           CSW_SHIELDGUN   // The real CS value, use CSI_SHELD instead.
#define CSI_VEST                CSW_VEST        // Custom
#define CSI_VESTHELM            CSW_VESTHELM    // Custom
#define CSI_DEFUSER             33              // Custom
#define CSI_NVGS                34              // Custom
#define CSI_SHIELD              35              // Custom - The value passed by the forward, more convenient for plugins.
#define CSI_PRIAMMO             36              // Custom
#define CSI_SECAMMO             37              // Custom
#define CSI_MAX_COUNT           38
#define CSI_LAST_WEAPON         CSW_LAST_WEAPON
 
#define CSI_ALL_WEAPONS         CSW_ALL_WEAPONS
#define CSI_ALL_PISTOLS         CSW_ALL_PISTOLS
#define CSI_ALL_SHOTGUNS        CSW_ALL_SHOTGUNS
#define CSI_ALL_SMGS            CSW_ALL_SMGS
#define CSI_ALL_RIFLES          CSW_ALL_RIFLES
#define CSI_ALL_SNIPERRIFLES    CSW_ALL_SNIPERRIFLES
#define CSI_ALL_MACHINEGUNS     CSW_ALL_MACHINEGUNS
#define CSI_ALL_GRENADES        CSW_ALL_GRENADES
#define CSI_ALL_ARMORS          CSW_ALL_ARMORS
#define CSI_ALL_GUNS            CSW_ALL_GUNS
Example:
#include <amxmodx>
#include <cstrike>
 
public CS_OnBuyAttempt(index, item)
{
    if (item == CSI_AWP)
    {
        client_print(index, print_chat, "You tried to buy an AWP.");
 
        return PLUGIN_HANDLED; // <-- Use this to block a buying
    }
}
 
public CS_OnBuy(index, item)
{
    if (item == CSI_DEAGLE)
    {
        client_print(index, print_chat, "You just bought a deagle and you're about to receive it.");
    }
}

Items info

Native Description
cs_get_user_weapon_entity  Returns active weapon entity.
/**
 * Returns active weapon entity.
 *
 * @param playerIndex   Player index
 *
 * @return              Weapon entity index on success or 0 if there is no active weapon
 * @error               If the client index is not within the range of 1 to
 *                      maxClients, or the client is not connected, an error will be
 *                      thrown.
 */
native cs_get_user_weapon_entity(playerIndex);
cs_get_user_weapon  Returns weapon index of the active weapon.
Note:More reliable than get_user_weapon.
/**
 * Returns weapon index of the active weapon.
 *
 * @note More reliable than get_user_weapon.
 *
 * @param playerIndex   Player index
 * @param clip          Optional variable to store clip ammo to
 * @param ammo          Optional variable to store backpack ammo to
 *
 * @return              Weapon index on success or 0 if there is no active weapon
 * @error               If the client index is not within the range of 1 to
 *                      maxClients, or the client is not connected, an error will be
 *                      thrown.
 */
native cs_get_user_weapon(playerIndex, &clip = 0, &ammo = 0);
cs_get_item_id  Returns the item id associated with an item name and its aliases.
Note:The item name is case sensitive an can be with or without weapon_ and item_ prefixes. This can be a command alias as well.
Values examples: ak47, weapon_ak47, kevlar, item_kevlar, vest, bullpup, ...
/**
 * Returns the item id associated with an item name and its aliases.
 *
 * @note The item name is case sensitive an can be with or without 
 *       weapon_ and item_ prefixes. This can be a command alias as well.
 *       Values examples: ak47, weapon_ak47, kevlar, item_kevlar, vest, bullpup, ...
 *
 * @param name          Alias or classname
 * @param classid       If item is a weapon, variable to store the associated 
 *                      weapon class id in (CS_WEAPONCLASS_* constants)
 *
 * @return              Item id (CSI_* constants)
 */
native any:cs_get_item_id(const name[], &CsWeaponClassType:classid = CS_WEAPONCLASS_NONE);
cs_get_translated_item_alias  Returns an item name associated with a command alias.
Note:The alias is case sensitive.
Note:If not an alias to a weapon, buffer will be set with the original alias.
/**
 * Returns an item name associated with a command alias.
 *
 * @note The alias is case sensitive.
 * @note If not an alias to a weapon, buffer will be set with the original alias.
 *
 * @param alias         Alias name
 * @param itemname      Buffer to store item name to
 * @param maxlength     Maximum buffer size
 *
 * @return              True if alias is translated, false otherwise
 */
native bool:cs_get_translated_item_alias(const alias[], itemname[], maxlength);
cs_get_item_alias  Returns the alias name associated with an item index.
/**
 * Returns the alias name associated with an item index.
 *
 * @param itemid          Item id (CSI_* constants)
 * @param name            Buffer to store alias name to
 * @param name_maxlen     Maximum buffer size
 * @param altname         Optional buffer to store if available alternative alias name to
 * @param altname_maxlen  Maximum buffer size
 *
 * @return                True if alias is found, false otherwise
 */
native bool:cs_get_item_alias(itemid, name[], name_maxlen, altname[] = "", altname_maxlen = 0);
cs_get_weapon_info  Returns some information about a weapon.
Note:The alias is case sensitive.
Note:If not an alias to a weapon, buffer will be set with the original alias.
/**
 * Weapon info types for use with cs_get_weapon_info().
 */
enum CsWeaponInfo
{
	CS_WEAPONINFO_COST          = 0,
	CS_WEAPONINFO_CLIP_COST     = 1,
	CS_WEAPONINFO_BUY_CLIP_SIZE = 2,
	CS_WEAPONINFO_GUN_CLIP_SIZE = 3,
	CS_WEAPONINFO_MAX_ROUNDS    = 4,
	CS_WEAPONINFO_AMMO_TYPE     = 5,
};
 
/**
 * Returns some information about a weapon.
 *
 * @param weapon_id     Weapon id, see CSW_* constants
 * @param type          Info type, see CS_WEAPONINFO_* constants
 *
 * @return              Weapon information value
 * @error               If weapon_id and type are out of bound, an error will be thrown.
 */
native any:cs_get_weapon_info(weapon_id, CsWeaponInfo:type);
Stock Description
cs_get_weapon_class  Returns a weapon class id associated with a weapon id.
/**
 * Returns a weapon class id associated with a weapon id.
 *
 * @param weapon_id     Weapon id (CSI_* constants)
 *
 * @return              Weapon class id (CS_WEAPONCLASS_* constants)
 */
stock CsWeaponClassType:cs_get_weapon_class(weapon_id)
{
	new CsWeaponClassType:type = CS_WEAPONCLASS_NONE;
 
	if (cs_is_valid_itemid(weapon_id, .weapon_only = true) || weapon_id == CSI_SHIELD)
	{
		switch (weapon_id)
		{
			case CSI_SHIELDGUN, CSI_SHIELD: 
			{
				type = CS_WEAPONCLASS_PISTOL;
			}
			case CSI_KNIFE: 
			{
				type = CS_WEAPONCLASS_KNIFE;
			}
			default:
			{
				new const bits = (1 << weapon_id);
 
				if(bits & CSI_ALL_PISTOLS)
				{
					type = CS_WEAPONCLASS_PISTOL;
				}
				else if(bits & CSI_ALL_GRENADES)
				{
					type = CS_WEAPONCLASS_GRENADE;
				}
				else if(bits & CSI_ALL_SMGS)
				{
					type = CS_WEAPONCLASS_SUBMACHINEGUN;
				}
				else if(bits & CSI_ALL_SHOTGUNS)
				{
					type = CS_WEAPONCLASS_SHOTGUN;
				}
				else if(bits & CSI_ALL_MACHINEGUNS)
				{
					type = CS_WEAPONCLASS_MACHINEGUN;
				}
				else if(bits & CSI_ALL_RIFLES)
				{
					type = CS_WEAPONCLASS_RIFLE;
				}
				else if(bits & CSI_ALL_SNIPERRIFLES)
				{
					type = CS_WEAPONCLASS_SNIPERRIFLE;
				}
			}
		}
	}
 
	return type;
}
cs_is_valid_itemid  Checks whether an item id is not out of bounds.
/**
 * Checks whether an item id is not out of bounds.
 *
 * @param id           Item id (CSI_* constants) 
 * @param weapon_only  If true, only the real weapon ids will be checked,
 *                     including shield as well 
 *
 * @return             True if item id is valid, false otherwise
 */
stock bool:cs_is_valid_itemid(id, bool:weapon_only = false)
{
	if (id <= CSI_NONE)
	{
		return false;
	}
 
	if (id > CSI_LAST_WEAPON && id != CSI_SHIELDGUN && weapon_only)
	{
		return false;
	}
 
	if (id >= CSI_MAX_COUNT)
	{
		return false;
	}
 
	return true;
}

New params

Forward Parameter Description
cs_set_user_deaths scoreboard  If true the scoreboard will be updated to reflect the new value.
/**
 * Sets client's deaths.
 *
 * @param index         Client index
 * @param newdeaths     New value to set
 * @param scoreboard    If true the scoreboard will be updated to reflect the new value.
 *
 * @noreturn
 * @error               If the client index is not within the range of 1 to
 *                      MaxClients, or the client is not connected, an error
 *                      will be thrown.
 */
native cs_set_user_deaths(index, newdeaths, bool:scoreboard = true);
cs_get_armoury_type
cs_set_armoury_type
count  Optional variable to store in the number of times that an item can be retrieved from the same entity before being hidden.
/**
 * Returns the armoury entity's weapon id.
 *
 * @note Not all weapon ids are supported by Counter-Strike, an armoury entity
 *       can not be a pistol, a knife or a bomb for exmaple. The full list is:
 *          CSW_SCOUT, CSW_HEGRENADE, CSW_XM1014, CSW_MAC10, CSW_AUG,
 *          CSW_SMOKEGRENADE, CSW_AWP, CSW_MP5NAVY, CSW_M249, CSW_M3, CSW_M4A1,
 *          CSW_TMP, CSW_G3SG1, CSW_VEST, CSW_VESTHELM, CSW_FLASHBANG,
 *          CSW_SG552, CSW_AK47, CSW_P90
 *
 * @param index     Armoury entity index
 * @param count     Optional variable to store in the number of times that an item can be retrieved  
 *                  from the same entity before being hidden
 *
 * @return          Weapon id
 * @error           If a non-armoury entity is provided, an error will be
 *                  thrown.
 */
native cs_get_armoury_type(index, &count = 1);
 
/**
 * Sets the amoury entity type.
 *
 * @note Not all weapon ids are supported by Counter-Strike, an armoury entity
 *       can not be a pistol, a knife or a bomb for exmaple. The full list is:
 *          CSW_SCOUT, CSW_HEGRENADE, CSW_XM1014, CSW_MAC10, CSW_AUG,
 *          CSW_SMOKEGRENADE, CSW_AWP, CSW_MP5NAVY, CSW_M249, CSW_M3, CSW_M4A1,
 *          CSW_TMP, CSW_G3SG1, CSW_VEST, CSW_VESTHELM, CSW_FLASHBANG,
 *          CSW_SG552, CSW_AK47, CSW_P90
 * @note This does not update the entity model.
 * @note On restart, entity is always unhidden and the count is restored (this can not be below 1).
 *
 * @param index     Armoury entity index
 * @param type      Weapon id
 * @param count     Number of times that an item can be retrieved from 
 *                  the same entity before being hidden
 *                  If zero, the entity is hidden
 *                  If below zero, nothing is set
 * @noreturn
 * @error           If a non-armoury entity is provided, an error will be
 *                  thrown.
 */
native cs_set_armoury_type(index, type, count = -1);
cs_set_user_model update_index  If true, the modelindex is updated as well.
Note:Updating modelindex is useful for custom models which don't have the same structure as the default ones (hitbox, etc..).
Model must be precached before
/**
 * Sets the client's player model.
 *
 * @note This is not a one-time set. The CStrike module will remember the
 *       selected model and try to prevent attempts at changing the player
 *       model, or immediately re-apply it if necessary.
 * @note Updating modelindex is useful for custom models which don't have 
 *       the same structure as the default ones (hitbox, etc..). Model must 
 *       be precached before.
 *
 * @param index           Client index
 * @param model           Model name
 * @param update_index    If true, the modelindex is updated as well
 *
 * @noreturn
 * @error                 If the client index is not within the range of 1 to
 *                        MaxClients, the client is not connected, the provided
 *                        model is empty, or if modeindex is updated and the 
 *                        provided model is not precached, an error will be thrown.
 */
native cs_set_user_model(index, const model[], bool:update_index = false);

Others

  • Hostage natives will work now with monster_scientist entity (alias of hostage_entity)
  • cs_get_user_armor Template:Armortype parameter is now optional
  • cs_set_weapon_silen Template:Draw animation has a new value of 2 which follows game behavior to properly draw the animation


Engine

Entity

Native Description
entity_intersects  Returns if two entities bounding boxes intersect by comparing their absolute minimum and maximum origins.
/**
 * Returns if two entities bounding boxes intersect by comparing their absolute
 * minimum and maximum origins.
 *
 * @param entity    Entity index 1
 * @param other     Entity index 2
 *
 * @return          True if entities intersect, false otherwise
 * @error           If an invalid entity index is provided, an error will be
 *                  thrown.
 */
native bool:entity_intersects(entity, other);
set_ent_rendering  Sets rendering options of an entity.
/**
 * Sets rendering options of an entity.
 *
 * @note For a list of valid rendering effects see the kRenderFx* constants in
 *       amxconst.inc
 * @note For a list of valid rendering modes see the kRender* constants in
 *       amxconst.inc
 * @note Rendering amount has different meanings depending on the rendering
 *       effect and mode used on the entity.
 *
 * @param index     Entity index
 * @param fx        Rendering effect
 * @param r         Red component of rendering color
 * @param g         Green component of rendering color
 * @param b         Blue component of rendering color
 * @param render    Rendering mode
 * @param amount    Rendering amount
 *
 * @noreturn
 * @error           If an invalid entity index is provided, an error will be
 *                  thrown.
 */
native set_ent_rendering(index, fx = kRenderFxNone, r = 0, g = 0, b = 0, render = kRenderNormal, amount = 0);


Hook

You can now unregister hooks from: register_impulse, register_think and register_touch.

Forward Description
unregister_impulse  Removes a previously registered impulse hook.
/**
 * Removes a previously registered impulse hook.
 *
 * @param registerid    Impulse forward id
 *
 * @return              1 on success, 0 if nothing was removed
 */
native unregister_impulse(registerid);
unregister_think  Removes a previously registered think hook.
/**
 * Removes a previously registered think hook.
 *
 * @param registerid    Think forward id
 *
 * @return              1 on success, 0 if nothing was removed
 */
native unregister_think(registerid);
unregister_touch  Removes a previously registered touch hook.
/**
 * Removes a previously registered touch hook.
 *
 * @param registerid    Touch forward id
 *
 * @return              1 on success, 0 if nothing was removed
 */
native unregister_touch(registerid);


Miscellaneous

  • is_visible is now working on player.
  • set_ent_rendering is new working on non-players entities.
  • get_info_keybuffer can now retrieve local key buffer (i.e. using -1).
  • trace_hull gets a new end destination parameter to make it useful.


Safer Natives

Safer natives which returns -1 if not entity found instead of 00 which is a valid value (worldspawn).

Native Description
get_global_edict2  Safe version of get_global_edict.
Returns a edict type value from the server globals.
/**
 * Returns a edict type value from the server globals.
 *
 * @note For a list of valid edict type entries, see the GL_* constants in
 *       engine_const.inc under the "Edict" section.
 * @note This native returns -1 as a safe error value if the edict retrieved is
 *       an invalid entity. Otherwise it is identical to get_global_edict().
 *
 * @param variable  Entry to retrieve from
 *
 * @return          Value of specified entry
 * @error           If an invalid entry is provided, an error will be thrown.
 */
native get_global_edict2(variable);
entity_get_edict2  Safe version of entity_get_edict.
Returns an edict type value from an entities entvar struct.
/**
 * Returns an edict type value from an entities entvar struct.
 *
 * @note For a list of valid edict type entries, see the EV_ENT_* constants in
 *       engine_const.inc
 * @note This native returns -1 as a safe error value if the edict retrieved
 *       from the entvar is an invalid entity. Otherwise it is identical to
 *       entity_get_edict().
 *
 * @param iIndex    Entity index
 * @param iKey      Entry to retrieve from
 *
 * @return          Entity index in specified entry, -1 if the edict in the
 *                  entvar is not a valid entity or an invalid entry was
 *                  specified
 * @error           If an invalid entity index is provided, an error will be
 *                  thrown.
 */
native entity_get_edict2(iIndex, iKey);


Usercmd

  • get_usercmd and set_usercmd are now working and can be used in client_cmdStart forward.
Forward Description
client_cmdStart  Called for CmdStart() on a client.
/**
 * Called for CmdStart() on a client.
 *
 * @note Use [get|set]_usercmd() to read and modify information in the usercmd
 *       struct.
 *
 * @param id    Client index
 *
 * @return      PLUGIN_CONTINUE to ignore, PLUGIN_HANDLED or higher to block
 */
forward client_cmdStart(id);


Fakemeta

KVD

This allows the creation of new KVD structures that can be used with Hamsandwich (Ham_Keyvalue).

Native Description
create_kvd
free_kvd
 Creates a KeyValueData handle.
/**
 * Creates a KeyValueData handle.
 *
 * @note Handles should be freed using free_kvd().
 *
 * @return		New KeyValueData handle
 */
native create_kvd();
 Frees a KeyValueData handle.
/**
 * Frees a KeyValueData handle.
 *
 * @param kvd_handle	KeyValueData handle
 *
 * @noreturn
 */
native free_kvd(kvd_handle);


Entity's Private Data (gamedata)

This is now possible to manage value from an entity's private data based off a class and member name.
The related gamedata files are located in data/gamedata/common.games/entities.games directory.

Example:
foo()
{
    new const item = get_ent_data_entity("CBasePlayer", "m_pActiveItem");
}
Native Description
get_ent_data
set_ent_data
 Retrieves an integer value from an entity's private data based off a class and member name.
/**
 * Retrieves an integer value from an entity's private data based off a class
 * and member name.
 *
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class
 *       member offset into the plugin, this native instead retrieves the
 *       necessary offset from the AMXX gamedata files at runtime, based on the
 *       provided class and member name.
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter
 *       offset and typing checks.
 * @note This native is used to access the following (C++/engine) data types:
 *       integer, boolean, short, character, pointer, structure, class,
 *       stringint and function. Unsigned variants (if applicable) are supported
 *       and will be converted automatically.
 *
 * @param entity    Entity index
 * @param class     Class name
 * @param member    Member name
 * @param element   Element to retrieve (starting from 0) if member is an array
 *
 * @return          Integer value
 * @error           If an invalid entity is provided, either class or member is
 *                  empty, no offset is found or an invalid offset is retrieved,
 *                  or the data type does not match, an error will be thrown.
 */
native any:get_ent_data(entity, const class[], const member[], element = 0);
 Sets an integer value to an entity's private data based off a class and member name.
/**
 * Sets an integer value to an entity's private data based off a class
 * and member name.
 *
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class
 *       member offset into the plugin, this native instead retrieves the
 *       necessary offset from the AMXX gamedata files at runtime, based on the
 *       provided class and member name.
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter
 *       offset and typing checks.
 * @note This native is used to access the following (C++/engine) data types:
 *       integer, boolean, short, character, pointer, stringint and function.
 *       Unsigned variants (if applicable) are supported and will be converted
 *       automatically.
 *
 * @param entity    Entity index
 * @param class     Class name
 * @param member    Member name
 * @param value     Value to set
 * @param element   Element to set (starting from 0) if member is an array
 *
 * @noreturn
 * @error           If an invalid entity is provided, either class or member is
 *                  empty, no offset is found or an invalid offset is retrieved,
 *                  or the data type does not match, an error will be thrown.
 */
native set_ent_data(entity, const class[], const member[], any:value, element = 0);
get_ent_data_float
set_ent_data_float
 Retrieves an float value from an entity's private data based off a class and member name.
/**
 * Retrieves a float value from an entity's private data based off a class
 * and member name.
 *
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class
 *       member offset into the plugin, this native instead retrieves the
 *       necessary offset from the AMXX gamedata files at runtime, based on the
 *       provided class and member name.
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter
 *       offset and typing checks.
 *
 * @param entity    Entity index
 * @param class     Class name
 * @param member    Member name
 * @param element   Element to retrieve (starting from 0) if member is an array
 *
 * @return          Float value
 * @error           If an invalid entity is provided, either class or member is
 *                  empty, no offset is found or an invalid offset is retrieved,
 *                  or the data type does not match, an error will be thrown.
 */
native Float:get_ent_data_float(entity, const class[], const member[], element = 0);
 Sets an float value to an entity's private data based off a class and member name.
/**
 * Sets a float value to an entity's private data based off a class
 * and member name.
 *
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class
 *       member offset into the plugin, this native instead retrieves the
 *       necessary offset from the AMXX gamedata files at runtime, based on the
 *       provided class and member name.
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter
 *       offset and typing checks.
 *
 * @param entity    Entity index
 * @param class     Class name
 * @param member    Member name
 * @param value     Value to set
 * @param element   Element to set (starting from 0) if member is an array
 *
 * @noreturn
 * @error           If an invalid entity is provided, either class or member is
 *                  empty, no offset is found or an invalid offset is retrieved,
 *                  or the data type does not match, an error will be thrown.
 */
native set_ent_data_float(entity, const class[], const member[], Float:value, element = 0);
get_ent_data_vector
set_ent_data_vector
 Retrieves a vector from an entity's private data based off a class and member name.
/**
 * Retrieves a vector from an entity's private data based off a class and member name.
 *
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class
 *       member offset into the plugin, this native instead retrieves the
 *       necessary offset from the AMXX gamedata files at runtime, based on the
 *       provided class and member name.
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter
 *       offset and typing checks.
 *
 * @param entity    Entity index
 * @param class     Class name
 * @param member    Member name
 * @param value     Vector buffer to store data in
 * @param element   Element to retrieve (starting from 0) if member is an array
 *
 * @noreturn
 * @error           If an invalid entity is provided, either class or member is
 *                  empty, no offset is found or an invalid offset is retrieved,
 *                  or the data type does not match, an error will be thrown.
 */
native get_ent_data_vector(entity, const class[], const member[], Float:value[3], element = 0);
 Sets a vector to an entity's private data based off a class and member name.
/**
 * Sets a vector to an entity's private data based off a class and member name.
 *
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class
 *       member offset into the plugin, this native instead retrieves the
 *       necessary offset from the AMXX gamedata files at runtime, based on the
 *       provided class and member name.
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter
 *       offset and typing checks.
 *
 * @param entity    Entity index
 * @param class     Class name
 * @param member    Member name
 * @param value     Vector to set
 * @param element   Element to set (starting from 0) if member is an array
 *
 * @noreturn
 * @error           If an invalid entity is provided, either class or member is
 *                  empty, no offset is found or an invalid offset is retrieved,
 *                  or the data type does not match, an error will be thrown.
 */
native set_ent_data_vector(entity, const class[], const member[], Float:value[3], element = 0);
get_ent_data_entity
set_ent_data_entity
 Retrieves an entity index from an entity's private data based off a class and member name.
/**
 * Retrieves an entity index from an entity's private data based off a class
 * and member name.
 *
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class
 *       member offset into the plugin, this native instead retrieves the
 *       necessary offset from the AMXX gamedata files at runtime, based on the
 *       provided class and member name.
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter
 *       offset and typing checks.
 * @note This native is used to access the following (C++/engine) data types:
 *       classptr, entvars, edict and ehandle.
 *
 * @param entity    Entity index
 * @param class     Class name
 * @param member    Member name
 * @param element   Element to retrieve (starting from 0) if member is an array
 *
 * @return          Entity index if found, -1 otherwise
 * @error           If an invalid entity is provided, either class or member is
 *                  empty, no offset is found or an invalid offset is retrieved,
 *                  or the data type does not match, an error will be thrown.
 */
native get_ent_data_entity(entity, const class[], const member[], element = 0);
 Sets an entity index to an entity's private data based off a class and member name.
/**
 * Sets an entity index to an entity's private data based off a class
 * and member name.
 *
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class
 *       member offset into the plugin, this native instead retrieves the
 *       necessary offset from the AMXX gamedata files at runtime, based on the
 *       provided class and member name.
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter
 *       offset and typing checks.
 * @note This native is used to access the following (C++/engine) data types:
 *       classptr, entvars, edict and ehandle.
 * @note Pass -1 as value to act as C++ NULL.
 *
 * @param entity    Entity index
 * @param class     Class name
 * @param member    Member name
 * @param value     Entity index to set
 * @param element   Element to set (starting from 0) if member is an array
 *
 * @noreturn
 * @error           If an invalid entity or value is provided, either class or member
 *                  is empty, no offset is found or an invalid offset is retrieved,
 *                  or the data type does not match, an error will be thrown.
 */
native set_ent_data_entity(entity, const class[], const member[], value, element = 0);
get_ent_data_string
set_ent_data_string
 Retrieves a string from an entity's private data based off a class and member name.
/**
 * Retrieves a string from an entity's private data based off a class and member name.
 *
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class
 *       member offset into the plugin, this native instead retrieves the
 *       necessary offset from the AMXX gamedata files at runtime, based on the
 *       provided class and member name.
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter
 *       offset and typing checks.
 * @note This native is used to access the following (C++/engine) data types:
 *       string, stringptr.
 *
 * @param entity    Entity index
 * @param class     Class name
 * @param member    Member name
 * @param value     Buffer to store data in
 * @param maxlen    Maximum size of the buffer
 * @param element   Element to retrieve (starting from 0) if member is an array
 *
 * @return          Number of cells written to buffer
 * @error           If an invalid entity is provided, either class or member is
 *                  empty, no offset is found or an invalid offset is retrieved,
 *                  or the data type does not match, an error will be thrown.
 */
native get_ent_data_string(entity, const class[], const member[], value[], maxlen, element = 0);
 Sets a string to an entity's private data based off a class and member name.
/**
 * Sets a string to an entity's private data based off a class and member name.
 *
 * @note Unlike the [get|set]_pdata_* natives that require compiling the class
 *       member offset into the plugin, this native instead retrieves the
 *       necessary offset from the AMXX gamedata files at runtime, based on the
 *       provided class and member name.
 * @note This native is safer than [get|set]_pdata_* as it can perform stricter
 *       offset and typing checks.
 * @note This native is used to access the following (C++/engine) data types:
 *       string, stringptr.
 *
 * @param entity    Entity index
 * @param class     Class name
 * @param member    Member name
 * @param value     String to set
 * @param element   Element to set (starting from 0) if member is an array
 *
 * @return          Number of cells written to buffer
 * @error           If an invalid entity is provided, either class or member is
 *                  empty, no offset is found or an invalid offset is retrieved,
 *                  or the data type does not match, an error will be thrown.
 */
native set_ent_data_string(entity, const class[], const member[], const value[], element = 0);
get_ent_data_size  Retrieves the size of array of n entity class member.
/**
 * Retrieves the size of array of n entity class member.
 *
 * @param class     Class name
 * @param member    Member name
 *
 * @return          Size of array (in elements), otherwise 1 if member is not an array
 * @error           If either class or member is empty, no offset is found or an invalid
 *                  offset is retrieved, an error will be thrown.
 */
native get_ent_data_size(const class[], const member[]);
find_ent_data_info  Finds a offset based off an entity class and member name.
/**
 * Finds a offset based off an entity class and member name.
 *
 * @param class     Class name
 * @param member    Member name
 * @param type      Optional variable to store member type in (FIELD_* constants)
 * @param arraysize Optional variable to store array size in, if member is an array
 * @param unsigned  Optional variable to store whether member is unsigned (short and char types only)
 *
 * @return          Class member offset
 * @error           If either class or member is empty, no offset is found or an invalid
 *                  offset is retrieved, an error will be thrown.
 */
native find_ent_data_info(const class[], const member[], &FieldType:type = FIELD_NONE, &arraysize = 0, &bool:unsigned = false);


Entity's Private Data

While it's encouraged to use the new natives based off gamedata, this completes the list with new data types supported: edict, bool, byte, short and ehandle.

Native Description
get_pdata_ent
set_pdata_ent
 Tries to retrieve an edict pointer from an entity's private data.
/**
 * Tries to retrieve an edict pointer from an entity's private data.
 *
 * This function is byte-addressable.  Unlike get_pdata_int() which searches in byte increments of 4,
 * get_pdata_ent searches in increments of 1.
 *
 * _linuxdiff value is what to add to the _offset for linux servers.
 * _macdiff value is what to add to the _offset for os x servers.
 *
 * A log error is thrown on invalid _index and _Offset.
 *
 * @param _index		Entity index.
 * @param _offset		Offset to search.
 * @param _linuxdiff	Linux difference.
 * @param _macdiff		Mac OS X difference.
 * @return				-2 if an invalid entity was found.
 *						-1 if an empty entity was found.
 * 						Otherwise, an entity index is returned.
 */
native get_pdata_ent(_index, _offset, _linuxdiff = 20, _macdiff = 20);
 Sets an edict pointer to an entity's private data.
/**
 * Sets an edict pointer to an entity's private data.
 *
 * This function is byte-addressable.  Unlike set_pdata_int() which searches in byte increments of 4,
 * set_pdata_ent searches in increments of 1.
 *
 * _linuxdiff value is what to add to the _offset for linux servers.
 * _macdiff value is what to add to the _offset for os x servers.
 *
 * A log error is thrown on invalid _index and _offset.
 *
 * @param _index        Entity index.
 * @param _offset       Offset to search.
 * @param _value        Value to set.
 * @param _linuxdiff    Linux difference.
 * @param _macdiff      Mac OS X difference.
 * @return              1 on success.
 */
native set_pdata_ent(_index, _offset, _value, _linuxdiff = 20, _macdiff = 20);
get_pdata_bool
set_pdata_bool
 Returns a boolean from an entity's private data.
/**
 * Returns a boolean from an entity's private data.
 *
 * This function is byte-addressable. Unlike get_pdata_int() which searches in byte increments of 4,
 * get_pdata_bool searches in increments of 1.
 *
 * _linuxdiff value is what to add to the _offset for linux servers.
 * _macdiff value is what to add to the _offset for os x servers.
 *
 * A log error is thrown on invalid _index and _offset.
 *
 * @param _index        Entity index.
 * @param _offset       Offset to search.
 * @param _linuxdiff    Linux difference.
 * @param _macdiff      Mac OS X difference.
 * @return              An boolean value is returned.
 */
native bool:get_pdata_bool(_index, _offset, _linuxdiff = 20, _macdiff = 20);
 Sets a boolean to an entity's private data.
/**
 * Sets a boolean to an entity's private data.
 *
 * This function is byte-addressable. Unlike set_pdata_int() which searches in byte increments of 4,
 * set_pdata_bool searches in increments of 1.
 *
 * _linuxdiff value is what to add to the _offset for linux servers.
 * _macdiff value is what to add to the _offset for os x servers.
 *
 * A log error is thrown on invalid _index and _offset.
 *
 * @param _index        Entity index.
 * @param _offset       Offset to search.
 * @param _value        Value to set.
 * @param _linuxdiff    Linux difference.
 * @param _macdiff      Mac OS X difference.
 * @return              1 on success.
 */
native set_pdata_bool(_index, _offset, bool:_value, _linuxdiff = 20, _macdiff = 20);
get_pdata_byte
set_pdata_byte
 Returns a byte value from an entity's private data.
/**
 * Returns a byte value from an entity's private data.
 *
 * This function is byte-addressable. Unlike get_pdata_int() which searches in byte increments of 4,
 * get_pdata_byte searches in increments of 1.
 *
 * _linuxdiff value is what to add to the _offset for linux servers.
 * _macdiff value is what to add to the _offset for os x servers.
 *
 * A log error is thrown on invalid _index and _offset.
 *
 * @param _index        Entity index.
 * @param _offset       Offset to search.
 * @param _linuxdiff    Linux difference.
 * @param _macdiff      Mac OS X difference.
 * @return              A byte value is returned.
 */
native get_pdata_byte(_index, _offset, _linuxdiff = 20, _macdiff = 20);
 Sets a byte value to an entity's private data.
/**
 * Sets a byte value to an entity's private data.
 *
 * This function is byte-addressable. Unlike set_pdata_int() which searches in byte increments of 4,
 * set_pdata_byte searches in increments of 1.
 *
 * _linuxdiff value is what to add to the _offset for linux servers.
 * _macdiff value is what to add to the _offset for os x servers.
 *
 * A log error is thrown on invalid _index and _offset.
 *
 * @param _index        Entity index.
 * @param _offset       Offset to search.
 * @param _value        Value to set.
 * @param _linuxdiff    Linux difference.
 * @param _macdiff      Mac OS X difference.
 * @return              1 on success.
 */
native set_pdata_byte(_index, _offset, _value, _linuxdiff = 20, _macdiff = 20);
get_pdata_short
set_pdata_short
 Returns a short value from an entity's private data.
/**
 * Returns a short value from an entity's private data.
 *
 * This function is byte-addressable. Unlike get_pdata_int() which searches in byte increments of 4,
 * get_pdata_short searches in increments of 1.
 *
 * _linuxdiff value is what to add to the _offset for linux servers.
 * _macdiff value is what to add to the _offset for os x servers.
 *
 * A log error is thrown on invalid _index and _offset.
 *
 * @param _index        Entity index.
 * @param _offset       Offset to search.
 * @param _linuxdiff    Linux difference.
 * @param _macdiff      Mac OS X difference.
 * @return              A short value is returned.
 */
native get_pdata_short(_index, _offset, _linuxdiff = 20, _macdiff = 20);
 Sets a short value to an entity's private data.
/**
 * Sets a short value to an entity's private data.
 *
 * This function is byte-addressable.  Unlike set_pdata_int() which searches in byte increments of 4,
 * set_pdata_short searches in increments of 1.
 *
 * _linuxdiff value is what to add to the _offset for linux servers.
 * _macdiff value is what to add to the _offset for os x servers.
 *
 * A log error is thrown on invalid _index and _offset.
 *
 * @param _index        Entity index.
 * @param _offset       Offset to search.
 * @param _value        Value to set.
 * @param _linuxdiff    Linux difference.
 * @param _macdiff      Mac OS X difference.
 * @return              1 on success.
 */
native set_pdata_short(_index, _offset, _value, _linuxdiff = 20, _macdiff = 20);
get_pdata_vector
set_pdata_vector
 Returns a vector from an entity's private data.
/**
 * Returns a vector from an entity's private data.
 *
 * This function is byte-addressable. Unlike get_pdata_int() which searches in byte increments of 4,
 * get_pdata_vector searches in increments of 1.
 *
 * _linuxdiff value is what to add to the _offset for linux servers.
 * _macdiff value is what to add to the _offset for os x servers.
 *
 * A log error is thrown on invalid _index and _offset.
 *
 * @param _index        Entity index.
 * @param _offset       Offset to search.
 * @param _output       Vector returned by reference.
 * @param _linuxdiff    Linux difference.
 * @param _macdiff      Mac OS X difference.
 * @return              1 on success.
 */
native get_pdata_vector(_index, _offset, Float:_output[3], _linuxdiff = 20, _macdiff = 20);
 Sets a vector to an entity's private data.
/**
 * Sets a vector to an entity's private data.
 *
 * This function is byte-addressable.  Unlike set_pdata_int() which searches in byte increments of 4,
 * set_pdata_vector searches in increments of 1.
 *
 * _linuxdiff value is what to add to the _offset for linux servers.
 * _macdiff value is what to add to the _offset for os x servers.
 *
 * A log error is thrown on invalid _index and _Offset.
 *
 * @param _index        Entity index.
 * @param _offset       Offset to search.
 * @param _origin       Value to set.
 * @param _linuxdiff    Linux difference.
 * @param _macdiff      Mac OS X difference.
 * @return              1 on success.
 */
native set_pdata_vector(_index, _offset, Float:_origin[3], _linuxdiff = 20, _macdiff = 20);
get_pdata_ehandle
set_pdata_ehandle
 Tries to retrieve an edict (entity encapsulation) pointer from an entity's private data.
/**
 * Tries to retrieve an edict (entity encapsulation) pointer from an entity's private data.
 *
 * This function is byte-addressable.  Unlike get_pdata_int() which searches in byte increments of 4,
 * get_pdata_ehandle searches in increments of 1.
 *
 * _linuxdiff value is what to add to the _offset for linux servers.
 * _macdiff value is what to add to the _offset for os x servers.
 *
 * A log error is thrown on invalid _index and _offset.
 *
 * @param _index        Entity index.
 * @param _offset       Offset to search.
 * @param _linuxdiff    Linux difference.
 * @param _macdiff      Mac OS X difference.
 * @return              -2 if an invalid entity was found.
 *                      -1 if an empty entity was found.
 *                      0 if serialnumber is not matching.
 *                      Otherwise, an entity index is returned.
 */
native get_pdata_ehandle(_index, _offset, _linuxdiff = 20, _macdiff = 20);
 Sets an edict (entity encapsulation) pointer to an entity's private data.
/**
 * Sets an edict (entity encapsulation) pointer to an entity's private data.
 *
 * This function is byte-addressable.  Unlike set_pdata_int() which searches in byte increments of 4,
 * set_pdata_ehandle searches in increments of 1.
 *
 * _linuxdiff value is what to add to the _offset for linux servers.
 * _macdiff value is what to add to the _offset for os x servers.
 *
 * A log error is thrown on invalid _index and _Offset.
 *
 * @param _index        Entity index.
 * @param _offset       Offset to search.
 * @param _value        Value to set.
 * @param _linuxdiff    Linux difference.
 * @param _macdiff      Mac OS X difference.
 * @return              1 on success.
 */
native set_pdata_ehandle(_index, _offset, _value, _linuxdiff = 20, _macdiff = 20);


Gamerules

You have now the ability to manage a value using the gamerules object based off a class and member name.
The gamedata files are located in /data/gamedata/common.games/gamerules.games directory.

Example:
foo()
{
    new const score = get_gamerules_int("CHalfLifeMultiplay", "m_iNumCTWins");
}
Native Description
get_gamerules_int
set_gamerules_int
 Retrieves an integer value from the gamerules object based off a class and member name.
/**
 * Retrieves an integer value from the gamerules object based off a class
 * and member name.
 *
 * @note This native is used to access the following (C++/engine) data types:
 *       integer, boolean, short, character, pointer, structure, class,
 *       stringint and function. Unsigned variants (if applicable) are supported
 *       and will be converted automatically.
 *
 * @param class     Class name
 * @param member    Member name
 * @param element   Element to retrieve (starting from 0) if member is an array
 *
 * @return          Integer value
 * @error           If member is empty, no offset is found or an invalid offset
 *                  is retrieved, or the data type does not match, an error will
 *                  be thrown.
 */
native any:get_gamerules_int(const class[], const member[], element = 0);
 Sets an integer value to the gamerules objecta based off a class and member name.
/**
 * Sets an integer value to the gamerules objecta based off a class
 * and member name.
 *
 * @note This native is used to access the following (C++/engine) data types:
 *       integer, boolean, short, character, pointer, stringint and function.
 *       Unsigned variants (if applicable) are supported and will be converted
 *       automatically.
 *
 * @param class     Class name
 * @param member    Member name
 * @param value     Value to set
 * @param element   Element to set (starting from 0) if member is an array
 *
 * @noreturn
 * @error           If member is empty, no offset is found or an invalid offset
 *                  is retrieved, or the data type does not match, an error will
 *                  be thrown.
 */
native set_gamerules_int(const class[], const member[], any:value, element = 0);
get_gamerules_float
set_gamerules_float
 Retrieves a float value from the gamerules object based off a class and member name.
/**
 * Retrieves a float value from the gamerules object based off a class
 * and member name.
 *
 * @param class     Class name
 * @param member    Member name
 * @param element   Element to retrieve (starting from 0) if member is an array
 *
 * @return          Float value
 * @error           If member is empty, no offset is found or an invalid offset
 *                  is retrieved, or the data type does not match, an error will
 *                  be thrown.
 */
native Float:get_gamerules_float(const class[], const member[], element = 0);
 Sets an float value to the gamerules objecta based off a class and member name.
/**
 * Sets a float value to the gamerules object based off a class
 * and member name.
 *
 * @param class     Class name
 * @param member    Member name
 * @param value     Value to set
 * @param element   Element to set (starting from 0) if member is an array
 *
 * @noreturn
 * @error           If member is empty, no offset is found or an invalid offset
 *                  is retrieved, or the data type does not match, an error will
 *                  be thrown.
 */
native set_gamerules_float(const class[], const member[], Float:value, element = 0);
get_gamerules_vector
set_gamerules_vector
 Retrieves a vector from the gamerules object based off a class and member name.
/**
 * Retrieves a vector from the gamerules object based off a class and member name.
 *
 * @param class     Class name
 * @param member    Member name
 * @param value     Vector buffer to store data in
 * @param element   Element to retrieve (starting from 0) if member is an array
 *
 * @noreturn
 * @error           If member is empty, no offset is found or an invalid offset
 *                  is retrieved, or the data type does not match, an error will
 *                  be thrown.
 */
native get_gamerules_vector(const class[], const member[], Float:value[3], element = 0);
 Sets a vector to the gamerules objecta based off a class and member name.
/**
 * Sets a vector to the gamerules object based off a class and member name.
 *
 * @param class     Class name
 * @param member    Member name
 * @param value     Vector to set
 * @param element   Element to set (starting from 0) if member is an array
 *
 * @noreturn
 * @error           If member is empty, no offset is found or an invalid offset
 *                  is retrieved, or the data type does not match, an error will
 *                  be thrown.
 */
native set_gamerules_vector(const class[], const member[], Float:value[3], element = 0);
get_gamerules_entity
set_gamerules_entity
 Retrieves an entity index from the gamerules object based off a class and member name.
/**
 * Retrieves an entity index from the gamerules object based off a class
 * and member name.
 *
 * @note This native is used to access the following (C++/engine) data types:
 *       classptr, entvars, edict and ehandle.
 *
 * @param class     Class name
 * @param member    Member name
 * @param element   Element to retrieve (starting from 0) if member is an array
 *
 * @return          Entity index if found, -1 otherwise
 * @error           If member is empty, no offset is found or an invalid offset
 *                  is retrieved, or the data type does not match, an error will
 *                  be thrown.
 */
native get_gamerules_entity(const class[], const member[], element = 0);
 Sets an entity index to the gamerules objecta based off a class and member name.
/**
 * Sets an entity index to the gamerules object based off a class
 * and member name.
 *
 * @note This native is used to access the following (C++/engine) data types:
 *       classptr, entvars, edict and ehandle.
 * @note Pass -1 as value to act as C++ NULL.
 *
 * @param class     Class name
 * @param member    Member name
 * @param value     Entity index to set
 * @param element   Element to set (starting from 0) if member is an array
 *
 * @noreturn
 * @error           If member is empty, no offset is found or an invalid offset
 *                  is retrieved, or the data type does not match, an error will
 *                  be thrown.
 */
native set_gamerules_entity(const class[], const member[], value, element = 0);
get_gamerules_string
set_gamerules_string
 Retrieves a string from the gamerules object based off a class and member name.
/**
 * Retrieves a string from the gamerules object based off a class and member name.
 *
 * @note This native is used to access the following (C++/engine) data types:
 *       string, stringptr.
 *
 * @param class     Class name
 * @param member    Member name
 * @param value     Buffer to store data in
 * @param maxlen    Maximum size of the buffer
 * @param element   Element to retrieve (starting from 0) if member is an array
 *
 * @return          Number of cells written to buffer
 * @error           If member is empty, no offset is found or an invalid offset
 *                  is retrieved, or the data type does not match, an error will
 *                  be thrown.
 */
native get_gamerules_string(const class[], const member[], value[], maxlen, element = 0);
 Sets a string to the gamerules objecta based off a class and member name.
/**
 * Sets a string to the gamerules object based off a class and member name.
 *
 * @note This native is used to access the following (C++/engine) data types:
 *       string, stringptr.
 *
 * @param class     Class name
 * @param member    Member name
 * @param value     String to set
 * @param element   Element to set (starting from 0) if member is an array
 *
 * @return          Number of cells written to buffer
 * @error           If member is empty, no offset is found or an invalid offset
 *                  is retrieved, or the data type does not match, an error will
 *                  be thrown.
 */
native set_gamerules_string(const class[], const member[], const value[], element = 0);
get_gamerules_size  Retrieves the size of array of a gamerules class member.
/**
 * Retrieves the size of array of a gamerules class member.
 *
 * @param class     Class name
 * @param member    Member name
 *
 * @return          Size of array (in elements), otherwise 1 if member is not an array
 * @error           If either class or member is empty, no offset is found or an invalid
 *                  offset is retrieved, an error will be thrown.
 */
native get_gamerules_size(const class[], const member[]);
find_gamerules_info  Finds a gamerules offset based off a class and member name.
/**
 * Finds a gamerules offset based off a class and member name.
 *
 * @param class     Class name
 * @param member    Member name
 * @param type      Optional variable to store member type in (FIELD_* constants)
 * @param arraysize Optional variable to store array size in, if member is an array
 * @param unsigned  Optional variable to store whether member is unsigned (short and char types only)
 *
 * @return          Class member offset
 * @error           If either class or member is empty, no offset is found or an invalid
 *                  offset is retrieved, an error will be thrown.
 */
native find_gamerules_info(const class[], const member[], &FieldType:type = FIELD_NONE, &arraysize = 0, &bool:unsigned = false);
Stock Description
get_field_basetype  Returns the data field base type based off a specific field type.
/**
 * Returns the data field base type based off a specific field type.
 *
 * @note From an AMXX plugin perspective, the (C++/engine) data types can be grouped
 *       in five base types: integer, float, vector, entity and string. This stock is
 *       essentially for convenience and debug purpose.
 *
 * @param type      Class member type (FIELD_* constants)
 * @param type_name Optional buffer to store base type name in
 * @param maxlen    Maximum size of the buffer
 *
 * @return          Base field type (BASEFIELD_* constants)
 */
stock BaseFieldType:get_field_basetype(FieldType:type, type_name[] = "", maxlen = 0)
{
    static const baseFieldTypeNames[BaseFieldType][] =
    {
        "none",
        "integer",
        "float",
        "vector",
        "entity",
        "string",
    };
 
    new BaseFieldType:baseType = BASEFIELD_NONE;
 
    switch (type)
    {
        case FIELD_INTEGER, FIELD_STRINGINT, FIELD_SHORT  , FIELD_CHARACTER,
             FIELD_CLASS  , FIELD_STRUCTURE, FIELD_POINTER, FIELD_FUNCTION,
             FIELD_BOOLEAN:
        {
            baseType = BASEFIELD_INTEGER;
        }
        case FIELD_FLOAT:
        {
            baseType = BASEFIELD_FLOAT;
        }
        case FIELD_VECTOR:
        {
            baseType = BASEFIELD_VECTOR;
        }
        case FIELD_CLASSPTR, FIELD_ENTVARS, FIELD_EDICT, FIELD_EHANDLE:
        {
            baseType = BASEFIELD_ENTITY;
        }
        case FIELD_STRINGPTR, FIELD_STRING:
        {
            baseType = BASEFIELD_STRING;
        }
    }
 
    if (maxlen > 0)
    {
        copy(type_name, maxlen, baseFieldTypeNames[baseType]);
    }
 
    return baseType;
}


Miscellaneous

  • get/set_pdata_cbase can now be used at map end whereas player's private datas are still valid.
  • EngFunc_PlayBackEvent can now receive a null invoker.
  • KeyValueData usage is now compatible with Hamsandwich module.


GeoIP

Library

The module uses the new MaxMind GeoIP2 API. The relevant advantages are:

  • Should be more precise
  • Data is localized (current supported languages: de, en, es, fr, ja, ru, pt-BR, zh-CN)

If you want further information, see What’s New in GeoIP2.

Note:GeoIP.dat is replaced with GeoLite2-Country.mmdb (default, downloadable) or GeoLite2-City.mmdb (downloadable).

Command

A geoip command is available for troubleshooting: geoip <command> [argument]

Command Description
version  Displays the geoip database metadata such as the current loaded database and its version.
  Database metadata
    Node count:    3998109
    Record size:   28 bits
    IP version:    IPv6
    Binary format: 2.0
    Build epoch:   1501721259 (2017-08-03 00:47:39 UTC)
    Type:          GeoLite2-City
    Languages:     de en es fr ja pt-BR ru zh-CN
    Description:
      en:   GeoLite2 City database
dump <ip> [output file]  Dumps all data from an IP address formatted in a JSON-ish fashion.
An output file is mod-based and if not provided, it will print in the console.
/**
* GEOIP2 DATA EXAMPLE:
*
* {
*   "city":  {
*       "confidence":  25,
*       "geoname_id": 54321,
*       "names":  {
*           "de":    "Los Angeles",
*           "en":    "Los Angeles",
*           "es":    "Los Ýngeles",
*           "fr":    "Los Angeles",
*           "ja":    "ロサンゼルス市",
*           "pt-BR":  "Los Angeles",
*           "ru":    "Лоѝ-Ннджелеѝ",
*           "zh-CN": "洛杉矶"
*       }
*   },
*   "continent":  {
*       "code":       "NA",
*       "geoname_id": 123456,
*       "names":  {
*           "de":    "Nordamerika",
*           "en":    "North America",
*           "es":    "América del Norte",
*           "fr":    "Amérique du Nord",
*           "ja":    "北アメリカ",
*           "pt-BR": "América do Norte",
*           "ru":    "Севернаѝ Нмерика",
*           "zh-CN": "北美洲"
*
*       }
*   },
*   "country":  {
*       "confidence":  75,
*       "geoname_id": "6252001",
*       "iso_code":    "US",
*       "names":  {
*           "de":     "USA",
*           "en":     "United States",
*           "es":     "Estados Unidos",
*           "fr":     "États-Unis",
*           "ja":     "アメリカ坈衆国",
*           "pt-BR":  "Estados Unidos",
*           "ru":     "СШН",
*           "zh-CN":  "美国"
*       }
*   },
*   "location":  {
*       "accuracy_radius":   20,
*       "latitude":          37.6293,
*       "longitude":         -122.1163,
*       "metro_code":        807,
*       "time_zone":         "America/Los_Angeles"
*   },
*   "postal": {
*       "code":       "90001",
*       "confidence": 10
*   },
*   "registered_country":  {
*       "geoname_id": "6252001",
*       "iso_code":    "US",
*       "names":  {
*           "de":     "USA",
*           "en":     "United States",
*           "es":     "Estados Unidos",
*           "fr":     "États-Unis",
*           "ja":     "アメリカ坈衆国",
*           "pt-BR":  "Estados Unidos",
*           "ru":     "СШН",
*           "zh-CN":  "美国"
*       }
*   },
*   "represented_country":  {
*      "geoname_id": "6252001",
*       "iso_code":    "US",
*       "names":  {
*           "de":     "USA",
*           "en":     "United States",
*           "es":     "Estados Unidos",
*           "fr":     "États-Unis",
*           "ja":     "アメリカ坈衆国",
*           "pt-BR":  "Estados Unidos",
*           "ru":     "СШН",
*           "zh-CN":  "美国"
*       },
*       "type": "military"
*   },
*   "subdivisions":  [
*       {
*           "confidence":  50,
*           "geoname_id": 5332921,
*           "iso_code":    "CA",
*           "names":  {
*               "de":    "Kalifornien",
*               "en":    "California",
*               "es":    "California",
*               "fr":    "Californie",
*               "ja":    "カリフォルニア",
*               "ru":    "Калифорниѝ",
*               "zh-CN": "加州"
*           }
*       }
*   ],
*   "traits": {
*       "autonomous_system_number":      "1239",
*       "autonomous_system_organization": "Linkem IR WiMax Network",
*       "domain":                        "example.com",
*       "is_anonymous_proxy":            true,
*       "is_transparent_proxy":          true,
*       "isp":                           "Linkem spa",
*       "ip_address":                    "1.2.3.4",
*       "organization":                  "Linkem IR WiMax Network",
*       "user_type":                     "traveler",
*   },
*   "maxmind": {
*       "queries_remaining":            "54321"
*   }
* }
*/

Deprecated natives

geoip_country has been marked as deprecated in favor of geoip_country_ex.
Hardcoding the maximum buffer length and returning "error" if nothing is found, were not quite the good idea.

New natives

The natives which can output localized data, have a new id parameter in order to retrieve data into the player's language.

/**
 * @param id        An optional player's index in order to return the result
 *                  in the player's language, if supported.
 *                  -1: the default language, which is english.
 *                   0: the server language. You can use LANG_SERVER define.
 *                 >=1: the player's language.
 */
Native Database Localized Description
geoip_country_ex Country / City Looks up the full country name.
/**
 * Looks up the full country name for the given IP address.
 *
 * @param ip        The IP address to lookup.
 * @param result    The result of the geoip lookup.
 * @param len       The maximum length of the result buffer.
 * @param id        An optional player's index in order to return the result
 *                  in the player's language, if supported.
 *                  -1: the default language, which is english.
 *                   0: the server language. You can use LANG_SERVER define.
 *                 >=1: the player's language.
 *
 * @return          The result length on successful lookup, 0 otherwise.
 */
native geoip_country_ex(const ip[], result[], len, id = -1);
geoip_city City Returns the (localized) city name.
/**
 * Look up the full city name for the given IP address.
 *
 * @note  This native requires GeoIP City database, which can be retrieved from:
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)
 *
 * @param ip        The IP address to look up.
 * @param result    The result of the geoip look up.
 * @param len       The maximum length of the result buffer.
 * @param id        An optional player's index in order to return the result
 *                  in the player's language, if supported.
 *                  -1: the default language, which is english.
 *                   0: the server language. You can use LANG_SERVER define.
 *                 >=1: the player's language.
 *
 * @return          The result length on successful lookup, 0 otherwise.
 */
native geoip_city(const ip[], result[], len, id = -1);
geoip_continent_code City Returns the continent code. Example: EU (Europe)
/**
 * Looks up the continent code for a given IP address.
 *
 * @note  This native requires GeoIP City database, which can be retrieved from:
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)
 * @note  The code can be retrieved as integer (See CONTINENT_* constants.) or string (2 characters).
 * @note  Possible continent codes are AF, AN, AS, EU, NA, OC, SA for
 *        Africa(1), Antarctica(2), Asia(3), Europe(4), North America(5), Oceania(6), South America(7).
 *
 * @param ip        The IP address to look up.
 * @param result    The result of the geoip look up.
 *
 * @return          The continent id on successful lookup, 0 otherwise.
 */
enum Continent
{
    CONTINENT_UNKNOWN = 0,
    CONTINENT_AFRICA,
    CONTINENT_ANTARCTICA,
    CONTINENT_ASIA,
    CONTINENT_EUROPE,
    CONTINENT_NORTH_AMERICA,
    CONTINENT_OCEANIA,
    CONTINENT_SOUTH_AMERICA,
};
native Continent:geoip_continent_code(const ip[], result[3]);
geoip_continent_name City Returns the (localized) continent name. Example: Europe
/**
 * Look up the full continent name for the given IP address.
 *
 * @note  This native requires GeoIP City database, which can be retrieved from:
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)
 *
 * @param ip        The IP address to look up.
 * @param result    The result of the geoip look up.
 * @param len       The maximum length of the result buffer.
 * @param id        An optional player's index in order to return the result
 *                  in the player's language, if supported.
 *                  -1: the default language, which is english.
 *                   0: the server language. You can use LANG_SERVER define.
 *                 >=1: the player's language.
 *
 * @return          The result length on successful lookup, 0 otherwise.
 */
native geoip_continent_name(const ip[], result[], len, id = -1);
geoip_region_code City Returns a region code.
/**
 * Look up the region/state code for the given IP address.
 * e.g. "US-OH", "DE-HH", IT-82, "FR-U", etc.
 *
 * @note  This native requires GeoIP City database, which can be retrieved from:
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)
 *
 * @param ip        The IP address to look up.
 * @param result    The result of the geoip look up.
 * @param len       The maximum length of the result buffer.
 *
 * @return          The result length on successful lookup, 0 otherwise.
 */
native geoip_region_code(const ip[], result[], len);
geoip_region_name City Returns a (localized) region name.
/**
 * Look up the full region/state name for the given IP address.
 *
 * @note  This native requires GeoIP City database, which can be retrieved from:
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)
 *
 * @param ip        The IP address to look up.
 * @param result    The result of the geoip look up.
 * @param len       The maximum length of the result buffer.
 * @param id        An optional player's index in order to return the result
 *                  in the player's language, if supported.
 *                  -1: the default language, which is english.
 *                   0: the server language. You can use LANG_SERVER define.
 *                 >=1: the player's language.
 *
 * @return          The result length on successful lookup, 0 otherwise.
 */
native geoip_region_name(const ip[], result[], len, id = -1);
geoip_latitude City Returns a city's latitude.
/**
 * Look up the city's latitude for the given IP address.
 *
 * @note  This native requires GeoIP City database, which can be retrieved from:
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)
 *
 * @param ip        The IP address to look up.
 *
 * @return          The result of the geoip look up, 0 if latitude is not found.
 */
native Float:geoip_latitude(const ip[]);
geoip_longitude City Returns a city's longitude.
/**
 * Look up the city's longitude for the given IP address.
 *
 * @note  This native requires GeoIP City database, which can be retrieved from:
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)
 *
 * @param ip        The IP address to look up.
 *
 * @return          The result of the geoip look up, 0 if longitude is not found.
 */
native Float:geoip_longitude(const ip[]);
geoip_distance City Calculates the distance between geographical coordinates.
/**
 * Calculate the distance between geographical coordinates, latitude and longitude.
 *
 * @note  This native requires GeoIP City database, which can be retrieved from:
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)
 *
 * @param lat1      The first IP latitude.
 * @param lon1      The first IP longitude.
 * @param lat2      The second IP latitude.
 * @param lon2      The second IP longitude.
 * @param system    The system of measurement, 0 = Metric(kilometers) or 1 = English(miles).
 *
 * @return          The distance as result in specified system of measurement.
 */
#define SYSTEM_METRIC   0 // kilometers
#define SYSTEM_IMPERIAL 1 // statute miles
 
native Float:geoip_distance(Float:lat1, Float:lon1, Float:lat2, Float:lon2, system = SYSTEM_METRIC);
geoip_timezone City Returns a full time zone. Example: Europe/Paris
/**
 * Look up the full time zone for the given IP address.
 * e.g. America/Los_Angeles, Europe/Paris.
 *
 * @note  This native requires GeoIP City database, which can be retrieved from:
 *        http://dev.maxmind.com/geoip/geoip2/geolite2/ (MaxMind DB binary)
 *
 * @param ip        The IP address to look up.
 * @param result    The result of the geoip look up.
 * @param len       The maximum length of the result buffer.
 *
 * @return          The result length on successful lookup, 0 otherwise.
 */
native geoip_timezone(const ip[], result[], len);


Hamsandwich

Games support

The following games are now supported:

  • Deathmatch Classic
  • Adrenaline Gamer
  • Opposing Forces

The following games have been updated to their latest version:

  • Sven Coop v5.17

ItemInfo structure

A new set of functions have added to manage the {ItemInfo structure.

Native Description
CreateHamItemInfo  Creates an ItemInfo handle.
The handle can be used in GetHamItemInfo and SetHamItemInfo.
/**
 * Creates an ItemInfo handle.  This value should never be altered.
 * The handle can be used in Get/SetHamItemInfo.
 *
 * NOTE: You must call FreeHamItemInfo() on every handle made with CreateHamItemInfo().
 *
 * @return			A new ItemInfo handle.
 */
native CreateHamItemInfo();
FreeHamItemInfo  Frees an ItemIndo handle created with CreateHamItemInfo.
/**
 * Frees an ItemIndo handle created with CreateHamItemInfo().  Do not call
 * this more than once per handle, or on handles not created through
 * CreateHamItemInfo().
 *
 * @param itemInfo_handle	ItemInfo handle created via CreateHamItemInfo().
 * @noreturn
 */
native FreeHamItemInfo(itemInfo_handle);
GetHamItemInfo
SetHamItemInfo
 Gets a parameter on the fly of the current hook.
/**
 * Gets a parameter on the fly of the current hook.
 * Use this on parameters that are iteminfo result handles.
 *
 * @param iteminfo_handle	Item info handle.
 * @param type				Item info type. See HamItemInfo constants.
 */
native GetHamItemInfo(iteminfo_handle, HamItemInfo:type, any:...);
 Sets a parameter on the fly of the current hook.
/**
 * Sets a parameter on the fly of the current hook.
 * Use this on parameters that are iteminfo result handles.
 *
 * @param iteminfo_handle	Item info handle.
 * @param type				Item info type. See HamItemInfo_ constants.
 */
native SetHamItemInfo(iteminfo_handle, HamItemInfo:type, any:...);
SetHamParamItemInfo  Sets a parameter on the fly of the current hook. This has no effect in post hooks.
/**
 * Sets a parameter on the fly of the current hook.  This has no effect in post hooks.
 * Use this on parameters that are trace result handles.
 *
 * @param which				Which parameter to change.  Starts at 1, and works up from the left to right.  1 is always "this".
 * @param iteminfo_handle	The value to change it to.
 */
native SetHamParamItemInfo(which, iteminfo_handle);

Miscellaneous

Native Description
SetParamEntity2  Sets a parameter on the fly of the current hook. This has no effect in post hooks
Note: Same as SetHamParamEntity except the changes made by this native are reflected in the corresponding post forward.
.
/**
 * Sets a parameter on the fly of the current hook.  This has no effect in post hooks.
 * Use this on parameters that are entities.
 *
 * @note Same as SetHamParamEntity except the changes made by this native are reflected in the corresponding post forward.
 *
 * @param which				Which parameter to change.  Starts at 1, and works up from the left to right.  1 is always "this".
 * @param value				The value to change it to.
 */
native SetHamParamEntity2(which, value);

Special bot

RegisterHam has now the ability to register a bot without player classname.

Native Parameter Description
RegisterHam specialbot  Whether or not to enable support for bot without "player" classname.
/**
 * Hooks the virtual table for the specified entity class.
 * An example would be: RegisterHam(Ham_TakeDamage, "player", "player_hurt");
 * Look at the Ham enum for parameter lists.
 *
 * @param function		The function to hook.
 * @param EntityClass	The entity classname to hook.
 * @param callback		The forward to call.
 * @param post			Whether or not to forward this in post.
 * @param specialbot	Whether or not to enable support for bot without "player" classname.
 * @return 				Returns a handle to the forward.  Use EnableHamForward/DisableHamForward to toggle the forward on or off.
 */
native HamHook:RegisterHam(Ham:function, const EntityClass[], const Callback[], Post=0, bool:specialbot = false);

For convenience a stock to make more intuitive registering a function on "player":

Stock Description
RegisterHamPlayer  Hooks the virtual table for the player class.
/**
 * Hooks the virtual table for the player class.
 * An example would be: RegisterHam(Ham_TakeDamage, "player_hurt");
 * Look at the Ham enum for parameter lists.
 *
 * @param function		The function to hook.
 * @param callback		The forward to call.
 * @param post			Whether or not to forward this in post.
 * @return 				Returns a handle to the forward.  Use EnableHamForward/DisableHamForward to toggle the forward on or off.
 */
stock HamHook:RegisterHamPlayer(Ham:function, const Callback[], Post=0)
{
    return RegisterHam(function, "player", Callback, Post, true);
}

Virtual function

A lot of missing virtual functions have been added for all games.
Some of the existing common functions have been renamed because they are mod-dependent.

Short overview:

  • Common
Ham_ChangeYaw
Ham_HasHumanGibs
Ham_HasAlienGibs
Ham_FadeMonster
Ham_GibMonster
Ham_BecomeDead
Ham_IRelationship
Ham_PainSound
Ham_ReportAIState
Ham_MonsterInitDead
Ham_Look
Ham_BestVisibleEnemy
Ham_FInViewCone
Ham_FVecInViewCone
Ham_GetDeathActivity
Ham_Item_GetItemInfo
  • Common (not supported by Counter-Strike, The Specialists and Natural Selection mods)
Ham_RunAI,
Ham_MonsterThink,
Ham_MonsterInit,
Ham_CheckLocalMove,
Ham_Move,
Ham_MoveExecute,
Ham_ShouldAdvanceRoute,
Ham_GetStoppedActivity,
Ham_Stop,
Ham_CheckRangeAttack1,
Ham_CheckRangeAttack2,
Ham_CheckMeleeAttack1,
Ham_CheckMeleeAttack2,
Ham_ScheduleChange,
Ham_CanPlaySequence,
Ham_CanPlaySentence,
Ham_PlaySentence,
Ham_PlayScriptedSentence,
Ham_SentenceStop,
Ham_GetIdealState,
Ham_SetActivity,
Ham_CheckEnemy,
Ham_FTriangulate,
Ham_SetYawSpeed,
Ham_BuildNearestRoute,
Ham_FindCover,
Ham_CoverRadius,
Ham_FCanCheckAttacks,
Ham_CheckAmmo,
Ham_IgnoreConditions,
Ham_FValidateHintType,
Ham_FCanActiveIdle,
Ham_ISoundMask,
Ham_HearingSensitivity,
Ham_BarnacleVictimBitten,
Ham_BarnacleVictimReleased,
Ham_PrescheduleThink,
Ham_DeathSound,
Ham_AlertSound,
Ham_IdleSound,
Ham_StopFollowing,
  • Specific to Counter-Strike
Ham_CS_Item_IsWeapon
Ham_CS_Weapon_SendWeaponAnim
Ham_CS_Player_ResetMaxSpeed
Ham_CS_Player_IsBot
Ham_CS_Player_GetAutoaimVector
Ham_CS_Player_Blind
Ham_CS_Player_OnTouchingWeapon
  • Specific to Day Of Defeat
Ham_DOD_SetScriptReset
Ham_DOD_Item_SpawnDeploy
Ham_DOD_Item_SetDmgTime
Ham_DOD_Item_DropGren
Ham_DOD_Weapon_IsUseable
Ham_DOD_Weapon_Aim
Ham_DOD_Weapon_flAim
Ham_DOD_Weapon_RemoveStamina
Ham_DOD_Weapon_ChangeFOV
Ham_DOD_Weapon_ZoomOut
Ham_DOD_Weapon_ZoomIn
Ham_DOD_Weapon_GetFOV
Ham_DOD_Weapon_PlayerIsWaterSniping
Ham_DOD_Weapon_UpdateZoomSpeed
Ham_DOD_Weapon_Special
Ham_DOD_Weapon_SendWeaponAnim
  • Specific to Earth's Special Forces
Ham_ESF_IsFighter
Ham_ESF_IsBuddy
Ham_ESF_EmitSound
Ham_ESF_EmitNullSound
Ham_ESF_IncreaseStrength
Ham_ESF_IncreasePL
Ham_ESF_SetPowerLevel
Ham_ESF_SetMaxPowerLevel
Ham_ESF_StopAniTrigger
Ham_ESF_StopFly
Ham_ESF_HideWeapon
Ham_ESF_ClientRemoveWeapon
Ham_ESF_SendClientsCustomModel
Ham_ESF_CanTurbo
Ham_ESF_CanPrimaryFire
Ham_ESF_CanSecondaryFire
Ham_ESF_CanStopFly
Ham_ESF_CanBlock
Ham_ESF_CanRaiseKi
Ham_ESF_CanRaiseStamina
Ham_ESF_CanTeleport
Ham_ESF_CanStartFly
Ham_ESF_CanStartPowerup
Ham_ESF_CanJump
Ham_ESF_CanWallJump
Ham_ESF_IsSuperJump
Ham_ESF_IsMoveBack
Ham_ESF_CheckWallJump
Ham_ESF_EnableWallJump
Ham_ESF_DisableWallJump
Ham_ESF_ResetWallJumpVars
Ham_ESF_GetWallJumpAnim
Ham_ESF_GetWallJumpAnim2
Ham_ESF_SetWallJumpAnimation
Ham_ESF_SetFlyMoveType
Ham_ESF_IsFlyMoveType
Ham_ESF_IsWalkMoveType
Ham_ESF_SetWalkMoveType
Ham_ESF_DrawChargeBar
Ham_ESF_StartBlock
Ham_ESF_StopBlock
Ham_ESF_StartFly
Ham_ESF_GetMaxSpeed
Ham_ESF_SetAnimation
Ham_ESF_PlayAnimation
Ham_ESF_GetMoveForward
Ham_ESF_GetMoveRight
Ham_ESF_GetMoveUp
Ham_ESF_AddBlindFX
Ham_ESF_RemoveBlindFX
Ham_ESF_DisablePSBar
Ham_ESF_AddBeamBoxCrosshair
Ham_ESF_RemoveBeamBoxCrosshair
Ham_ESF_DrawPSWinBonus
Ham_ESF_DrawPSBar
Ham_ESF_LockCrosshair
Ham_ESF_UnLockCrosshair
Ham_ESF_RotateCrosshair
Ham_ESF_UnRotateCrosshair
Ham_ESF_WaterMove
Ham_ESF_CheckTimeBasedDamage
Ham_ESF_DoesSecondaryAttack
Ham_ESF_DoesPrimaryAttack
Ham_ESF_RemoveSpecialModes
Ham_ESF_StopTurbo
Ham_ESF_TakeBean
Ham_ESF_GetPowerLevel
Ham_ESF_RemoveAllOtherWeapons
Ham_ESF_StopSwoop
Ham_ESF_SetDeathAnimation
Ham_ESF_SetModel
Ham_ESF_AddAttacks
Ham_ESF_EmitClassSound
Ham_ESF_CheckLightning
Ham_ESF_FreezeControls
Ham_ESF_UnFreezeControls
Ham_ESF_UpdateKi
Ham_ESF_UpdateHealth
Ham_ESF_GetTeleportDir
Ham_ESF_Weapon_HolsterWhenMeleed
  • Specific to Natural Selection
Ham_NS_SetBoneController
Ham_NS_SaveDataForReset
Ham_NS_GetHull
Ham_NS_GetMaxWalkSpeed
Ham_NS_SetTeamID
Ham_NS_GetEffectivePlayerClass
Ham_NS_GetAuthenticationMask
Ham_NS_EffectivePlayerClassChanged
Ham_NS_NeedsTeamUpdate
Ham_NS_SendTeamUpdate
Ham_NS_SendWeaponUpdate
Ham_NS_InitPlayerFromSpawn
Ham_NS_PackDeadPlayerItems
Ham_NS_GetAnimationForActivity
Ham_NS_StartObserver
Ham_NS_StopObserver
Ham_NS_GetAdrenalineFactor
Ham_NS_GiveNamedItem
Ham_NS_Suicide
Ham_NS_GetCanUseWeapon
Ham_NS_Weapon_GetWeaponPrimeTime
Ham_NS_Weapon_PrimeWeapon
Ham_NS_Weapon_GetIsWeaponPrimed
Ham_NS_Weapon_GetIsWeaponPriming
Ham_NS_Weapon_DefaultDeploy
Ham_NS_Weapon_DefaultReload
Ham_NS_Weapon_GetDeployTime
  • Specific to Sven Coop
Ham_SC_GetClassification,
Ham_SC_IsMonster,
Ham_SC_IsPhysX,
Ham_SC_IsPointEntity,
Ham_SC_IsMachine,
Ham_SC_CriticalRemove,
Ham_SC_UpdateOnRemove,
Ham_SC_FVisible,
Ham_SC_FVisibleFromPos,
Ham_SC_IsFacings,
Ham_SC_GetPointsForDamage,
Ham_SC_GetDamagePoints,
Ham_SC_OnCreate,
Ham_SC_OnDestroy,
Ham_SC_IsValidEntity,
Ham_SC_ShouldFadeOnDeath,
Ham_SC_SetupFriendly,
Ham_SC_ReviveThink,
Ham_SC_Revive,
Ham_SC_StartMonster,
Ham_SC_CheckRangeAttack1_Move,
Ham_SC_CheckRangeAttack2_Move,
Ham_SC_CheckMeleeAttack1_Move,
Ham_SC_CheckMeleeAttack2_Move,
Ham_SC_CheckTankUsage,
Ham_SC_SetGaitActivity,
Ham_SC_FTriangulate,
Ham_SC_FTriangulateExtension,
Ham_SC_FindCoverGrenade,
Ham_SC_FindCoverDistance,
Ham_SC_FindAttackPoint,
Ham_SC_FValidateCover,
Ham_SC_NoFriendlyFire1,
Ham_SC_NoFriendlyFire2,
Ham_SC_NoFriendlyFire3,
Ham_SC_NoFriendlyFireToPos,
Ham_SC_FVisibleGunPos,
Ham_SC_FInBulletCone,
Ham_SC_CallGibMonster,
Ham_SC_CheckTimeBasedDamage,
Ham_SC_IsMoving,
Ham_SC_IsPlayerFollowing,
Ham_SC_StartPlayerFollowing,
Ham_SC_StopPlayerFollowing,
Ham_SC_UseSound,
Ham_SC_UnUseSound,
Ham_SC_RideMonster,
Ham_SC_CheckApplyGenericAttacks,
Ham_SC_CheckScared,
Ham_SC_CheckCreatureDanger,
Ham_SC_CheckFallDamage,
Ham_SC_CheckRevival,
Ham_SC_MedicCallSound,
 
Ham_SC_Player_MenuInputPerformed,
Ham_SC_Player_IsMenuInputDone,
Ham_SC_Player_SpecialSpawn,
Ham_SC_Player_IsValidInfoEntity,
Ham_SC_Player_LevelEnd,
Ham_SC_Player_VoteStarted,
Ham_SC_Player_CanStartNextVote,
Ham_SC_Player_Vote,
Ham_SC_Player_HasVoted,
Ham_SC_Player_ResetVote,
Ham_SC_Player_LastVoteInput,
Ham_SC_Player_InitVote,
Ham_SC_Player_TimeToStartNextVote,
Ham_SC_Player_ResetView,
Ham_SC_Player_GetLogFrequency,
Ham_SC_Player_LogPlayerStats,
Ham_SC_Player_DisableCollisionWithPlayer,
Ham_SC_Player_EnableCollisionWithPlayer,
Ham_SC_Player_CanTouchPlayer,
 
Ham_SC_Item_Materialize,
 
Ham_SC_Weapon_BulletAccuracy,
Ham_SC_Weapon_TertiaryAttack,
Ham_SC_Weapon_BurstSupplement,
Ham_SC_Weapon_GetP_Model,
Ham_SC_Weapon_GetW_Model,
Ham_SC_Weapon_GetV_Model,
Ham_SC_Weapon_PrecacheCustomModels,
Ham_SC_Weapon_IsMultiplayer,
Ham_SC_Weapon_FRunfuncs,
Ham_SC_Weapon_SetFOV,
Ham_SC_Weapon_FCanRun,
Ham_SC_Weapon_CustomDecrement,
Ham_SC_Weapon_SetV_Model,
Ham_SC_Weapon_SetP_Model,
Ham_SC_Weapon_ChangeWeaponSkin,
 
Ham_SC_TakeHealth,
Ham_SC_TakeArmor,
Ham_SC_GiveAmmo,
Ham_SC_CheckAttacker,
Ham_SC_Player_IsConnected,
 
Ham_SC_PreSpawn,
Ham_SC_PostSpawn,
Ham_SC_OnKeyValueUpdate,
Ham_SC_SetClassification,
Ham_SC_IsTriggered,
Ham_SC_MyCustomPointer,
Ham_SC_MyItemPointer,
Ham_SC_AddPoints,
Ham_SC_AddPointsToTeam,
Ham_SC_RemovePlayerItem,
Ham_SC_OnControls,
Ham_SC_IsSneaking,
Ham_SC_IsAlive,
Ham_SC_IsBSPModel,
Ham_SC_ReflectGauss,
Ham_SC_HasTarget,
Ham_SC_IsInWorld,
Ham_SC_IsPlayer,
Ham_SC_IsNetClient,
Ham_SC_IsBreakable,
Ham_SC_SUB_UseTargets,
Ham_SC_IsLockedByMaster,
Ham_SC_FBecomeProne,
Ham_SC_FVecVisible,
Ham_SC_SetPlayerAlly,
Ham_SC_OnSetOriginByMap,
Ham_SC_IsRevivable,
Ham_SC_BeginRevive,
Ham_SC_EndRevive,
Ham_SC_CanPlaySequence,
Ham_SC_CanPlaySentence2,
Ham_SC_PlayScriptedSentence,
Ham_SC_Item_AddToPlayer,
Ham_SC_Item_AddDuplicate,
Ham_SC_Item_AddAmmoFromItem,
Ham_SC_Item_GetPickupSound,
Ham_SC_Item_CanCollect,
Ham_SC_Item_Collect,
Ham_SC_Item_GetItemInfo,
Ham_SC_Item_CanDeploy,
Ham_SC_Item_Deploy,
Ham_SC_Item_CanHolster,
Ham_SC_Item_InactiveItemPreFrame,
Ham_SC_Item_InactiveItemPostFrame,
Ham_SC_Item_DetachFromPlayer,
Ham_SC_Item_UpdateClientData,
Ham_SC_Item_GetRespawnTime,
Ham_SC_Item_CanHaveDuplicates,
Ham_SC_Weapon_ExtractAmmoFromItem,
Ham_SC_Weapon_AddWeapon,
Ham_SC_Weapon_GetAmmo1Drop,
Ham_SC_Weapon_GetAmmo2Drop,
Ham_SC_Weapon_PlayEmptySound,
Ham_SC_Weapon_IsUsable,
Ham_SC_Weapon_FinishReload,
Ham_SC_Weapon_ShouldReload,
Ham_SC_Weapon_ShouldWeaponIdle,
Ham_SC_Weapon_UseDecrement,
Ham_SC_Player_EnteredObserver,
Ham_SC_Player_LeftObserver,
Ham_SC_Player_IsObserver,
  • Specific to Opposing Force
Ham_OPF_MySquadTalkMonsterPointer
Ham_OPF_WeaponTimeBase
  • Specific to Team Fortress Classic
Ham_TFC_DB_GetItemName
Ham_TFC_IsTriggered
Ham_TFC_Killed
Ham_TFC_RadiusDamage
Ham_TFC_RadiusDamage2
Ham_TFC_Weapon_GetNextAttackDelay
Ham_TFC_Weapon_SendWeaponAnim
  • Specific to The Specialists
Ham_TS_Weapon_AlternateAttack

See ham_const.inc for a full list (it starts from line 1182).

MySQL

Connectivity

To improve the connectivity, few features have been added.

Feature Description
Reconnection This has MySQL automatically reconnects if times out or loses connection through MYSQL_OPT_RECONNECT option.
This should prevent "MySQL server has gone away" errors after a while.
Timeout This establishes a default read/write timeout for MySQL connectivity through MYSQL_OPT_CONNECT_TIMEOUT option.
A new option to set globally the timeout (60s by default) can be found in core.ini and a new amx_sql_timeout cvar in sql.cfg .
; MySQL default timeout
mysql_timeout 60
amx_sql_timeout "60"

Miscellaneous

  • Module threading has been updated to be more responsive. This should help in reducing potential hang up in situations such as on change map or lost connection.

Character Set

Stock Description
MySQL_SetCharset  Sets the character set of the current connection.
/**
 * Sets the character set of the current connection.
 * Like SET NAMES .. in mysql, but stays after connection problems.
 *
 * If a connection tuple is supplied, this should be called before SQL_Connect or SQL_ThreadQuery.
 * Also note the change will remain until you call this function with another value.
 * This native does nothing in SQLite.
 *
 * Example: "utf8", "latin1"
 *
 * @param h					Database or connection tuple Handle.
 * @param charset			The character set string to change to.
 * @return					True, if character set was changed, false otherwise.
 */
native bool:SQL_SetCharset(Handle:h, const charset[]);


RegEx

Library

The internal PCRE library version has been updated from 6.4 to 8.35 and has been compiled with UTF-8 support.
If you are interested, see the changelog.

Miscellaneous

  • regex_subtr: The internal static buffer has been increased to match the same size as core and has been made UTF-8 safe.
  • The maximum number of sub-patterns has been increased from 30 to 150.

New Natives & Stocks

Native Description
regex_compile_ex  Precompiles a regular expression.
Note:Similar as regex_compile/_c but with the differences that you can use directly PCRE_* flags and the error parameter is an integer associated to REGEX_ERROR_* flags.
/**
 * Precompiles a regular expression.
 *
 * @note  Use this if you intend on using the same expression multiple times.
 *        Pass the regex handle returned here to regex_match_c() to check for matches.
 *
 * @note  Unlike regex_compile(), this allows you to use PCRE flags directly.
 *
 * @param pattern       The regular expression pattern.
 * @param flags         General flags for the regular expression, see PCRE_* defines.
 * @param error         Error message encountered, if applicable.
 * @param maxLen        Maximum string length of the error buffer.
 * @param errcode       Regex type error code encountered, if applicable. See REGEX_ERROR_* defines.
 *
 * @return              Valid regex handle (> 0) on success, or -1 on failure.
 */
native Regex:regex_compile_ex(const pattern[], flags = 0, error[]= "", maxLen = 0, &errcode = 0);
/**
 * Flags for compiling regex expressions.
 * These come directly from the pcre library and can be used in regex_compile_ex.
 */
#define PCRE_CASELESS           0x00000001  /* Ignore Case */
#define PCRE_MULTILINE          0x00000002  /* Multilines (affects ^ and $ so that they match the start/end of a line rather than matching the start/end of the string). */
#define PCRE_DOTALL             0x00000004  /* Single line (affects . so that it matches any character, even new line characters). */
#define PCRE_EXTENDED           0x00000008  /* Pattern extension (ignore whitespace and # comments). */
#define PCRE_ANCHORED           0x00000010  /* Force pattern anchoring. */
#define PCRE_DOLLAR_ENDONLY     0x00000020  /* $ not to match newline at end. */
#define PCRE_UNGREEDY           0x00000200  /* Invert greediness of quantifiers */
#define PCRE_NOTEMPTY           0x00000400  /* An empty string is not a valid match. */
#define PCRE_UTF8               0x00000800  /* Use UTF-8 Chars */
#define PCRE_NO_UTF8_CHECK      0x00002000  /* Do not check the pattern for UTF-8 validity (only relevant if PCRE_UTF8 is set) */
#define PCRE_NEVER_UTF          0x00010000  /* Lock out interpretation of the pattern as UTF-8 */
#define PCRE_FIRSTLINE          0x00040000  /* Force matching to be before newline */
#define PCRE_DUPNAMES           0x00080000  /* Allow duplicate names for subpattern */
#define PCRE_NEWLINE_CR         0x00100000  /* Specify that a newline is indicated by a single character CR           )                            */
#define PCRE_NEWLINE_CRLF       0x00300000  /* specify that a newline is indicated by the two-character CRLF sequence )  Overrides the default     */
#define PCRE_NEWLINE_ANY        0x00400000  /* Specify that any Unicode newline sequence should be recognized.        )  newline definition (LF)   */
#define PCRE_NEWLINE_ANYCRLF    0x00500000  /* Specify that any of CR, LF and CRLF sequences should be recognized     )                            */
#define PCRE_UCP                0x20000000  /* Change the way PCRE processes \B, \b, \D, \d, \S, \s, \W, \w etc. to use Unicode properties */
/**
 * Regex expression error codes.
 * This can be used with regex_compile_ex and regex_match_ex.
 */
enum /*RegexError*/
{
    REGEX_ERROR_NONE           =  0,    /* No error */
    REGEX_ERROR_NOMATCH        = -1,    /* No match was found */
    REGEX_ERROR_NULL           = -2,
    REGEX_ERROR_BADOPTION      = -3,
    REGEX_ERROR_BADMAGIC       = -4,
    REGEX_ERROR_UNKNOWN_OPCODE = -5,
    REGEX_ERROR_NOMEMORY       = -6,
    REGEX_ERROR_NOSUBSTRING    = -7,
    REGEX_ERROR_MATCHLIMIT     = -8,
    REGEX_ERROR_CALLOUT        = -9,    /* Never used by PCRE itself */
    REGEX_ERROR_BADUTF8        = -10,
    REGEX_ERROR_BADUTF8_OFFSET = -11,
    REGEX_ERROR_PARTIAL        = -12,
    REGEX_ERROR_BADPARTIAL     = -13,
    REGEX_ERROR_INTERNAL       = -14,
    REGEX_ERROR_BADCOUNT       = -15,
    REGEX_ERROR_DFA_UITEM      = -16,
    REGEX_ERROR_DFA_UCOND      = -17,
    REGEX_ERROR_DFA_UMLIMIT    = -18,
    REGEX_ERROR_DFA_WSSIZE     = -19,
    REGEX_ERROR_DFA_RECURSE    = -20,
    REGEX_ERROR_RECURSIONLIMIT = -21,
    REGEX_ERROR_NULLWSLIMIT    = -22,   /* No longer actually used */
    REGEX_ERROR_BADNEWLINE     = -23,
    REGEX_ERROR_BADOFFSET      = -24,
    REGEX_ERROR_SHORTUTF8      = -25,
    REGEX_ERROR_RECURSELOOP    = -26,
    REGEX_ERROR_JIT_STACKLIMIT = -27,
    REGEX_ERROR_BADMODE        = -28,
    REGEX_ERROR_BADENDIANNESS  = -29,
    REGEX_ERROR_DFA_BADRESTART = -30,
    REGEX_ERROR_JIT_BADOPTION  = -31,
    REGEX_ERROR_BADLENGTH      = -32,
    REGEX_ERROR_UNSET          = -33
};
regex_match_all
regex_match_all_c
 Matches a string against a regular (compiled) expression pattern, matching all occurrences of the pattern inside the string.
Note:This is similar to using the g flag in perl regex.
/**
 * Matches a string against a regular expression pattern, matching all occurrences of the
 * pattern inside the string. This is similar to using the "g" flag in perl regex.
 *
 * @note  If you intend on using the same regular expression pattern
 *        multiple times, consider using regex_compile and regex_match_ex
 *        instead of making this function reparse the expression each time.
 *
 * @note  Flags only exist in amxmodx 1.8 and later.
 *
 * @note  You should free the returned handle with regex_free()
 *        when you are done extracting all of the substrings.
 *
 * @param string        The string to check.
 * @param pattern       The regular expression pattern.
 * @param flags         General flags for the regular expression, see PCRE_* defines.
 * @param error         Error message encountered, if applicable.
 * @param maxLen        Maximum string length of the error buffer.
 * @param errcode       Regex type error code encountered, if applicable. See REGEX_ERROR_* defines.
 *
 * @return              -2 = Matching error (error code is stored in ret)
 *                      -1 = Error in pattern (error message and offset # in error and ret)
 *                       0 = No match.
 *                      >1 = Handle for getting more information (via regex_substr)
 */
native Regex:regex_match_all(const string[], const pattern[], flags = 0, error[]= "", maxLen = 0, &errcode = 0);
 
/**
 * Matches a string against a pre-compiled regular expression pattern, matching all
 * occurrences of the pattern inside the string. This is similar to using the "g" flag
 * in perl regex.
 *
 * @note  You should free the returned handle (with regex_free())
 *        when you are done with this pattern.
 *
 * @note  Use the regex handle passed to this function to extract
 *        matches with regex_substr().
 *
 * @param pattern       The regular expression pattern.
 * @param string        The string to check.
 * @param ret           Error code, if applicable, or number of results on success.
 *                      See REGEX_ERROR_* defines.
 *
 * @return              -2 = Matching error (error code is stored in ret)
 *                       0 = No match.
 *                      >1 = Number of results.
 */
native regex_match_all_c(const string[], Regex:pattern, &ret = 0);
Stock Description
regex_match_simple  Matches a string against a regular expression pattern. Useful if you need to use the pattern one time.}
/**
 * Matches a string against a regular expression pattern.
 *
 * @note  If you intend on using the same regular expression pattern
 *        multiple times, consider using compile regex_compile_ex and regex_match*
 *        instead of making this function reparse the expression each time.
 *
 * @param str           The string to check.
 * @param pattern       The regular expression pattern.
 * @param flags         General flags for the regular expression.
 * @param error         Error message, if applicable.
 * @param maxLen        Maximum length of the error buffer.
 * @param errcode       Regex type error code encountered, if applicable. See REGEX_ERROR_* defines.
 *
 * @return              -2 = Matching error (error code is stored in ret)
 *                      -1 = Pattern error (error code is stored in ret)
 *                       0 = No match.
 *                      >1 = Number of results.
 */
stock regex_match_simple(const str[], const pattern[], flags = 0, error[]= "", maxLen = 0, &errcode = 0)
{
    new Regex:regex = regex_compile_ex(pattern, flags, error, maxLen, errcode);
    if (regex < REGEX_OK)
    {
        return -1;
    }
    new substrings = regex_match_c(str, regex);
    regex_free(regex);
    return substrings;
}


Socket

  • WinSock is now update from version 1.1 to 2.2
  • Natives won't be registered if WinSock can't be started

Improvements

Native Parameter Description
socket_open _flags

The following flags are additive:

  • SOCK_NON_BLOCKING: if set, the socket will be on nonblocking mode
  • SOCK_LIBC_ERRORS: f set, the new libc errors will be seen on _error
/**
 * Error reporting
 */
#define SOCK_ERROR_OK               0 /* No error */
#define SOCK_ERROR_CREATE_SOCKET    1 /* Couldn't create a socket */
#define SOCK_ERROR_SERVER_UNKNOWN   2 /* Server unknown */
#define SOCK_ERROR_WHILE_CONNECTING 3 /* Error while connecting */
 
/**
 * Connects to the given node and service via TCP/UDP.
 *
 * @note There's 2 types of error reporting on this function that you can use.
 * @note Default error codes:
 *       0 - No error
 *       1 - Error while creating socket
 *       2 - Couldn't resolve hostname
 *       3 - Couldn't connect
 * @note New, more expressive libc error codes:
 *       https://www.gnu.org/software/libc/manual/html_node/Error-Codes.html
 *       https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/errno.h
 *       https://msdn.microsoft.com/en-us/library/ms740668.aspx
 *
 * @note The currently available bit flags are:
 *       - SOCK_NON_BLOCKING : if set, the socket will be on nonblocking mode
 *       - SOCK_LIBC_ERRORS : if set, the new libc errors will be seen on _error
 *
 * @note If no flags are set, the behaviour of the function will not be modified.
 *
 * @note Multiple flags may be set at the same time using the | operator. 
 *       For example, SOCK_NON_BLOCKING|SOCK_LIBC_ERRORS will create a nonblocking socket with libc error codes.
 *
 * @note If you're creating a new nonblocking socket, _hostname should be numeric to avoid calling the 
 *       name resolution server and potentially blocking the call.
 *
 * @note If the socket is a nonblocking one, the returned socket descriptor may be still connecting and 
 *       further checks should be done with socket_is_writable() before trying to send data.
 *
 * @param _hostname    Node to connect to
 * @param _port        Service to connect to
 * @param _protocol    Connect via SOCKET_TCP or SOCKET_UDP
 * @param _error       Set an error code here if anything goes wrong
 * @param _flags       Optional bit flags that change the behaviour of the function
 *
 * @return             A socket descriptor (a positive integer) on success
 *                     -1 on failure
*/
native socket_open(const _hostname[], _port, _protocol = SOCKET_TCP, &_error, _flags = 0);
Note:An example is available at PR 301

New natives

Native Description
socket_is_writable  Checks if a socket is marked as writable.
/**
 * Checks if a socket is marked as writable.
 *
 * @note Use this function to check if a nonblocking socket is ready to be used.
 * @note Set _timeout to 0 avoid blocking the call.
 * @note An UDP socket is always writable.
 *
 * @param _socket    Socket descriptor
 * @param _timeout   Amount of time to block the call waiting for the socket to be marked as writable or
 *                   for the timeout to expire, in µSeconds (1 sec = 1000000 µsec)
 *
 * @return           1 if the socket is marked as writable
 *                   0 otherwise
 */
native socket_is_writable(_socket, _timeout = 100000);
socket_is_readable  Checks if a socket is marked as readable.
Note:This function is an alias of socket_change which is now deprecated.
/**
 * Checks if a socket is marked as readable.
 *
 * @note You can use this function to make sure there's something on the socket and avoid a blocking call.
 * @note Set _timeout to 0 avoid blocking the call.
 * @note A socket will become readable if there's any data or an EOF.
 *
 * @param _socket    Socket descriptor
 * @param _timeout   Amount of time to block the call waiting for the socket to be marked as readable or
 *                   for the timeout to expire, in µSeconds (1 sec = 1000000 µsec)
 *
 * @return           1 if the socket is marked as readable
 *                   0 otherwise
 */
native socket_is_readable(_socket, _timeout = 100000);


SQLite

Library

The SQLite library version has been updated from 3.3.13 to 3.24.0.
If you are interested, see the changelog.

Character Set

Stock Description
SQL_SetCharset  Sets the character set of the current connection.
/**
 * Sets the character set of the current connection.
 * Like SET NAMES .. in mysql, but stays after connection problems.
 *
 * If a connection tuple is supplied, this should be called before SQL_Connect or SQL_ThreadQuery.
 * Also note the change will remain until you call this function with another value.
 * This native does nothing in SQLite.
 *
 * Example: "utf8", "latin1"
 *
 * @param h					Database or connection tuple Handle.
 * @param charset			The character set string to change to.
 * @return					True, if character set was changed, false otherwise.
 */
native bool:SQL_SetCharset(Handle:h, const charset[]);

Miscellaneous

  • The queuetime value is now properly passed to the SQL_ThreadQuery callback.

New module

JSON

A JSON module is now part of the official AMX Mod X package.

Essentially:

  • Supports decoding and encoding (also with pretty format)
  • Relies on Parson, which is lighweight and simple JSON library written in C
  • Supports dot notation (Values can be accessed by typing objectA.objectB.value)
  • Allows us to iterate through arrays and objects
Note:Examples are available on Github an in the testsuite directory, see textparse.sma.
Native Description
General
json_parse  Parses JSON string or a file that contains JSON.
/**
 * Parses JSON string or a file that contains JSON.
 *
 * @note                    Needs to be freed using json_free() native.
 *
 * @param string            String to parse
 * @param is_file           True to treat string param as filename, false otherwise
 * @param with_comments     True if parsing JSON includes comments (it will ignore them), false otherwise
 *
 * @return                  JSON handle, Invalid_JSONValue if error occurred
 */
native JSON:json_parse(const string[], bool:is_file = false, bool:with_comments = false);
json_equals  Checks if the first value is the same as the second one.
/**
 * Checks if the first value is the same as the second one.
 *
 * @param value1            JSON handle
 * @param value2            JSON handle
 *
 * @return                  True if they are the same, false otherwise
 * @error                   If passed value is not a valid handle
 */
native bool:json_equals(const JSON:value1, const JSON:value2);
json_validate  Validates json by checking if object have identically named fields with matching types.
/**
 * Validates json by checking if object have identically named
 * fields with matching types.
 *
 * @note                    Schema {"name":"", "age":0} will validate
 *                          {"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"},
 *                          but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}.
 *
 * @note                    In case of arrays, only first value in schema
 *                          is checked against all values in tested array.
 *
 * @note                    Empty objects ({}) validate all objects,
 *                          empty arrays ([]) validate all arrays,
 *                          null validates values of every type.
 *
 * @param schema            JSON handle
 * @param value             JSON handle
 *
 * @return                  True if passed value is valid, false otherwise
 * @error                   If a schema handle or value handle is invalid
 */
native bool:json_validate(const JSON:schema, const JSON:value);
json_get_parent  Gets value's parent handle.
/**
 * Gets value's parent handle.
 *
 * @note                  Parent's handle needs to be freed using json_free() native.
 *
 * @param value           JSON handle
 *
 * @return                Parent's handle
 */
native JSON:json_get_parent(const JSON:value);
json_get_type  Gets JSON type of passed value.
/**
 * Gets JSON type of passed value.
 *
 * @param value             JSON handle
 *
 * @return                  JSON type (JSONType constants)
 * @error                   If a value handle is invalid
 */
native JSONType:json_get_type(const JSON:value);
json_init_object
json_init_array
json_init_string
json_init_number
json_init_real
json_init_bool
 Inits an empty object.
/**
 * Inits an empty object.
 *
 * @note                    Needs to be freed using json_free() native.
 *
 * @return                  JSON handle, Invalid_JSON if error occurred
 */
native JSON:json_init_object();
 Inits an empty array.
/**
 * Inits an empty array.
 *
 * @note                    Needs to be freed using json_free() native.
 *
 * @return                  JSON handle, Invalid_JSON if error occurred
 */
native JSON:json_init_array();
 Inits string data.
/**
 * Inits string data.
 *
 * @note                    Needs to be freed using json_free() native.
 *
 * @param value             String that the handle will be initialized with
 *
 * @return                  JSON handle, Invalid_JSON if error occurred
 */
native JSON:json_init_string(const value[]);
 Inits a number.
/**
 * Inits a number.
 *
 * @note                    Needs to be freed using json_free() native.
 *
 * @param value             Integer number that the handle will be initialized with
 *
 * @return                  JSON handle, Invalid_JSON if error occurred
 */
native JSON:json_init_number(value);
 Inits a real number.
/**
 * Inits a real number.
 *
 * @note                    Needs to be freed using json_free() native.
 *
 * @param value             Real number that the handle will be initialized with
 *
 * @return                  JSON handle, Invalid_JSON if error occurred
 */
native JSON:json_init_real(Float:value);
 Inits a boolean value.
/**
 * Inits a boolean value.
 *
 * @note                    Needs to be freed using json_free() native.
 *
 * @param value             Boolean value that the handle will be initialized with
 *
 * @return                  JSON handle, Invalid_JSON if error occurred
 */
native JSON:json_init_bool(bool:value);
json_init_null  Inits a null.
/**
 * Inits a null.
 *
 * @note                    Needs to be freed using json_free() native.
 *
 * @return                  JSON handle, Invalid_JSON if error occurred
 */
native JSON:json_init_null();
json_deep_copy  Creates deep copy of passed value.
/**
 * Creates deep copy of passed value.
 *
 * @note                    Needs to be freed using json_free() native.
 *
 * @param value             JSON handle to be copied
 *
 * @return                  JSON handle, Invalid_JSON if error occurred
 * @error                   If passed value is not a valid handle
 */
native JSON:json_deep_copy(const JSON:value);
json_free  Frees handle.
/**
 * Frees handle.
 *
 * @param handle            JSON handle to be freed
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid handle
 */
native bool:json_free(&JSON:handle);
json_get_string
json_get_number
json_get_real
json_get_bool
 Gets string data.
/**
 * Gets string data.
 *
 * @param value             JSON handle
 * @param buffer            Buffer to copy string to
 * @param maxlen            Maximum size of the buffer
 *
 * @return                  The number of cells written to the buffer
 * @error                   If passed value is not a valid handle
 */
native json_get_string(const JSON:value, buffer[], maxlen);
 Gets a number.
/**
 * Gets a number.
 *
 * @param value             JSON handle
 *
 * @return                  Number
 * @error                   If passed value is not a valid handle
 */
native json_get_number(const JSON:value);
 Gets a real number.
/**
 * Gets a real number.
 *
 * @param value             JSON handle
 *
 * @return                  Real number
 * @error                   If passed value is not a valid handle
 */
native Float:json_get_real(const JSON:value);
 Gets a boolean value.
/**
 * Gets a boolean value.
 *
 * @param value             JSON handle
 *
 * @return                  Boolean value
 * @error                   If passed value is not a valid handle
 */
native bool:json_get_bool(const JSON:value);
Array
json_array_get_value
json_array_get_string
json_array_get_number
json_array_get_real
json_array_get_bool
json_array_get_count
 Gets a value from the array.
/**
 * Gets a value from the array.
 *
 * @note                    Needs to be freed using json_free() native.
 *
 * @param array             Array handle
 * @param index             Position in the array (starting from 0)
 *
 * @return                  JSON handle, Invalid_JSON if error occurred
 * @error                   If passed handle is not a valid array
 */
native JSON:json_array_get_value(const JSON:array, index);
 Gets string data from the array.
/**
 * Gets string data from the array.
 *
 * @param array             Array handle
 * @param index             Position in the array (starting from 0)
 * @param buffer            Buffer to copy string to
 * @param maxlen            Maximum size of the buffer
 *
 * @return                  The number of cells written to the buffer
 * @error                   If passed handle is not a valid array
 */
native json_array_get_string(const JSON:array, index, buffer[], maxlen);
 Gets a number from the array.
/**
 * Gets a number from the array.
 *
 * @param array             Array handle
 * @param index             Position in the array (starting from 0)
 *
 * @return                  The number as integer
 * @error                   If passed handle is not a valid array
 */
native json_array_get_number(const JSON:array, index);
 Gets a real number from the array.
/**
 * Gets a real number from the array.
 *
 * @param array             Array handle
 * @param index             Position in the array (starting from 0)
 *
 * @return                  The number as float
 * @error                   If passed handle is not a valid array
 */
native Float:json_array_get_real(const JSON:array, index);
 Gets a boolean value from the array.
/**
 * Gets a boolean value from the array.
 *
 * @param array             Array handle
 * @param index             Position in the array (starting from 0)
 *
 * @return                  Boolean value
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_get_bool(const JSON:array, index);
 Gets count of the elements in the array.
/**
 * Gets count of the elements in the array.
 *
 * @param array             Array handle
 *
 * @return                  Number of elements in the array
 * @error                   If passed handle is not a valid array
 */
native json_array_get_count(const JSON:array);
json_array_replace_value
json_array_replace_string
json_array_replace_number
json_array_replace_real
json_array_replace_bool
json_array_replace_null
 Replaces an element in the array with value.
/**
 * Replaces an element in the array with value.
 *
 * @param array             Array handle
 * @param index             Position in the array to be replaced
 * @param value             JSON handle to set
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_replace_value(JSON:array, index, const JSON:value);
 Replaces an element in the array with string data.
/**
 * Replaces an element in the array with string data.
 *
 * @param array             Array handle
 * @param index             Position in the array to be replaced
 * @param string            String to copy
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_replace_string(JSON:array, index, const string[]);
 Replaces an element in the array with number.
/**
 * Replaces an element in the array with number.
 *
 * @param array             Array handle
 * @param index             Position in the array to be replaced
 * @param number            Number to set
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_replace_number(JSON:array, index, number);
 Replaces an element in the array with real number.
/**
 * Replaces an element in the array with real number.
 *
 * @param array             Array handle
 * @param index             Position in the array to be replaced
 * @param number            Real number to set
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_replace_real(JSON:array, index, Float:number);
 Replaces an element in the array with boolean value.
/**
 * Replaces an element in the array with boolean value.
 *
 * @param array             Array handle
 * @param index             Position in the array to be replaced
 * @param boolean           Boolean value to set
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_replace_bool(JSON:array, index, bool:boolean);
 Replaces an element in the array with null.
/**
 * Replaces an element in the array with null.
 *
 * @param array             Array handle
 * @param index             Position in the array to be replaced
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_replace_null(JSON:array, index);
json_array_append_value
json_array_append_string
json_array_append_number
json_array_append_real
json_array_append_bool
json_array_append_null
 Appends a value in the array.
/**
 * Appends a value in the array.
 *
 * @param array             Array handle
 * @param value             JSON handle to set
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_append_value(JSON:array, const JSON:value);
 Appends string data in the array.
/**
 * Appends string data in the array.
 *
 * @param array             Array handle
 * @param string            String to copy
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_append_string(JSON:array, const string[]);
 Appends a number in the array.
/**
 * Appends a number in the array.
 *
 * @param array             Array handle
 * @param number            Number to set
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_append_number(JSON:array, number);
 Appends a real number in the array.
/**
 * Appends a real number in the array.
 *
 * @param array             Array handle
 * @param number            Real number to set
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_append_real(JSON:array, Float:number);
 Appends a boolean value in the array.
/**
 * Appends a boolean value in the array.Appends a boolean value in the array.
 *
 * @param array             Array handle
 * @param boolean           Boolean value to set
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_append_bool(JSON:array, bool:boolean);
 Appends a null in the array.
/**
 * Appends a null in the array.
 *
 * @param array             Array handle
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_append_null(JSON:array);
json_array_remove  Removes an element from the array.
/**
 * Removes an element from the array.
 *
 * @note                    Order of values in array may change during execution.
 *
 * @param array             Array handle
 * @param index             Position in the array (starting from 0)
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_remove(JSON:array, index);
json_array_clear  Removes all elements from the array.
/**
 * Removes all elements from the array.
 *
 * @param array             Array handle
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid array
 */
native bool:json_array_clear(JSON:array);
Object
json_object_get_value
json_object_get_string
json_object_get_number
json_object_get_real
json_object_get_bool
 Gets a value from the object.
/**
 * Gets a value from the object.
 *
 * @note                    Needs to be freed using json_free() native.
 * @note                    If dot notation is used some values may be inaccessible
 *                          because valid names in JSON can contain dots.
 *
 * @param object            Object handle
 * @param name              Key name
 * @param dot_not           True to use dot notation, false to not
 *
 * @return                  JSON handle, Invalid_JSON if error occurred
 * @error                   If passed handle is not a valid object
 */
native JSON:json_object_get_value(const JSON:object, const name[], bool:dot_not = false);
 Gets string data from the object.
/**
 * Gets string data from the object.
 *
 * @note                    If dot notation is used some values may be inaccessible
 *                          because valid names in JSON can contain dots.
 *
 * @param object            Object handle
 * @param name              Key name
 * @param buffer            Buffer to copy string to
 * @param maxlen            Maximum size of the buffer
 * @param dot_not           True to use dot notation, false to not
 *
 * @return                  The number of cells written to the buffer
 * @error                   If passed handle is not a valid object
 */
native json_object_get_string(const JSON:object, const name[], buffer[], maxlen, bool:dot_not = false);
 Gets a number from the object.
/**
 * Gets a number from the object.
 *
 * @note                    If dot notation is used some values may be inaccessible
 *                          because valid names in JSON can contain dots.
 *
 * @param object            Object handle
 * @param name              Key name
 * @param dot_not           True to use dot notation, false to not
 *
 * @return                  Number
 * @error                   If passed handle is not a valid object
 */
native json_object_get_number(const JSON:object, const name[], bool:dot_not = false);
 Gets a real number from the object.
/**
 * Gets a real number from the object.
 *
 * @note                    If dot notation is used some values may be inaccessible
 *                          because valid names in JSON can contain dots.
 *
 * @param object            Object handle
 * @param name              Key name
 * @param dot_not           True to use dot notation, false to not
 *
 * @return                  Real number
 * @error                   If passed handle is not a valid object
 */
native Float:json_object_get_real(const JSON:object, const name[], bool:dot_not = false);
 Gets a boolean value from the object.
/**
 * Gets a boolean value from the object.
 *
 * @note                    If dot notation is used some values may be inaccessible
 *                          because valid names in JSON can contain dots.
 *
 * @param object            Object handle
 * @param name              Key name
 * @param dot_not           True to use dot notation, false to not
 *
 * @return                  Boolean value
 * @error                   If passed handle is not a valid object
 */
native bool:json_object_get_bool(const JSON:object, const name[], bool:dot_not = false);
json_object_get_count
json_object_get_name
 Gets count of the keys in the object.
/**
 * Gets count of the keys in the object.
 *
 * @param object            Object handle
 *
 * @return                  Keys count
 * @error                   If passed handle is not a valid object
 */
native json_object_get_count(const JSON:object);
 Gets name of the object's key.
/**
 * Gets name of the object's key.
 *
 * @param object            Object handle
 * @param index             Position from which get key name
 * @param buffer            Buffer to copy string to
 * @param maxlen            Maximum size of the buffer
 *
 * @return                  The number of cells written to the buffer
 * @error                   If passed handle is not a valid object
 */
native json_object_get_name(const JSON:object, index, buffer[], maxlen);
json_object_get_value_at  Gets a value at the specified position from the object.
/**
 * Gets a value at the specified position from the object.
 *
 * @note                    Needs to be freed using json_free() native.
 *
 * @param object            Object handle
 * @param index             Position from which get key name
 * @param buffer            Buffer to copy string to
 * @param maxlen            Maximum size of the buffer
 *
 * @return                  The number of cells written to the buffer
 * @error                   If passed handle is not a valid object
 */
native JSON:json_object_get_value_at(const JSON:object, index);
json_object_has_value  Checks if the object has a value with a specific name and type.
/**
 * Checks if the object has a value with a specific name and type.
 *
 * @param object            Object handle
 * @param name              Key name
 * @param type              Type of value, if JSONError type will not be checked
 * @param dot_not           True to use dot notation, false to not
 *
 * @return                  True if has, false if not
 * @error                   If passed handle is not a valid object
 */
native bool:json_object_has_value(const JSON:object, const name[], JSONType:type = JSONError, bool:dot_not = false);
json_object_set_value
json_object_set_string
json_object_set_number
json_object_set_real
json_object_set_bool
json_object_set_null
 Sets a value in the object.
/**
 * Sets a value in the object.
 *
 * @note                    If dot notation is used some values may be inaccessible
 *                          because valid names in JSON can contain dots.
 * @note                    It also removes the old value if any.
 *
 * @param object            Object handle
 * @param name              Key name
 * @param value             JSON handle to set
 * @param dot_not           True to use dot notation, false to not
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid object
 */
native bool:json_object_set_value(JSON:object, const name[], const JSON:value, bool:dot_not = false);
 Sets string data in the object.
/**
 * Sets string data in the object.
 *
 * @note                    If dot notation is used some values may be inaccessible
 *                          because valid names in JSON can contain dots.
 * @note                    It also removes the old value if any.
 *
 * @param object            Object handle
 * @param name              Key name
 * @param string            String to copy
 * @param dot_not           True to use dot notation, false to not
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid object
 */
native bool:json_object_set_string(JSON:object, const name[], const string[], bool:dot_not = false);
 Sets a number in the object.
/**
 * Sets a number in the object.
 *
 * @note                    If dot notation is used some values may be inaccessible
 *                          because valid names in JSON can contain dots.
 * @note                    It also removes the old value if any.
 *
 * @param object            Object handle
 * @param name              Key name
 * @param number            Number to set
 * @param dot_not           True to use dot notation, false to not
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid object
 */
native bool:json_object_set_number(JSON:object, const name[], number, bool:dot_not = false);
 Sets a real number in the object.
/**
 * Sets a real number in the object.
 *
 * @note                    If dot notation is used some values may be inaccessible
 *                          because valid names in JSON can contain dots.
 * @note                    It also removes the old value if any.
 *
 * @param object            Object handle
 * @param name              Key name
 * @param number            Real number to set
 * @param dot_not           True to use dot notation, false to not
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid object
 */
native bool:json_object_set_real(JSON:object, const name[], Float:number, bool:dot_not = false);
 Sets a boolean value in the object.
/**
 * Sets a boolean value in the object.
 *
 * @note                    If dot notation is used some values may be inaccessible
 *                          because valid names in JSON can contain dots.
 * @note                    It also removes the old value if any.
 *
 * @param object            Object handle
 * @param name              Key name
 * @param boolean           Boolean value to set
 * @param dot_not           True to use dot notation, false to not
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid object
 */
native bool:json_object_set_bool(JSON:object, const name[], bool:boolean, bool:dot_not = false);
 Sets a null in the object.
/**
 * Sets a null in the object.
 *
 * @note                    If dot notation is used some values may be inaccessible
 *                          because valid names in JSON can contain dots.
 * @note                    It also removes the old value if any.
 *
 * @param object            Object handle
 * @param name              Key name
 * @param dot_not           True to use dot notation, false to not
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid object
 */
native bool:json_object_set_null(JSON:object, const name[], bool:dot_not = false);
json_object_remove  Removes a key and its value in the object.
/**
 * Removes a key and its value in the object.
 *
 * @note                    If dot notation is used some values may be inaccessible
 *                          because valid names in JSON can contain dots.
 *
 * @param object            Object handle
 * @param name              Key name
 * @param dot_not           True to use dot notation, false to not
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid object
 */
native bool:json_object_remove(JSON:object, const name[], bool:dot_not = false);
json_object_clear  Removes all keys and their values in the object.
/**
 * Removes all keys and their values in the object.
 *
 * @param object            Object handle
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid object
 */
native bool:json_object_clear(JSON:object);
Serialization
json_serial_size  Gets size of serialization.
/**
 * Gets size of serialization.
 *
 * @param value             JSON handle
 * @param pretty            True to count size for pretty format, false to not
 * @param null_byte         True to include null byte, false to not
 *
 * @return                  Size of serialized string
 * @error                   If passed handle is not a valid value
 */
native json_serial_size(const JSON:value, bool:pretty = false, bool:null_byte = false);
json_serial_to_string  Copies serialized string to the buffer.
/**
 * Copies serialized string to the buffer.
 *
 * @param value             JSON handle
 * @param buffer            Buffer to copy string to
 * @param maxlen            Maximum size of the buffer
 * @param pretty            True to format pretty JSON string, false to not
 *
 * @return                  The number of cells written to the buffer
 * @error                   If passed handle is not a valid value
 */
native json_serial_to_string(const JSON:value, buffer[], maxlen, bool:pretty = false);
json_serial_to_file  Copies serialized string to the file.
/**
 * Copies serialized string to the file.
 *
 * @param value             JSON handle
 * @param file              Path to the file
 * @param pretty            True to format pretty JSON string, false to not
 *
 * @return                  True if succeed, false otherwise
 * @error                   If passed handle is not a valid value
 */
native bool:json_serial_to_file(const JSON:value, const file[], bool:pretty = false);
Constants & Macros:
/*
 * JSON types
 */
enum JSONType
{
    JSONError   = -1,
    JSONNull    = 1,
    JSONString  = 2,
    JSONNumber  = 3,
    JSONObject  = 4,
    JSONArray   = 5,
    JSONBoolean = 6
};
 
/*
 * JSON invalid handle
 */
enum JSON
{
    Invalid_JSON = -1
}
 
/**
 * Helper macros for checking type
 */
#define json_is_object(%1)   (%1 != Invalid_JSON && json_get_type(%1) == JSONObject)
#define json_is_array(%1)    (%1 != Invalid_JSON && json_get_type(%1) == JSONArray)
#define json_is_string(%1)   (%1 != Invalid_JSON && json_get_type(%1) == JSONString)
#define json_is_number(%1)   (%1 != Invalid_JSON && json_get_type(%1) == JSONNumber)
#define json_is_bool(%1)     (%1 != Invalid_JSON && json_get_type(%1) == JSONBoolean)
#define json_is_null(%1)     (%1 != Invalid_JSON && json_get_type(%1) == JSONNull)
#define json_is_true(%1)     (%1 != Invalid_JSON && json_is_bool(%1) && json_get_bool(%1))
#define json_is_false(%1)    (%1 != Invalid_JSON && json_is_bool(%1) && !json_get_bool(%1))