Den Savegamecode hoch auf 3.20 portiert. Muss noch mal ordentlich

durchgetestet werden, gerade auf 32Bit und Linux
This commit is contained in:
Yamagi Burmeister 2009-04-10 14:23:07 +00:00
parent 347d281530
commit 2590b35e2a
2 changed files with 86 additions and 130 deletions

View file

@ -559,10 +559,10 @@ extern int meansOfDeath;
extern edict_t *g_edicts; extern edict_t *g_edicts;
#define FOFS(x) (int)&(((edict_t *)0)->x) #define FOFS(x) (size_t)&(((edict_t *)NULL)->x)
#define STOFS(x) (int)&(((spawn_temp_t *)0)->x) #define STOFS(x) (size_t)&(((spawn_temp_t *)NULL)->x)
#define LLOFS(x) (int)&(((level_locals_t *)0)->x) #define LLOFS(x) (size_t)&(((level_locals_t *)NULL)->x)
#define CLOFS(x) (int)&(((gclient_t *)0)->x) #define CLOFS(x) (size_t)&(((gclient_t *)NULL)->x)
#define random() ((rand () & 0x7fff) / ((float)0x7fff)) #define random() ((rand () & 0x7fff) / ((float)0x7fff))
#define crandom() (2.0 * (random() - 0.5)) #define crandom() (2.0 * (random() - 0.5))
@ -631,6 +631,8 @@ typedef enum {
F_EDICT, // index on disk, pointer in memory F_EDICT, // index on disk, pointer in memory
F_ITEM, // index on disk, pointer in memory F_ITEM, // index on disk, pointer in memory
F_CLIENT, // index on disk, pointer in memory F_CLIENT, // index on disk, pointer in memory
F_FUNCTION,
F_MMOVE,
F_IGNORE F_IGNORE
} fieldtype_t; } fieldtype_t;

View file

@ -1,13 +1,8 @@
#include "g_local.h" #include "g_local.h"
#if defined(_DEBUG) && defined(_Z_TESTMODE) #define Function(f) {#f, f}
void InitTestWeapon(void);
void InitTestItem(void);
#endif
mmove_t mmove_reloc;
field_t fields[] = { field_t fields[] = {
{"classname", FOFS(classname), F_LSTRING}, {"classname", FOFS(classname), F_LSTRING},
@ -70,83 +65,33 @@ field_t fields[] = {
{"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP}, {"maxyaw", STOFS(maxyaw), F_FLOAT, FFL_SPAWNTEMP},
{"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP}, {"minpitch", STOFS(minpitch), F_FLOAT, FFL_SPAWNTEMP},
{"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP}, {"maxpitch", STOFS(maxpitch), F_FLOAT, FFL_SPAWNTEMP},
{"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP} {"nextmap", STOFS(nextmap), F_LSTRING, FFL_SPAWNTEMP},
};
// -------- just for savegames ----------
// all pointer fields should be listed here, or savegames
// won't work properly (they will crash and burn).
// this wasn't just tacked on to the fields array, because
// these don't need names, we wouldn't want map fields using
// some of these, and if one were accidentally present twice
// it would double swizzle (fuck) the pointer.
field_t savefields[] =
{
{"", FOFS(classname), F_LSTRING},
{"", FOFS(target), F_LSTRING},
{"", FOFS(targetname), F_LSTRING},
{"", FOFS(killtarget), F_LSTRING},
{"", FOFS(team), F_LSTRING},
{"", FOFS(pathtarget), F_LSTRING},
{"", FOFS(deathtarget), F_LSTRING},
{"", FOFS(combattarget), F_LSTRING},
{"", FOFS(model), F_LSTRING},
{"", FOFS(model2), F_LSTRING},
{"", FOFS(model3), F_LSTRING},
{"", FOFS(model4), F_LSTRING},
{"", FOFS(map), F_LSTRING},
{"", FOFS(message), F_LSTRING},
{"", FOFS(client), F_CLIENT},
{"", FOFS(item), F_ITEM},
{"", FOFS(goalentity), F_EDICT},
{"", FOFS(movetarget), F_EDICT},
{"", FOFS(enemy), F_EDICT},
{"", FOFS(oldenemy), F_EDICT},
{"", FOFS(activator), F_EDICT},
{"", FOFS(groundentity), F_EDICT},
{"", FOFS(teamchain), F_EDICT},
{"", FOFS(teammaster), F_EDICT},
{"", FOFS(owner), F_EDICT},
{"", FOFS(mynoise), F_EDICT},
{"", FOFS(mynoise2), F_EDICT},
{"", FOFS(target_ent), F_EDICT},
{"", FOFS(chain), F_EDICT},
// evolve {0, 0, 0, 0}
{"", FOFS(laser), F_EDICT},
{"", FOFS(zRaduisList), F_EDICT},
{"", FOFS(zSchoolChain), F_EDICT},
{"", FOFS(rideWith[0]), F_EDICT},
{"", FOFS(rideWith[1]), F_EDICT},
{"", FOFS(mteam), F_LSTRING},
{NULL, 0, F_INT}
}; };
field_t levelfields[] = field_t levelfields[] =
{ {
{"", LLOFS(changemap), F_LSTRING}, {"changemap", LLOFS(changemap), F_LSTRING},
{"", LLOFS(sight_client), F_EDICT}, {"sight_client", LLOFS(sight_client), F_EDICT},
{"", LLOFS(sight_entity), F_EDICT}, {"sight_entity", LLOFS(sight_entity), F_EDICT},
{"", LLOFS(sound_entity), F_EDICT}, {"sound_entity", LLOFS(sound_entity), F_EDICT},
{"", LLOFS(sound2_entity), F_EDICT}, {"sound2_entity", LLOFS(sound2_entity), F_EDICT},
{NULL, 0, F_INT} {NULL, 0, F_INT}
}; };
field_t clientfields[] = field_t clientfields[] =
{ {
{"", CLOFS(pers.weapon), F_ITEM}, {"pers.weapon", CLOFS(pers.weapon), F_ITEM},
{"", CLOFS(pers.lastweapon), F_ITEM}, {"pers.lastweapon", CLOFS(pers.lastweapon), F_ITEM},
{"", CLOFS(pers.lastweapon2), F_ITEM}, {"pers.lastweapon2", CLOFS(pers.lastweapon2), F_ITEM},
{"", CLOFS(newweapon), F_ITEM}, {"newweapon", CLOFS(newweapon), F_ITEM},
// evolve // evolve
{"", CLOFS(zCameraTrack), F_EDICT}, {"zCameraTrack", CLOFS(zCameraTrack), F_EDICT},
{"", CLOFS(zCameraLocalEntity), F_EDICT}, {"zCameraLocalEntitiy", CLOFS(zCameraLocalEntity), F_EDICT},
{NULL, 0, F_INT} {NULL, 0, F_INT}
}; };
@ -204,23 +149,10 @@ void InitGame (void)
bob_roll = gi.cvar ("bob_roll", "0.002", 0); bob_roll = gi.cvar ("bob_roll", "0.002", 0);
gamedir = gi.cvar ("gamedir", "baseq2", CVAR_SERVERINFO); gamedir = gi.cvar ("gamedir", "baseq2", CVAR_SERVERINFO);
#ifdef CACHE_SOUND
printSoundRejects = gi.cvar("printsoundrejects", "0", CVAR_SERVERINFO);
#endif
// items // items
InitItems (); InitItems ();
#if defined(_DEBUG) && defined(_Z_TESTMODE)
gi.dprintf ("==== InitTestWeapon ====\n");
InitTestWeapon();
gi.dprintf ("==== InitTestItem ====\n");
InitTestItem();
#endif
Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), ""); Com_sprintf (game.helpmessage1, sizeof(game.helpmessage1), "");
Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), ""); Com_sprintf (game.helpmessage2, sizeof(game.helpmessage2), "");
@ -248,6 +180,9 @@ void WriteField1 (FILE *f, field_t *field, byte *base)
int len; int len;
int index; int index;
if (field->flags & FFL_SPAWNTEMP)
return;
p = (void *)(base + field->ofs); p = (void *)(base + field->ofs);
switch (field->type) switch (field->type)
{ {
@ -288,16 +223,38 @@ void WriteField1 (FILE *f, field_t *field, byte *base)
*(int *)p = index; *(int *)p = index;
break; break;
//relative to code segment
case F_FUNCTION:
if (*(byte **)p == NULL)
index = 0;
else
index = *(byte **)p - ((byte *)InitGame);
*(int *)p = index;
break;
//relative to data segment
case F_MMOVE:
if (*(byte **)p == NULL)
index = 0;
else
index = *(byte **)p - (byte *)&mmove_reloc;
*(int *)p = index;
break;
default: default:
gi.error ("WriteEdict: unknown field type"); gi.error ("WriteEdict: unknown field type");
} }
} }
void WriteField2 (FILE *f, field_t *field, byte *base) void WriteField2 (FILE *f, field_t *field, byte *base)
{ {
int len; int len;
void *p; void *p;
if (field->flags & FFL_SPAWNTEMP)
return;
p = (void *)(base + field->ofs); p = (void *)(base + field->ofs);
switch (field->type) switch (field->type)
{ {
@ -309,6 +266,8 @@ void WriteField2 (FILE *f, field_t *field, byte *base)
fwrite (*(char **)p, len, 1, f); fwrite (*(char **)p, len, 1, f);
} }
break; break;
default:
break;
} }
} }
@ -318,6 +277,9 @@ void ReadField (FILE *f, field_t *field, byte *base)
int len; int len;
int index; int index;
if (field->flags & FFL_SPAWNTEMP)
return;
p = (void *)(base + field->ofs); p = (void *)(base + field->ofs);
switch (field->type) switch (field->type)
{ {
@ -334,17 +296,11 @@ void ReadField (FILE *f, field_t *field, byte *base)
*(char **)p = NULL; *(char **)p = NULL;
else else
{ {
*(char **)p = gi.TagMalloc (len, TAG_LEVEL); /*
fread (*(char **)p, len, 1, f); SBF: FIXME - 32 extra bytes alloc'd since the saved
} string might not be long enough
break; */
case F_GSTRING: *(char **)p = gi.TagMalloc (32+len, TAG_LEVEL);
len = *(int *)p;
if (!len)
*(char **)p = NULL;
else
{
*(char **)p = gi.TagMalloc (len, TAG_GAME);
fread (*(char **)p, len, 1, f); fread (*(char **)p, len, 1, f);
} }
break; break;
@ -370,6 +326,24 @@ void ReadField (FILE *f, field_t *field, byte *base)
*(gitem_t **)p = &itemlist[index]; *(gitem_t **)p = &itemlist[index];
break; break;
//relative to code segment
case F_FUNCTION:
index = *(int *)p;
if ( index == 0 )
*(byte **)p = NULL;
else
*(byte **)p = ((byte *)InitGame) + index;
break;
//relative to data segment
case F_MMOVE:
index = *(int *)p;
if (index == 0)
*(byte **)p = NULL;
else
*(byte **)p = (byte *)&mmove_reloc + index;
break;
default: default:
gi.error ("ReadEdict: unknown field type"); gi.error ("ReadEdict: unknown field type");
} }
@ -441,7 +415,7 @@ A single player death will automatically restore from the
last save position. last save position.
============ ============
*/ */
void WriteGame (char *filename, qboolean autosave) void WriteGame (const char *filename, qboolean autosave)
{ {
FILE *f; FILE *f;
int i; int i;
@ -468,16 +442,14 @@ void WriteGame (char *filename, qboolean autosave)
fclose (f); fclose (f);
} }
void ReadGame (char *filename) void ReadGame (const char *filename)
{ {
FILE *f; FILE *f;
int i; int i;
char str[16]; char str[16];
gi.FreeTags (TAG_GAME); gi.FreeTags (TAG_GAME);
#ifdef CACHE_SOUND
initSoundList();
#endif
f = fopen (filename, "rb"); f = fopen (filename, "rb");
if (!f) if (!f)
gi.error ("Couldn't open %s", filename); gi.error ("Couldn't open %s", filename);
@ -503,7 +475,6 @@ void ReadGame (char *filename)
//========================================================== //==========================================================
/* /*
============== ==============
WriteEdict WriteEdict
@ -516,15 +487,11 @@ void WriteEdict (FILE *f, edict_t *ent)
field_t *field; field_t *field;
edict_t temp; edict_t temp;
if (Q_stricmp(ent->classname, "misc_viper") == 0)
{
temp = *ent;
}
// all of the ints, floats, and vectors stay as they are // all of the ints, floats, and vectors stay as they are
temp = *ent; temp = *ent;
// change the pointers to lengths or indexes // change the pointers to lengths or indexes
for (field=savefields ; field->name ; field++) for (field=fields ; field->name ; field++)
{ {
WriteField1 (f, field, (byte *)&temp); WriteField1 (f, field, (byte *)&temp);
} }
@ -533,7 +500,7 @@ void WriteEdict (FILE *f, edict_t *ent)
fwrite (&temp, sizeof(temp), 1, f); fwrite (&temp, sizeof(temp), 1, f);
// now write any allocated data following the edict // now write any allocated data following the edict
for (field=savefields ; field->name ; field++) for (field=fields ; field->name ; field++)
{ {
WriteField2 (f, field, (byte *)ent); WriteField2 (f, field, (byte *)ent);
} }
@ -570,7 +537,6 @@ void WriteLevelLocals (FILE *f)
} }
} }
/* /*
============== ==============
ReadEdict ReadEdict
@ -584,7 +550,7 @@ void ReadEdict (FILE *f, edict_t *ent)
fread (ent, sizeof(*ent), 1, f); fread (ent, sizeof(*ent), 1, f);
for (field=savefields ; field->name ; field++) for (field=fields ; field->name ; field++)
{ {
ReadField (f, field, (byte *)ent); ReadField (f, field, (byte *)ent);
} }
@ -609,17 +575,13 @@ void ReadLevelLocals (FILE *f)
} }
} }
//==========================================================
/* /*
================= =================
WriteLevel WriteLevel
================= =================
*/ */
void WriteLevel (char *filename) void WriteLevel (const char *filename)
{ {
int i; int i;
edict_t *ent; edict_t *ent;
@ -654,8 +616,6 @@ void WriteLevel (char *filename)
fwrite (&i, sizeof(i), 1, f); fwrite (&i, sizeof(i), 1, f);
fclose (f); fclose (f);
// write out zaero between level
} }
@ -663,7 +623,7 @@ void WriteLevel (char *filename)
================= =================
ReadLevel ReadLevel
SpawnEntities will already have been called on the SpawnEntities will allready have been called on the
level the same way it was when the level was saved. level the same way it was when the level was saved.
That is necessary to get the baselines That is necessary to get the baselines
@ -675,7 +635,7 @@ calling ReadLevel.
No clients are connected yet. No clients are connected yet.
================= =================
*/ */
void ReadLevel (char *filename) void ReadLevel (const char *filename)
{ {
int entnum; int entnum;
FILE *f; FILE *f;
@ -690,9 +650,7 @@ void ReadLevel (char *filename)
// free any dynamic memory allocated by loading the level // free any dynamic memory allocated by loading the level
// base state // base state
gi.FreeTags (TAG_LEVEL); gi.FreeTags (TAG_LEVEL);
#ifdef CACHE_SOUND
initSoundList();
#endif
// wipe all the entities // wipe all the entities
memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0])); memset (g_edicts, 0, game.maxentities*sizeof(g_edicts[0]));
globals.num_edicts = maxclients->value+1; globals.num_edicts = maxclients->value+1;
@ -707,11 +665,7 @@ void ReadLevel (char *filename)
// check function pointer base address // check function pointer base address
fread (&base, sizeof(base), 1, f); fread (&base, sizeof(base), 1, f);
if (base != (void *)InitGame) gi.dprintf("Function offsets %d\n", ((byte *)base) - ((byte *)InitGame));
{
fclose (f);
gi.error ("ReadLevel: function pointers have moved");
}
// load the level locals // load the level locals
ReadLevelLocals (f); ReadLevelLocals (f);