ref: 4a005eafa7faea031cf386d5aea53716d0864c69
parent: 21bc4c4ab90df0455eaeba6a4c959005493f0a76
author: Simon Howard <[email protected]>
date: Sun Aug 25 18:13:11 EDT 2013
Read/write mobj_t structures to savegame files portably. Subversion-branch: /branches/v2-branch Subversion-revision: 2626
--- a/src/hexen/sv_save.c
+++ b/src/hexen/sv_save.c
@@ -120,10 +120,8 @@
static void UnarchiveMisc(void);
static void SetMobjArchiveNums(void);
static void RemoveAllThinkers(void);
-static void MangleMobj(mobj_t * mobj);
-static void RestoreMobj(mobj_t * mobj);
static int GetMobjNum(mobj_t * mobj);
-static void SetMobjPtr(int *archiveNum);
+static void SetMobjPtr(mobj_t **ptr, unsigned int archiveNum);
static void MangleSSThinker(ssthinker_t * sst);
static void RestoreSSThinker(ssthinker_t * sst);
static void RestoreSSThinkerNoSD(ssthinker_t * sst);
@@ -156,7 +154,7 @@
static int MobjCount;
static mobj_t **MobjList;
-static int **TargetPlayerAddrs;
+static mobj_t ***TargetPlayerAddrs;
static int TargetPlayerCount;
static byte *SaveBuffer;
static boolean SavingPlayers;
@@ -780,7 +778,437 @@
}
+//
+// thinker_t
+//
+static void StreamIn_thinker_t(thinker_t *str)
+{
+ // struct thinker_s *prev, *next;
+ // Pointers are discarded:
+ GET_LONG;
+ str->prev = NULL;
+ GET_LONG;
+ str->next = NULL;
+
+ // think_t function;
+ // Function pointer is discarded:
+ GET_LONG;
+ str->function = NULL;
+}
+
+static void StreamOut_thinker_t(thinker_t *str)
+{
+ // struct thinker_s *prev, *next;
+ StreamOutPtr(str->prev);
+ StreamOutPtr(str->next);
+
+ // think_t function;
+ StreamOutPtr(&str->function);
+}
+
+
+//
+// mobj_t
+//
+
+static void StreamInMobjSpecials(mobj_t *mobj)
+{
+ unsigned int special1, special2;
+
+ special1 = GET_LONG;
+ special2 = GET_LONG;
+
+ mobj->special1.i = special1;
+ mobj->special2.i = special2;
+
+ switch (mobj->type)
+ {
+ // Just special1
+ case MT_BISH_FX:
+ case MT_HOLY_FX:
+ case MT_DRAGON:
+ case MT_THRUSTFLOOR_UP:
+ case MT_THRUSTFLOOR_DOWN:
+ case MT_MINOTAUR:
+ case MT_SORCFX1:
+ SetMobjPtr(&mobj->special1.m, special1);
+ break;
+
+ // Just special2
+ case MT_LIGHTNING_FLOOR:
+ case MT_LIGHTNING_ZAP:
+ SetMobjPtr(&mobj->special2.m, special2);
+ break;
+
+ // Both special1 and special2
+ case MT_HOLY_TAIL:
+ case MT_LIGHTNING_CEILING:
+ SetMobjPtr(&mobj->special1.m, special1);
+ SetMobjPtr(&mobj->special2.m, special2);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void StreamIn_mobj_t(mobj_t *str)
+{
+ unsigned int i;
+
+ // thinker_t thinker;
+ StreamIn_thinker_t(&str->thinker);
+
+ // fixed_t x, y, z;
+ str->x = GET_LONG;
+ str->y = GET_LONG;
+ str->z = GET_LONG;
+
+ // struct mobj_s *snext, *sprev;
+ // Pointer values are discarded:
+ GET_LONG;
+ str->snext = NULL;
+ GET_LONG;
+ str->sprev = NULL;
+
+ // angle_t angle;
+ str->angle = GET_LONG;
+
+ // spritenum_t sprite;
+ str->sprite = GET_LONG;
+
+ // int frame;
+ str->frame = GET_LONG;
+
+ // struct mobj_s *bnext, *bprev;
+ // Values are read but discarded; this will be restored when the thing's
+ // position is set.
+ GET_LONG;
+ str->bnext = NULL;
+ GET_LONG;
+ str->bprev = NULL;
+
+ // struct subsector_s *subsector;
+ // Read but discard: pointer will be restored when thing position is set.
+ GET_LONG;
+ str->subsector = NULL;
+
+ // fixed_t floorz, ceilingz;
+ str->floorz = GET_LONG;
+ str->ceilingz = GET_LONG;
+
+ // fixed_t floorpic;
+ str->floorpic = GET_LONG;
+
+ // fixed_t radius, height;
+ str->radius = GET_LONG;
+ str->height = GET_LONG;
+
+ // fixed_t momx, momy, momz;
+ str->momx = GET_LONG;
+ str->momy = GET_LONG;
+ str->momz = GET_LONG;
+
+ // int validcount;
+ str->validcount = GET_LONG;
+
+ // mobjtype_t type;
+ str->type = GET_LONG;
+
+ // mobjinfo_t *info;
+ // Pointer value is read but discarded.
+ GET_LONG;
+ str->info = NULL;
+
+ // int tics;
+ str->tics = GET_LONG;
+
+ // state_t *state;
+ // Restore as index into states table.
+ i = GET_LONG;
+ str->state = &states[i];
+
+ // int damage;
+ str->damage = GET_LONG;
+
+ // int flags;
+ str->flags = GET_LONG;
+
+ // int flags2;
+ str->flags2 = GET_LONG;
+
+ // specialval_t special1;
+ // specialval_t special2;
+ // Read in special values: there are special cases to deal with with
+ // mobj pointers.
+ StreamInMobjSpecials(str);
+
+ // int health;
+ str->health = GET_LONG;
+
+ // int movedir;
+ str->movedir = GET_LONG;
+
+ // int movecount;
+ str->movecount = GET_LONG;
+
+ // struct mobj_s *target;
+ i = GET_LONG;
+ SetMobjPtr(&str->target, i);
+
+ // int reactiontime;
+ str->reactiontime = GET_LONG;
+
+ // int threshold;
+ str->threshold = GET_LONG;
+
+ // struct player_s *player;
+ // Saved as player number.
+ i = GET_LONG;
+ if (i == 0)
+ {
+ str->player = NULL;
+ }
+ else
+ {
+ str->player = &players[i - 1];
+ str->player->mo = str;
+ }
+
+ // int lastlook;
+ str->lastlook = GET_LONG;
+
+ // fixed_t floorclip;
+ str->floorclip = GET_LONG;
+
+ // int archiveNum;
+ str->archiveNum = GET_LONG;
+
+ // short tid;
+ str->tid = GET_WORD;
+
+ // byte special;
+ str->special = GET_BYTE;
+
+ // byte args[5];
+ for (i=0; i<5; ++i)
+ {
+ str->args[i] = GET_BYTE;
+ }
+}
+
+static void StreamOutMobjSpecials(mobj_t *mobj)
+{
+ unsigned int special1, special2;
+ boolean corpse;
+
+ corpse = (mobj->flags & MF_CORPSE) != 0;
+ special1 = mobj->special1.i;
+ special2 = mobj->special2.i;
+
+ switch (mobj->type)
+ {
+ // Just special1
+ case MT_BISH_FX:
+ case MT_HOLY_FX:
+ case MT_DRAGON:
+ case MT_THRUSTFLOOR_UP:
+ case MT_THRUSTFLOOR_DOWN:
+ case MT_MINOTAUR:
+ case MT_SORCFX1:
+ case MT_MSTAFF_FX2:
+ if (corpse)
+ {
+ special1 = MOBJ_NULL;
+ }
+ else
+ {
+ special1 = GetMobjNum(mobj->special1.m);
+ }
+ break;
+
+ // Just special2
+ case MT_LIGHTNING_FLOOR:
+ case MT_LIGHTNING_ZAP:
+ if (corpse)
+ {
+ special2 = MOBJ_NULL;
+ }
+ else
+ {
+ special2 = GetMobjNum(mobj->special2.m);
+ }
+ break;
+
+ // Both special1 and special2
+ case MT_HOLY_TAIL:
+ case MT_LIGHTNING_CEILING:
+ if (corpse)
+ {
+ special1 = MOBJ_NULL;
+ special2 = MOBJ_NULL;
+ }
+ else
+ {
+ special1 = GetMobjNum(mobj->special1.m);
+ special2 = GetMobjNum(mobj->special2.m);
+ }
+ break;
+
+ // Miscellaneous
+ case MT_KORAX:
+ special1 = 0; // Searching index
+ break;
+
+ default:
+ break;
+ }
+
+ // Write special values to savegame file.
+
+ StreamOutLong(special1);
+ StreamOutLong(special2);
+}
+
+static void StreamOut_mobj_t(mobj_t *str)
+{
+ int i;
+
+ // thinker_t thinker;
+ StreamOut_thinker_t(&str->thinker);
+
+ // fixed_t x, y, z;
+ StreamOutLong(str->x);
+ StreamOutLong(str->y);
+ StreamOutLong(str->z);
+
+ // struct mobj_s *snext, *sprev;
+ StreamOutPtr(str->snext);
+ StreamOutPtr(str->sprev);
+
+ // angle_t angle;
+ StreamOutLong(str->angle);
+
+ // spritenum_t sprite;
+ StreamOutLong(str->sprite);
+
+ // int frame;
+ StreamOutLong(str->frame);
+
+ // struct mobj_s *bnext, *bprev;
+ StreamOutPtr(str->bnext);
+ StreamOutPtr(str->bprev);
+
+ // struct subsector_s *subsector;
+ StreamOutPtr(str->subsector);
+
+ // fixed_t floorz, ceilingz;
+ StreamOutLong(str->floorz);
+ StreamOutLong(str->ceilingz);
+
+ // fixed_t floorpic;
+ StreamOutLong(str->floorpic);
+
+ // fixed_t radius, height;
+ StreamOutLong(str->radius);
+ StreamOutLong(str->height);
+
+ // fixed_t momx, momy, momz;
+ StreamOutLong(str->momx);
+ StreamOutLong(str->momy);
+ StreamOutLong(str->momz);
+
+ // int validcount;
+ StreamOutLong(str->validcount);
+
+ // mobjtype_t type;
+ StreamOutLong(str->type);
+
+ // mobjinfo_t *info;
+ StreamOutPtr(str->info);
+
+ // int tics;
+ StreamOutLong(str->tics);
+
+ // state_t *state;
+ // Save as index into the states table.
+ StreamOutLong(str->state - states);
+
+ // int damage;
+ StreamOutLong(str->damage);
+
+ // int flags;
+ StreamOutLong(str->flags);
+
+ // int flags2;
+ StreamOutLong(str->flags2);
+
+ // specialval_t special1;
+ // specialval_t special2;
+ // There are lots of special cases for the special values:
+ StreamOutMobjSpecials(str);
+
+ // int health;
+ StreamOutLong(str->health);
+
+ // int movedir;
+ StreamOutLong(str->movedir);
+
+ // int movecount;
+ StreamOutLong(str->movecount);
+
+ // struct mobj_s *target;
+ if ((str->flags & MF_CORPSE) != 0)
+ {
+ StreamOutLong(MOBJ_NULL);
+ }
+ else
+ {
+ StreamOutLong(GetMobjNum(str->target));
+ }
+
+ // int reactiontime;
+ StreamOutLong(str->reactiontime);
+
+ // int threshold;
+ StreamOutLong(str->threshold);
+
+ // struct player_s *player;
+ // Stored as index into players[] array, if there is a player pointer.
+ if (str->player != NULL)
+ {
+ StreamOutLong(str->player - players + 1);
+ }
+ else
+ {
+ StreamOutLong(0);
+ }
+
+ // int lastlook;
+ StreamOutLong(str->lastlook);
+
+ // fixed_t floorclip;
+ StreamOutLong(str->floorclip);
+
+ // int archiveNum;
+ StreamOutLong(str->archiveNum);
+
+ // short tid;
+ StreamOutWord(str->tid);
+
+ // byte special;
+ StreamOutByte(str->special);
+
+ // byte args[5];
+ for (i=0; i<5; ++i)
+ {
+ StreamOutByte(str->args[i]);
+ }
+}
+
+
+
//==========================================================================
//
// SV_SaveGame
@@ -1142,7 +1570,7 @@
{
for (i = 0; i < TargetPlayerCount; i++)
{
- *TargetPlayerAddrs[i] = (int) targetPlayerMobj;
+ *TargetPlayerAddrs[i] = targetPlayerMobj;
}
Z_Free(TargetPlayerAddrs);
}
@@ -1451,7 +1879,6 @@
{
int count;
thinker_t *thinker;
- mobj_t tempMobj;
StreamOutLong(ASEG_MOBJS);
StreamOutLong(MobjCount);
@@ -1468,9 +1895,7 @@
continue;
}
count++;
- memcpy(&tempMobj, thinker, sizeof(mobj_t));
- MangleMobj(&tempMobj);
- StreamOutBuffer(&tempMobj, sizeof(mobj_t));
+ StreamOut_mobj_t((mobj_t *) thinker);
}
if (count != MobjCount)
{
@@ -1490,7 +1915,7 @@
mobj_t *mobj;
AssertSegment(ASEG_MOBJS);
- TargetPlayerAddrs = Z_Malloc(MAX_TARGET_PLAYERS * sizeof(int *),
+ TargetPlayerAddrs = Z_Malloc(MAX_TARGET_PLAYERS * sizeof(mobj_t **),
PU_STATIC, NULL);
TargetPlayerCount = 0;
MobjCount = GET_LONG;
@@ -1502,10 +1927,15 @@
for (i = 0; i < MobjCount; i++)
{
mobj = MobjList[i];
- memcpy(mobj, SavePtr.b, sizeof(mobj_t));
- SavePtr.b += sizeof(mobj_t);
+ StreamIn_mobj_t(mobj);
+
+ // Restore broken pointers.
+ mobj->info = &mobjinfo[mobj->type];
+ P_SetThingPosition(mobj);
+ mobj->floorz = mobj->subsector->sector->floorheight;
+ mobj->ceilingz = mobj->subsector->sector->ceilingheight;
+
mobj->thinker.function = P_MobjThinker;
- RestoreMobj(mobj);
P_AddThinker(&mobj->thinker);
}
P_CreateTIDList();
@@ -1514,89 +1944,6 @@
//==========================================================================
//
-// MangleMobj
-//
-//==========================================================================
-
-static void MangleMobj(mobj_t * mobj)
-{
- boolean corpse;
-
- corpse = mobj->flags & MF_CORPSE;
- mobj->state = (state_t *) (mobj->state - states);
- if (mobj->player)
- {
- mobj->player = (player_t *) ((mobj->player - players) + 1);
- }
- if (corpse)
- {
- mobj->target = (mobj_t *) MOBJ_NULL;
- }
- else
- {
- mobj->target = (mobj_t *) GetMobjNum(mobj->target);
- }
- switch (mobj->type)
- {
- // Just special1
- case MT_BISH_FX:
- case MT_HOLY_FX:
- case MT_DRAGON:
- case MT_THRUSTFLOOR_UP:
- case MT_THRUSTFLOOR_DOWN:
- case MT_MINOTAUR:
- case MT_SORCFX1:
- case MT_MSTAFF_FX2:
- if (corpse)
- {
- mobj->special1.m = MOBJ_NULL;
- }
- else
- {
- mobj->special1.m = GetMobjNum(mobj->special1.m);
- }
- break;
-
- // Just special2
- case MT_LIGHTNING_FLOOR:
- case MT_LIGHTNING_ZAP:
- if (corpse)
- {
- mobj->special2.m = MOBJ_NULL;
- }
- else
- {
- mobj->special2.m = GetMobjNum(mobj->special2.m);
- }
- break;
-
- // Both special1 and special2
- case MT_HOLY_TAIL:
- case MT_LIGHTNING_CEILING:
- if (corpse)
- {
- mobj->special1.m = MOBJ_NULL;
- mobj->special2.m = MOBJ_NULL;
- }
- else
- {
- mobj->special1.m = GetMobjNum(mobj->special1.m);
- mobj->special2.m = GetMobjNum(mobj->special2.m);
- }
- break;
-
- // Miscellaneous
- case MT_KORAX:
- mobj->special1.i = 0; // Searching index
- break;
-
- default:
- break;
- }
-}
-
-//==========================================================================
-//
// GetMobjNum
//
//==========================================================================
@@ -1616,78 +1963,29 @@
//==========================================================================
//
-// RestoreMobj
-//
-//==========================================================================
-
-static void RestoreMobj(mobj_t * mobj)
-{
- mobj->state = &states[(int) mobj->state];
- if (mobj->player)
- {
- mobj->player = &players[(int) mobj->player - 1];
- mobj->player->mo = mobj;
- }
- P_SetThingPosition(mobj);
- mobj->info = &mobjinfo[mobj->type];
- mobj->floorz = mobj->subsector->sector->floorheight;
- mobj->ceilingz = mobj->subsector->sector->ceilingheight;
- SetMobjPtr((int *) &mobj->target);
- switch (mobj->type)
- {
- // Just special1
- case MT_BISH_FX:
- case MT_HOLY_FX:
- case MT_DRAGON:
- case MT_THRUSTFLOOR_UP:
- case MT_THRUSTFLOOR_DOWN:
- case MT_MINOTAUR:
- case MT_SORCFX1:
- SetMobjPtr(&mobj->special1.i);
- break;
-
- // Just special2
- case MT_LIGHTNING_FLOOR:
- case MT_LIGHTNING_ZAP:
- SetMobjPtr(&mobj->special2.i);
- break;
-
- // Both special1 and special2
- case MT_HOLY_TAIL:
- case MT_LIGHTNING_CEILING:
- SetMobjPtr(&mobj->special1.i);
- SetMobjPtr(&mobj->special2.i);
- break;
-
- default:
- break;
- }
-}
-
-//==========================================================================
-//
// SetMobjPtr
//
//==========================================================================
-static void SetMobjPtr(int *archiveNum)
+static void SetMobjPtr(mobj_t **ptr, unsigned int archiveNum)
{
- if (*archiveNum == MOBJ_NULL)
+ if (archiveNum == MOBJ_NULL)
{
- *archiveNum = 0;
- return;
+ *ptr = NULL;
}
- if (*archiveNum == MOBJ_XX_PLAYER)
+ else if (archiveNum == MOBJ_XX_PLAYER)
{
if (TargetPlayerCount == MAX_TARGET_PLAYERS)
{
I_Error("RestoreMobj: exceeded MAX_TARGET_PLAYERS");
}
- TargetPlayerAddrs[TargetPlayerCount++] = archiveNum;
- *archiveNum = 0;
- return;
+ TargetPlayerAddrs[TargetPlayerCount++] = ptr;
+ *ptr = NULL;
}
- *archiveNum = (int) MobjList[*archiveNum];
+ else
+ {
+ *ptr = MobjList[archiveNum];
+ }
}
//==========================================================================
@@ -1829,7 +2127,7 @@
{
script->line = &lines[(int) script->line];
}
- SetMobjPtr((int *) &script->activator);
+ SetMobjPtr(&script->activator, (int) script->activator);
}
//==========================================================================