[TUT] Tries
Posted: Sat Sep 26, 2026 5:21 pm
Before we start, this tutorial is for everyone that don’t know how to use tries. I will assume that you know the basics of pawn / amxx language.
Basically, tries let you store data associated to a key (string). The data usually is an integer or a string.
- All the examples will be generally simple. I just want to show you how to use tries
So, for the first example I will demonstrate how to detect if a player has a Steam ID in the black list.
For the second example, we will associate a Steam ID with an integer, and check if the player is an ADMIN, MOD or VIP.
If you understand this, you know how to work with TrieCreate, TrieDestroy, TrieGetCell, TrieSetCell and TrieKeyExists.
Now let’s work with a few more natives.
For the third example, we will use admin commands to block some nicknames.
For the TrieGetString and TrieSetString we will associate some VIP dates to Steam IDs.
And for the last... let's work with TrieSetArray and TrieGetArray.
This plugin read the stats of a file and save it by Steam ID.
That's all
Basically, tries let you store data associated to a key (string). The data usually is an integer or a string.
- All the examples will be generally simple. I just want to show you how to use tries
So, for the first example I will demonstrate how to detect if a player has a Steam ID in the black list.
Code: Select all
#include < amxmodx >
new Trie:g_tAuthIdBlackList // g means global; t means trie
public plugin_init( )
{
register_plugin( "trie example", "1.0.1", "guipatinador" )
g_tAuthIdBlackList = TrieCreate( ) // Create the trie...
TrieSetCell( g_tAuthIdBlackList, "STEAM_2:3:123456", 1 )
TrieSetCell( g_tAuthIdBlackList, "STEAM_2:3:654321", 1 )
TrieSetCell( g_tAuthIdBlackList, "STEAM_2:3:123654", 1 )
TrieSetCell( g_tAuthIdBlackList, "STEAM_2:3:456123", 1 )
// First param = name of the trie
// Second param = string with the Steam ID blacklisted (this is the key and it should be unique)
// Third param = it is our integer, we will not use this
}
public plugin_end( )
{
TrieDestroy( g_tAuthIdBlackList ) // Destroys the trie when the map changes or the server shuts down
}
public client_authorized( id )
{
new szAuthID[ 35 ]; get_user_authid( id, szAuthID, charsmax( szAuthID ) )
if( TrieKeyExists( g_tAuthIdBlackList, szAuthID ) )
{
// The Steam ID (key), exist in the trie
server_cmd( "kick #%i ^"Your Steam ID is blacklisted^"", get_user_userid( id ) )
}
else
{
// The Steam ID is not in the trie
// We won’t do anything because the Steam ID is not blacklisted
}
} Code: Select all
#include < amxmodx >
new Trie:g_tAuthIdOfPeople
#define LOGFILE "steamidsofpeople.log"
// Just to be more easy...
#define ADMIN 1
#define MOD 2
#define VIP 3
public plugin_init( )
{
register_plugin( "trie example", "1.0.2", "guipatinador" )
g_tAuthIdOfPeople = TrieCreate( )
TrieSetCell( g_tAuthIdOfPeople, "STEAM_2:3:123456", ADMIN ) // admin is 1
TrieSetCell( g_tAuthIdOfPeople, "STEAM_2:3:654321", ADMIN )
TrieSetCell( g_tAuthIdOfPeople, "STEAM_2:3:123654", MOD ) // mod is 2
TrieSetCell( g_tAuthIdOfPeople, "STEAM_2:3:456123", VIP ) // vip is 3
}
public plugin_end( )
{
TrieDestroy( g_tAuthIdOfPeople )
}
public client_authorized( id )
{
new szAuthID[ 35 ]; get_user_authid( id, szAuthID, charsmax( szAuthID ) )
new iNum
// This will save our integer (ADMIN, MOD or VIP) in iNum, if the key is on the trie
if( TrieGetCell( g_tAuthIdOfPeople, szAuthID, iNum ) )
{
switch( iNum )
{
case ADMIN:
log_to_file( LOGFILE, "A Admin entered the server" )
case MOD:
log_to_file( LOGFILE, "A Mod entered the server" )
case VIP:
log_to_file( LOGFILE, "A Vip entered the server" )
}
}
else // The key (Steam ID) is not in the trie
{
log_to_file( LOGFILE, "A normal player entered the server" )
}
} Now let’s work with a few more natives.
For the third example, we will use admin commands to block some nicknames.
Code: Select all
#include < amxmodx >
#include < amxmisc >
new Trie:g_tNicks
#define ADMIN_FLAG ADMIN_RCON
public plugin_init( )
{
register_plugin( "trie example", "1.0.3", "guipatinador" )
register_concmd( "amx_blocknick", "BlockNickCmd", ADMIN_FLAG, "<name to block>" )
register_concmd( "amx_unblocknick", "UnBlockNickCmd", ADMIN_FLAG, "<name to unblock>" )
register_concmd( "amx_removenicks", "RemoveNicksCmd", ADMIN_FLAG )
g_tNicks = TrieCreate( )
}
public plugin_end( )
{
TrieDestroy( g_tNicks )
}
public BlockNickCmd( id, level, cid )
{
if( !cmd_access( id, level, cid, 2 ) )
return PLUGIN_HANDLED
new szName[ 32 ]
read_argv( 1, szName, charsmax( szName ) )
// First we’ll check if the username is in the trie
// If it is, we won't do anything
// If it isn’t, we’ll add the nick
// I will show two methods
// METHOD ONE
if( TrieKeyExists( g_tNicks, szName ) )
{
client_print( id, print_console, "Username already added before" )
}
else
{
TrieSetCell( g_tNicks, szName, 1 )
client_print( id, print_console, "Username added with success" )
}
/*
// METHOD TWO
new iNum
new bool:bNameAlreadyAdded = TrieGetCell( g_tNicks, szName, iNum )
if( bNameAlreadyAdded )
{
client_print( id, print_console, "Username already added before" )
}
else
{
TrieSetCell( g_tNicks, szName, 1 )
client_print( id, print_console, "Username added with success" )
}
*/
return PLUGIN_HANDLED
}
public UnBlockNickCmd( id, level, cid )
{
if( !cmd_access( id, level, cid, 2 ) )
return PLUGIN_HANDLED
new szName[ 32 ]
read_argv( 1, szName, charsmax( szName ) )
if( TrieDeleteKey( g_tNicks, szName ) )
{
client_print( id, print_console, "Username deleted with success" )
}
else
{
client_print( id, print_console, "Username already deleted before" )
}
/*
// If you want to delete, without print a message just do this
TrieDeleteKey( g_tNicks, szName )
*/
return PLUGIN_HANDLED
}
public RemoveNicksCmd( id, level, cid )
{
if( !cmd_access( id, level, cid, 1 ) )
return PLUGIN_HANDLED
TrieClear( g_tNicks ) // This one clears all the keys of the trie and the data
client_print( id, print_console, "All the blocked usernames were deleted" )
return PLUGIN_HANDLED
}
public client_authorized( id )
{
new szName[ 32 ]; get_user_name( id, szName, charsmax( szName ) )
if( TrieKeyExists( g_tNicks, szName ) )
{
server_cmd( "kick #%i ^"Your nickname is blocked^"", get_user_userid( id ) )
}
/*
// Note that this will also work
new iNum
if( TrieGetCell( g_tNicks, szName, iNum ) )
{
server_cmd( "kick #%i ^"Your nickname is blocked^"", get_user_userid( id ) )
}
*/
} Code: Select all
#include < amxmodx >
#include < amxmisc >
new Trie:g_tVipDate
new const VIPDATE[ ][ ][ ] = {
{ "STEAM_2:3:123456", "01-04-2013" },
{ "STEAM_2:3:654321", "25-02-2013" },
{ "STEAM_2:3:123654", "13-03-2013" },
{ "STEAM_2:3:456123", "09-01-2013" }
}
public plugin_init( )
{
register_plugin( "trie example", "1.0.4", "guipatinador" )
register_clcmd( "say /vipdate", "VipDate" )
g_tVipDate = TrieCreate( )
new i
for( i = 0; i < sizeof VIPDATE; i++ )
{
TrieSetString( g_tVipDate, VIPDATE[ i ][ 0 ], VIPDATE[ i ][ 1 ] )
// First param = name of the trie
// Second param = Steam ID (key)
// Third param = date when the vip ends (string)
}
}
public plugin_end( )
{
TrieDestroy( g_tVipDate )
}
public VipDate( id )
{
new szAuthID[ 35 ]; get_user_authid( id, szAuthID, charsmax( szAuthID ) )
// First we’ll check if the Steam ID of the player is in the trie
new szVipDate[ 12 ]
if( TrieGetString( g_tVipDate, szAuthID, szVipDate, charsmax( szVipDate ) ) )
{
// The user is vip because the Steam ID is one of the keys of the trie
client_print( id, print_chat, "Your VIP will end in: %s", szVipDate )
}
else
{
// User is not vip
client_print( id, print_chat, "You are not VIP" )
}
} This plugin read the stats of a file and save it by Steam ID.
Code: Select all
#include < amxmodx >
#include < amxmisc >
new Trie:g_StatsOfPlayers
new g_szAuthID[ 33 ][ 35 ] // This will save the Steam ID of any player
enum _:Stats {
SteamID[ 35 ],
Kills,
Deaths,
KillsKnife,
KillsHE
}
// Those are the stats we want to save. Note that the Steam ID is a string, the rest are integers
public plugin_init( )
{
register_plugin( "trie example", "1.0.5", "guipatinador" )
register_clcmd( "say /mystats", "PrintStats" ) // We will use this command to see the stats
g_StatsOfPlayers = TrieCreate( )
ReadStatsFromFile( ) // Reads stats from the file when the server starts or the map changes
}
public plugin_end( )
{
TrieDestroy( g_StatsOfPlayers )
}
public ReadStatsFromFile( )
{
new szFilePath[ 128 ]
get_configsdir( szFilePath, charsmax( szFilePath ) )
add( szFilePath, charsmax( szFilePath ), "/stats_of_players.ini" ) // File where the stats are saved
new f = fopen( szFilePath, "rt" )
if( !f )
{
new szMessage[ 256 ]
formatex( szMessage, charsmax( szMessage ), "Unable to open %s", szFilePath )
set_fail_state( szMessage )
}
new szDataFromFile[ 128 ]
new Data[ Stats ]
new szKills[ 5 ]
new szDeaths[ 5 ]
new szKnife[ 5 ]
new szHE[ 5 ]
while( !feof( f ) ) // Opens the file
{
fgets( f, szDataFromFile, charsmax( szDataFromFile ) )
if( !szDataFromFile[ 0 ] || szDataFromFile[ 0 ] == ';' || szDataFromFile[ 0 ] == '/' && szDataFromFile[ 1 ] == '/' )
continue
trim( szDataFromFile )
parse( szDataFromFile,
Data[ SteamID ], charsmax( Data[ SteamID ] ), // This is our key
szKills, charsmax( szKills ),
szDeaths, charsmax( szDeaths ),
szKnife, charsmax( szKnife ),
szHE, charsmax( szHE ) )
// All those things are strings. Let's convert to integers
Data[ Kills ] = str_to_num( szKills )
Data[ Deaths ] = str_to_num( szDeaths )
Data[ KillsKnife ] = str_to_num( szKnife )
Data[ KillsHE ] = str_to_num( szHE )
// This will save the Steam ID and the stats in the trie
TrieSetArray( g_StatsOfPlayers, Data[ SteamID ], Data, sizeof Data )
// First param = name of the trie
// Second param = key (string) (in this case it's the Steam ID)
// Third param = array that contains the stats
// Fourth param = size of the array (note that 'sizeof Data - 1' will not work)
}
fclose( f ) // Closes the file
}
public client_authorized( id )
{
get_user_authid( id, g_szAuthID[ id ], charsmax( g_szAuthID[ ] ) )
}
public PrintStats( id )
{
new Data[ Stats ]
if( TrieGetArray( g_StatsOfPlayers, g_szAuthID[ id ], Data, sizeof Data ) )
{
// The params are similar to TrieSetString
// First = name of the array
// Second = key. g_szAuthID[ id ] contains the Steam ID of the player that types /mystats
// Third = array to retrieve the data
// Fourth = size
client_print( id, print_chat, "Steam ID: %s | Kills: %i | Deaths: %i | Knife: %i | HE: %i", Data[ SteamID ], Data[ Kills ], Data[ Deaths ], Data[ KillsKnife ], Data[ KillsHE ] )
}
// If the Steam ID doesn't exist in the file, it is better to print another message
else
{
client_print( id, print_chat, "Your Steam ID do not have stats saved" )
}
}