The current implementation of our plugin works fine for a single game. However, as soon as the server changes maps, all the counters are set back to zero. This is because Admin Mod unloads and reloads your plugins on each map change.
There are two methods for maintaining data across map changes.
For this example, we will use the vault.
First, we need to write the list of player names and their associated name change count to the vault. Ideally we would do this when our plugin is being shutdown, but we don't know when this is happen. Therefore it needs to be done inside plugin_info on each name change.
The vault stores strings using a string lookup key. To prevent the size of the vault growing out of control over time, we won't use the player name as the vault key. we will use their index.
The support function WriteToVault is used to write a single player's name and the number of times the have changed it to the vault. It also generates a vault key based on the index of the user.
/* Support Functions */
WriteToVault(index,name[],changes) {
new key[KEY_SIZE];
newdata[MAX_DATA_LENGTH];
snprintf(key,KEY_SIZE,"Changes%i",index);
snprintf(data,MAX_DATA_LENGTH,"%i %s",changes,name);
set_vaultdata(key,data);
}
When the plugin reloads after a map change, all the users will rejoin. At this point we need to check in the vault to see if we have saved their previous number of name changes. Therefore we write a support function ReadFromVault that returns the number of name changes for a particular player stored in the vault. If there is no data stored in the vault for this player, 0 is returned.
ReadFromVault(name[]) {
new i;
new key[KEY_SIZE];
new data[MAX_DATA_LENGTH];
new savedname[MAX_DATA_LENGTH];
new savedchanges[MAX_DATA_LENGTH];
new args;
for (i=1;i<MAX_PLAYERS;i++) {
snprintf(key,KEY_SIZE,"Changes%i",i);
get_vaultdata(key,data,MAX_DATA_LENGTH);
args=strsplit(data," ",savedchanges,MAX_DATA_LENGTH,savedname,MAX_DATA_LENGTH);
if (args==2) {
if (streq(savedname,name)) {
return strtonum(savedchanges);
}
}
}
return 0;
}
We need to call both ReadFromVault and WriteToVault in plugin_info. We call ReadFromVault when a player joins to determine the initial value to which to set their number of changes. We call WriteToVault when a player changes their name, so the vault data is accurate should a map change occur at this point.
public plugin_info(HLOldName, HLNewName, UserIndex) {
new OldName[MAX_NAME_LENGTH];
new NewName[MAX_NAME_LENGTH];
convert_string(HLOldName,OldName,MAX_NAME_LENGTH);
convert_string(HLNewName,NewName,MAX_NAME_LENGTH);
if (strlen(OldName) == 0) {
/* Player is connecting */
g_NameChanges[UserIndex] = ReadFromVault(NewName);
}
else {
if (streq(OldName,NewName) == 0) {
/* Player is changing their name */
g_NameChanges[UserIndex] = g_NameChanges[UserIndex] + 1;
WriteToVault(UserIndex,NewName,g_NameChanges[UserIndex]);
new msg[MAX_TEXT_LENGTH];
snprintf(msg,MAX_TEXT_LENGTH,"Player %s has changed their name %i times",NewName,g_NameChanges[UserIndex]);
log(msg);
}
}
return PLUGIN_CONTINUE;
}
However there is another less obvious place where we need to call WriteToVault. When a player leaves the server we need to erase the information about them in the vault. Otherwise if they rejoin at some point in the future (the next day even) and no other player has used their slot in the intervening period their number of name changes will still be in the vault.
The purpose of this plugin is to log the number of name changes while connected, not in a users entire time on the server. Therefore, plugin_disocnnect needs to change:
public plugin_disconnect(HLUserName, UserIndex) {
g_NameChanges[UserIndex] = 0;
WriteToVault(UserIndex,"",0);
return PLUGIN_CONTINUE;
}
Below is the final source code for this plugin. You can compile it and test that it retains the number of name changes across maps. In addition to the above changes, the constant KEY_SIZE is added, and forward declarations for the two new functions.
/*********************************************************
* Player tracking plugin - Version 1.2 *
*********************************************************
* *
* Name: plugin_track *
* Author: ravenousbugblatterbeast@hotmail.com *
* Released: 1st September 2002 *
* *
* Version 1.2: *
* *
* - Name change counts are retained across map *
* changes. *
* *
* Version 1.1: *
* *
* - Command added to report number of changes *
* *
* Version 1.0: *
* *
* - Initial version *
* *
*********************************************************
*/
/* Includes */
#include <core>
#include <console>
#include <string>
#include <plugin>
#include <admin>
#include <adminlib>
/* Constants */
/* Size of a vault key */
#define KEY_SIZE 10
/* Global Variables */
new g_Version[]="1.2"; /* Plugin version number */
new g_NameChanges[MAX_PLAYERS]; /* Number of times each player has changed their name */
/* Function Declarations */
forward AdminNameChanges(HLCommand,HLData,HLUserName,UserIndex);
forward WriteToVault(index,name[],changes);
forward ReadFromVault(name[]);
/* Event Handlers */
public plugin_init() {
plugin_registerinfo("Player tracking Plugin","Counts player name changes",g_Version);
plugin_registercmd("admin_namechanges","AdminNameChanges",ACCESS_ALL,
"admin_namechanges: Report how many times each player has changed their name");
return PLUGIN_CONTINUE;
}
public plugin_info(HLOldName, HLNewName, UserIndex) {
new OldName[MAX_NAME_LENGTH];
new NewName[MAX_NAME_LENGTH];
convert_string(HLOldName,OldName,MAX_NAME_LENGTH);
convert_string(HLNewName,NewName,MAX_NAME_LENGTH);
if (strlen(OldName) == 0) {
/* Player is connecting */
g_NameChanges[UserIndex] = ReadFromVault(NewName);
}
else {
if (streq(OldName,NewName) == 0) {
/* Player is changing their name */
g_NameChanges[UserIndex] = g_NameChanges[UserIndex] + 1;
WriteToVault(UserIndex,NewName,g_NameChanges[UserIndex]);
new msg[MAX_TEXT_LENGTH];
snprintf(msg,MAX_TEXT_LENGTH,"Player %s has changed their name %i times",NewName,g_NameChanges[UserIndex]);
log(msg);
}
}
return PLUGIN_CONTINUE;
}
public plugin_disconnect(HLUserName, UserIndex) {
g_NameChanges[UserIndex] = 0;
WriteToVault(UserIndex,"",0);
return PLUGIN_CONTINUE;
}
/* Command Handlers */
public AdminNameChanges(HLCommand,HLData,HLUserName,UserIndex) {
new c = maxplayercount();
new i;
new name[MAX_NAME_LENGTH];
new msg[MAX_TEXT_LENGTH];
new display;
new search[MAX_DATA_LENGTH];
convert_string(HLData,search,MAX_DATA_LENGTH);
for (i=1; i<=c; i++) {
if (playerinfo(i, name, MAX_NAME_LENGTH)==1) {
display = 1;
if (strlen(search)>0) {
if (streq(search,name)==0) {
display = 0;
}
}
if (display) {
snprintf(msg,MAX_TEXT_LENGTH,"%s has changed their name %i times.", name, g_NameChanges[i]);
selfmessage(msg);
}
}
}
return PLUGIN_HANDLED;
}
/* Support Functions */
WriteToVault(index,name[],changes) {
new key[KEY_SIZE];
newdata[MAX_DATA_LENGTH];
snprintf(key,KEY_SIZE,"Changes%i",index);
snprintf(data,MAX_DATA_LENGTH,"%i %s",changes,name);
set_vaultdata(key,data);
}
ReadFromVault(name[]) {
new i;
new key[KEY_SIZE];
new data[MAX_DATA_LENGTH];
new savedname[MAX_DATA_LENGTH];
new savedchanges[MAX_DATA_LENGTH];
new args;
for (i=1;i<MAX_PLAYERS;i++) {
snprintf(key,KEY_SIZE,"Changes%i",i);
get_vaultdata(key,data,MAX_DATA_LENGTH);
args=strsplit(data," ",savedchanges,MAX_DATA_LENGTH,savedname,MAX_DATA_LENGTH);
if (args==2) {
if (streq(savedname,name)) {
return strtonum(savedchanges);
}
}
}
return 0;
}
There are two logic bugs in this plugin (well two *intentional* logic bugs anyway). Two situations in which the plugin will report inaccurate data. See if you can spot either one and think of a way to fix them.
Clue: Neither bug existed in the previous version.
Click here for the answer