AMX Mod X Moderator
Join Date: Feb 2005
Location: NJ, USA
|
05-13-2018
, 13:01
[TUT] nVault Top 15
|
#1
|
nVault Top 15
Over the years I've seen many scripters ask how to create a top 15 for data that is stored in nVault. Since the nVault module has no retrieve-all or sorting functionality this is not possible without the use of nVault Utility. While not required to complete this, I am providing an example using the nVault Array include since I think this is a cleaner approach than storing all data as a string and then parsing components of the string for the calculation.
High-level explanation for how nVault Utility works:
nVault Utility uses the file natives to read data from the vault file in binary format. Each item (key:data) in nVault is stored at an offset within the file, with 0 being the position of the first record, the next record is positioned based off of the size of the previous record, etc. This offset, or location of player data, will be used as a reference to the player data to make this top 15 possible.
Steps for creating a Top 15:- Read all records in the vault file and store the player-data offset and XP value to a 2-dimension array.
- Sort this array using the XP value as the sort value.
- Loop through this sorted array to build the top 15. With each iteration, the players data offset will be used to re-read their data from the vault. Any piece of data that is stored in the nVault array record can be used in the top 15 (name, steam id, xp, etc).
Requirements:Note: You must delete your vault file or prune all data before implementing this since nvault_read_array() will fail if you try to read data that was not stored using nvault_set_array().
Plugin chat commands:- top15 - Display the top 15.
- loadtestdata - Loads 100 test records to the vault in 'Player_# [XP]' format. The players name includes their stored XP value so you can confirm it is sorting accurately.
PHP Code:
#include <amxmodx> #include <nvault> #include <nvault_util> #include <nvault_array>
//Allocate additional memory to plugin to prevent stack error #pragma dynamic 16384
new const Version[] = "0.1";
new const VaultName[] = "XP_Top15_Example";
//This determines the max number of players that will be included in your top 15 calculation. It is best to keep this at a //value <= the max players that you expect to have data saved in the vault. If the number of player data saved exceeds this //value then your top 15 will not be accurate since some players will be left out. const Max_Player_Support = 3000;
//Components of data that will be saved for each player. enum PlayerData { PlayerName[ 32 ], XP }
new pdData[ MAX_PLAYERS + 1 ][ PlayerData ]; new g_AuthID[ MAX_PLAYERS + 1 ][ 34 ]; new bool:g_BotOrHLTV[ MAX_PLAYERS + 1 ]; new g_Vault;
//In your plugin, you set a players XP using the below: //pdData[ id ][ XP ] = 12345; public plugin_init() { register_plugin( "nVault Top 15" , Version , "bugsy" ); register_clcmd( "say top15" , "ShowTop15" ); register_clcmd( "say loadtestdata" , "LoadTestData" ); if ( ( g_Vault = nvault_open( VaultName ) ) == INVALID_HANDLE ) { set_fail_state( "Failed to open vault" ); } }
public plugin_end() { nvault_close( g_Vault ); }
public client_authorized( id ) { if ( !( g_BotOrHLTV[ id ] = bool:( is_user_bot( id ) || is_user_hltv( id ) ) ) ) { //Get players' steam-id so it can be used to retrieve their data from the vault. get_user_authid( id , g_AuthID[ id ] , charsmax( g_AuthID[] ) ); //Retrieve player data from vault. nvault_get_array( g_Vault , g_AuthID[ id ] , pdData[ id ][ PlayerData:0 ] , sizeof( pdData[] ) ); } }
public client_disconnect( id ) { if ( !g_BotOrHLTV[ id ] ) { //To avoid having to monitor for name changes in-game, the players name is retrieved and saved when disconnecting. get_user_name( id , pdData[ id ][ PlayerName ] , charsmax( pdData[][ PlayerName ] ) ); //Save player data to vault. nvault_set_array( g_Vault , g_AuthID[ id ] , pdData[ id ][ PlayerData:0 ] , sizeof( pdData[] ) ); } }
public ShowTop15( id ) { enum _:Top15Info { nVault_Offset, XP_Value } static iSortData[ Max_Player_Support ][ Top15Info ]; new iVault , iRow , iCount , iNextOffset , iCurrentOffset , szKey[ 45 ] , iAvailablePlayers , pdVal[ PlayerData ]; new szMOTD[ 1501 ] , iPos; //Close and re-open vault so the journal writes to the vault so nvault_util gets most up to date data. nvault_close( g_Vault ); g_Vault = nvault_open( VaultName ); //Open vault for nvault utility usage. iVault = nvault_util_open( VaultName ); //Get count of total number of records in the vault. iCount = nvault_util_count( iVault ); //Loop through all records in the vault. for ( iRow = 0 ; iRow < iCount && iRow < Max_Player_Support ; iRow++ ) { //Read record from vault. iNextOffset will hold the position of the next record in the vault. iNextOffset = nvault_util_read_array( iVault , iNextOffset , szKey , charsmax( szKey ) , pdVal[ PlayerData:0 ] , sizeof( pdVal ) ); //Set nVault_Offset to the byte offset for this players data. This will allow for retrieving any data for this player that needs to appear in the top 15 (name, steam id, etc.) //iPrevOffset is used since iOffset holds the position of the NEXT record, not current. iSortData[ iRow ][ nVault_Offset ] = iCurrentOffset; //Set Player_XP value in array to his XP value. This will be used for sorting. iSortData[ iRow ][ XP_Value ] = pdVal[ XP ]; //Since nvault_util_read_array() holds the position of the next record, we have to hold the current offset separately. iCurrentOffset = iNextOffset; } //Sort the array. SortCustom2D( iSortData , min( iCount , Max_Player_Support ) , "CompareXP" );
//Prepare top 15 MOTD. iPos = formatex( szMOTD , charsmax( szMOTD ) , "<body bgcolor=#000000><font color=#98f5ff><pre>" ); iPos += formatex( szMOTD[ iPos ] , charsmax( szMOTD ) - iPos , "%2s %-22.22s %3s^n" , "#" , "Name" , "XP" ); //This will account for if the vault has less than 15 player data records stored. iAvailablePlayers = min( iCount , 15 ); //Build the top 15. iAvailablePlayers is set to the smaller of 15 or the total records in the vault. for ( iRow = 0 ; iRow < iAvailablePlayers ; iRow++ ) { //Get nVault player data offset value which was set in the above loop. iCurrentOffset = iSortData[ iRow ][ nVault_Offset ]; //Read data at the players offset so we can retrieve their name to be displayed in the top 15. nvault_util_read_array( iVault , iCurrentOffset , szKey , charsmax( szKey ) , pdVal[ PlayerData:0 ] , sizeof( pdVal ) ); //Format line in MOTD. iPos += formatex( szMOTD[ iPos ] , charsmax( szMOTD ) - iPos ,"%2d %-22.22s %3d^n", ( iRow + 1 ) , pdVal[ PlayerName ] , pdVal[ XP ] ); } //Close nvault utility file. nvault_util_close( iVault ); formatex( szMOTD[ iPos ], charsmax( szMOTD ) - iPos , "</body></font></pre>" ); show_motd( id , szMOTD , "XP Top 15" ); return PLUGIN_HANDLED; }
public LoadTestData() { new szAuthID[ 10 ] , pdData[ PlayerData ] , iRow , iXP; for ( iRow = 0 ; iRow < 100 ; iRow++ ) { formatex( szAuthID , charsmax( szAuthID ) , "STEAM_%d" , iRow ); iXP = random( 9999 ); formatex( pdData[ PlayerName ] , charsmax( pdData[ PlayerName ] ) , "Player_%d [%d]" , iRow , iXP ); pdData[ XP ] = iXP; nvault_set_array( g_Vault , szAuthID , pdData[ PlayerData:0 ] , sizeof( pdData ) ); } return PLUGIN_HANDLED; }
public CompareXP( elem1[] , elem2[] ) { if ( elem1[ 1 ] > elem2[ 1 ] ) return -1; else if(elem1[ 1 ] < elem2[ 1 ] ) return 1; return 0; }
__________________
Last edited by Bugsy; 06-28-2019 at 21:48.
|
|