Intro
nVault is an AMX-X tool designed for an easy method of saving and retrieving data from an external file. I have seen many people ask how to save data in a plugin so it can be retrieved after a map change or server restart. nVault will allow you to do this and it is very simple to use. nVault stores data using a key:data system; each chunk of data that you save has a unique key that corresponds to it. Both key and data are always strings when saving but data can be retrieved as integer, float, or string (see nvault_get). Data is saved to a nvault file in binary format, not plain text; this means that you cannot edit the file in [your favorite text editor here] but there is an nVault Editor that can be used. Also note that you cannot iterate through entries in a nvault file with the native nvault functions. You can iterate through entries using the nVault Utility include file. The ability the store arrays in nVault can also be accomplished with the nVault Utility.
nVault is a binary vault implementation. It allows you to open named vaults (which are stored in
data\vault) and read/write to them at any time.
The vault is implemented with a simple hash lookup, and the binary file format is primitive. However, it
should be much faster than AMX Mod X's built-in vault for most things. Each entry is also timestamped,
so you can prune for old entries.
Furthermore, the vault attempts to be journaled. That is, it keeps a log of everything it does, so if the
server crashes, it can "replay" the journal and recover damage. The journal is erased on synchronization
to the vault binary, which occurs on vault close/mapchange.
These are the available nvault functions:
Code:
nvault_open - Opens a vault by name (such as "myvault").
nvault_close - Closes a vault.
nvault_lookup - Looks up a vault value for full information.
nvault_get - Gets a vault value by returning an int setting a byref float or setting a string & maxlength.
nvault_set - Sets a vault value with current timestamp.
nvault_pset - Sets a permanent vault value with no timestamp.
nvault_remove - Remove an entry from vault.
nvault_touch - "Touches" a key to update its timestamp value.
nvault_prune - Prunes the vault for entries that are within the given timestamps.
nvault_open
Before doing any transactions with a vault, it must first be opened. This is done with the nvault_open command; it takes 1 string parameter which is the name of the file that is created on the servers hard-disk ([name].vault). When you call the nvault_open() command, it will return a handle (integer value) that is used by all of the other nvault functions as a reference to that particular vault. If an error occurs when opening the vault, nvault_open() will return -1 (INVALID_HANDLE) so it is a good idea to verify if it opened correctly prior to using any other commands.
Code:
nvault_open( const szVaultName[] )
szVaultName = This will be the name of your vault. Every time you want to communicate with this vault you must always use the same name to access that vault. A file will be created in data\vault folder named [szVaultName].vault
Return value: Vault id on success, -1 on failure.
PHP Code:
//Open a vault and throw a plugin error if INVALID_HANDLE is returned. new iVaultHandle = nvault_open( "testvault" );
nvault_close
This function will close the vault. It takes the vault handle to close as a parameter. Once a vault is closed you cannot do any transactions with the vault until it is re-opened. In most circumstances it is best to put nvault_close() in plugin_end(). Failure to close a vault file will cause it to be corrupt and you will lose all data.
Code:
nvault_close( iHandle )
iHandle = The handle of the vault that we want to close
Return value: 1 on success, 0 on failure
PHP Code:
//Open and close a vault. new iVaultHandle = nvault_open( "testvault" );
nvault_close( iVaultHandle );
nvault_lookup
This function will lookup data using a string key and will place the found data into szValue by-reference for a max of iMaxLength characters. If data is found, the function will return 1 (true), if no data found 0 (false). Timestamp will hold the time at which the entry was written/updated or touched last. This function can only retrieve data from the vault and store it into a string variable. See timestamps section below for an explanation of how timestamps work. This function should be used if you would like to see if a particular key exists in the vault.
Code:
nvault_lookup( iHandle , const szKey[] , szValue[] , iMaxLength , iTimestamp )
iHandle = The handle returned from nvault_open.
szKey = The key you want to use for the data lookup.
szValue = The string variable that will store the data we are retrieving.
iMaxLength = The max length of the string we want read into szValue.
iTimestamp = Will hold a timestamp for when entry was written or last touched.
Return value: 1 if data exists, 0 if no data exists.
PHP Code:
//Lookup a string stored in a vault using the players steamid as the key. new szAuthID[35]; new szData[30]; new iTimestamp; new iVault; new iDataExists
get_user_authid( id , szAuthID , charsmax( szAuthID ) );
//An entry was found, the data for this key is now stored in szData. if ( iDataExists ) { client_print( id , print_chat , "Data=%s Timestamp=%d" , szData , iTimestamp ); } else { client_print( id , print_chat , "No entry found with key %s" , szAuthID ); }
nvault_get
This function is very similar to nvault_lookup; it looks up data in a vault using the specified key. However, nvault_get is a bit more flexible than nvault_lookup because it allows you to retrieve data directly into a variable other than string. This will negate the need for you to do any data conversion once the data is retrieved as you would need to do if you use nvault_lookup to retrieve a float or int. Note, nvault_get does not allow you to retrieve the timestamp so if you do need the timestamp then you will need to use nvault_lookup.
Code:
nvault_get( handle , const szKey[] , ... )
handle = The handle returned from nvault_open.
key = The key you want to use for the data lookup.
[...] = [Variable # of parameters] This can either be a float variable, string & maxlen, or empty. See below
The number of parameters tells the function what type of data you wish to retrieve. Parameter count starts after szKey[]
0 parameters = nvault_get will return the integer value.
1 parameters = the float value will be passed by reference.
2 parameters = the string value will be passed by ref for maxlen characters.
Integer: iValue = nvault_get( iHandle , szKey[] );
Return value: Integer value that was found, or 0 if the key was not found or if the data value is non-numerical (ie. a string).
Float: nvault_get( iHandle , szKey[] , float );
Return value: 1 if data found, or 0 if key was not found.
String: nvault_get( iHandle , szKey[] , szValue[] , iMaxLen );
Return value: Length of string data retrieved, or 0 if key was not found.
PHP Code:
//Retrieve an integer, float, and string value from a vault. new iVault; new szAuthID[35]; new szData[30];
//To retrieve a number that is stored as the data new iNumber = nvault_get( iVault , szAuthID );
//To retrieve a float that is stored as the data new Float: fValue; nvault_get( iVault , szAuthID , fValue );
//To retrieve a string that is stored as the data new szDataString[10]; nvault_get( iVault , szAuthID , szDataString , charsmax( szDataString ) );
nvault_set
This will write data to the vault and timestamp the entry.
Code:
nvault_set( handle , const key[] , const value[] )
handle = The handle returned from nvault_open.
key = The key you want to use for the data lookup.
value = The string you want to write to vault
Return value: 1 on success, 0 on failure.
PHP Code:
//Save the phrase "hello world" to vault using steamid as the key. new iVault; new szAuthID[35]; new szData[30];
//Pass the value directly with no variable nvault_set( iVault , szAuthID , "hello world" );
//Pass the value with a string variable new szText[] = "hello world"; nvault_set( iVault , szAuthID , szText );
nvault_pset
The same as nvault_set() except this writes an entry without a timestamp so the entry will not be removed by the nvault_prune() function (if called). The timestamp value is 0 when permanent.
Code:
Return value: 1 on success, 0 on failure.
nvault_remove
This removes an entry from the vault that has the specified key value.
Code:
nvault_remove( handle , const key[] )
handle = The handle returned from nvault_open.
key = The key of the vault entry to remove.
Return value: 1 on success, 0 on failure.
PHP Code:
//Remove an entry from vault new iVault;
iVault = nvault_open( "testvault" );
//Set a test entry with key "test entry" nvault_set( iVault , "test entry" , "test value" );
//Remove the entry that was just saved nvault_remove( iVault , "test entry" );
nvault_touch
This function will 'touch' an entry, updating it's timestamp; the entry value will remain unchanged. If the key does not exist that is being touched, an empty entry for that key will be created. See timestamps section below for an explanation of timestamps.
Code:
nvault_touch( iHandle , const szKey[] , [ iTimestamp = -1 ] )
iHandle = The handle of the vault
szKey = The key for which we want to update timestamp
iTimeStamp - [Optional param] If not passed to the function (or -1 is passed)
it will update the key with the current time. Otherwise it will update the
key with the timestamp specified.
Return value: 1 on success, 0 on failure.
PHP Code:
//Touch the entry new iVault; new szAuthID[35];
iVault = nvault_open( "testvault" );
get_user_authid( id , szAuthID , charsmax( szAuthID ) );
//Touch the entry with current timestamp nvault_touch( iVault , szAuthID );
nvault_prune
This function is used to remove entries that fall within the specified start and end timestamps. A timestamp value is in seconds so keep this in consideration when pruning entries. See timestamps section below for an explanation of timestamps.
Code:
nvault_prune( iHandle , iStart , iEnd )
iHandle = The handle returned from nvault_open.
iStart = The timestamp where to begin removing entries.
iEnd = The timestamp where to stop removing entries.
Return value: Number of vault entries pruned on success, 0 on failure.
PHP Code:
new iVault;
iVault = nvault_open( "testvault" );
//Remove all entries in vault. 0 = earliest possible time, get_systime() = now. nvault_prune( iVault , 0 , get_systime() );
//Remove entries in vault that are 15 days old or more. //get_systime() returns the current timestamp //1 day = 86400 seconds = 60 secs * 60 mins * 24 hours nvault_prune( iVault , 0 , get_systime() - ( 15 * 86400 ) );
Timestamps
Timestamps in nvault are in unix-time format (aka POSIX time) which is equal to the number of seconds that have elapsed since midnight January 1, 1970. To prune or compare a timestamp retrieved in nvault_lookup, you can do simple multiplication to convert seconds to minutes, hours, days, or weeks. Example: Day = 60 * 60 * 24 = 86400.
In the above nvault_prune example it shows how to prune entries that are 15 days old or more. If you wanted to prune entries that are 10+ minutes old, you would do nvault_prune( iHandle , 0 , get_systime() - ( 60 * 10 ) ).
Using nVault in your plugin
If you will be using nvault functions constantly throughout your plugin, it is best to keep the nvault file open while your plugin is running. To do this, use a global variable to hold the handle and call nvault_open() in plugin_init() or plugin_config() (or anywhere you choose). To close the vault, call nvault_close() in plugin_end().
nVault Limitations
The major things (IMO) that are missing in nVault is the ability to determine the number of entries in a vault, the ability to cycle through entries in a vault, and storing arrays. I created an include file, nVault Utility which provides this missing functionality. Just be advised, the nVault handle used with nVault and nVault Utility are *NOT* interchangeable, which means you will have 2 separate handles if you are working with both at the same time (ie. you cannot use the handle returned by nvault_open() with functions in nVault utility and vice-versa. The only exception for this is for the two functions nvault_set_array() and nvault_get_array(), which do use the handle returned by nvault_open().
Example Plugin
The below plugin shows how to do save a players money and score to the vault. When a user disconnects, these items are saved and when he re-connects they get restored.
Plugin
PHP Code:
//This plugin allows you to save your money and score to vault using your steamid as the key. Since we are saving two //different items both using steam-id as the key, we must format the key for each individual item. For money, the key //will be "STEAM_0:0:1234MONEY" and score will be "STEAM_0:0:1234SCORE". If you are only saving one piece of information //to the vault with the players steamid then you can use the steamid alone without formatting it. You can save multiple //items in each nvault entry but for the sake of keeping this example basic I am using a separate key for each. If you //save multiple items you will need to parse each individual item after reading from the vault.
new g_Vault; //Global var to hold our vault handle new g_szAuthID[33][35]; //Global array to store auth ids of players new g_pExpireDays; //CVar pointer for expiredays cvar
public plugin_cfg() { //Open our vault and have g_Vault store the handle. g_Vault = nvault_open( "yourvault" );
//Make the plugin error if vault did not successfully open if ( g_Vault == INVALID_HANDLE ) set_fail_state( "Error opening nVault" );
//This will remove all entries in the vault that are 5+ (or cvar+) days old at server-start //or map-change nvault_prune( g_Vault , 0 , get_systime() - ( 86400 * get_pcvar_num( g_pExpireDays ) ) ); }
public plugin_end() { //Close the vault when the plugin ends (map change\server shutdown\restart) nvault_close( g_Vault ); }
public client_authorized(id) { //Get the connecting users authid and store it in our global string array so it //will not need to be retrieved every time we want to do an nvault transaction. get_user_authid( id , g_szAuthID[id] , charsmax( g_szAuthID[] ) ); }
public cmdSaveMoney(id) { //Save a single item into the value of the entry. //Example: STEAM_0:0:1234 16000
new szMoney[7]; //Data holder for the money amount new szKey[40]; //Key used to save money "STEAM_0:0:1234MONEY"
//If our money key was found, set the users money to the value we read from vault and //delete the key so the player will not get the same money again. if ( iMoney ) { cs_set_user_money( id , iMoney , 1 ); nvault_remove( g_Vault , szKey );
client_print( id , print_chat , "* Your money was loaded from vault: $%d" , iMoney ); } else { client_print( id , print_chat , "* You have no money entry in vault." ); } }
public cmdSaveScore(id) { //Save 2 items into the value of the entry. //Example: STEAM_0:0:1234 15 5
new szData[8]; //Data key holding kills and deaths in this format: "15 2" new szKey[40]; //Key to store data: "STEAM_0:0:1234SCORE"
//If data was found if ( nvault_get( g_Vault , szKey , szData , charsmax( szData ) ) ) { //Look for a space within the data (is used to separate kills and deaths) new iSpacePos = contain( szData , " " );
if ( iSpacePos > -1 ) { new szKills[4]; new szDeaths[4];
//Put kills and deaths into their own variables so they can be handled individually formatex( szKills , charsmax( szKills ) , "%s" , szData ); formatex( szDeaths , charsmax( szDeaths ) , "%s" , szData[ iSpacePos + 1 ] );
//Set the players score with these values. set_user_frags( id , str_to_num( szKills ) ); cs_set_user_deaths( id , str_to_num( szDeaths ) );
client_print( id , print_chat , "* Your score was loaded: %s kills, %s deaths" , szKills , szDeaths ); } } else { client_print( id , print_chat , "* You have no score entry in vault." ); } }
The overhead for SQL isn't always necessary for basic data storage. nVault also does not require the knowledge of how to write queries. nVault provides a very basic and easy to understand means of saving\retrieving data to an external file.
The overhead for SQL isn't always necessary for basic data storage. nVault also does not require the knowledge of how to write queries. nVault provides a very basic and easy to understand means of saving\retrieving data to an external file.
ofc it does but most things i did were very simple to create using ordinary textfiles. i mostly use sql cuz the data is shown in huge motd which are php files... i think you understand
set_user_kills( id , str_to_num( szKills );
set_user_deaths( id , str_to_num( szDeaths );
client_print( id , print_chat , "* Your score was loaded: %s kills, %s deaths" , szKills , szDeaths );
}
}
else
{
client_print( id , print_chat , "* You have no score entry in vault." );
}
}
The overhead for SQL isn't always necessary for basic data storage. nVault also does not require the knowledge of how to write queries. nVault provides a very basic and easy to understand means of saving\retrieving data to an external file.
This is why I said I'm going to stick with SQL, since I know how to query it is not a problem for me . It's definitely a helpful and nice tutorial for everyone else but as long as it is not extremely incomplex, temporary or limited data that has to be stored I will always use SQL.
Question: I have a bad opinion about vaults ever since my old WC3 Server suffered from a huge XP-database and crashed on every mapchange. Is this still possible with nVault?
This is why I said I'm going to stick with SQL, since I know how to query it is not a problem for me . It's definitely a helpful and nice tutorial for everyone else but as long as it is not extremely incomplex, temporary or limited data that has to be stored I will always use SQL.
Question: I have a bad opinion about vaults ever since my old WC3 Server suffered from a huge XP-database and crashed on every mapchange. Is this still possible with nVault?
Even if querying isn't a problem for you it could still be overkill depending on what you are storing. If you are only storing a single item and only need to retrieve it based on a single key then it is a waste of CPU to use SQL. Whatever floats your boat though.
I've never had any issues with nVault. I have used it for all of my data saving needs.