|
Hi Guys i
thought someone might find this useful so im posting a STAT saving system and
details of how to add it the code is forward and backward compatible ie you
can add new things to save and the old files will still work or you can load
a new file that has extra things on a old version...
Please Make a new file
call it what you will load_save.c for example
And add the followinf
functions:
//[QBS]===========================================
// This peice of code is designed to be used for
// player Persistance & global stats
// Coded By [QBS]Quadrant
//================================================
//load_save.c
#include "g_local.h" // talks to q2 engine
#include "load_save.h"
#include //[QBS] DISK MAKE/REMOVE DIR'S
static const char *
PSUBDIR = "save/playerfiles";// subdir in your mod folder to save
to
/* this version always zero-terminates, unlike the silly standard one */
// mysnprintf is coded by Blinky
int mysnprintf(char * buffer, size_t count, const char * fmt, ...)
{
va_list argptr;
int ret;
va_start(argptr, fmt);
ret = _vsnprintf(buffer, count, fmt, argptr);
va_end(argptr);
buffer[count-1]=0; /* Always put zero at end */
return ret;
}
//ok the below peices of
code in this comment are to define the
//gamepath which is very useful,,
static void SetFilename(char * filename,int len, edict_t *ent)
{
char mod[16];
_mkdir ("your_mod/save/playerfiles");//[QBS] make the dir if we
dont have it
if (gamepath->string
&& gamepath->string[0])
strcpy(mod, gamepath->string);
else
strcpy(mod, "baseq2");
mysnprintf(filename, len, "%s/%s/%s.DAT", mod, PSUBDIR,ent->client->pers.netname);
}
//=======================================================================================
void WRITE_PLAYER_STATS
(edict_t *ent)// SAVE PLAYER
{
edict_t *attacker;
edict_t *self;
char filename[128];
FILE *FH;
attacker = ent;
self = ent;
ent = ent; //[QBS]what the hell lol :)
SetFilename(filename, sizeof(filename), ent);
// MISC
/*
ok what things should we have on player persistance
example
Deaths
Kills
Time played
Kill Percentage Worked out from kills to deaths
Player Password (to protect players character maybe)
*/
// DAT.player_password =
ent->client->player_password;//example
DAT.version = file_version;
// EXP
DAT.score = ent->client->resp.score;// was used in testing
DAT.health = ent->health;
//[QBS] Player tracking
anything you like can go here
DAT.player_deaths =
ent->client->resp.player_deaths;
DAT.player_kills_given = ent->client->resp.player_kills_given;
//[QBS]end
/*
If you wanted you could have this post to a global system at this point to
have global data for all servers running your mod
*/
if ((FH = fopen( filename, "wb")) == NULL)
{
// gi.cprintf(ent, PRINT_HIGH, "File is already in use\n");
return;
}
fwrite ( &DAT, sizeof(DAT), 1, FH );
fclose ( FH );
}
//======================================================================================
void READ_PLAYER_STATS
(edict_t *ent)// LOAD
{
FILE *FH;
char filename[128];
//[QBS]attempt to make global
edict_t *attacker;
edict_t *self;
attacker = ent;
self = ent;
ent = ent; //what the hell lol :)
//[QBS]end
SetFilename(filename, sizeof(filename), ent);
if ((FH = fopen(
filename, "rb")) == NULL)
{
// gi.cprintf(ent, PRINT_HIGH, "Player not found making new player.data
file\n");
WRITE_PLAYER_STATS (ent);
return;
}
fread ( &DAT, sizeof(DAT), 1, FH );
fclose ( FH );
if (DAT.version != file_version)// delete if not needed
// gi.cprintf(ent, PRINT_HIGH, "Incorrect file version.\n");//
delete if not needed
/*
if (DAT.player_password != ent->client->player_password)
{
gi.centerprintf (ent, "Incorrect Password:\n %c",ent->client->player_password);
return;
}
*/
ent->client->resp.score
= DAT.score;
ent->health = DAT.health;
ent->client->player_password = DAT.player_password;
ent->client->resp.player_deaths
= DAT.player_deaths;
ent->client->resp.player_kills_given = DAT.player_kills_given;//[QBS]end
//gi.cprintf(ent, PRINT_HIGH, "Player was loaded correctly.\n");
// ent->client->resp.loaded = 1;
}
//======================================================================================
ok next you need to make
a header file for the above load_save.h etc
void WRITE_PLAYER_STATS
(edict_t *ent);
void READ_PLAYER_STATS (edict_t *ent);
// ANYTHING YOU WISH TO
SAVE MUST ALSO BE ADDED TO THE BELOW STRUCTURE
struct player_save
{
//MISC
int version;
// PASSWORD
// char pwd[32];
int player_password;
// EXPERIENCE
int health;
int player_deaths;
int player_kills_given;
int score;
}DAT;
//=======================================================================================
Ok the most important
thing now is to call these functions at suitable places one mistake people
make is they dont save the player often enough and then if there is a server
crash people loose lots of points etc and get very unhappy so i save on every
kill or death and on player disconnect...
ok to load the player we
need to call READ_PLAYER_STATS (ent);
the best locations for
this are as follows
If you are using a menu
system in your mod to join a player or for a player to pick a class etc then
i would call it from this menu..
I would also call this say
in InitClientPersistant in p_client.c for none menu games or where for
example you are switching from a spectator to active player..
ok next to save the player we need to call WRITE_PLAYER_STATS (ent);
This would be best done
as follows
if you collect an item
that is very important to the game or if you just gained some player
experience in some way that is a lot etc that it would be nice to call the
save function.
ok in player_die after
the points have been added or deducted for the dead player and the attacker
etc we would save the changes to both players as follows
if
(attacker->client)// yes attacker was client
{
WRITE_PLAYER_STATS(attacker);//[QBS]
}
else//[QBS] must have been the world that killed them
{
}
if (!self->client)
return;
WRITE_PLAYER_STATS(self);//[QBS] dead dude !! he's dead Jim !!! hehehe
//[QBS]1end
ok next at the bottom of ClientDisconnect we would call this function to save
there last stats
WRITE_PLAYER_STATS
(ent);//[QBS]
//=======================================================================================
Ok that ends this
Tutorial i hope you guys will find it useful adn post feedback ok bye...
|