Thread: [TUT] Tries
View Single Post
Author Message
guipatinador
SourceMod Donner Party
Join Date: Oct 2009
Location: Poortugal
Old 11-27-2012 , 13:46   [TUT] Tries
Reply With Quote #1

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.

Some considerations on this tutorial:
- I will not make comparisons between tries and arrays (https://forums.alliedmods.net/showthread.php?t=88396)
- I will not talk about TrieSetArray and TrieGetArray - already made
- 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.

PHP Code:
#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...
    
    
TrieSetCellg_tAuthIdBlackList"STEAM_2:3:123456")
    
TrieSetCellg_tAuthIdBlackList"STEAM_2:3:654321")
    
TrieSetCellg_tAuthIdBlackList"STEAM_2:3:123654")
    
TrieSetCellg_tAuthIdBlackList"STEAM_2:3:456123")
    
    
// 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( )
{
    
TrieDestroyg_tAuthIdBlackList // Destroys the trie when the map changes or the server shuts down
}

public 
client_authorizedid )
{
    new 
szAuthID35 ]; get_user_authididszAuthIDcharsmaxszAuthID ) )
    
    if( 
TrieKeyExistsg_tAuthIdBlackListszAuthID ) )
    {
        
// The Steam ID (key), exist in the trie
        
server_cmd"kick #%i ^"Your Steam ID is blacklisted^""get_user_useridid ) )
    }
    
    else
    {
        
// The Steam ID is not in the trie
        // We won’t do anything because the Steam ID is not blacklisted
    
}

For the second example, we will associate a Steam ID with an integer, and check if the player is an ADMIN, MOD or VIP.

PHP Code:
#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( )
    
    
TrieSetCellg_tAuthIdOfPeople"STEAM_2:3:123456"ADMIN // admin is 1
    
TrieSetCellg_tAuthIdOfPeople"STEAM_2:3:654321"ADMIN )
    
TrieSetCellg_tAuthIdOfPeople"STEAM_2:3:123654"MOD // mod is 2
    
TrieSetCellg_tAuthIdOfPeople"STEAM_2:3:456123"VIP // vip is 3
}

public 
plugin_end( )
{
    
TrieDestroyg_tAuthIdOfPeople )
}

public 
client_authorizedid )
{
    new 
szAuthID35 ]; get_user_authididszAuthIDcharsmaxszAuthID ) )
    
    new 
iNum
    
    
// This will save our integer (ADMIN, MOD or VIP) in iNum, if the key is on the trie
    
if( TrieGetCellg_tAuthIdOfPeopleszAuthIDiNum ) )
    {
        switch( 
iNum )
        {
            case 
ADMIN:
                
log_to_fileLOGFILE"A Admin entered the server" )
            
            case 
MOD:
                
log_to_fileLOGFILE"A Mod entered the server" )
            
            case 
VIP:
                
log_to_fileLOGFILE"A Vip entered the server" )
        }
    }
    
    else 
// The key (Steam ID) is not in the trie
    
{
        
log_to_fileLOGFILE"A normal player entered the server" )
    }

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.

PHP Code:
#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( )
{
    
TrieDestroyg_tNicks )
}

public 
BlockNickCmdidlevelcid )
{
    if( !
cmd_accessidlevelcid) )
        return 
PLUGIN_HANDLED
    
    
new szName32 ]    
    
read_argv1szNamecharsmaxszName ) )
    
    
// 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( TrieKeyExistsg_tNicksszName ) )
    {
        
client_printidprint_console"Username already added before" )    
    }
    
    else
    {
        
TrieSetCellg_tNicksszName)
        
client_printidprint_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 
UnBlockNickCmdidlevelcid )
{
    if( !
cmd_accessidlevelcid) )
        return 
PLUGIN_HANDLED
    
    
new szName32 ]    
    
read_argv1szNamecharsmaxszName ) )
    
    if( 
TrieDeleteKeyg_tNicksszName ) )
    {
        
client_printidprint_console"Username deleted with success" )
    }
    
    else
    {
        
client_printidprint_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 
RemoveNicksCmdidlevelcid )
{
    if( !
cmd_accessidlevelcid) )
        return 
PLUGIN_HANDLED
    
    TrieClear
g_tNicks // This one clears all the keys of the trie and the data
    
client_printidprint_console"All the blocked usernames were deleted" )
    
    return 
PLUGIN_HANDLED
}

public 
client_authorizedid )
{
    new 
szName32 ]; get_user_nameidszNamecharsmaxszName ) )
    
    if( 
TrieKeyExistsg_tNicksszName ) )
    {
        
server_cmd"kick #%i ^"Your nickname is blocked^""get_user_useridid ) )
    }
    
    
/*
    // 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 ) )
    }
    */

For the TrieGetString and TrieSetString we will associate some VIP dates to Steam IDs.

PHP Code:
#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( 0sizeof VIPDATEi++ )
    {
        
TrieSetStringg_tVipDateVIPDATE][ ], VIPDATE][ ] )
        
// First param = name of the trie
        // Second param = Steam ID (key)
        // Third param = date when the vip ends (string)
    
}
}

public 
plugin_end( )
{
    
TrieDestroyg_tVipDate )
}

public 
VipDateid )
{
    new 
szAuthID35 ]; get_user_authididszAuthIDcharsmaxszAuthID ) )
    
    
// First we’ll check if the Steam ID of the player is in the trie
    
new szVipDate12 ]
    if( 
TrieGetStringg_tVipDateszAuthIDszVipDatecharsmaxszVipDate ) ) )
    {
        
// The user is vip because the Steam ID is one of the keys of the trie
        
client_printidprint_chat"Your VIP will end in: %s"szVipDate )
    }
    
    else
    {
        
// User is not vip
        
client_printidprint_chat"You are not VIP" )
    }

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.

PHP Code:
#include < amxmodx >
#include < amxmisc >

new Trie:g_StatsOfPlayers

new g_szAuthID33 ][ 35 // This will save the Steam ID of any player

enum _:Stats {
    
SteamID35 ],
    
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( )
{
    
TrieDestroyg_StatsOfPlayers )
}

public 
ReadStatsFromFile( )
{
    new 
szFilePath128 ]
    
get_configsdirszFilePathcharsmaxszFilePath ) )
    
addszFilePathcharsmaxszFilePath ), "/stats_of_players.ini" // File where the stats are saved
    
    
new fopenszFilePath"rt" )
    
    if( !
)
    {
        new 
szMessage256 ]
        
formatexszMessagecharsmaxszMessage ), "Unable to open %s"szFilePath )
        
set_fail_stateszMessage )
    }
    
    new 
szDataFromFile128 ]
    new 
DataStats ]
    new 
szKills]
    new 
szDeaths]
    new 
szKnife]
    new 
szHE]
    
    while( !
feof) ) // Opens the file
    
{
        
fgetsfszDataFromFilecharsmaxszDataFromFile ) )
        
        if( !
szDataFromFile] || szDataFromFile] == ';' || szDataFromFile] == '/' && szDataFromFile] == '/' )
            continue
        
        
trimszDataFromFile )
        
parseszDataFromFile,
        
DataSteamID ], charsmaxDataSteamID ] ), // This is our key
        
szKillscharsmaxszKills ),
        
szDeathscharsmaxszDeaths ),
        
szKnifecharsmaxszKnife ),
        
szHEcharsmaxszHE ) )
        
        
// All those things are strings. Let's convert to integers
        
DataKills ] = str_to_numszKills )
        
DataDeaths ] = str_to_numszDeaths )
        
DataKillsKnife ] = str_to_numszKnife )
        
DataKillsHE ] = str_to_numszHE )
        
        
// This will save the Steam ID and the stats in the trie
        
TrieSetArrayg_StatsOfPlayersDataSteamID ], Datasizeof 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// Closes the file
}

public 
client_authorizedid )
{
    
get_user_authididg_szAuthIDid ], charsmaxg_szAuthID[ ] ) )
}

public 
PrintStatsid )
{
    new 
DataStats ]
    
    if( 
TrieGetArrayg_StatsOfPlayersg_szAuthIDid ], Datasizeof 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_printidprint_chat"Steam ID: %s | Kills: %i | Deaths: %i | Knife: %i | HE: %i"DataSteamID ], DataKills ], DataDeaths ], DataKillsKnife ], DataKillsHE ] )
    }
    
    
//  If the Steam ID doesn't exist in the file, it is better to print another message
    
else
    {
        
client_printidprint_chat"Your Steam ID do not have stats saved" )
    }

That's all

Last edited by guipatinador; 03-09-2013 at 15:39.
guipatinador is offline