diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 21fd66e97..8ad22558e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -6441,8 +6441,9 @@ static void Command_Archivetest_f(void) } // test archive - CONS_Printf("LUA_Archive...\n"); - LUA_Archive(&save, true); + CONS_Printf("LUA_Sync Archive...\n"); + save.write = true; + LUA_Sync(&save, true, false); WRITEUINT8(save.p, 0x7F); wrote = (UINT32)(save.p - save.buffer); @@ -6452,8 +6453,9 @@ static void Command_Archivetest_f(void) // test unarchive save.p = save.buffer; - CONS_Printf("LUA_UnArchive...\n"); - LUA_UnArchive(&save, true, false); + save.write = false; + CONS_Printf("LUA_Sync Unarchive...\n"); + LUA_Sync(&save, true, false); i = READUINT8(save.p); if (i != 0x7F || wrote != (UINT32)(save.p - save.buffer)) { diff --git a/src/g_demo.c b/src/g_demo.c index 388142013..141916b44 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -45,7 +45,7 @@ // SRB2Kart #include "d_netfil.h" // nameonly -#include "lua_script.h" // LUA_ArchiveDemo and LUA_UnArchiveDemo +#include "lua_script.h" // LUA_Sync #include "lua_libs.h" // gL (Lua state) #include "k_kart.h" @@ -2940,7 +2940,7 @@ void G_BeginRecording(void) // player lua vars, always saved even if empty if (demoflags & DF_LUAVARS) - LUA_Archive(&demobuf, false); + LUA_Sync(&demobuf, false, false); memset(&oldcmd,0,sizeof(oldcmd)); memset(&oldghost,0,sizeof(oldghost)); @@ -3793,7 +3793,7 @@ void G_DoPlayDemo(char *defdemoname) LUA_ClearState(); // No modeattacking check, DF_LUAVARS won't be present here. - LUA_UnArchive(&demobuf, false, G_CompatLevel(0x0002)); + LUA_Sync(&demobuf, false, G_CompatLevel(0x0002)); } splitscreen = 0; diff --git a/src/lua_script.c b/src/lua_script.c index 6d32162ac..ed719bcbb 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -1846,8 +1846,9 @@ void LUA_Step(void) } } -void LUA_Archive(savebuffer_t *save, boolean network) +void LUA_Sync(savebuffer_t *save, boolean network, boolean compat) { + UINT32 mobjnum; INT32 i; thinker_t *th; @@ -1858,71 +1859,60 @@ void LUA_Archive(savebuffer_t *save, boolean network) { if (!playeringame[i] && i > 0) // NEVER skip player 0, this is for dedi servs. continue; + // all players in game will be archived, even if they just add a 0. - ArchiveExtVars(&save->p, &players[i], "player"); + if (save->write) + ArchiveExtVars(&save->p, &players[i], "player"); + else + UnArchiveExtVars(&save->p, &players[i], compat); } - if (network == true) + if (save->write) { - if (gamestate == GS_LEVEL) + if (network == true) { - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + if (gamestate == GS_LEVEL) { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; - // archive function will determine when to skip mobjs, - // and write mobjnum in otherwise. - ArchiveExtVars(&save->p, th, "mobj"); + // archive function will determine when to skip mobjs, + // and write mobjnum in otherwise. + ArchiveExtVars(&save->p, th, "mobj"); + } } + + WRITEUINT32(save->p, UINT32_MAX); // end of mobjs marker, replaces mobjnum. + + LUA_HookNetArchive(NetArchive, save); // call the NetArchive hook in archive mode } - - WRITEUINT32(save->p, UINT32_MAX); // end of mobjs marker, replaces mobjnum. - LUA_HookNetArchive(NetArchive, save); // call the NetArchive hook in archive mode + ArchiveTables(&save->p); } - - ArchiveTables(&save->p); - - if (gL) - lua_pop(gL, 1); // pop tables -} - -void LUA_UnArchive(savebuffer_t *save, boolean network, boolean compat) -{ - UINT32 mobjnum; - INT32 i; - thinker_t *th; - - if (gL) - lua_newtable(gL); // tables to be read - - for (i = 0; i < MAXPLAYERS; i++) + else { - if (!playeringame[i] && i > 0) // same here, this is to synch dediservs properly. - continue; - UnArchiveExtVars(&save->p, &players[i], compat); + if (network == true) + { + do { + mobjnum = READUINT32(save->p); // read a mobjnum + for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) + { + if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) + continue; + if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj + continue; + UnArchiveExtVars(&save->p, th, false); // apply variables + } + } while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker. + + LUA_HookNetArchive(NetUnArchive, save); // call the NetArchive hook in unarchive mode + } + + UnArchiveTables(&save->p, compat); } - if (network == true) - { - do { - mobjnum = READUINT32(save->p); // read a mobjnum - for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) - { - if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) - continue; - if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj - continue; - UnArchiveExtVars(&save->p, th, false); // apply variables - } - } while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker. - - LUA_HookNetArchive(NetUnArchive, save); // call the NetArchive hook in unarchive mode - } - - UnArchiveTables(&save->p, compat); - if (gL) lua_pop(gL, 1); // pop tables } diff --git a/src/lua_script.h b/src/lua_script.h index 084333f8d..41b9ee590 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -61,8 +61,7 @@ void LUA_DumpFile(const char *filename); #endif fixed_t LUA_EvalMath(const char *word); void LUA_Step(void); -void LUA_Archive(savebuffer_t *save, boolean network); -void LUA_UnArchive(savebuffer_t *save, boolean network, boolean compat); +void LUA_Sync(savebuffer_t *save, boolean network, boolean compat); void LUA_SetCFunctionField(lua_State *L, const char *name, lua_CFunction value); diff --git a/src/p_saveg.c b/src/p_saveg.c index f0ec19a4e..e848841e4 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -48,6 +48,192 @@ savedata_t savedata; +UINT8 P_SyncUINT8(savebuffer_t *save, UINT8 v) +{ + if (save->write) + { + WRITEUINT8(save->p,v); + return v; + } + else + return READUINT8(save->p); +} + +SINT8 P_SyncSINT8(savebuffer_t *save, SINT8 v) +{ + if (save->write) + { + WRITESINT8(save->p,v); + return v; + } + else + return READSINT8(save->p); +} + +UINT16 P_SyncUINT16(savebuffer_t *save, UINT16 v) +{ + if (save->write) + { + WRITEUINT16(save->p, v); + return v; + } + else + return READUINT16(save->p); +} + +INT16 P_SyncINT16(savebuffer_t *save, INT16 v) +{ + if (save->write) + { + WRITEINT16(save->p, v); + return v; + } + else + return READINT16(save->p); +} + +UINT32 P_SyncUINT32(savebuffer_t *save, UINT32 v) +{ + if (save->write) + { + WRITEUINT32(save->p, v); + return v; + } + else + return READUINT32(save->p); +} + +INT32 P_SyncINT32(savebuffer_t *save, INT32 v) +{ + if (save->write) + { + WRITEINT32(save->p, v); + return v; + } + else + return READINT32(save->p); +} + +char P_SyncChar(savebuffer_t *save, char v) +{ + if (save->write) + { + WRITECHAR(save->p, v); + return v; + } + else + return READCHAR(save->p); +} + +fixed_t P_SyncFixed(savebuffer_t *save, fixed_t v) +{ + if (save->write) + { + WRITEFIXED(save->p, v); + return v; + } + else + return READFIXED(save->p); +} + +angle_t P_SyncAngle(savebuffer_t *save, angle_t v) +{ + if (save->write) + { + WRITEANGLE(save->p, v); + return v; + } + else + return READANGLE(save->p); +} + +void P_SyncStringN(savebuffer_t *save, char *s, size_t n) +{ + if (save->write) + WRITESTRINGN(save->p, s, n); + else + READSTRINGN(save->p, s, n); +} + +void P_SyncStringL(savebuffer_t *save, char *s, size_t n) +{ + if (save->write) + WRITESTRINGL(save->p, s, n); + else + READSTRINGL(save->p, s, n); +} + +void P_SyncString(savebuffer_t *save, char *s) +{ + if (save->write) + WRITESTRING(save->p, s); + else + READSTRING(save->p, s); +} + +void P_SyncMem(savebuffer_t *save, void *s, size_t n) +{ + if (save->write) + WRITEMEM(save->p, s, n); + else + READMEM(save->p, s, n); +} + +mobj_t *P_SyncMobj(savebuffer_t *save, mobj_t *mo) +{ + if (save->write) + { + WRITEUINT32(save->p, mo ? mo->mobjnum : 0); + return mo; + } + else + return (mobj_t *)(uintptr_t)READUINT32(save->p); +} + +mobj_t *P_SyncMobjAndRelink(savebuffer_t *save, mobj_t *mo) +{ + if (save->write) + { + WRITEUINT32(save->p, mo ? mo->mobjnum : 0); + return mo; + } + else + { + UINT32 mobjnum = READUINT32(save->p); + return mobjnum == 0 ? NULL : P_FindNewPosition(mobjnum); + } +} + +waypoint_t *P_SyncWaypoint(savebuffer_t *save, waypoint_t *wp) +{ + if (save->write) + { + WRITEUINT32(save->p, K_GetWaypointHeapIndex(wp)); + return wp; + } + else + return (waypoint_t *)(uintptr_t)READUINT32(save->p); +} + +#define SYNC(v) v = _Generic(v, \ + SINT8: P_SyncSINT8, \ + INT16: P_SyncINT16, \ + INT32: P_SyncINT32, \ + UINT8: P_SyncUINT8, \ + UINT16: P_SyncUINT16, \ + UINT32: P_SyncUINT32, \ + mobj_t *: P_SyncMobj, \ + waypoint_t *: P_SyncWaypoint \ +)(save, v) + +#define SYNCBOOLEAN(v) v = _Generic(v, \ + boolean: P_SyncUINT8 \ +)(save, v) + +#define SYNCRELINK(v) v = _Generic(v, \ + mobj_t *: P_SyncMobjAndRelink \ +)(save, v) + // Block UINT32s to attempt to ensure that the correct data is // being sent and received #define ARCHIVEBLOCK_MISC 0x7FEEDEED @@ -59,15 +245,6 @@ savedata_t savedata; #define ARCHIVEBLOCK_SPECIALS 0x7F228378 #define ARCHIVEBLOCK_WAYPOINTS 0x7F46498F -// Note: This cannot be bigger -// than an UINT16 -typedef enum -{ - AWAYVIEW = 0x01, - FOLLOWITEM = 0x02, - FOLLOWER = 0x04, -} player_saveflags; - static inline void P_ArchivePlayer(savebuffer_t *save) { const player_t *player = &players[consoleplayer]; @@ -92,798 +269,410 @@ static inline void P_UnArchivePlayer(savebuffer_t *save) savedata.score = READUINT32(save->p); } -static void P_NetArchivePlayers(savebuffer_t *save) +static void P_NetSyncPlayers(savebuffer_t *save) { TracyCZone(__zone, true); INT32 i, j; - UINT16 flags; -// size_t q; - WRITEUINT32(save->p, ARCHIVEBLOCK_PLAYERS); - - for (i = 0; i < MAXPLAYERS; i++) - { - WRITESINT8(save->p, (SINT8)adminplayers[i]); - - for (j = 0; j < PWRLV_NUMTYPES; j++) - { - WRITEINT16(save->p, clientpowerlevels[i][j]); - } - WRITEINT16(save->p, clientPowerAdd[i]); - - if (!playeringame[i]) - continue; - - flags = 0; - - // no longer send ticcmds - - WRITESTRINGN(save->p, player_names[i], MAXPLAYERNAME); - - WRITEUINT8(save->p, playerconsole[i]); - WRITEINT32(save->p, splitscreen_invitations[i]); - - WRITEANGLE(save->p, players[i].angleturn); - WRITEANGLE(save->p, players[i].aiming); - WRITEANGLE(save->p, players[i].drawangle); - WRITEANGLE(save->p, players[i].viewrollangle); - WRITEANGLE(save->p, players[i].tilt); - WRITEANGLE(save->p, players[i].awayviewaiming); - WRITEINT32(save->p, players[i].awayviewtics); - - WRITEUINT8(save->p, players[i].playerstate); - WRITEUINT32(save->p, players[i].pflags); - WRITEUINT8(save->p, players[i].panim); - WRITEUINT8(save->p, players[i].spectator); - WRITEUINT32(save->p, players[i].spectatewait); - - WRITEUINT16(save->p, players[i].flashpal); - WRITEUINT16(save->p, players[i].flashcount); - - WRITEUINT8(save->p, players[i].skincolor); - WRITEINT32(save->p, players[i].skin); - WRITEUINT32(save->p, players[i].availabilities); - WRITEUINT32(save->p, players[i].score); - WRITESINT8(save->p, players[i].lives); - WRITESINT8(save->p, players[i].xtralife); - WRITEFIXED(save->p, players[i].speed); - WRITEFIXED(save->p, players[i].lastspeed); - WRITEINT32(save->p, players[i].deadtimer); - WRITEUINT32(save->p, players[i].exiting); - - //////////////////////////// - // Conveyor Belt Movement // - //////////////////////////// - WRITEFIXED(save->p, players[i].cmomx); // Conveyor momx - WRITEFIXED(save->p, players[i].cmomy); // Conveyor momy - WRITEFIXED(save->p, players[i].rmomx); // "Real" momx (momx - cmomx) - WRITEFIXED(save->p, players[i].rmomy); // "Real" momy (momy - cmomy) - - WRITEINT16(save->p, players[i].totalring); - WRITEUINT32(save->p, players[i].realtime); - for (j = 0; j < LAP__MAX; j++) - { - WRITEUINT32(save->p, players[i].laptime[j]); - } - WRITEUINT8(save->p, players[i].laps); - WRITEUINT8(save->p, players[i].latestlap); - - WRITEUINT32(save->p, players[i].starposttime); - WRITEINT16(save->p, players[i].starpostx); - WRITEINT16(save->p, players[i].starposty); - WRITEINT16(save->p, players[i].starpostz); - WRITEINT32(save->p, players[i].starpostnum); - WRITEANGLE(save->p, players[i].starpostangle); - WRITEUINT8(save->p, (UINT8)players[i].starpostflip); - WRITEINT32(save->p, players[i].prevcheck); - WRITEINT32(save->p, players[i].nextcheck); - - WRITEUINT8(save->p, players[i].ctfteam); - - WRITEUINT8(save->p, players[i].checkskip); - - WRITEINT16(save->p, players[i].lastsidehit); - WRITEINT16(save->p, players[i].lastlinehit); - - WRITEINT32(save->p, players[i].onconveyor); - - WRITEUINT32(save->p, players[i].jointime); - WRITEUINT32(save->p, players[i].spectatorreentry); - - WRITEUINT32(save->p, players[i].grieftime); - WRITEUINT8(save->p, players[i].griefstrikes); - - WRITEUINT8(save->p, players[i].splitscreenindex); - - if (players[i].awayviewmobj) - flags |= AWAYVIEW; - - if (players[i].followmobj) - flags |= FOLLOWITEM; - - if (players[i].follower) - flags |= FOLLOWER; - - WRITEUINT16(save->p, flags); - - if (flags & AWAYVIEW) - WRITEUINT32(save->p, players[i].awayviewmobj->mobjnum); - - if (flags & FOLLOWITEM) - WRITEUINT32(save->p, players[i].followmobj->mobjnum); - - WRITEUINT32(save->p, (UINT32)players[i].followitem); - - WRITEUINT32(save->p, players[i].charflags); - - // SRB2kart - WRITEUINT8(save->p, players[i].kartspeed); - WRITEUINT8(save->p, players[i].kartweight); - - for (j = 0; j < MAXPREDICTTICS; j++) - { - WRITEINT16(save->p, players[i].lturn_max[j]); - WRITEINT16(save->p, players[i].rturn_max[j]); - } - - WRITEUINT8(save->p, players[i].followerskin); - WRITEUINT8(save->p, players[i].followerready); // booleans are really just numbers eh?? - WRITEUINT16(save->p, players[i].followercolor); - if (flags & FOLLOWER) - WRITEUINT32(save->p, players[i].follower->mobjnum); - - for (j = 0; j < NUMPOWERS; j++) - WRITEUINT16(save->p, players[i].powers[j]); - for (j = 0; j < NUMKARTSTUFF; j++) - WRITEINT32(save->p, players[i].kartstuff[j]); - - WRITEUINT16(save->p, players[i].nocontrol); - WRITEUINT8(save->p, players[i].carry); - WRITEUINT16(save->p, players[i].dye); - - WRITEUINT8(save->p, players[i].position); - WRITEUINT8(save->p, players[i].oldposition); - WRITEUINT8(save->p, players[i].positiondelay); - WRITEUINT32(save->p, players[i].distancetofinish); - WRITEUINT32(save->p, players[i].distancetofinishprev); - WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].currentwaypoint)); - WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].nextwaypoint)); - WRITEUINT16(save->p, players[i].bigwaypointgap); - WRITEUINT32(save->p, players[i].airtime); - WRITEUINT8(save->p, players[i].startboost); - - WRITEUINT8(save->p, players[i].dropdash); - WRITEUINT8(save->p, players[i].respawn); - - WRITEUINT16(save->p, players[i].flashing); - WRITEUINT16(save->p, players[i].spinouttimer); - WRITEINT32(save->p, players[i].spinoutrot); - WRITEUINT8(save->p, players[i].spinouttype); - WRITEUINT16(save->p, players[i].flipovertimer); - WRITEANGLE(save->p, players[i].flipoverangle); - WRITEINT16(save->p, players[i].squishedtimer); - WRITEUINT8(save->p, players[i].instashield); - WRITEUINT8(save->p, players[i].wipeoutslow); - WRITEUINT8(save->p, players[i].justbumped); - WRITEUINT8(save->p, players[i].noclip); - - WRITESINT8(save->p, players[i].drift); - WRITESINT8(save->p, players[i].driftlock); - WRITEFIXED(save->p, players[i].driftcharge); - WRITEUINT8(save->p, players[i].driftboost); - - WRITESINT8(save->p, players[i].aizdriftstrat); - WRITEINT32(save->p, players[i].aizdrifttilt); - WRITEINT32(save->p, players[i].aizdriftturn); - WRITEFIXED(save->p, players[i].slipdashcharge); - WRITESINT8(save->p, players[i].slipdashdir); - - WRITEFIXED(save->p, players[i].offroad); - WRITEFIXED(save->p, players[i].tiregrease); - WRITEUINT8(save->p, players[i].pogospring); - WRITEUINT8(save->p, players[i].brakestop); - WRITEUINT8(save->p, players[i].waterskip); - - WRITEUINT8(save->p, players[i].dashpadcooldown); - - WRITEFIXED(save->p, players[i].boostpower); - WRITEFIXED(save->p, players[i].speedboost); - WRITEFIXED(save->p, players[i].prevspeedboost); - WRITEFIXED(save->p, players[i].accelboost); - WRITEANGLE(save->p, players[i].boostangle); - WRITEUINT8(save->p, players[i].numsneakers); - WRITEUINT8(save->p, players[i].numboosts); - - WRITEFIXED(save->p, players[i].draftpower); - WRITEUINT16(save->p, players[i].draftleeway); - WRITESINT8(save->p, players[i].lastdraft); - - // boostinfo_t - WRITEFIXED(save->p, players[i].boostinfo.stackspeedboost); - WRITEFIXED(save->p, players[i].boostinfo.nonstackspeedboost); - WRITEFIXED(save->p, players[i].boostinfo.accelboost); - WRITEUINT8(save->p, players[i].boostinfo.grade); - - WRITEUINT8(save->p, players[i].tripwireState); - WRITEUINT8(save->p, players[i].tripwirePass); - WRITEUINT16(save->p, players[i].tripwireLeniency); - WRITEUINT8(save->p, players[i].tripwireReboundDelay); - - WRITEUINT16(save->p, players[i].itemroulette); - WRITEUINT16(save->p, players[i].previtemroulette); - WRITEUINT16(save->p, players[i].itemblink); - WRITEUINT16(save->p, players[i].itemblinkmode); - WRITEUINT8(save->p, players[i].roulettetype); - - WRITESINT8(save->p, players[i].itemtype); - WRITEUINT8(save->p, players[i].itemamount); - WRITESINT8(save->p, players[i].throwdir); - - WRITEUINT8(save->p, players[i].sadtimer); - - WRITESINT8(save->p, players[i].rings); - WRITESINT8(save->p, players[i].ringmin); - WRITESINT8(save->p, players[i].ringmax); - WRITEUINT8(save->p, players[i].pickuprings); - WRITEUINT8(save->p, players[i].ringdelay); - WRITEUINT8(save->p, players[i].ringlock); - WRITEUINT16(save->p, players[i].ringboost); - WRITEUINT16(save->p, players[i].ringtime); - WRITEUINT16(save->p, players[i].superring); - WRITEUINT8(save->p, players[i].nextringaward); - WRITEUINT8(save->p, players[i].ringvolume); - WRITEUINT8(save->p, players[i].ringtransparency); - - WRITEUINT8(save->p, players[i].airdroptime); - WRITEUINT8(save->p, players[i].ringdrop); - - WRITEUINT8(save->p, players[i].curshield); - - WRITEUINT8(save->p, players[i].bubblecool); - WRITEUINT8(save->p, players[i].bubbleblowup); - WRITEUINT8(save->p, players[i].bubblehealth); - WRITEUINT16(save->p, players[i].bubbleboost); - - WRITEUINT16(save->p, players[i].flamedash); - WRITEINT32(save->p, players[i].flametimer); - WRITEUINT8(save->p, players[i].flamestore); - - WRITEUINT16(save->p, players[i].hyudorotimer); - WRITESINT8(save->p, players[i].stealingtimer); - - WRITEUINT16(save->p, players[i].sneakertimer); - WRITEUINT16(save->p, players[i].realsneakertimer); - WRITEUINT8(save->p, players[i].floorboost); - WRITEUINT16(save->p, players[i].chaintimer); - - WRITEUINT8(save->p, players[i].boostcharge); - - WRITEFIXED(save->p, players[i].slopeboost); - WRITEFIXED(save->p, players[i].prevslopeboost); - WRITEFIXED(save->p, players[i].slopeaccel); - - WRITEINT16(save->p, players[i].growshrinktimer); - WRITEINT16(save->p, players[i].growcancel); - - WRITEUINT16(save->p, players[i].rocketsneakertimer); - - WRITEUINT16(save->p, players[i].invincibilitytimer); - WRITEUINT16(save->p, players[i].maxinvincibilitytime); - WRITEUINT16(save->p, players[i].invincibilitybottleneck); - WRITEINT16(save->p, players[i].invincibilitycancel); - - WRITEUINT8(save->p, players[i].eggmanexplode); - WRITESINT8(save->p, players[i].eggmanblame); - - WRITEUINT16(save->p, players[i].bananadrag); - - WRITESINT8(save->p, players[i].lastjawztarget); - WRITEUINT8(save->p, players[i].jawztargetdelay); - - WRITEUINT8(save->p, players[i].confirmVictim); - WRITEUINT8(save->p, players[i].confirmVictimDelay); - - WRITEINT32(save->p, players[i].interpoints); - WRITEUINT32(save->p, players[i].roundscore); - WRITEUINT8(save->p, players[i].emeralds); - WRITEUINT8(save->p, players[i].bumper); - WRITEINT16(save->p, players[i].karmadelay); - WRITEINT16(save->p, players[i].karmamode); - WRITEINT16(save->p, players[i].karmapoints); - WRITEINT16(save->p, players[i].wanted); - - WRITESINT8(save->p, players[i].glanceDir); - - WRITEUINT16(save->p, players[i].breathTimer); - - WRITEUINT8(save->p, players[i].lastsafelap); - WRITEUINT8(save->p, players[i].lastsafestarpost); - - WRITEUINT8(save->p, players[i].typing_timer); - WRITEUINT8(save->p, players[i].typing_duration); - - WRITEUINT8(save->p, players[i].kickstartaccel); - - WRITEUINT8(save->p, players[i].itemflags); - - // botvars_t - WRITEUINT8(save->p, players[i].bot); - WRITEUINT8(save->p, players[i].botvars.style); - WRITEUINT8(save->p, players[i].botvars.difficulty); - WRITEUINT8(save->p, players[i].botvars.diffincrease); - WRITEUINT8(save->p, players[i].botvars.rival); - WRITEFIXED(save->p, players[i].botvars.rubberband); - WRITEUINT16(save->p, players[i].botvars.controller); - - WRITEFIXED(save->p, players[i].outrun); - WRITEUINT8(save->p, players[i].outruntime); - - // sonicloopsvars_t - WRITEFIXED(save->p, players[i].loop.radius); - WRITEFIXED(save->p, players[i].loop.revolution); - WRITEFIXED(save->p, players[i].loop.min_revolution); - WRITEFIXED(save->p, players[i].loop.max_revolution); - WRITEANGLE(save->p, players[i].loop.yaw); - WRITEFIXED(save->p, players[i].loop.origin.x); - WRITEFIXED(save->p, players[i].loop.origin.y); - WRITEFIXED(save->p, players[i].loop.origin.z); - WRITEFIXED(save->p, players[i].loop.origin_shift.x); - WRITEFIXED(save->p, players[i].loop.origin_shift.y); - WRITEFIXED(save->p, players[i].loop.shift.x); - WRITEFIXED(save->p, players[i].loop.shift.y); - WRITEUINT8(save->p, players[i].loop.flip); - - // sonicloopcamvars_t - WRITEUINT32(save->p, players[i].loop.camera.enter_tic); - WRITEUINT32(save->p, players[i].loop.camera.exit_tic); - WRITEUINT32(save->p, players[i].loop.camera.zoom_in_speed); - WRITEUINT32(save->p, players[i].loop.camera.zoom_out_speed); - WRITEFIXED(save->p, players[i].loop.camera.dist); - WRITEANGLE(save->p, players[i].loop.camera.pan); - WRITEFIXED(save->p, players[i].loop.camera.pan_speed); - WRITEUINT32(save->p, players[i].loop.camera.pan_accel); - WRITEUINT32(save->p, players[i].loop.camera.pan_back); - - // Restored NiGHTS stuff - WRITEUINT32(save->p, players[i].bumpertime); - WRITEINT32(save->p, players[i].linkcount); - WRITEUINT32(save->p, players[i].linktimer); - WRITEINT32(save->p, players[i].maxlink); - - // Fix janky landing particle - WRITEUINT8(save->p, players[i].prevonground); - - // Wall Transfer bonus - WRITEUINT8(save->p, players[i].walltransfered); - WRITEUINT8(save->p, players[i].walltransferboost); - - } - TracyCZoneEnd(__zone); -} - -static void P_NetUnArchivePlayers(savebuffer_t *save) -{ - TracyCZone(__zone, true); - - INT32 i, j; - UINT16 flags; - - if (READUINT32(save->p) != ARCHIVEBLOCK_PLAYERS) + if (P_SyncUINT32(save, ARCHIVEBLOCK_PLAYERS) != ARCHIVEBLOCK_PLAYERS) I_Error("Bad $$$.sav at archive block Players"); for (i = 0; i < MAXPLAYERS; i++) { - adminplayers[i] = (INT32)READSINT8(save->p); + adminplayers[i] = (INT32)P_SyncSINT8(save, adminplayers[i]); for (j = 0; j < PWRLV_NUMTYPES; j++) { - clientpowerlevels[i][j] = READINT16(save->p); + SYNC(clientpowerlevels[i][j]); } - clientPowerAdd[i] = READINT16(save->p); + SYNC(clientPowerAdd[i]); - // Do NOT memset player struct to 0 - // other areas may initialize data elsewhere - //memset(&players[i], 0, sizeof (player_t)); if (!playeringame[i]) continue; - // NOTE: sending tics should (hopefully) no longer be necessary + // no longer send ticcmds - READSTRINGN(save->p, player_names[i], MAXPLAYERNAME); + P_SyncStringN(save, player_names[i], MAXPLAYERNAME); - playerconsole[i] = READUINT8(save->p); - splitscreen_invitations[i] = READINT32(save->p); + SYNC(playerconsole[i]); + SYNC(splitscreen_invitations[i]); - players[i].angleturn = READANGLE(save->p); - players[i].aiming = READANGLE(save->p); - players[i].drawangle = players[i].old_drawangle = READANGLE(save->p); - players[i].viewrollangle = READANGLE(save->p); - players[i].tilt = READANGLE(save->p); - players[i].awayviewaiming = READANGLE(save->p); - players[i].awayviewtics = READINT32(save->p); + SYNC(players[i].angleturn); + SYNC(players[i].aiming); + SYNC(players[i].drawangle); + SYNC(players[i].viewrollangle); + SYNC(players[i].tilt); + SYNC(players[i].awayviewaiming); + SYNC(players[i].awayviewtics); - players[i].playerstate = READUINT8(save->p); - players[i].pflags = READUINT32(save->p); - players[i].panim = READUINT8(save->p); - players[i].spectator = READUINT8(save->p); - players[i].spectatewait = READUINT32(save->p); + SYNC(players[i].playerstate); + SYNC(players[i].pflags); + SYNC(players[i].panim); + SYNCBOOLEAN(players[i].spectator); + SYNC(players[i].spectatewait); - players[i].flashpal = READUINT16(save->p); - players[i].flashcount = READUINT16(save->p); + SYNC(players[i].flashpal); + SYNC(players[i].flashcount); - players[i].skincolor = READUINT8(save->p); - players[i].skin = READINT32(save->p); - players[i].availabilities = READUINT32(save->p); - players[i].score = READUINT32(save->p); - players[i].lives = READSINT8(save->p); - players[i].xtralife = READSINT8(save->p); // Ring Extra Life counter - players[i].speed = READFIXED(save->p); // Player's speed (distance formula of MOMX and MOMY values) - players[i].lastspeed = READFIXED(save->p); - players[i].deadtimer = READINT32(save->p); // End game if game over lasts too long - players[i].exiting = READUINT32(save->p); // Exitlevel timer + SYNC(players[i].skincolor); + SYNC(players[i].skin); + SYNC(players[i].availabilities); + SYNC(players[i].score); + SYNC(players[i].lives); + SYNC(players[i].xtralife); + SYNC(players[i].speed); + SYNC(players[i].lastspeed); + SYNC(players[i].deadtimer); + SYNC(players[i].exiting); //////////////////////////// // Conveyor Belt Movement // //////////////////////////// - players[i].cmomx = READFIXED(save->p); // Conveyor momx - players[i].cmomy = READFIXED(save->p); // Conveyor momy - players[i].rmomx = READFIXED(save->p); // "Real" momx (momx - cmomx) - players[i].rmomy = READFIXED(save->p); // "Real" momy (momy - cmomy) + SYNC(players[i].cmomx); // Conveyor momx + SYNC(players[i].cmomy); // Conveyor momy + SYNC(players[i].rmomx); // "Real" momx (momx - cmomx) + SYNC(players[i].rmomy); // "Real" momy (momy - cmomy) - players[i].totalring = READINT16(save->p); // Total number of rings obtained for GP - players[i].realtime = READUINT32(save->p); // integer replacement for leveltime + SYNC(players[i].totalring); + SYNC(players[i].realtime); for (j = 0; j < LAP__MAX; j++) { - players[i].laptime[j] = READUINT32(save->p); + SYNC(players[i].laptime[j]); } - players[i].laps = READUINT8(save->p); // Number of laps (optional) - players[i].latestlap = READUINT8(save->p); - - players[i].starposttime = READUINT32(save->p); - players[i].starpostx = READINT16(save->p); - players[i].starposty = READINT16(save->p); - players[i].starpostz = READINT16(save->p); - players[i].starpostnum = READINT32(save->p); - players[i].starpostangle = READANGLE(save->p); - players[i].starpostflip = (boolean)READUINT8(save->p); - players[i].prevcheck = READINT32(save->p); - players[i].nextcheck = READINT32(save->p); + SYNC(players[i].laps); + SYNC(players[i].latestlap); - players[i].ctfteam = READUINT8(save->p); // 1 == Red, 2 == Blue + SYNC(players[i].starposttime); + SYNC(players[i].starpostx); + SYNC(players[i].starposty); + SYNC(players[i].starpostz); + SYNC(players[i].starpostnum); + SYNC(players[i].starpostangle); + SYNCBOOLEAN(players[i].starpostflip); + SYNC(players[i].prevcheck); + SYNC(players[i].nextcheck); - players[i].checkskip = READUINT8(save->p); + SYNC(players[i].ctfteam); - players[i].lastsidehit = READINT16(save->p); - players[i].lastlinehit = READINT16(save->p); + SYNC(players[i].checkskip); - players[i].onconveyor = READINT32(save->p); + SYNC(players[i].lastsidehit); + SYNC(players[i].lastlinehit); - players[i].jointime = READUINT32(save->p); - players[i].spectatorreentry = READUINT32(save->p); + SYNC(players[i].onconveyor); - players[i].grieftime = READUINT32(save->p); - players[i].griefstrikes = READUINT8(save->p); + SYNC(players[i].jointime); + SYNC(players[i].spectatorreentry); - players[i].splitscreenindex = READUINT8(save->p); + SYNC(players[i].grieftime); + SYNC(players[i].griefstrikes); - flags = READUINT16(save->p); + SYNC(players[i].splitscreenindex); - if (flags & AWAYVIEW) - players[i].awayviewmobj = (mobj_t *)(size_t)READUINT32(save->p); + SYNC(players[i].awayviewmobj); + SYNC(players[i].followmobj); + SYNC(players[i].followitem); - if (flags & FOLLOWITEM) - players[i].followmobj = (mobj_t *)(size_t)READUINT32(save->p); - - players[i].followitem = (mobjtype_t)READUINT32(save->p); - - //SetPlayerSkinByNum(i, players[i].skin); - players[i].charflags = READUINT32(save->p); + SYNC(players[i].charflags); // SRB2kart - players[i].kartspeed = READUINT8(save->p); - players[i].kartweight = READUINT8(save->p); - + SYNC(players[i].kartspeed); + SYNC(players[i].kartweight); + for (j = 0; j < MAXPREDICTTICS; j++) { - players[i].lturn_max[j] = READINT16(save->p); - players[i].rturn_max[j] = READINT16(save->p); + SYNC(players[i].lturn_max[j]); + SYNC(players[i].rturn_max[j]); } - players[i].followerskin = READUINT8(save->p); - players[i].followerready = READUINT8(save->p); - players[i].followercolor = READUINT16(save->p); - if (flags & FOLLOWER) - players[i].follower = (mobj_t *)(size_t)READUINT32(save->p); + SYNC(players[i].followerskin); + SYNCBOOLEAN(players[i].followerready); + SYNC(players[i].followercolor); + + SYNC(players[i].follower); for (j = 0; j < NUMPOWERS; j++) - players[i].powers[j] = READUINT16(save->p); + SYNC(players[i].powers[j]); for (j = 0; j < NUMKARTSTUFF; j++) - players[i].kartstuff[j] = READINT32(save->p); + SYNC(players[i].kartstuff[j]); - players[i].nocontrol = READUINT16(save->p); - players[i].carry = READUINT8(save->p); - players[i].dye = READUINT16(save->p); + SYNC(players[i].nocontrol); + SYNC(players[i].carry); + SYNC(players[i].dye); - players[i].position = READUINT8(save->p); - players[i].oldposition = READUINT8(save->p); - players[i].positiondelay = READUINT8(save->p); - players[i].distancetofinish = READUINT32(save->p); - players[i].distancetofinishprev = READUINT32(save->p); - players[i].currentwaypoint = (waypoint_t *)(size_t)READUINT32(save->p); + SYNC(players[i].position); + SYNC(players[i].oldposition); + SYNC(players[i].positiondelay); + SYNC(players[i].distancetofinish); + SYNC(players[i].distancetofinishprev); + SYNC(players[i].currentwaypoint); + SYNC(players[i].nextwaypoint); + SYNC(players[i].bigwaypointgap); + SYNC(players[i].airtime); + SYNC(players[i].startboost); - players[i].nextwaypoint = (waypoint_t *)(size_t)READUINT32(save->p); - players[i].bigwaypointgap = READUINT16(save->p); - players[i].airtime = READUINT32(save->p); - players[i].startboost = READUINT8(save->p); + SYNC(players[i].dropdash); + SYNC(players[i].respawn); - players[i].dropdash = READUINT8(save->p); - players[i].respawn = READUINT8(save->p); + SYNC(players[i].flashing); + SYNC(players[i].spinouttimer); + SYNC(players[i].spinoutrot); + SYNC(players[i].spinouttype); + SYNC(players[i].flipovertimer); + SYNC(players[i].flipoverangle); + SYNC(players[i].squishedtimer); + SYNC(players[i].instashield); + SYNC(players[i].wipeoutslow); + SYNC(players[i].justbumped); + SYNCBOOLEAN(players[i].noclip); - players[i].flashing = READUINT16(save->p); - players[i].spinouttimer = READUINT16(save->p); - players[i].spinoutrot = READINT32(save->p); - players[i].spinouttype = READUINT8(save->p); - players[i].flipoverangle = READUINT16(save->p); - players[i].flipovertimer = READANGLE(save->p); - players[i].squishedtimer = READINT16(save->p); - players[i].instashield = READUINT8(save->p); - players[i].wipeoutslow = READUINT8(save->p); - players[i].justbumped = READUINT8(save->p); - players[i].noclip = READUINT8(save->p); + SYNC(players[i].drift); + SYNC(players[i].driftlock); + SYNC(players[i].driftcharge); + SYNC(players[i].driftboost); - players[i].drift = READSINT8(save->p); - players[i].driftlock = READSINT8(save->p); - players[i].driftcharge = READFIXED(save->p); - players[i].driftboost = READUINT8(save->p); + SYNC(players[i].aizdriftstrat); + SYNC(players[i].aizdrifttilt); + SYNC(players[i].aizdriftturn); + SYNC(players[i].slipdashcharge); + SYNC(players[i].slipdashdir); - players[i].aizdriftstrat = READSINT8(save->p); - players[i].aizdrifttilt = READINT32(save->p); - players[i].aizdriftturn = READINT32(save->p); - players[i].slipdashcharge = READFIXED(save->p); - players[i].slipdashdir = READSINT8(save->p); + SYNC(players[i].offroad); + SYNC(players[i].tiregrease); + SYNC(players[i].pogospring); + SYNC(players[i].brakestop); + SYNC(players[i].waterskip); - players[i].offroad = READFIXED(save->p); - players[i].tiregrease = READFIXED(save->p); - players[i].pogospring = READUINT8(save->p); - players[i].brakestop = READUINT8(save->p); - players[i].waterskip = READUINT8(save->p); + SYNC(players[i].dashpadcooldown); - players[i].dashpadcooldown = READUINT8(save->p); + SYNC(players[i].boostpower); + SYNC(players[i].speedboost); + SYNC(players[i].prevspeedboost); + SYNC(players[i].accelboost); + SYNC(players[i].boostangle); + SYNC(players[i].numsneakers); + SYNC(players[i].numboosts); - players[i].boostpower = READFIXED(save->p); - players[i].speedboost = READFIXED(save->p); - players[i].prevspeedboost = READFIXED(save->p); - players[i].accelboost = READFIXED(save->p); - players[i].boostangle = READANGLE(save->p); - players[i].numsneakers = READUINT8(save->p); - players[i].numboosts = READUINT8(save->p); - - players[i].draftpower = READFIXED(save->p); - players[i].draftleeway = READUINT16(save->p); - players[i].lastdraft = READSINT8(save->p); + SYNC(players[i].draftpower); + SYNC(players[i].draftleeway); + SYNC(players[i].lastdraft); // boostinfo_t - players[i].boostinfo.stackspeedboost = READFIXED(save->p); - players[i].boostinfo.nonstackspeedboost = READFIXED(save->p); - players[i].boostinfo.accelboost = READFIXED(save->p); - players[i].boostinfo.grade = READUINT8(save->p); + SYNC(players[i].boostinfo.stackspeedboost); + SYNC(players[i].boostinfo.nonstackspeedboost); + SYNC(players[i].boostinfo.accelboost); + SYNC(players[i].boostinfo.grade); - players[i].tripwireState = READUINT8(save->p); - players[i].tripwirePass = READUINT8(save->p); - players[i].tripwireLeniency = READUINT16(save->p); - players[i].tripwireReboundDelay = READUINT8(save->p); + SYNC(players[i].tripwireState); + SYNC(players[i].tripwirePass); + SYNC(players[i].tripwireLeniency); + SYNC(players[i].tripwireReboundDelay); - players[i].itemroulette = READUINT16(save->p); - players[i].previtemroulette = READUINT16(save->p); - players[i].itemblink = READUINT16(save->p); - players[i].itemblinkmode = READUINT16(save->p); - players[i].roulettetype = READUINT8(save->p); + SYNC(players[i].itemroulette); + SYNC(players[i].previtemroulette); + SYNC(players[i].itemblink); + SYNC(players[i].itemblinkmode); + SYNC(players[i].roulettetype); - players[i].itemtype = READSINT8(save->p); - players[i].itemamount = READUINT8(save->p); - players[i].throwdir = READSINT8(save->p); + SYNC(players[i].itemtype); + SYNC(players[i].itemamount); + SYNC(players[i].throwdir); - players[i].sadtimer = READUINT8(save->p); + SYNC(players[i].sadtimer); - players[i].rings = READSINT8(save->p); - players[i].ringmin = READSINT8(save->p); - players[i].ringmax = READSINT8(save->p); - players[i].pickuprings = READUINT8(save->p); - players[i].ringdelay = READUINT8(save->p); - players[i].ringlock = READUINT8(save->p); - players[i].ringboost = READUINT16(save->p); - players[i].ringtime = READUINT16(save->p);; - players[i].superring = READUINT16(save->p); - players[i].nextringaward = READUINT8(save->p); - players[i].ringvolume = READUINT8(save->p); - players[i].ringtransparency = READUINT8(save->p); + SYNC(players[i].rings); + SYNC(players[i].ringmin); + SYNC(players[i].ringmax); + SYNC(players[i].pickuprings); + SYNC(players[i].ringdelay); + SYNC(players[i].ringlock); + SYNC(players[i].ringboost); + SYNC(players[i].ringtime); + SYNC(players[i].superring); + SYNC(players[i].nextringaward); + SYNC(players[i].ringvolume); + SYNC(players[i].ringtransparency); - players[i].airdroptime = READUINT8(save->p); - players[i].ringdrop = READUINT8(save->p); + SYNC(players[i].airdroptime); + SYNCBOOLEAN(players[i].ringdrop); - players[i].curshield = READUINT8(save->p); + SYNC(players[i].curshield); - players[i].bubblecool = READUINT8(save->p); - players[i].bubbleblowup = READUINT8(save->p); - players[i].bubblehealth = READUINT8(save->p); - players[i].bubbleboost = READUINT16(save->p); + SYNC(players[i].bubblecool); + SYNC(players[i].bubbleblowup); + SYNC(players[i].bubblehealth); + SYNC(players[i].bubbleboost); - players[i].flamedash = READUINT16(save->p); - players[i].flametimer = READINT32(save->p); - players[i].flamestore = READUINT8(save->p); + SYNC(players[i].flamedash); + SYNC(players[i].flametimer); + SYNC(players[i].flamestore); - players[i].hyudorotimer = READUINT16(save->p); - players[i].stealingtimer = READSINT8(save->p); + SYNC(players[i].hyudorotimer); + SYNC(players[i].stealingtimer); - players[i].sneakertimer = READUINT16(save->p); - players[i].realsneakertimer = READUINT16(save->p); - players[i].floorboost = READUINT8(save->p); - players[i].chaintimer = READUINT16(save->p); - - players[i].boostcharge = READUINT8(save->p); + SYNC(players[i].sneakertimer); + SYNC(players[i].realsneakertimer); + SYNC(players[i].floorboost); + SYNC(players[i].chaintimer); - players[i].slopeboost = READFIXED(save->p); - players[i].prevslopeboost = READFIXED(save->p); - players[i].slopeaccel = READFIXED(save->p); + SYNC(players[i].boostcharge); - players[i].growshrinktimer = READINT16(save->p); - players[i].growcancel = READINT16(save->p); + SYNC(players[i].slopeboost); + SYNC(players[i].prevslopeboost); + SYNC(players[i].slopeaccel); - players[i].rocketsneakertimer = READUINT16(save->p); + SYNC(players[i].growshrinktimer); + SYNC(players[i].growcancel); - players[i].invincibilitytimer = READUINT16(save->p); - players[i].maxinvincibilitytime = READUINT16(save->p); - players[i].invincibilitybottleneck = READUINT16(save->p); - players[i].invincibilitycancel = READINT16(save->p); + SYNC(players[i].rocketsneakertimer); - players[i].eggmanexplode = READUINT8(save->p); - players[i].eggmanblame = READSINT8(save->p); + SYNC(players[i].invincibilitytimer); + SYNC(players[i].maxinvincibilitytime); + SYNC(players[i].invincibilitybottleneck); + SYNC(players[i].invincibilitycancel); - players[i].bananadrag = READUINT16(save->p); + SYNC(players[i].eggmanexplode); + SYNC(players[i].eggmanblame); - players[i].lastjawztarget = READSINT8(save->p); - players[i].jawztargetdelay = READUINT8(save->p); + SYNC(players[i].bananadrag); - players[i].confirmVictim = READUINT8(save->p); - players[i].confirmVictimDelay = READUINT8(save->p); + SYNC(players[i].lastjawztarget); + SYNC(players[i].jawztargetdelay); - players[i].interpoints = READINT32(save->p); - players[i].roundscore = READUINT32(save->p); - players[i].emeralds = READUINT8(save->p); - players[i].bumper = READUINT8(save->p); - players[i].karmadelay = READINT16(save->p); - players[i].karmamode = READINT16(save->p); - players[i].karmapoints = READINT16(save->p); - players[i].wanted = READINT16(save->p); + SYNC(players[i].confirmVictim); + SYNC(players[i].confirmVictimDelay); - players[i].glanceDir = READSINT8(save->p); + SYNC(players[i].interpoints); + SYNC(players[i].roundscore); + SYNC(players[i].emeralds); + SYNC(players[i].bumper); + SYNC(players[i].karmadelay); + SYNC(players[i].karmamode); + SYNC(players[i].karmapoints); + SYNC(players[i].wanted); - players[i].breathTimer = READUINT16(save->p); + SYNC(players[i].glanceDir); - players[i].lastsafelap = READUINT8(save->p); - players[i].lastsafestarpost = READUINT8(save->p); + SYNC(players[i].breathTimer); - players[i].typing_timer = READUINT8(save->p); - players[i].typing_duration = READUINT8(save->p); + SYNC(players[i].lastsafelap); + SYNC(players[i].lastsafestarpost); - players[i].kickstartaccel = READUINT8(save->p); + SYNC(players[i].typing_timer); + SYNC(players[i].typing_duration); - players[i].itemflags = READUINT8(save->p); + SYNC(players[i].kickstartaccel); + + SYNC(players[i].itemflags); // botvars_t - players[i].bot = READUINT8(save->p); - players[i].botvars.style = READUINT8(save->p); - players[i].botvars.difficulty = READUINT8(save->p); - players[i].botvars.diffincrease = READUINT8(save->p); - players[i].botvars.rival = (boolean)READUINT8(save->p); - players[i].botvars.rubberband = READFIXED(save->p); - players[i].botvars.controller = READUINT16(save->p); + SYNCBOOLEAN(players[i].bot); + SYNC(players[i].botvars.style); + SYNC(players[i].botvars.difficulty); + SYNC(players[i].botvars.diffincrease); + SYNCBOOLEAN(players[i].botvars.rival); + SYNC(players[i].botvars.rubberband); + SYNC(players[i].botvars.controller); - players[i].outrun = READFIXED(save->p); - players[i].outruntime = READUINT8(save->p); + SYNC(players[i].outrun); + SYNC(players[i].outruntime); // sonicloopsvars_t - players[i].loop.radius = READFIXED(save->p); - players[i].loop.revolution = READFIXED(save->p); - players[i].loop.min_revolution = READFIXED(save->p); - players[i].loop.max_revolution = READFIXED(save->p); - players[i].loop.yaw = READANGLE(save->p); - players[i].loop.origin.x = READFIXED(save->p); - players[i].loop.origin.y = READFIXED(save->p); - players[i].loop.origin.z = READFIXED(save->p); - players[i].loop.origin_shift.x = READFIXED(save->p); - players[i].loop.origin_shift.y = READFIXED(save->p); - players[i].loop.shift.x = READFIXED(save->p); - players[i].loop.shift.y = READFIXED(save->p); - players[i].loop.flip = READUINT8(save->p); + SYNC(players[i].loop.radius); + SYNC(players[i].loop.revolution); + SYNC(players[i].loop.min_revolution); + SYNC(players[i].loop.max_revolution); + SYNC(players[i].loop.yaw); + SYNC(players[i].loop.origin.x); + SYNC(players[i].loop.origin.y); + SYNC(players[i].loop.origin.z); + SYNC(players[i].loop.origin_shift.x); + SYNC(players[i].loop.origin_shift.y); + SYNC(players[i].loop.shift.x); + SYNC(players[i].loop.shift.y); + SYNCBOOLEAN(players[i].loop.flip); // sonicloopcamvars_t - players[i].loop.camera.enter_tic = READUINT32(save->p); - players[i].loop.camera.exit_tic = READUINT32(save->p); - players[i].loop.camera.zoom_in_speed = READUINT32(save->p); - players[i].loop.camera.zoom_out_speed = READUINT32(save->p); - players[i].loop.camera.dist = READFIXED(save->p); - players[i].loop.camera.pan = READANGLE(save->p); - players[i].loop.camera.pan_speed = READFIXED(save->p); - players[i].loop.camera.pan_accel = READUINT32(save->p); - players[i].loop.camera.pan_back = READUINT32(save->p); - + SYNC(players[i].loop.camera.enter_tic); + SYNC(players[i].loop.camera.exit_tic); + SYNC(players[i].loop.camera.zoom_in_speed); + SYNC(players[i].loop.camera.zoom_out_speed); + SYNC(players[i].loop.camera.dist); + SYNC(players[i].loop.camera.pan); + SYNC(players[i].loop.camera.pan_speed); + SYNC(players[i].loop.camera.pan_accel); + SYNC(players[i].loop.camera.pan_back); // Restored NiGHTS stuff - players[i].bumpertime = READUINT32(save->p); - players[i].linkcount = READINT32(save->p); - players[i].linktimer = READUINT32(save->p); - players[i].maxlink = READINT32(save->p); + SYNC(players[i].bumpertime); + SYNC(players[i].linkcount); + SYNC(players[i].linktimer); + SYNC(players[i].maxlink); // Fix janky landing particle - players[i].prevonground = (boolean)READUINT8(save->p); + SYNCBOOLEAN(players[i].prevonground); // Wall Transfer bonus - players[i].walltransfered = (boolean)READUINT8(save->p); - players[i].walltransferboost = READUINT8(save->p); + SYNCBOOLEAN(players[i].walltransfered); + SYNC(players[i].walltransferboost); - //players[i].viewheight = P_GetPlayerViewHeight(players[i]); // scale cannot be factored in at this point } TracyCZoneEnd(__zone); } -static void P_NetArchiveParties(savebuffer_t *save) +static void P_NetSyncParties(savebuffer_t *save) { TracyCZone(__zone, true); INT32 i, k; UINT8 partySize; - WRITEUINT32(save->p, ARCHIVEBLOCK_PARTIES); + if (P_SyncUINT32(save, ARCHIVEBLOCK_PARTIES) != ARCHIVEBLOCK_PARTIES) + I_Error("Bad $$$.sav at archive block Parties"); - for (i = 0; i < MAXPLAYERS; i++) + if (!save->write) { - if (!playeringame[i]) - continue; - - partySize = G_PartySize(i); - - WRITEUINT8(save->p, partySize); - - for (k = 0; k < partySize; ++k) + for (i = 0; i < MAXPLAYERS; i++) { - WRITEUINT8(save->p, G_PartyMember(i, k)); + if (!playeringame[i]) + continue; + + G_DestroyParty(i); + G_BuildLocalSplitscreenParty(i); } } - TracyCZoneEnd(__zone); -} - -static void P_NetUnArchiveParties(savebuffer_t *save) -{ - TracyCZone(__zone, true); - - INT32 i, k; - UINT8 partySize; - - if (READUINT32(save->p) != ARCHIVEBLOCK_PARTIES) - I_Error("Bad $$$.sav at archive block Parties"); - - for (i = 0; i < MAXPLAYERS; i++) + if (save->write) { - if (!playeringame[i]) - continue; - - G_DestroyParty(i); - G_BuildLocalSplitscreenParty(i); - } - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!playeringame[i]) - continue; - - partySize = READUINT8(save->p); - - for (k = 0; k < partySize; ++k) + for (i = 0; i < MAXPLAYERS; i++) { - G_JoinParty(i, READUINT8(save->p)); + if (!playeringame[i]) + continue; + + partySize = G_PartySize(i); + + WRITEUINT8(save->p, partySize); + + for (k = 0; k < partySize; ++k) + { + WRITEUINT8(save->p, G_PartyMember(i, k)); + } + } + } + else + { + for (i = 0; i < MAXPLAYERS; i++) + { + if (!playeringame[i]) + continue; + + partySize = READUINT8(save->p); + + for (k = 0; k < partySize; ++k) + { + G_JoinParty(i, READUINT8(save->p)); + } } } @@ -987,133 +776,120 @@ static void ClearNetColormaps(void) net_colormaps = NULL; } -static void P_NetArchiveColormaps(savebuffer_t *save) -{ - TracyCZone(__zone, true); - - // We save and then we clean up our colormap mess - extracolormap_t *exc, *exc_next; - UINT32 i = 0; - WRITEUINT32(save->p, num_net_colormaps); // save for safety - - for (exc = net_colormaps; i < num_net_colormaps; i++, exc = exc_next) - { - // We must save num_net_colormaps worth of data - // So fill non-existent entries with default. - if (!exc) - exc = R_CreateDefaultColormap(false); - - WRITEUINT8(save->p, exc->fadestart); - WRITEUINT8(save->p, exc->fadeend); - WRITEUINT8(save->p, exc->flags); - - WRITEINT32(save->p, exc->rgba); - WRITEINT32(save->p, exc->fadergba); - -#ifdef EXTRACOLORMAPLUMPS - WRITESTRINGN(save->p, exc->lumpname, 9); -#endif - - exc_next = exc->next; - Z_Free(exc); // don't need anymore - } - - num_net_colormaps = 0; - num_ffloors = 0; - net_colormaps = NULL; - - TracyCZoneEnd(__zone); -} - -static void P_NetUnArchiveColormaps(savebuffer_t *save) +static void P_NetSyncColormaps(savebuffer_t *save) { TracyCZone(__zone, true); // When we reach this point, we already populated our list with // dummy colormaps. Now that we are loading the color data, // set up the dummies. - extracolormap_t *exc, *existing_exc, *exc_next = NULL; + extracolormap_t *exc, *existing_exc = NULL, *exc_next = NULL; UINT32 i = 0; - num_net_colormaps = READUINT32(save->p); + SYNC(num_net_colormaps); for (exc = net_colormaps; i < num_net_colormaps; i++, exc = exc_next) { - UINT8 fadestart, fadeend, flags; - INT32 rgba, fadergba; + // TODO: Merge these paths (got lazy since i've been at this for so long now) + if (save->write) + { + // We must save num_net_colormaps worth of data + // So fill non-existent entries with default. + if (!exc) + exc = R_CreateDefaultColormap(false); + + WRITEUINT8(save->p, exc->fadestart); + WRITEUINT8(save->p, exc->fadeend); + WRITEUINT8(save->p, exc->flags); + + WRITEINT32(save->p, exc->rgba); + WRITEINT32(save->p, exc->fadergba); + #ifdef EXTRACOLORMAPLUMPS - char lumpname[9]; + WRITESTRINGN(save->p, exc->lumpname, 9); #endif - fadestart = READUINT8(save->p); - fadeend = READUINT8(save->p); - flags = READUINT8(save->p); + exc_next = exc->next; + Z_Free(exc); // don't need anymore + } + else + { + UINT8 fadestart, fadeend, flags; + INT32 rgba, fadergba; +#ifdef EXTRACOLORMAPLUMPS + char lumpname[9]; +#endif - rgba = READINT32(save->p); - fadergba = READINT32(save->p); + fadestart = READUINT8(save->p); + fadeend = READUINT8(save->p); + flags = READUINT8(save->p); + + rgba = READINT32(save->p); + fadergba = READINT32(save->p); #ifdef EXTRACOLORMAPLUMPS - READSTRINGN(save->p, lumpname, 9); + READSTRINGN(save->p, lumpname, 9); + + if (lumpname[0]) + { + if (!exc) + // no point making a new entry since nothing points to it, + // but we needed to read the data so now continue + continue; + + exc_next = exc->next; // this gets overwritten during our operations here, so get it now + existing_exc = R_ColormapForName(lumpname); + *exc = *existing_exc; + R_AddColormapToList(exc); // see HACK note below on why we're adding duplicates + continue; + } +#endif - if (lumpname[0]) - { if (!exc) // no point making a new entry since nothing points to it, // but we needed to read the data so now continue continue; exc_next = exc->next; // this gets overwritten during our operations here, so get it now - existing_exc = R_ColormapForName(lumpname); - *exc = *existing_exc; - R_AddColormapToList(exc); // see HACK note below on why we're adding duplicates - continue; - } -#endif - if (!exc) - // no point making a new entry since nothing points to it, - // but we needed to read the data so now continue - continue; + exc->fadestart = fadestart; + exc->fadeend = fadeend; + exc->flags = flags; - exc_next = exc->next; // this gets overwritten during our operations here, so get it now - - exc->fadestart = fadestart; - exc->fadeend = fadeend; - exc->flags = flags; - - exc->rgba = rgba; - exc->fadergba = fadergba; + exc->rgba = rgba; + exc->fadergba = fadergba; #ifdef EXTRACOLORMAPLUMPS - exc->lump = LUMPERROR; - exc->lumpname[0] = 0; + exc->lump = LUMPERROR; + exc->lumpname[0] = 0; #endif - existing_exc = R_GetColormapFromListByValues(rgba, fadergba, fadestart, fadeend, flags); + existing_exc = R_GetColormapFromListByValues(rgba, fadergba, fadestart, fadeend, flags); - if (existing_exc) - exc->colormap = existing_exc->colormap; - else - // CONS_Debug(DBG_RENDER, "Creating Colormap: rgba(%d,%d,%d,%d) fadergba(%d,%d,%d,%d)\n", - // R_GetRgbaR(rgba), R_GetRgbaG(rgba), R_GetRgbaB(rgba), R_GetRgbaA(rgba), - // R_GetRgbaR(fadergba), R_GetRgbaG(fadergba), R_GetRgbaB(fadergba), R_GetRgbaA(fadergba)); - exc->colormap = R_CreateLightTable(exc); + if (existing_exc) + exc->colormap = existing_exc->colormap; + else + // CONS_Debug(DBG_RENDER, "Creating Colormap: rgba(%d,%d,%d,%d) fadergba(%d,%d,%d,%d)\n", + // R_GetRgbaR(rgba), R_GetRgbaG(rgba), R_GetRgbaB(rgba), R_GetRgbaA(rgba), + // R_GetRgbaR(fadergba), R_GetRgbaG(fadergba), R_GetRgbaB(fadergba), R_GetRgbaA(fadergba)); + exc->colormap = R_CreateLightTable(exc); - // HACK: If this dummy is a duplicate, we're going to add it - // to the extra_colormaps list anyway. I think this is faster - // than going through every loaded sector and correcting their - // colormap address to the pre-existing one, PER net_colormap entry - R_AddColormapToList(exc); + // HACK: If this dummy is a duplicate, we're going to add it + // to the extra_colormaps list anyway. I think this is faster + // than going through every loaded sector and correcting their + // colormap address to the pre-existing one, PER net_colormap entry + R_AddColormapToList(exc); - if (i < num_net_colormaps-1 && !exc_next) - exc_next = R_CreateDefaultColormap(false); + if (i < num_net_colormaps-1 && !exc_next) + exc_next = R_CreateDefaultColormap(false); + } } // if we still have a valid net_colormap after iterating up to num_net_colormaps, // some sector had a colormap index higher than num_net_colormaps. We done goofed or $$$ was corrupted. // In any case, add them to the colormap list too so that at least the sectors' colormap // addresses are valid and accounted properly - if (exc_next) + if (!save->write && exc_next) { existing_exc = R_GetDefaultColormap(); for (exc = exc_next; exc; exc = exc->next) @@ -1135,48 +911,57 @@ static void P_NetUnArchiveColormaps(savebuffer_t *save) /// World Archiving /// -#define SD_FLOORHT 0x01 -#define SD_CEILHT 0x02 -#define SD_FLOORPIC 0x04 -#define SD_CEILPIC 0x08 -#define SD_LIGHT 0x10 -#define SD_SPECIAL 0x20 -#define SD_DIFF2 0x40 -#define SD_FFLOORS 0x80 +// each byte contains 7 flags +// the most significant bit indicates a following extra byte +enum sectordiff_e +{ + SD_FLOORHT = 0<<3, + SD_CEILHT, + SD_FLOORPIC, + SD_CEILPIC, + SD_LIGHT, + SD_SPECIAL, + SD_FFLOORS, -// diff2 flags -#define SD_FXOFFS 0x01 -#define SD_FYOFFS 0x02 -#define SD_CXOFFS 0x04 -#define SD_CYOFFS 0x08 -#define SD_FLOORANG 0x10 -#define SD_CEILANG 0x20 -#define SD_TAG 0x40 -#define SD_DIFF3 0x80 + // diff2 flags + SD_FXOFFS = 1<<3, + SD_FYOFFS, + SD_CXOFFS, + SD_CYOFFS, + SD_FLOORANG, + SD_CEILANG, + SD_TAG, -// diff3 flags -#define SD__UNUSED 0x01 -#define SD_COLORMAP 0x02 -#define SD_CRUMBLESTATE 0x04 -#define SD_FLOORLIGHT 0x08 -#define SD_CEILLIGHT 0x10 -#define SD_FLAG 0x20 -#define SD_SPECIALFLAG 0x40 -#define SD_DIFF4 0x80 + // diff3 flags + SD__UNUSED = 2<<3, + SD_COLORMAP, + SD_CRUMBLESTATE, + SD_FLOORLIGHT, + SD_CEILLIGHT, + SD_FLAG, + SD_SPECIALFLAG, -//diff4 flags -#define SD_DAMAGETYPE 0x01 -#define SD_TRIGGERTAG 0x02 -#define SD_TRIGGERER 0x04 -#define SD_GRAVITY 0x08 -#define SD_ACTION 0x10 -#define SD_ARGS 0x20 -#define SD_STRINGARGS 0x40 -#define SD_DIFF5 0x80 + //diff4 flags + SD_DAMAGETYPE = 3<<3, + SD_TRIGGERTAG, + SD_TRIGGERER, + SD_GRAVITY, + SD_ACTION, + SD_ARGS, + SD_STRINGARGS, -//diff5 flags -#define SD_ACTIVATION 0x01 -#define SD_BOTCONTROLLER 0x02 + //diff5 flags + SD_ACTIVATION = 4<<3, + SD_BOTCONTROLLER, + + SD__MAX +}; + +enum ffloordiff_e +{ + FD_FLAGS, + FD_ALPHA, +}; static boolean P_SectorArgsEqual(const sector_t *sc, const sector_t *spawnsc) { @@ -1203,27 +988,42 @@ static boolean P_SectorStringArgsEqual(const sector_t *sc, const sector_t *spawn return true; } -#define LD_FLAG 0x01 -#define LD_SPECIAL 0x02 -#define LD_TAG 0x04 -#define LD_S1TEXOFF 0x08 -#define LD_S1TOPTEX 0x10 -#define LD_S1BOTTEX 0x20 -#define LD_S1MIDTEX 0x40 -#define LD_DIFF2 0x80 +enum linediff_e +{ + LD_FLAG = 0<<3, + LD_SPECIAL, + LD_TAG, + LD_S1TEXOFF, + LD_S1TOPTEX, + LD_S1BOTTEX, + LD_S1MIDTEX, -// diff2 flags -#define LD_S2TEXOFF 0x01 -#define LD_S2TOPTEX 0x02 -#define LD_S2BOTTEX 0x04 -#define LD_S2MIDTEX 0x08 -#define LD_ARGS 0x10 -#define LD_STRINGARGS 0x20 -#define LD__UNUSED 0x40 -#define LD_DIFF3 0x80 + // diff2 flags + LD_S2TEXOFF = 1<<3, + LD_S2TOPTEX, + LD_S2BOTTEX, + LD_S2MIDTEX, + LD_ARGS, + LD_STRINGARGS, + LD__UNUSED, -// diff3 flags -#define LD_ACTIVATION 0x01 + // diff3 flags + LD_ACTIVATION = 2<<3, + + LD__MAX +}; + +// diff macros +#define SETB(b) (diff[b / (8*sizeof(*diff))] |= (1 << (b & (8*sizeof(*diff) - 1)))) +#define DIFFNE(x, field, b) if (x->field != spawn##x->field) SETB(b) +#define DIFFIF(x, field, b) if (x->field) SETB(b) +#define DIFF(x, b) if (x) SETB(b) + +// sync macros +#define GETB(b) (diff[b / (8*sizeof(*diff))] & (1 << (b & (8*sizeof(*diff) - 1)))) +#define SYNCF(b, v) if (GETB(b)) SYNC(v) +#define SYNCFB(b, v) if (GETB(b)) SYNCBOOLEAN(v) +#define SYNCDEF(b, v, d) (GETB(b) ? SYNC(v) : (v = d)) static boolean P_LineArgsEqual(const line_t *li, const line_t *spawnli) { @@ -1250,9 +1050,6 @@ static boolean P_LineStringArgsEqual(const line_t *li, const line_t *spawnli) return true; } -#define FD_FLAGS 0x01 -#define FD_ALPHA 0x02 - // Check if any of the sector's FOFs differ from how they spawned static boolean CheckFFloorDiff(const sector_t *ss) { @@ -1272,551 +1069,426 @@ static boolean CheckFFloorDiff(const sector_t *ss) // Special case: save the stats of all modified ffloors along with their ffloor "number"s // we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed -static void ArchiveFFloors(savebuffer_t *save, const sector_t *ss) +static void SyncFFloors(savebuffer_t *save, const sector_t *ss) { size_t j = 0; // ss->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc ffloor_t *rover; - UINT8 fflr_diff; - for (rover = ss->ffloors; rover; rover = rover->next) - { - fflr_diff = 0; // reset diff flags - if (rover->fofflags != rover->spawnflags) - fflr_diff |= FD_FLAGS; - if (rover->alpha != rover->spawnalpha) - fflr_diff |= FD_ALPHA; - - if (fflr_diff) - { - WRITEUINT16(save->p, j); // save ffloor "number" - WRITEUINT8(save->p, fflr_diff); - if (fflr_diff & FD_FLAGS) - WRITEUINT32(save->p, rover->fofflags); - if (fflr_diff & FD_ALPHA) - WRITEINT16(save->p, rover->alpha); - } - j++; - } - WRITEUINT16(save->p, 0xffff); -} - -static void UnArchiveFFloors(savebuffer_t *save, const sector_t *ss) -{ - UINT16 j = 0; // number of current ffloor in loop UINT16 fflr_i; // saved ffloor "number" of next modified ffloor - UINT16 fflr_diff; // saved ffloor diff - ffloor_t *rover; + UINT8 diff[1]; - rover = ss->ffloors; - if (!rover) // it is assumed sectors[i].ffloors actually exists, but just in case... - I_Error("Sector does not have any ffloors!"); + if (!save->write) + fflr_i = READUINT16(save->p); // get first modified ffloor's number ready - fflr_i = READUINT16(save->p); // get first modified ffloor's number ready - for (;;) // for some reason the usual for (rover = x; ...) thing doesn't work here? + for (rover = ss->ffloors; rover; rover = rover->next, j++) { - if (fflr_i == 0xffff) // end of modified ffloors list, let's stop already - break; - // should NEVER need to be checked - //if (rover == NULL) - //break; - if (j != fflr_i) // this ffloor was not modified + memset(diff, 0, sizeof(diff)); + if (save->write) { - j++; - rover = rover->next; - continue; + if (rover->fofflags != rover->spawnflags) + SETB(FD_FLAGS); + if (rover->alpha != rover->spawnalpha) + SETB(FD_ALPHA); + + if (diff[0] == 0) + continue; + + WRITEUINT16(save->p, j); + } + else + { + if (fflr_i == 0xffff) // end of modified ffloors list, let's stop already + break; + if (j != fflr_i) // this ffloor was not modified + continue; + + fflr_i = READUINT16(save->p); // get next ffloor "number" ready } - fflr_diff = READUINT8(save->p); + SYNC(diff[0]); + SYNCF(FD_FLAGS, rover->fofflags); + SYNCF(FD_ALPHA, rover->alpha); + } - if (fflr_diff & FD_FLAGS) - rover->fofflags = READUINT32(save->p); - if (fflr_diff & FD_ALPHA) - rover->alpha = READINT16(save->p); + if (save->write) + WRITEUINT16(save->p, 0xffff); +} - fflr_i = READUINT16(save->p); // get next ffloor "number" ready +static void DiffSectors(savebuffer_t *save, const sector_t *ss, const sector_t *spawnss, UINT8 diff[]) +{ + DIFFNE(ss, floorheight, SD_FLOORHT); + DIFFNE(ss, ceilingheight, SD_CEILHT); + DIFFNE(ss, floorpic, SD_FLOORPIC); + DIFFNE(ss, ceilingpic, SD_CEILPIC); + DIFFNE(ss, lightlevel, SD_LIGHT); + DIFFNE(ss, special, SD_SPECIAL); + if (ss->ffloors && CheckFFloorDiff(ss)) + SETB(SD_FFLOORS); - j++; - rover = rover->next; + DIFFNE(ss, floor_xoffs, SD_FXOFFS); + DIFFNE(ss, floor_yoffs, SD_FYOFFS); + DIFFNE(ss, ceiling_xoffs, SD_CXOFFS); + DIFFNE(ss, ceiling_yoffs, SD_CYOFFS); + DIFFNE(ss, floorpic_angle, SD_FLOORANG); + DIFFNE(ss, ceilingpic_angle, SD_CEILANG); + if (!Tag_Compare(&ss->tags, &spawnss->tags)) + SETB(SD_TAG); + + //DIFFNE(ss, ..., SD__UNUSED); + DIFFNE(ss, extra_colormap, SD_COLORMAP); + DIFFIF(ss, crumblestate, SD_CRUMBLESTATE); + if (ss->floorlightlevel != spawnss->floorlightlevel || ss->floorlightabsolute != spawnss->floorlightabsolute) + SETB(SD_FLOORLIGHT); + if (ss->ceilinglightlevel != spawnss->ceilinglightlevel || ss->ceilinglightabsolute != spawnss->ceilinglightabsolute) + SETB(SD_CEILLIGHT); + DIFFNE(ss, flags, SD_FLAG); + DIFFNE(ss, specialflags, SD_SPECIALFLAG); + + DIFFNE(ss, damagetype, SD_DAMAGETYPE); + DIFFNE(ss, triggertag, SD_TRIGGERTAG); + DIFFNE(ss, triggerer, SD_TRIGGERER); + DIFFNE(ss, gravity, SD_GRAVITY); + DIFFNE(ss, action, SD_ACTION); + if (!P_SectorArgsEqual(ss, spawnss)) + SETB(SD_ARGS); + if (!P_SectorStringArgsEqual(ss, spawnss)) + SETB(SD_STRINGARGS); + + DIFFNE(ss, activation, SD_ACTIVATION); + if (/*ss->botController.trick != spawnss->botController.trick + ||*/ss->botController.flags != spawnss->botController.flags + || ss->botController.forceAngle != spawnss->botController.forceAngle) + { + SETB(SD_BOTCONTROLLER); } } -static void ArchiveSectors(savebuffer_t *save) +static void SyncSectors(savebuffer_t *save) { - size_t i, j; - const sector_t *ss = sectors; - const sector_t *spawnss = spawnsectors; - UINT8 diff, diff2, diff3, diff4, diff5; + size_t i = 0, j; + sector_t *sec; + UINT8 diff[(SD__MAX>>3) + 1]; - for (i = 0; i < numsectors; i++, ss++, spawnss++) + for (;;) { - diff = diff2 = diff3 = diff4 = diff5 = 0; - if (ss->floorheight != spawnss->floorheight) - diff |= SD_FLOORHT; - if (ss->ceilingheight != spawnss->ceilingheight) - diff |= SD_CEILHT; - // - // flats - // - if (ss->floorpic != spawnss->floorpic) - diff |= SD_FLOORPIC; - if (ss->ceilingpic != spawnss->ceilingpic) - diff |= SD_CEILPIC; - - if (ss->lightlevel != spawnss->lightlevel) - diff |= SD_LIGHT; - if (ss->special != spawnss->special) - diff |= SD_SPECIAL; - - if (ss->floor_xoffs != spawnss->floor_xoffs) - diff2 |= SD_FXOFFS; - if (ss->floor_yoffs != spawnss->floor_yoffs) - diff2 |= SD_FYOFFS; - if (ss->ceiling_xoffs != spawnss->ceiling_xoffs) - diff2 |= SD_CXOFFS; - if (ss->ceiling_yoffs != spawnss->ceiling_yoffs) - diff2 |= SD_CYOFFS; - if (ss->floorpic_angle != spawnss->floorpic_angle) - diff2 |= SD_FLOORANG; - if (ss->ceilingpic_angle != spawnss->ceilingpic_angle) - diff2 |= SD_CEILANG; - - if (!Tag_Compare(&ss->tags, &spawnss->tags)) - diff2 |= SD_TAG; - - if (ss->extra_colormap != spawnss->extra_colormap) - diff3 |= SD_COLORMAP; - if (ss->crumblestate) - diff3 |= SD_CRUMBLESTATE; - - if (ss->floorlightlevel != spawnss->floorlightlevel || ss->floorlightabsolute != spawnss->floorlightabsolute) - diff3 |= SD_FLOORLIGHT; - if (ss->ceilinglightlevel != spawnss->ceilinglightlevel || ss->ceilinglightabsolute != spawnss->ceilinglightabsolute) - diff3 |= SD_CEILLIGHT; - if (ss->flags != spawnss->flags) - diff3 |= SD_FLAG; - if (ss->specialflags != spawnss->specialflags) - diff3 |= SD_SPECIALFLAG; - if (ss->damagetype != spawnss->damagetype) - diff4 |= SD_DAMAGETYPE; - if (ss->triggertag != spawnss->triggertag) - diff4 |= SD_TRIGGERTAG; - if (ss->triggerer != spawnss->triggerer) - diff4 |= SD_TRIGGERER; - if (ss->gravity != spawnss->gravity) - diff4 |= SD_GRAVITY; - - if (ss->action != spawnss->action) - diff4 |= SD_ACTION; - if (!P_SectorArgsEqual(ss, spawnss)) - diff4 |= SD_ARGS; - if (!P_SectorStringArgsEqual(ss, spawnss)) - diff4 |= SD_STRINGARGS; - if (ss->activation != spawnss->activation) - diff5 |= SD_ACTIVATION; - if (/*ss->botController.trick != spawnss->botController.trick - ||*/ss->botController.flags != spawnss->botController.flags - || ss->botController.forceAngle != spawnss->botController.forceAngle) + memset(diff, 0, sizeof(diff)); + if (save->write) { - diff5 |= SD_BOTCONTROLLER; + if (++i == numsectors) + break; + + DiffSectors(save, §ors[i], &spawnsectors[i], diff); + for (j = sizeof(diff)-1; j > 0; j--) + if (diff[j]) + diff[j-1] |= 0x80; + if (diff[0] == 0) + continue; + + WRITEUINT16(save->p, i); + } + else + { + i = READUINT16(save->p); + + if (i == 0xffff) + break; + + if (i >= numsectors) + I_Error("Invalid sector number %zu from server (expected end at %zu)", i, numsectors); } - if (ss->ffloors && CheckFFloorDiff(ss)) - diff |= SD_FFLOORS; + sec = §ors[i]; + j = 0; + do + SYNC(diff[j]); + while (diff[j++] & 0x80); - if (diff5) - diff4 |= SD_DIFF5; - - if (diff4) - diff3 |= SD_DIFF4; - - if (diff3) - diff2 |= SD_DIFF3; - - if (diff2) - diff |= SD_DIFF2; - - if (diff) + SYNCF(SD_FLOORHT, sec->floorheight); + SYNCF(SD_CEILHT, sec->ceilingheight); + if (GETB(SD_FLOORPIC)) { - WRITEUINT16(save->p, i); - WRITEUINT8(save->p, diff); - if (diff & SD_DIFF2) - WRITEUINT8(save->p, diff2); - if (diff2 & SD_DIFF3) - WRITEUINT8(save->p, diff3); - if (diff3 & SD_DIFF4) - WRITEUINT8(save->p, diff4); - if (diff4 & SD_DIFF5) - WRITEUINT8(save->p, diff5); - if (diff & SD_FLOORHT) - WRITEFIXED(save->p, ss->floorheight); - if (diff & SD_CEILHT) - WRITEFIXED(save->p, ss->ceilingheight); - if (diff & SD_FLOORPIC) - WRITEMEM(save->p, levelflats[ss->floorpic].name, 8); - if (diff & SD_CEILPIC) - WRITEMEM(save->p, levelflats[ss->ceilingpic].name, 8); - if (diff & SD_LIGHT) - WRITEINT16(save->p, ss->lightlevel); - if (diff & SD_SPECIAL) - WRITEINT16(save->p, ss->special); - if (diff2 & SD_FXOFFS) - WRITEFIXED(save->p, ss->floor_xoffs); - if (diff2 & SD_FYOFFS) - WRITEFIXED(save->p, ss->floor_yoffs); - if (diff2 & SD_CXOFFS) - WRITEFIXED(save->p, ss->ceiling_xoffs); - if (diff2 & SD_CYOFFS) - WRITEFIXED(save->p, ss->ceiling_yoffs); - if (diff2 & SD_FLOORANG) - WRITEANGLE(save->p, ss->floorpic_angle); - if (diff2 & SD_CEILANG) - WRITEANGLE(save->p, ss->ceilingpic_angle); - if (diff2 & SD_TAG) + if (save->write) + WRITEMEM(save->p, levelflats[sec->floorpic].name, 8); + else { - WRITEUINT32(save->p, ss->tags.count); - for (j = 0; j < ss->tags.count; j++) - WRITEINT16(save->p, ss->tags.tags[j]); + sectors[i].floorpic = P_AddLevelFlatRuntime((char *)save->p); + save->p += 8; } + } + if (GETB(SD_CEILPIC)) + { + if (save->write) + WRITEMEM(save->p, levelflats[sec->ceilingpic].name, 8); + else + { + sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)save->p); + save->p += 8; + } + } + SYNCF(SD_LIGHT, sec->lightlevel); + SYNCF(SD_SPECIAL, sec->special); + if (GETB(SD_FFLOORS)) + SyncFFloors(save, sec); - if (diff3 & SD_COLORMAP) - WRITEUINT32(save->p, CheckAddNetColormapToList(ss->extra_colormap)); + SYNCF(SD_FXOFFS, sec->floor_xoffs); + SYNCF(SD_FYOFFS, sec->floor_yoffs); + SYNCF(SD_CXOFFS, sec->ceiling_xoffs); + SYNCF(SD_CYOFFS, sec->ceiling_yoffs); + SYNCF(SD_FLOORANG, sec->floorpic_angle); + SYNCF(SD_CEILANG, sec->ceilingpic_angle); + if (GETB(SD_TAG)) + { + if (save->write) + { + WRITEUINT32(save->p, sec->tags.count); + for (j = 0; j < sec->tags.count; j++) + WRITEINT16(save->p, sec->tags.tags[j]); + } + else + { + size_t ncount = READUINT32(save->p); + + // Remove entries from global lists. + for (j = 0; j < sectors[i].tags.count; j++) + Taggroup_Remove(tags_sectors, sectors[i].tags.tags[j], i); + + // Reallocate if size differs. + if (ncount != sectors[i].tags.count) + { + sectors[i].tags.count = ncount; + sectors[i].tags.tags = Z_Realloc(sectors[i].tags.tags, ncount*sizeof(mtag_t), PU_LEVEL, NULL); + } + + for (j = 0; j < ncount; j++) + sectors[i].tags.tags[j] = READINT16(save->p); + + // Add new entries. + for (j = 0; j < sectors[i].tags.count; j++) + Taggroup_Add(tags_sectors, sectors[i].tags.tags[j], i); + } + } + + if (GETB(SD_COLORMAP)) + { + if (save->write) + WRITEUINT32(save->p, CheckAddNetColormapToList(sec->extra_colormap)); // returns existing index if already added, or appends to net_colormaps and returns new index - if (diff3 & SD_CRUMBLESTATE) - WRITEINT32(save->p, ss->crumblestate); - if (diff3 & SD_FLOORLIGHT) - { - WRITEINT16(save->p, ss->floorlightlevel); - WRITEUINT8(save->p, ss->floorlightabsolute); - } - if (diff3 & SD_CEILLIGHT) - { - WRITEINT16(save->p, ss->ceilinglightlevel); - WRITEUINT8(save->p, ss->ceilinglightabsolute); - } - if (diff3 & SD_FLAG) - WRITEUINT32(save->p, ss->flags); - if (diff3 & SD_SPECIALFLAG) - WRITEUINT32(save->p, ss->specialflags); - if (diff4 & SD_DAMAGETYPE) - WRITEUINT8(save->p, ss->damagetype); - if (diff4 & SD_TRIGGERTAG) - WRITEINT16(save->p, ss->triggertag); - if (diff4 & SD_TRIGGERER) - WRITEUINT8(save->p, ss->triggerer); - if (diff4 & SD_GRAVITY) - WRITEFIXED(save->p, ss->gravity); + else + sec->extra_colormap = GetNetColormapFromList(READUINT32(save->p)); + } + SYNCF(SD_CRUMBLESTATE, sec->crumblestate); + SYNCF(SD_FLOORLIGHT, sec->floorlightlevel); + SYNCFB(SD_FLOORLIGHT, sec->floorlightabsolute); + SYNCF(SD_CEILLIGHT, sec->ceilinglightlevel); + SYNCFB(SD_CEILLIGHT, sec->ceilinglightabsolute); + SYNCF(SD_FLAG, sec->flags); + SYNCF(SD_SPECIALFLAG, sec->specialflags); - if (diff4 & SD_ACTION) - WRITEINT16(save->p, ss->action); - if (diff4 & SD_ARGS) + if (!save->write && GETB(SD_FLAG)) + CheckForReverseGravity |= sec->flags & MSF_GRAVITYFLIP; + + SYNCF(SD_DAMAGETYPE, sec->damagetype); + SYNCF(SD_TRIGGERTAG, sec->triggertag); + SYNCF(SD_TRIGGERER, sec->triggerer); + SYNCF(SD_GRAVITY, sec->gravity); + SYNCF(SD_ACTION, sec->action); + if (GETB(SD_ARGS)) + { + for (j = 0; j < NUM_SCRIPT_ARGS; j++) + SYNC(sec->args[j]); + } + if (GETB(SD_STRINGARGS)) + { + for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) { - for (j = 0; j < NUM_SCRIPT_ARGS; j++) - WRITEINT32(save->p, ss->args[j]); - } - if (diff4 & SD_STRINGARGS) - { - for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) + if (save->write) { size_t len, k; - if (!ss->stringargs[j]) + if (!sec->stringargs[j]) { WRITEINT32(save->p, 0); continue; } - len = strlen(ss->stringargs[j]); + len = strlen(sec->stringargs[j]); WRITEINT32(save->p, len); for (k = 0; k < len; k++) - WRITECHAR(save->p, ss->stringargs[j][k]); + WRITECHAR(save->p, sec->stringargs[j][k]); + } + else + { + size_t len = READINT32(save->p); + size_t k; + + if (!len) + { + Z_Free(sectors[i].stringargs[j]); + sectors[i].stringargs[j] = NULL; + continue; + } + + sectors[i].stringargs[j] = Z_Realloc(sectors[i].stringargs[j], len + 1, PU_LEVEL, NULL); + for (k = 0; k < len; k++) + sectors[i].stringargs[j][k] = READCHAR(save->p); + sectors[i].stringargs[j][len] = '\0'; } } - if (diff5 & SD_ACTIVATION) - WRITEUINT32(save->p, ss->activation); + } - if (diff5 & SD_BOTCONTROLLER) + SYNCF(SD_ACTIVATION, sec->activation); + if (GETB(SD_BOTCONTROLLER)) + { + if (save->write) { - //WRITEUINT8(save->p, ss->botController.trick); - WRITEUINT32(save->p, ss->botController.flags); - WRITEANGLE(save->p, ss->botController.forceAngle); + //WRITEUINT8(save->p, sec->botController.trick); + WRITEUINT32(save->p, sec->botController.flags); + WRITEANGLE(save->p, sec->botController.forceAngle); + } + else + { + //sectors[i].botController.trick = READUINT8(save->p); + sectors[i].botController.flags = READUINT32(save->p); + sectors[i].botController.forceAngle = READANGLE(save->p); } - - if (diff & SD_FFLOORS) - ArchiveFFloors(save, ss); } } - WRITEUINT16(save->p, 0xffff); + if (save->write) + WRITEUINT16(save->p, 0xffff); } -static void UnArchiveSectors(savebuffer_t *save) +static void DiffLines(savebuffer_t *save, const line_t *li, const line_t *spawnli, UINT8 diff[]) { - UINT16 i, j; - UINT8 diff, diff2, diff3, diff4, diff5; + const side_t *si, *spawnsi; + + DIFFNE(li, flags, LD_FLAG); + DIFFNE(li, special, LD_SPECIAL); + if (!Tag_Compare(&li->tags, &spawnli->tags)) + SETB(LD_TAG); + + if (!P_LineArgsEqual(li, spawnli)) + SETB(LD_ARGS); + + if (!P_LineStringArgsEqual(li, spawnli)) + SETB(LD_STRINGARGS); + + DIFFNE(li, activation, LD_ACTIVATION); + + if (li->sidenum[0] != 0xffff) + { + si = &sides[li->sidenum[0]]; + spawnsi = &spawnsides[li->sidenum[0]]; + DIFFNE(si, textureoffset, LD_S1TEXOFF); + //SoM: 4/1/2000: Some textures are colormaps. Don't worry about invalid textures. + DIFFNE(si, toptexture, LD_S1TOPTEX); + DIFFNE(si, bottomtexture, LD_S1BOTTEX); + DIFFNE(si, midtexture, LD_S1MIDTEX); + } + if (li->sidenum[1] != 0xffff) + { + si = &sides[li->sidenum[1]]; + spawnsi = &spawnsides[li->sidenum[1]]; + DIFFNE(si, textureoffset, LD_S2TEXOFF); + DIFFNE(si, toptexture, LD_S2TOPTEX); + DIFFNE(si, bottomtexture, LD_S2BOTTEX); + DIFFNE(si, midtexture, LD_S2MIDTEX); + } +} + +static void SyncLines(savebuffer_t *save) +{ + size_t i = 0, j; + line_t *li; + side_t *si; + UINT8 diff[(LD__MAX>>3)+1]; + for (;;) { - i = READUINT16(save->p); + memset(diff, 0, sizeof(diff)); + if (save->write) + { + if (++i == numlines) + break; - if (i == 0xffff) - break; + DiffLines(save, &lines[i], &spawnlines[i], diff); + for (j = sizeof(diff)-1; j > 0; j--) + if (diff[j]) + diff[j-1] |= 0x80; + if (diff[0] == 0) + continue; - if (i > numsectors) - I_Error("Invalid sector number %u from server (expected end at %s)", i, sizeu1(numsectors)); - - diff = READUINT8(save->p); - if (diff & SD_DIFF2) - diff2 = READUINT8(save->p); + WRITEUINT16(save->p, i); + } else - diff2 = 0; - if (diff2 & SD_DIFF3) - diff3 = READUINT8(save->p); - else - diff3 = 0; - if (diff3 & SD_DIFF4) - diff4 = READUINT8(save->p); - else - diff4 = 0; - - if (diff4 & SD_DIFF5) - diff5 = READUINT8(save->p); - else - diff5 = 0; - - if (diff & SD_FLOORHT) - sectors[i].floorheight = READFIXED(save->p); - if (diff & SD_CEILHT) - sectors[i].ceilingheight = READFIXED(save->p); - if (diff & SD_FLOORPIC) { - sectors[i].floorpic = P_AddLevelFlatRuntime((char *)save->p); - save->p += 8; - } - if (diff & SD_CEILPIC) - { - sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)save->p); - save->p += 8; - } - if (diff & SD_LIGHT) - sectors[i].lightlevel = READINT16(save->p); - if (diff & SD_SPECIAL) - sectors[i].special = READINT16(save->p); + i = READUINT16(save->p); - if (diff2 & SD_FXOFFS) - sectors[i].floor_xoffs = READFIXED(save->p); - if (diff2 & SD_FYOFFS) - sectors[i].floor_yoffs = READFIXED(save->p); - if (diff2 & SD_CXOFFS) - sectors[i].ceiling_xoffs = READFIXED(save->p); - if (diff2 & SD_CYOFFS) - sectors[i].ceiling_yoffs = READFIXED(save->p); - if (diff2 & SD_FLOORANG) - sectors[i].floorpic_angle = READANGLE(save->p); - if (diff2 & SD_CEILANG) - sectors[i].ceilingpic_angle = READANGLE(save->p); - if (diff2 & SD_TAG) - { - size_t ncount = READUINT32(save->p); + if (i == 0xffff) + break; - // Remove entries from global lists. - for (j = 0; j < sectors[i].tags.count; j++) - Taggroup_Remove(tags_sectors, sectors[i].tags.tags[j], i); - - // Reallocate if size differs. - if (ncount != sectors[i].tags.count) - { - sectors[i].tags.count = ncount; - sectors[i].tags.tags = Z_Realloc(sectors[i].tags.tags, ncount*sizeof(mtag_t), PU_LEVEL, NULL); - } - - for (j = 0; j < ncount; j++) - sectors[i].tags.tags[j] = READINT16(save->p); - - // Add new entries. - for (j = 0; j < sectors[i].tags.count; j++) - Taggroup_Add(tags_sectors, sectors[i].tags.tags[j], i); + if (i >= numlines) + I_Error("Invalid line number %zu from server", i); } + li = &lines[i]; + j = 0; + do + SYNC(diff[j]); + while (diff[j++] & 0x80); - if (diff3 & SD_COLORMAP) - sectors[i].extra_colormap = GetNetColormapFromList(READUINT32(save->p)); - if (diff3 & SD_CRUMBLESTATE) - sectors[i].crumblestate = READINT32(save->p); - if (diff3 & SD_FLOORLIGHT) + SYNCF(LD_FLAG, li->flags); + SYNCF(LD_SPECIAL, li->special); + if (GETB(LD_TAG)) { - sectors[i].floorlightlevel = READINT16(save->p); - sectors[i].floorlightabsolute = READUINT8(save->p); - } - if (diff3 & SD_CEILLIGHT) - { - sectors[i].ceilinglightlevel = READINT16(save->p); - sectors[i].ceilinglightabsolute = READUINT8(save->p); - } - if (diff3 & SD_FLAG) - { - sectors[i].flags = READUINT32(save->p); - CheckForReverseGravity |= (sectors[i].flags & MSF_GRAVITYFLIP); - } - if (diff3 & SD_SPECIALFLAG) - sectors[i].specialflags = READUINT32(save->p); - if (diff4 & SD_DAMAGETYPE) - sectors[i].damagetype = READUINT8(save->p); - if (diff4 & SD_TRIGGERTAG) - sectors[i].triggertag = READINT16(save->p); - if (diff4 & SD_TRIGGERER) - sectors[i].triggerer = READUINT8(save->p); - if (diff4 & SD_GRAVITY) - sectors[i].gravity = READFIXED(save->p); - - if (diff4 & SD_ACTION) - sectors[i].action = READINT16(save->p); - if (diff4 & SD_ARGS) - { - for (j = 0; j < NUM_SCRIPT_ARGS; j++) - sectors[i].args[j] = READINT32(save->p); - } - if (diff4 & SD_STRINGARGS) - { - for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) - { - size_t len = READINT32(save->p); - size_t k; - - if (!len) - { - Z_Free(sectors[i].stringargs[j]); - sectors[i].stringargs[j] = NULL; - continue; - } - - sectors[i].stringargs[j] = Z_Realloc(sectors[i].stringargs[j], len + 1, PU_LEVEL, NULL); - for (k = 0; k < len; k++) - sectors[i].stringargs[j][k] = READCHAR(save->p); - sectors[i].stringargs[j][len] = '\0'; - } - } - if (diff5 & SD_ACTIVATION) - sectors[i].activation = READUINT32(save->p); - - if (diff5 & SD_BOTCONTROLLER) - { - //sectors[i].botController.trick = READUINT8(save->p); - sectors[i].botController.flags = READUINT32(save->p); - sectors[i].botController.forceAngle = READANGLE(save->p); - } - - if (diff & SD_FFLOORS) - UnArchiveFFloors(save, §ors[i]); - } -} - -static void ArchiveLines(savebuffer_t *save) -{ - size_t i, j; - const line_t *li = lines; - const line_t *spawnli = spawnlines; - const side_t *si; - const side_t *spawnsi; - UINT8 diff, diff2, diff3; - - for (i = 0; i < numlines; i++, spawnli++, li++) - { - diff = diff2 = diff3 = 0; - - if (li->flags != spawnli->flags) - diff |= LD_FLAG; - - if (li->special != spawnli->special) - diff |= LD_SPECIAL; - - if (!Tag_Compare(&li->tags, &spawnli->tags)) - diff |= LD_TAG; - - if (!P_LineArgsEqual(li, spawnli)) - diff2 |= LD_ARGS; - - if (!P_LineStringArgsEqual(li, spawnli)) - diff2 |= LD_STRINGARGS; - - if (li->activation != spawnli->activation) - diff3 |= LD_ACTIVATION; - - if (li->sidenum[0] != 0xffff) - { - si = &sides[li->sidenum[0]]; - spawnsi = &spawnsides[li->sidenum[0]]; - if (si->textureoffset != spawnsi->textureoffset) - diff |= LD_S1TEXOFF; - //SoM: 4/1/2000: Some textures are colormaps. Don't worry about invalid textures. - if (si->toptexture != spawnsi->toptexture) - diff |= LD_S1TOPTEX; - if (si->bottomtexture != spawnsi->bottomtexture) - diff |= LD_S1BOTTEX; - if (si->midtexture != spawnsi->midtexture) - diff |= LD_S1MIDTEX; - } - if (li->sidenum[1] != 0xffff) - { - si = &sides[li->sidenum[1]]; - spawnsi = &spawnsides[li->sidenum[1]]; - if (si->textureoffset != spawnsi->textureoffset) - diff2 |= LD_S2TEXOFF; - if (si->toptexture != spawnsi->toptexture) - diff2 |= LD_S2TOPTEX; - if (si->bottomtexture != spawnsi->bottomtexture) - diff2 |= LD_S2BOTTEX; - if (si->midtexture != spawnsi->midtexture) - diff2 |= LD_S2MIDTEX; - } - - if (diff3) - diff2 |= LD_DIFF3; - - if (diff2) - diff |= LD_DIFF2; - - if (diff) - { - WRITEINT16(save->p, i); - WRITEUINT8(save->p, diff); - if (diff & LD_DIFF2) - WRITEUINT8(save->p, diff2); - if (diff2 & LD_DIFF3) - WRITEUINT8(save->p, diff3); - if (diff & LD_FLAG) - WRITEUINT32(save->p, li->flags); - if (diff & LD_SPECIAL) - WRITEINT16(save->p, li->special); - if (diff & LD_TAG) + if (save->write) { WRITEUINT32(save->p, li->tags.count); for (j = 0; j < li->tags.count; j++) WRITEINT16(save->p, li->tags.tags[j]); } - - si = &sides[li->sidenum[0]]; - if (diff & LD_S1TEXOFF) - WRITEFIXED(save->p, si->textureoffset); - if (diff & LD_S1TOPTEX) - WRITEINT32(save->p, si->toptexture); - if (diff & LD_S1BOTTEX) - WRITEINT32(save->p, si->bottomtexture); - if (diff & LD_S1MIDTEX) - WRITEINT32(save->p, si->midtexture); - - si = &sides[li->sidenum[1]]; - if (diff2 & LD_S2TEXOFF) - WRITEFIXED(save->p, si->textureoffset); - if (diff2 & LD_S2TOPTEX) - WRITEINT32(save->p, si->toptexture); - if (diff2 & LD_S2BOTTEX) - WRITEINT32(save->p, si->bottomtexture); - if (diff2 & LD_S2MIDTEX) - WRITEINT32(save->p, si->midtexture); - if (diff2 & LD_ARGS) + else { - for (j = 0; j < NUM_SCRIPT_ARGS; j++) - WRITEINT32(save->p, li->args[j]); + size_t ncount = READUINT32(save->p); + + // Remove entries from global lists. + for (j = 0; j < lines[i].tags.count; j++) + Taggroup_Remove(tags_lines, lines[i].tags.tags[j], i); + + // Reallocate if size differs. + if (ncount != lines[i].tags.count) + { + lines[i].tags.count = ncount; + lines[i].tags.tags = (mtag_t*)Z_Realloc(lines[i].tags.tags, ncount*sizeof(mtag_t), PU_LEVEL, NULL); + } + + for (j = 0; j < ncount; j++) + lines[i].tags.tags[j] = READINT16(save->p); + + // Add new entries. + for (j = 0; j < lines[i].tags.count; j++) + Taggroup_Add(tags_lines, lines[i].tags.tags[j], i); } - if (diff2 & LD_STRINGARGS) + } + + si = &sides[li->sidenum[0]]; + SYNCF(LD_S1TEXOFF, si->textureoffset); + SYNCF(LD_S1TOPTEX, si->toptexture); + SYNCF(LD_S1BOTTEX, si->bottomtexture); + SYNCF(LD_S1MIDTEX, si->midtexture); + + si = &sides[li->sidenum[1]]; + SYNCF(LD_S2TEXOFF, si->textureoffset); + SYNCF(LD_S2TOPTEX, si->toptexture); + SYNCF(LD_S2BOTTEX, si->bottomtexture); + SYNCF(LD_S2MIDTEX, si->midtexture); + if (GETB(LD_ARGS)) + { + for (j = 0; j < NUM_SCRIPT_ARGS; j++) + SYNC(li->args[j]); + } + if (GETB(LD_STRINGARGS)) + { + if (save->write) { for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) { @@ -1834,157 +1506,58 @@ static void ArchiveLines(savebuffer_t *save) WRITECHAR(save->p, li->stringargs[j][k]); } } - if (diff3 & LD_ACTIVATION) - WRITEUINT32(save->p, li->activation); - } - } - WRITEUINT16(save->p, 0xffff); -} - -static void UnArchiveLines(savebuffer_t *save) -{ - UINT16 i, j; - line_t *li; - side_t *si; - UINT8 diff, diff2, diff3; - - for (;;) - { - i = READUINT16(save->p); - - if (i == 0xffff) - break; - if (i > numlines) - I_Error("Invalid line number %u from server", i); - - diff = READUINT8(save->p); - li = &lines[i]; - - if (diff & LD_DIFF2) - diff2 = READUINT8(save->p); - else - diff2 = 0; - - if (diff2 & LD_DIFF3) - diff3 = READUINT8(save->p); - else - diff3 = 0; - - if (diff & LD_FLAG) - li->flags = READUINT32(save->p); - if (diff & LD_SPECIAL) - li->special = READINT16(save->p); - if (diff & LD_TAG) - { - size_t ncount = READUINT32(save->p); - - // Remove entries from global lists. - for (j = 0; j < lines[i].tags.count; j++) - Taggroup_Remove(tags_lines, lines[i].tags.tags[j], i); - - // Reallocate if size differs. - if (ncount != lines[i].tags.count) + else { - lines[i].tags.count = ncount; - lines[i].tags.tags = (mtag_t*)Z_Realloc(lines[i].tags.tags, ncount*sizeof(mtag_t), PU_LEVEL, NULL); - } - - for (j = 0; j < ncount; j++) - lines[i].tags.tags[j] = READINT16(save->p); - - // Add new entries. - for (j = 0; j < lines[i].tags.count; j++) - Taggroup_Add(tags_lines, lines[i].tags.tags[j], i); - } - - si = &sides[li->sidenum[0]]; - if (diff & LD_S1TEXOFF) - si->textureoffset = READFIXED(save->p); - if (diff & LD_S1TOPTEX) - si->toptexture = READINT32(save->p); - if (diff & LD_S1BOTTEX) - si->bottomtexture = READINT32(save->p); - if (diff & LD_S1MIDTEX) - si->midtexture = READINT32(save->p); - - si = &sides[li->sidenum[1]]; - if (diff2 & LD_S2TEXOFF) - si->textureoffset = READFIXED(save->p); - if (diff2 & LD_S2TOPTEX) - si->toptexture = READINT32(save->p); - if (diff2 & LD_S2BOTTEX) - si->bottomtexture = READINT32(save->p); - if (diff2 & LD_S2MIDTEX) - si->midtexture = READINT32(save->p); - if (diff2 & LD_ARGS) - { - for (j = 0; j < NUM_SCRIPT_ARGS; j++) - li->args[j] = READINT32(save->p); - } - if (diff2 & LD_STRINGARGS) - { - for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) - { - size_t len = READINT32(save->p); - size_t k; - - if (!len) + for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) { - Z_Free(li->stringargs[j]); - li->stringargs[j] = NULL; - continue; - } + size_t len = READINT32(save->p); + size_t k; - li->stringargs[j] = Z_Realloc(li->stringargs[j], len + 1, PU_LEVEL, NULL); - for (k = 0; k < len; k++) - li->stringargs[j][k] = READCHAR(save->p); - li->stringargs[j][len] = '\0'; + if (!len) + { + Z_Free(li->stringargs[j]); + li->stringargs[j] = NULL; + continue; + } + + li->stringargs[j] = Z_Realloc(li->stringargs[j], len + 1, PU_LEVEL, NULL); + for (k = 0; k < len; k++) + li->stringargs[j][k] = READCHAR(save->p); + li->stringargs[j][len] = '\0'; + } } } - if (diff3 & LD_ACTIVATION) - li->activation = READUINT32(save->p); + SYNCF(LD_ACTIVATION, li->activation); } + + if (save->write) + WRITEUINT16(save->p, 0xffff); } -static void P_NetArchiveWorld(savebuffer_t *save) +static void P_NetSyncWorld(savebuffer_t *save) { TracyCZone(__zone, true); - // initialize colormap vars because paranoia - ClearNetColormaps(); - - WRITEUINT32(save->p, ARCHIVEBLOCK_WORLD); - - ArchiveSectors(save); - ArchiveLines(save); - R_ClearTextureNumCache(false); - - TracyCZoneEnd(__zone); -} - -static void P_NetUnArchiveWorld(savebuffer_t *save) -{ - TracyCZone(__zone, true); - - UINT16 i; - - if (READUINT32(save->p) != ARCHIVEBLOCK_WORLD) + if (P_SyncUINT32(save, ARCHIVEBLOCK_WORLD) != ARCHIVEBLOCK_WORLD) I_Error("Bad $$$.sav at archive block World"); // initialize colormap vars because paranoia ClearNetColormaps(); // count the level's ffloors so that colormap loading can have an upper limit - for (i = 0; i < numsectors; i++) - { - ffloor_t *rover; - for (rover = sectors[i].ffloors; rover; rover = rover->next) - num_ffloors++; - } + if (!save->write) + for (size_t i = 0; i < numsectors; i++) + { + ffloor_t *rover; + for (rover = sectors[i].ffloors; rover; rover = rover->next) + num_ffloors++; + } - UnArchiveSectors(save); - UnArchiveLines(save); + SyncSectors(save); + SyncLines(save); + if (save->write) + R_ClearTextureNumCache(false); TracyCZoneEnd(__zone); } @@ -2040,132 +1613,80 @@ static boolean P_ThingScriptEqual(const mobj_t *mobj, const mapthing_t *mapthing return true; } -typedef enum +enum mobj_diff_t { - MD_SPAWNPOINT = 1, - MD_POS = 1<<1, - MD_TYPE = 1<<2, - MD_MOM = 1<<3, - MD_RADIUS = 1<<4, - MD_HEIGHT = 1<<5, - MD_FLAGS = 1<<6, - MD_HEALTH = 1<<7, - MD_RTIME = 1<<8, - MD_STATE = 1<<9, - MD_TICS = 1<<10, - MD_SPRITE = 1<<11, - MD_FRAME = 1<<12, - MD_EFLAGS = 1<<13, - MD_PLAYER = 1<<14, - MD_MOVEDIR = 1<<15, - MD_MOVECOUNT = 1<<16, - MD_THRESHOLD = 1<<17, - MD_LASTLOOK = 1<<18, - MD_TARGET = 1<<19, - MD_TRACER = 1<<20, - MD_FRICTION = 1<<21, - MD_MOVEFACTOR = 1<<22, - MD_FLAGS2 = 1<<23, - MD_FUSE = 1<<24, - MD_WATERTOP = 1<<25, - MD_WATERBOTTOM = 1<<26, - MD_SCALE = 1<<27, - MD_DSCALE = 1<<28, - MD_ARGS = 1<<29, - MD_STRINGARGS = 1<<30, - MD_MORE = (INT32)(1U<<31) -} mobj_diff_t; + MD_SPAWNPOINT = 0<<5, + MD_POS, + MD_TYPE, + MD_MOM, + MD_RADIUS, + MD_HEIGHT, + MD_FLAGS, + MD_HEALTH, + MD_RTIME, + MD_STATE, + MD_TICS, + MD_SPRITE, + MD_FRAME, + MD_EFLAGS, + MD_PLAYER, + MD_MOVEDIR, + MD_MOVECOUNT, + MD_THRESHOLD, + MD_LASTLOOK, + MD_TARGET, + MD_TRACER, + MD_FRICTION, + MD_MOVEFACTOR, + MD_FLAGS2, + MD_FUSE, + MD_WATERTOP, + MD_WATERBOTTOM, + MD_SCALE, + MD_DSCALE, + MD_ARGS, + MD_STRINGARGS, -typedef enum -{ - MD2_CUSVAL = 1, - MD2_CVMEM = 1<<1, - MD2_SKIN = 1<<2, - MD2_COLOR = 1<<3, - MD2_SCALESPEED = 1<<4, - MD2_EXTVAL1 = 1<<5, - MD2_EXTVAL2 = 1<<6, - MD2_HNEXT = 1<<7, - MD2_HPREV = 1<<8, - MD2_FLOORROVER = 1<<9, - MD2_CEILINGROVER = 1<<10, - MD2_SLOPE = 1<<11, - MD2_COLORIZED = 1<<12, - MD2_MIRRORED = 1<<13, - MD2_ROLLANGLE = 1<<14, - MD2_SHADOWSCALE = 1<<15, - MD2_RENDERFLAGS = 1<<16, - MD2_TID = 1<<17, - MD2_SPRITESCALE = 1<<18, - MD2_SPRITEOFFSET = 1<<19, - MD2_WORLDOFFSET = 1<<20, - MD2_SPECIAL = 1<<21, - MD2_FLOORSPRITESLOPE = 1<<22, - MD2_DISPOFFSET = 1<<23, - MD2_BOSS3CAP = 1<<24, - MD2_WAYPOINTCAP = 1<<25, - MD2_KITEMCAP = 1<<26, - MD2_ITNEXT = 1<<27, - MD2_LASTMOMZ = 1<<28, - MD2_TERRAIN = 1<<29, - MD2_LIGHTLEVEL = 1<<30, - MD2_MORE = (INT32)(1U<<31) -} mobj_diff2_t; + MD2_CUSVAL = 1<<5, + MD2_CVMEM, + MD2_SKIN, + MD2_COLOR, + MD2_SCALESPEED, + MD2_EXTVAL1, + MD2_EXTVAL2, + MD2_HNEXT, + MD2_HPREV, + MD2_FLOORROVER, + MD2_CEILINGROVER, + MD2_SLOPE, + MD2_COLORIZED, + MD2_MIRRORED, + MD2_ROLLANGLE, + MD2_SHADOWSCALE, + MD2_RENDERFLAGS, + MD2_TID, + MD2_SPRITESCALE, + MD2_SPRITEOFFSET, + MD2_WORLDOFFSET, + MD2_SPECIAL, + MD2_FLOORSPRITESLOPE, + MD2_DISPOFFSET, + MD2_BOSS3CAP, + MD2_WAYPOINTCAP, + MD2_KITEMCAP, + MD2_ITNEXT, + MD2_LASTMOMZ, + MD2_TERRAIN, + MD2_LIGHTLEVEL, -typedef enum -{ - MD3_GRAVITY = 1, - MD3_MISCCAP = 1<<1, - MD3_BAKEDOFFSET = 1<<2, - MD3_EXTVAL3 = 1<<3, - MD3_SHIELDTRACER = 1<<4, -} mobj_diff3_t; + MD3_GRAVITY = 2<<5, + MD3_MISCCAP, + MD3_BAKEDOFFSET, + MD3_EXTVAL3, + MD3_SHIELDTRACER, -typedef enum -{ - tc_mobj, - tc_ceiling, - tc_floor, - tc_flash, - tc_strobe, - tc_glow, - tc_fireflicker, - tc_thwomp, - tc_camerascanner, - tc_elevator, - tc_continuousfalling, - tc_bouncecheese, - tc_startcrumble, - tc_marioblock, - tc_marioblockchecker, - tc_floatsector, - tc_crushceiling, - tc_scroll, - tc_friction, - tc_pusher, - tc_laserflash, - tc_lightfade, - tc_executor, - tc_raisesector, - tc_noenemies, - tc_eachtime, - tc_disappear, - tc_fade, - tc_fadecolormap, - tc_planedisplace, - tc_dynslopeline, - tc_dynslopevert, - tc_polyrotate, // haleyjd 03/26/06: polyobjects - tc_polymove, - tc_polywaypoint, - tc_polyslidedoor, - tc_polyswingdoor, - tc_polyflag, - tc_polydisplace, - tc_polyrotdisplace, - tc_polyfade, - tc_end -} specials_e; + MD__MAX +}; static inline UINT32 SaveMobjnum(const mobj_t *mobj) { @@ -2173,16 +1694,70 @@ static inline UINT32 SaveMobjnum(const mobj_t *mobj) return 0; } -static UINT32 SaveSector(const sector_t *sector) +static mobj_t *SyncMobj(savebuffer_t *save, mobj_t *mobj) { - if (sector) return (UINT32)(sector - sectors); - return 0xFFFFFFFF; + if (save->write) + { + if (mobj) WRITEUINT32(save->p, mobj->mobjnum); + else WRITEUINT32(save->p, 0); + return mobj; + } + else + { + UINT32 mobjnum = READUINT32(save->p); + if (mobjnum == 0) return NULL; + return (mobj_t *)(size_t)mobjnum; + } } -static UINT32 SaveLine(const line_t *line) +static sector_t *LoadSector(UINT32 sector) { - if (line) return (UINT32)(line - lines); - return 0xFFFFFFFF; + if (sector >= numsectors) return NULL; + return §ors[sector]; +} + +static UINT32 SaveSector(sector_t *sector) +{ + if (sector) return (UINT32)(sector - sectors); + else return 0xFFFFFFFF; +} + +static sector_t *SyncSector(savebuffer_t *save, sector_t *sector) +{ + if (save->write) + { + if (sector) WRITEUINT32(save->p, (UINT32)(sector - sectors)); + else WRITEUINT32(save->p, 0xFFFFFFFF); + return sector; + } + else + { + UINT32 sectornum = READUINT32(save->p); + if (sectornum >= numsectors) return NULL; + return §ors[sectornum]; + } +} + +static line_t *SyncLine(savebuffer_t *save, line_t *line) +{ + if (save->write) + { + if (line) WRITEUINT32(save->p, (UINT32)(line - lines)); + else WRITEUINT32(save->p, 0xFFFFFFFF); + return line; + } + else + { + UINT32 linenum = READUINT32(save->p); + if (linenum >= numlines) return NULL; + return &lines[linenum]; + } +} + +static inline player_t *LoadPlayer(UINT32 player) +{ + if (player >= MAXPLAYERS) return NULL; + return &players[player]; } static inline UINT32 SavePlayer(const player_t *player) @@ -2191,76 +1766,75 @@ static inline UINT32 SavePlayer(const player_t *player) return 0xFFFFFFFF; } -static UINT32 SaveSlope(const pslope_t *slope) +static pslope_t *SyncSlope(savebuffer_t *save, pslope_t *slope) { - if (slope) return (UINT32)(slope->id); - return 0xFFFFFFFF; + if (save->write) + { + if (slope) WRITEUINT32(save->p, (UINT32)(slope->id)); + else WRITEUINT32(save->p, 0xFFFFFFFF); + return slope; + } + else + { + UINT32 slopeid = READUINT32(save->p); + pslope_t *p = slopelist; + if (slopeid > slopecount) return NULL; + do + { + if (p->id == slopeid) + return p; + } while ((p = p->next)); + return NULL; + } } -static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static mobjtype_t g_doomednum_to_mobjtype[UINT16_MAX]; + +static void CalculateDoomednumToMobjtype(void) { - const mobj_t *mobj = (const mobj_t *)th; - UINT32 diff; - UINT32 diff2; - UINT32 diff3; - size_t j; + memset(g_doomednum_to_mobjtype, MT_NULL, sizeof(g_doomednum_to_mobjtype)); - // Ignore stationary hoops - these will be respawned from mapthings. - if (mobj->type == MT_HOOP) - return; + for (size_t i = MT_NULL+1; i < NUMMOBJTYPES; i++) + { + if (mobjinfo[i].doomednum > 0 && mobjinfo[i].doomednum <= UINT16_MAX) + { + g_doomednum_to_mobjtype[ mobjinfo[i].doomednum ] = i; + } + } +} - // These are NEVER saved. - if (mobj->type == MT_HOOPCOLLIDE) - return; - - // This hoop has already been collected. - if (mobj->type == MT_HOOPCENTER && mobj->threshold == 4242) - return; - - // MT_SPARK: used for debug stuff - if (mobj->type == MT_SPARK) - return; - - // This is a non-synched visual effect mobj - if (mobj->flags2 & MF2_DONTSYNC) - return; - - diff = diff2 = diff3 = 0; - - if (mobj->spawnpoint) +static void DiffMobj(const mobj_t *mobj, UINT32 diff[]) +{ + if (mobj->spawnpoint && mobj->info->doomednum != -1) { // spawnpoint is not modified but we must save it since it is an identifier - diff = MD_SPAWNPOINT; + SETB(MD_SPAWNPOINT); if ((mobj->x != mobj->spawnpoint->x << FRACBITS) || (mobj->y != mobj->spawnpoint->y << FRACBITS) || (mobj->angle != FixedAngle(mobj->spawnpoint->angle*FRACUNIT)) || (mobj->pitch != FixedAngle(mobj->spawnpoint->pitch*FRACUNIT)) || (mobj->roll != FixedAngle(mobj->spawnpoint->roll*FRACUNIT)) ) - diff |= MD_POS; + SETB(MD_POS); - if (mobj->info->doomednum != mobj->spawnpoint->type) - diff |= MD_TYPE; - - if (!P_ThingArgsEqual(mobj, mobj->spawnpoint)) - diff |= MD_ARGS; - - if (!P_ThingStringArgsEqual(mobj, mobj->spawnpoint)) - diff |= MD_STRINGARGS; - - if (!P_ThingScriptEqual(mobj, mobj->spawnpoint)) - diff2 |= MD2_SPECIAL; + DIFF(mobj->info->doomednum != mobj->spawnpoint->type, MD_TYPE); + DIFF(!P_ThingArgsEqual(mobj, mobj->spawnpoint), MD_ARGS); + DIFF(!P_ThingStringArgsEqual(mobj, mobj->spawnpoint), MD_STRINGARGS); + DIFF(!P_ThingScriptEqual(mobj, mobj->spawnpoint), MD2_SPECIAL); } else { + size_t j; + // not a map spawned thing, so make it from scratch - diff = MD_POS | MD_TYPE; + SETB(MD_POS); + SETB(MD_TYPE); for (j = 0; j < NUM_MAPTHING_ARGS; j++) { if (mobj->args[j] != 0) { - diff |= MD_ARGS; + SETB(MD_ARGS); break; } } @@ -2269,21 +1843,19 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 { if (mobj->stringargs[j] != NULL) { - diff |= MD_STRINGARGS; + SETB(MD_STRINGARGS); break; } } if (mobj->special != 0) - { - diff2 |= MD2_SPECIAL; - } + SETB(MD2_SPECIAL); for (j = 0; j < NUM_SCRIPT_ARGS; j++) { if (mobj->script_args[j] != 0) { - diff2 |= MD2_SPECIAL; + SETB(MD2_SPECIAL); break; } } @@ -2292,1222 +1864,1662 @@ static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 { if (mobj->stringargs[j] != NULL) { - diff2 |= MD2_SPECIAL; + SETB(MD2_SPECIAL); break; } } } // not the default but the most probable - if (mobj->momx != 0 || mobj->momy != 0 || mobj->momz != 0 || mobj->pmomz != 0) - diff |= MD_MOM; - if (mobj->radius != FixedMul(mapobjectscale, mobj->info->radius)) - diff |= MD_RADIUS; - if (mobj->height != FixedMul(mapobjectscale, mobj->info->height)) - diff |= MD_HEIGHT; - if (mobj->flags != mobj->info->flags) - diff |= MD_FLAGS; - if (mobj->flags2) - diff |= MD_FLAGS2; - if (mobj->health != mobj->info->spawnhealth) - diff |= MD_HEALTH; - if (mobj->reactiontime != mobj->info->reactiontime) - diff |= MD_RTIME; - if ((statenum_t)(mobj->state-states) != mobj->info->spawnstate) - diff |= MD_STATE; - if (mobj->tics != mobj->state->tics) - diff |= MD_TICS; - if (mobj->sprite != mobj->state->sprite) - diff |= MD_SPRITE; - if (mobj->sprite == SPR_PLAY && mobj->sprite2 != (mobj->state->frame&FF_FRAMEMASK)) - diff |= MD_SPRITE; - if (mobj->frame != mobj->state->frame) - diff |= MD_FRAME; - if (mobj->anim_duration != (UINT16)mobj->state->var2) - diff |= MD_FRAME; - if (mobj->eflags) - diff |= MD_EFLAGS; - if (mobj->player) - diff |= MD_PLAYER; + DIFF(mobj->momx != 0 || mobj->momy != 0 || mobj->momz != 0 || mobj->pmomz != 0, MD_MOM); + DIFF(mobj->radius != FixedMul(mapobjectscale, mobj->info->radius), MD_RADIUS); + DIFF(mobj->height != FixedMul(mapobjectscale, mobj->info->height), MD_HEIGHT); + DIFF(mobj->flags != mobj->info->flags, MD_FLAGS); + DIFF(mobj->flags2, MD_FLAGS2); + DIFF(mobj->health != mobj->info->spawnhealth, MD_HEALTH); + DIFF(mobj->reactiontime != mobj->info->reactiontime, MD_RTIME); + DIFF((statenum_t)(mobj->state-states) != mobj->info->spawnstate, MD_STATE); + DIFF(mobj->tics != mobj->state->tics, MD_TICS); + DIFF(mobj->sprite != mobj->state->sprite, MD_SPRITE); + DIFF(mobj->sprite == SPR_PLAY && mobj->sprite2 != (mobj->state->frame&FF_FRAMEMASK), MD_SPRITE); + DIFF(mobj->frame != mobj->state->frame, MD_FRAME); + DIFF(mobj->anim_duration != (UINT16)mobj->state->var2, MD_FRAME); + DIFF(mobj->eflags, MD_EFLAGS); + DIFF(mobj->player, MD_PLAYER); - if (mobj->movedir) - diff |= MD_MOVEDIR; - if (mobj->movecount) - diff |= MD_MOVECOUNT; - if (mobj->threshold) - diff |= MD_THRESHOLD; - if (mobj->lastlook != -1) - diff |= MD_LASTLOOK; - if (mobj->target) - diff |= MD_TARGET; - if (mobj->tracer) - diff |= MD_TRACER; - if (mobj->friction != ORIG_FRICTION) - diff |= MD_FRICTION; - if (mobj->movefactor != FRACUNIT) - diff |= MD_MOVEFACTOR; - if (mobj->fuse) - diff |= MD_FUSE; - if (mobj->watertop != INT32_MAX) - diff |= MD_WATERTOP; - if (mobj->waterbottom) - diff |= MD_WATERBOTTOM; - if (mobj->scale != mapobjectscale) - diff |= MD_SCALE; - if (mobj->destscale != mobj->scale) - diff |= MD_DSCALE; - if (mobj->scalespeed != mapobjectscale/12) - diff2 |= MD2_SCALESPEED; + DIFF(mobj->movedir, MD_MOVEDIR); + DIFF(mobj->movecount, MD_MOVECOUNT); + DIFF(mobj->threshold, MD_THRESHOLD); + DIFF(mobj->lastlook != -1, MD_LASTLOOK); + DIFF(mobj->target, MD_TARGET); + DIFF(mobj->tracer, MD_TRACER); + DIFF(mobj->friction != ORIG_FRICTION, MD_FRICTION); + DIFF(mobj->movefactor != FRACUNIT, MD_MOVEFACTOR); + DIFF(mobj->fuse, MD_FUSE); + DIFF(mobj->watertop != INT32_MAX, MD_WATERTOP); + DIFF(mobj->waterbottom, MD_WATERBOTTOM); + DIFF(mobj->scale != mapobjectscale, MD_SCALE); + DIFF(mobj->destscale != mobj->scale, MD_DSCALE); + DIFF(mobj->scalespeed != mapobjectscale/12, MD2_SCALESPEED); - if (mobj->cusval) - diff2 |= MD2_CUSVAL; - if (mobj->cvmem) - diff2 |= MD2_CVMEM; - if (mobj->color) - diff2 |= MD2_COLOR; - if (mobj->skin) - diff2 |= MD2_SKIN; - if (mobj->extravalue1) - diff2 |= MD2_EXTVAL1; - if (mobj->extravalue2) - diff2 |= MD2_EXTVAL2; - if (mobj->hnext) - diff2 |= MD2_HNEXT; - if (mobj->hprev) - diff2 |= MD2_HPREV; - if (mobj->standingslope) - diff2 |= MD2_SLOPE; - if (mobj->colorized) - diff2 |= MD2_COLORIZED; - if (mobj->floorrover) - diff2 |= MD2_FLOORROVER; - if (mobj->ceilingrover) - diff2 |= MD2_CEILINGROVER; - if (mobj->mirrored) - diff2 |= MD2_MIRRORED; - if (mobj->rollangle) - diff2 |= MD2_ROLLANGLE; - if (mobj->shadowscale) - diff2 |= MD2_SHADOWSCALE; - if (mobj->renderflags) - diff2 |= MD2_RENDERFLAGS; - if (mobj->tid != 0) - diff2 |= MD2_TID; - if (mobj->spritexscale != FRACUNIT || mobj->spriteyscale != FRACUNIT) - diff2 |= MD2_SPRITESCALE; - if (mobj->spritexoffset || mobj->spriteyoffset || - mobj->rollingxoffset || mobj->rollingyoffset) - diff2 |= MD2_SPRITEOFFSET; - if (mobj->sprxoff || mobj->spryoff || mobj->sprzoff) - diff2 |= MD2_WORLDOFFSET; + DIFF(mobj->cusval, MD2_CUSVAL); + DIFF(mobj->cvmem, MD2_CVMEM); + DIFF(mobj->color, MD2_COLOR); + DIFF(mobj->skin, MD2_SKIN); + DIFF(mobj->extravalue1, MD2_EXTVAL1); + DIFF(mobj->extravalue2, MD2_EXTVAL2); + DIFF(mobj->hnext, MD2_HNEXT); + DIFF(mobj->hprev, MD2_HPREV); + DIFF(mobj->standingslope, MD2_SLOPE); + DIFF(mobj->colorized, MD2_COLORIZED); + DIFF(mobj->floorrover, MD2_FLOORROVER); + DIFF(mobj->ceilingrover, MD2_CEILINGROVER); + DIFF(mobj->mirrored, MD2_MIRRORED); + DIFF(mobj->rollangle, MD2_ROLLANGLE); + DIFF(mobj->shadowscale, MD2_SHADOWSCALE); + DIFF(mobj->renderflags, MD2_RENDERFLAGS); + DIFF(mobj->tid != 0, MD2_TID); + DIFF(mobj->spritexscale != FRACUNIT || mobj->spriteyscale != FRACUNIT, MD2_SPRITESCALE); + DIFF(mobj->spritexoffset || mobj->spriteyoffset || mobj->rollingxoffset || mobj->rollingyoffset, MD2_SPRITEOFFSET); + DIFF(mobj->sprxoff || mobj->spryoff || mobj->sprzoff, MD2_WORLDOFFSET); if (mobj->floorspriteslope) { pslope_t *slope = mobj->floorspriteslope; - if (slope->zangle || slope->zdelta || slope->xydirection + DIFF(slope->zangle || slope->zdelta || slope->xydirection || slope->o.x || slope->o.y || slope->o.z || slope->d.x || slope->d.y || slope->normal.x || slope->normal.y - || (slope->normal.z != FRACUNIT)) - diff2 |= MD2_FLOORSPRITESLOPE; + || (slope->normal.z != FRACUNIT), + MD2_FLOORSPRITESLOPE); } - if (mobj->lightlevel) - diff2 |= MD2_LIGHTLEVEL; - if (mobj->dispoffset) - diff2 |= MD2_DISPOFFSET; - if (mobj == boss3cap) - diff2 |= MD2_BOSS3CAP; - if (mobj == waypointcap) - diff2 |= MD2_WAYPOINTCAP; - if (mobj == kitemcap) - diff2 |= MD2_KITEMCAP; - if (mobj->itnext) - diff2 |= MD2_ITNEXT; - if (mobj->lastmomz) - diff2 |= MD2_LASTMOMZ; - if (mobj->terrain != NULL || mobj->terrainOverlay != NULL) - diff2 |= MD2_TERRAIN; + DIFF(mobj->lightlevel, MD2_LIGHTLEVEL); + DIFF(mobj->dispoffset, MD2_DISPOFFSET); + DIFF(mobj == boss3cap, MD2_BOSS3CAP); + DIFF(mobj == waypointcap, MD2_WAYPOINTCAP); + DIFF(mobj == kitemcap, MD2_KITEMCAP); + DIFF(mobj->itnext, MD2_ITNEXT); + DIFF(mobj->lastmomz, MD2_LASTMOMZ); + DIFF(mobj->terrain != NULL || mobj->terrainOverlay != NULL, MD2_TERRAIN); - if (mobj->gravity != FRACUNIT) - diff3 |= MD3_GRAVITY; - if (mobj == misccap) - diff3 |= MD3_MISCCAP; - if (mobj->bakexoff || mobj->bakeyoff || mobj->bakezoff || mobj->bakexpiv || - mobj->bakeypiv || mobj->bakezpiv) - diff3 |= MD3_BAKEDOFFSET; - if (mobj->extravalue3) - diff3 |= MD3_EXTVAL3; - if (mobj->shieldtracer) - diff3 |= MD3_SHIELDTRACER; + DIFF(mobj->gravity != FRACUNIT, MD3_GRAVITY); + DIFF(mobj == misccap, MD3_MISCCAP); + DIFF(mobj->bakexoff || mobj->bakeyoff || mobj->bakezoff || mobj->bakexpiv || mobj->bakeypiv || mobj->bakezpiv, MD3_BAKEDOFFSET); + DIFF(mobj->extravalue3, MD3_EXTVAL3); + DIFF(mobj->shieldtracer, MD3_SHIELDTRACER); +} - if (diff3 != 0) - diff2 |= MD2_MORE; +static thinker_t *SyncMobjThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) +{ + mobj_t *mobj = (mobj_t *)th; + UINT32 diff[(MD__MAX>>5)+1] = {0}; + size_t j; - if (diff2 != 0) - diff |= MD_MORE; - - // Scrap all of that. If we're a hoop center, this is ALL we're saving. - if (mobj->type == MT_HOOPCENTER) - diff = MD_SPAWNPOINT; - - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, diff); - if (diff & MD_MORE) - WRITEUINT32(save->p, diff2); - if (diff2 & MD2_MORE) - WRITEUINT32(save->p, diff3); - - WRITEFIXED(save->p, mobj->z); // Force this so 3dfloor problems don't arise. - WRITEFIXED(save->p, mobj->floorz); - WRITEFIXED(save->p, mobj->ceilingz); - - if (diff2 & MD2_FLOORROVER) + if (save->write) { - WRITEUINT32(save->p, SaveSector(mobj->floorrover->target)); - WRITEUINT16(save->p, P_GetFFloorID(mobj->floorrover)); - } + // Ignore stationary hoops - these will be respawned from mapthings. + if (mobj->type == MT_HOOP) + return th; - if (diff2 & MD2_CEILINGROVER) - { - WRITEUINT32(save->p, SaveSector(mobj->ceilingrover->target)); - WRITEUINT16(save->p, P_GetFFloorID(mobj->ceilingrover)); - } + // These are NEVER saved. + if (mobj->type == MT_HOOPCOLLIDE) + return th; - if (diff & MD_SPAWNPOINT) - { - size_t z; + // This hoop has already been collected. + if (mobj->type == MT_HOOPCENTER && mobj->threshold == 4242) + return th; - for (z = 0; z < nummapthings; z++) - { - if (&mapthings[z] != mobj->spawnpoint) - continue; - WRITEUINT16(save->p, z); - break; - } + // MT_SPARK: used for debug stuff + if (mobj->type == MT_SPARK) + return th; + + // This is a non-synched visual effect mobj + if (mobj->flags2 & MF2_DONTSYNC) + return th; + + // Scrap all of that. If we're a hoop center, this is ALL we're saving. if (mobj->type == MT_HOOPCENTER) - return; + SETB(MD_SPAWNPOINT); + else + DiffMobj(mobj, diff); + + for (j = sizeof(diff)/sizeof(*diff)-1; j > 0; j--) + if (diff[j]) + diff[j-1] |= 0x80000000; + + // already read by the client + WRITEUINT8(save->p, type); } - if (diff & MD_TYPE) - WRITEUINT32(save->p, mobj->type); - if (diff & MD_POS) + j = 0; + do + SYNC(diff[j]); + while (diff[j++] & 0x80000000); + + if (GETB(MD_SPAWNPOINT)) { - WRITEFIXED(save->p, mobj->x); - WRITEFIXED(save->p, mobj->y); - WRITEANGLE(save->p, mobj->angle); - WRITEANGLE(save->p, mobj->pitch); - WRITEANGLE(save->p, mobj->roll); + if (save->write) + { + size_t z; + + for (z = 0; z < nummapthings; z++) + { + if (&mapthings[z] != mobj->spawnpoint) + continue; + WRITEUINT16(save->p, z); + break; + } + if (mobj->type == MT_HOOPCENTER) + return th; + } + else + { + UINT16 spawnpointnum = READUINT16(save->p); + + if (mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case + { + P_SpawnHoop(&mapthings[spawnpointnum]); + return NULL; + } + + mobj = P_AllocateMobj(); + + mobj->spawnpoint = &mapthings[spawnpointnum]; + mapthings[spawnpointnum].mobj = mobj; + } } - if (diff & MD_MOM) + else if (!save->write) + mobj = P_AllocateMobj(); + + // declare this as a valid mobj as soon as possible. + mobj->thinker.function.acp1 = thinker; + + // manually link to thinkerlist, since the thinker isn't returned anymore + if (!save->write) + P_AddThinker(THINK_MOBJ, &mobj->thinker); + + SYNC(mobj->z); // Force this so 3dfloor problems don't arise. + SYNC(mobj->floorz); + SYNC(mobj->ceilingz); + + if (GETB(MD2_FLOORROVER)) { - WRITEFIXED(save->p, mobj->momx); - WRITEFIXED(save->p, mobj->momy); - WRITEFIXED(save->p, mobj->momz); - WRITEFIXED(save->p, mobj->pmomz); + if (save->write) + { + WRITEUINT32(save->p, SaveSector(mobj->floorrover->target)); + WRITEUINT16(save->p, P_GetFFloorID(mobj->floorrover)); + } + else + { + sector_t *sec = LoadSector(READUINT32(save->p)); + UINT16 id = READUINT16(save->p); + mobj->floorrover = P_GetFFloorByID(sec, id); + } } - if (diff & MD_RADIUS) - WRITEFIXED(save->p, mobj->radius); - if (diff & MD_HEIGHT) - WRITEFIXED(save->p, mobj->height); - if (diff & MD_FLAGS) - WRITEUINT32(save->p, mobj->flags); - if (diff & MD_FLAGS2) - WRITEUINT32(save->p, mobj->flags2); - if (diff & MD_HEALTH) - WRITEINT32(save->p, mobj->health); - if (diff & MD_RTIME) - WRITEINT32(save->p, mobj->reactiontime); - if (diff & MD_STATE) - WRITEUINT16(save->p, mobj->state-states); - if (diff & MD_TICS) - WRITEINT32(save->p, mobj->tics); - if (diff & MD_SPRITE) { - WRITEUINT16(save->p, mobj->sprite); - if (mobj->sprite == SPR_PLAY) - WRITEUINT8(save->p, mobj->sprite2); - } - if (diff & MD_FRAME) + + if (GETB(MD2_CEILINGROVER)) { - WRITEUINT32(save->p, mobj->frame); - WRITEUINT16(save->p, mobj->anim_duration); + if (save->write) + { + WRITEUINT32(save->p, SaveSector(mobj->ceilingrover->target)); + WRITEUINT16(save->p, P_GetFFloorID(mobj->ceilingrover)); + } + else + { + sector_t *sec = LoadSector(READUINT32(save->p)); + UINT16 id = READUINT16(save->p); + mobj->ceilingrover = P_GetFFloorByID(sec, id); + } } - if (diff & MD_EFLAGS) - WRITEUINT16(save->p, mobj->eflags); - if (diff & MD_PLAYER) - WRITEUINT8(save->p, mobj->player-players); - if (diff & MD_MOVEDIR) - WRITEANGLE(save->p, mobj->movedir); - if (diff & MD_MOVECOUNT) - WRITEINT32(save->p, mobj->movecount); - if (diff & MD_THRESHOLD) - WRITEINT32(save->p, mobj->threshold); - if (diff & MD_LASTLOOK) - WRITEINT32(save->p, mobj->lastlook); - if (diff & MD_TARGET) - WRITEUINT32(save->p, mobj->target->mobjnum); - if (diff & MD_TRACER) - WRITEUINT32(save->p, mobj->tracer->mobjnum); - if (diff & MD_FRICTION) - WRITEFIXED(save->p, mobj->friction); - if (diff & MD_MOVEFACTOR) - WRITEFIXED(save->p, mobj->movefactor); - if (diff & MD_FUSE) - WRITEINT32(save->p, mobj->fuse); - if (diff & MD_WATERTOP) - WRITEFIXED(save->p, mobj->watertop); - if (diff & MD_WATERBOTTOM) - WRITEFIXED(save->p, mobj->waterbottom); - if (diff & MD_SCALE) - WRITEFIXED(save->p, mobj->scale); - if (diff & MD_DSCALE) - WRITEFIXED(save->p, mobj->destscale); - if (diff2 & MD2_SCALESPEED) - WRITEFIXED(save->p, mobj->scalespeed); - if (diff & MD_ARGS) + + if (GETB(MD_TYPE)) + { + SYNC(mobj->type); + } + else if (!save->write) + { + mobjtype_t new_type = MT_NULL; + if (mobj->spawnpoint) + { + new_type = g_doomednum_to_mobjtype[mobj->spawnpoint->type]; + } + + if (new_type <= MT_NULL || new_type >= NUMMOBJTYPES) + { + if (mobj->spawnpoint) + CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing doomednum %d\n", mobj->spawnpoint->type); + else + CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing doomednum NULL\n"); + + I_Error("Netsave corrupted"); + } + + mobj->type = new_type; + } + mobj->info = &mobjinfo[mobj->type]; + if (GETB(MD_POS)) + { + SYNC(mobj->x); + SYNC(mobj->y); + SYNC(mobj->angle); + SYNC(mobj->pitch); + SYNC(mobj->roll); + } + else + { + mobj->x = mobj->old_x = mobj->spawnpoint->x << FRACBITS; + mobj->y = mobj->old_y = mobj->spawnpoint->y << FRACBITS; + mobj->angle = mobj->old_angle = FixedAngle(mobj->spawnpoint->angle*FRACUNIT); + mobj->pitch = mobj->old_pitch = FixedAngle(mobj->spawnpoint->pitch*FRACUNIT); + mobj->roll = mobj->old_roll = FixedAngle(mobj->spawnpoint->roll*FRACUNIT); + } + + SYNCF(MD_MOM, mobj->momx); + SYNCF(MD_MOM, mobj->momy); + SYNCF(MD_MOM, mobj->momz); + SYNCF(MD_MOM, mobj->pmomz); + + SYNCDEF(MD_RADIUS, mobj->radius, mobj->info->radius); + SYNCDEF(MD_HEIGHT, mobj->height, mobj->info->height); + SYNCDEF(MD_FLAGS, mobj->flags, mobj->info->flags); + SYNCF(MD_FLAGS2, mobj->flags2); + SYNCDEF(MD_HEALTH, mobj->health, mobj->info->spawnhealth); + SYNCDEF(MD_RTIME, mobj->reactiontime, mobj->info->reactiontime); + if (GETB(MD_STATE)) + { + if (save->write) + WRITEUINT16(save->p, mobj->state-states); + else + mobj->state = &states[READUINT16(save->p)]; + } + else + mobj->state = &states[mobj->info->spawnstate]; + SYNCF(MD_TICS, mobj->tics); + SYNCDEF(MD_SPRITE, mobj->sprite, mobj->state->sprite); + if (mobj->sprite == SPR_PLAY) + SYNCDEF(MD_SPRITE, mobj->sprite2, mobj->state->frame & FF_FRAMEMASK); + SYNCDEF(MD_FRAME, mobj->frame, mobj->state->frame); + SYNCDEF(MD_FRAME, mobj->anim_duration, (UINT16)mobj->state->var2); + SYNCF(MD_EFLAGS, mobj->eflags); + if (GETB(MD_PLAYER)) + { + UINT8 i; + i = P_SyncUINT8(save, mobj->player-players); + mobj->player = &players[i]; + mobj->player->mo = mobj; + } + SYNCF(MD_MOVEDIR, mobj->movedir); + SYNCF(MD_MOVECOUNT, mobj->movecount); + SYNCF(MD_THRESHOLD, mobj->threshold); + SYNCDEF(MD_LASTLOOK, mobj->lastlook, -1); + SYNCF(MD_TARGET, mobj->target); + SYNCF(MD_TRACER, mobj->tracer); + SYNCDEF(MD_FRICTION, mobj->friction, ORIG_FRICTION); + SYNCDEF(MD_MOVEFACTOR, mobj->movefactor, FRACUNIT); + SYNCF(MD_FUSE, mobj->fuse); + SYNCF(MD_WATERTOP, mobj->watertop); + SYNCF(MD_WATERBOTTOM, mobj->waterbottom); + SYNCDEF(MD_SCALE, mobj->scale, FRACUNIT); + SYNCDEF(MD_DSCALE, mobj->destscale, mobj->scale); + SYNCDEF(MD2_SCALESPEED, mobj->scalespeed, FRACUNIT/12); + if (GETB(MD_ARGS)) { for (j = 0; j < NUM_MAPTHING_ARGS; j++) - WRITEINT32(save->p, mobj->args[j]); + SYNC(mobj->args[j]); } - if (diff & MD_STRINGARGS) + if (GETB(MD_STRINGARGS)) { for (j = 0; j < NUM_MAPTHING_STRINGARGS; j++) { - size_t len, k; - - if (!mobj->stringargs[j]) + size_t len = P_SyncINT32(save, mobj->stringargs[j] ? strlen(mobj->stringargs[j]) : 0); + if (!len) { - WRITEINT32(save->p, 0); + if (!save->write) + { + Z_Free(mobj->stringargs[j]); + mobj->stringargs[j] = NULL; + } continue; } - len = strlen(mobj->stringargs[j]); - WRITEINT32(save->p, len); - for (k = 0; k < len; k++) - WRITECHAR(save->p, mobj->stringargs[j][k]); + if (!save->write) + mobj->stringargs[j] = Z_Realloc(mobj->stringargs[j], len + 1, PU_LEVEL, NULL); + P_SyncMem(save, mobj->stringargs[j], len); + mobj->stringargs[j][len] = '\0'; } } - if (diff2 & MD2_CUSVAL) - WRITEINT32(save->p, mobj->cusval); - if (diff2 & MD2_CVMEM) - WRITEINT32(save->p, mobj->cvmem); - if (diff2 & MD2_SKIN) - WRITEUINT16(save->p, (UINT16)((skin_t *)mobj->skin - skins)); - if (diff2 & MD2_COLOR) - WRITEUINT16(save->p, mobj->color); - if (diff2 & MD2_EXTVAL1) - WRITEINT32(save->p, mobj->extravalue1); - if (diff2 & MD2_EXTVAL2) - WRITEINT32(save->p, mobj->extravalue2); - if (diff2 & MD2_HNEXT) - WRITEUINT32(save->p, mobj->hnext->mobjnum); - if (diff2 & MD2_HPREV) - WRITEUINT32(save->p, mobj->hprev->mobjnum); - if (diff2 & MD2_ITNEXT) - WRITEUINT32(save->p, mobj->itnext->mobjnum); - if (diff2 & MD2_SLOPE) - WRITEUINT16(save->p, mobj->standingslope->id); - if (diff2 & MD2_COLORIZED) - WRITEUINT8(save->p, mobj->colorized); - if (diff2 & MD2_MIRRORED) - WRITEUINT8(save->p, mobj->mirrored); - if (diff2 & MD2_ROLLANGLE) - WRITEANGLE(save->p, mobj->rollangle); - if (diff2 & MD2_SHADOWSCALE) - { - WRITEFIXED(save->p, mobj->shadowscale); - WRITEUINT8(save->p, mobj->whiteshadow); - WRITEUINT8(save->p, mobj->shadowcolor); - } - if (diff2 & MD2_RENDERFLAGS) - { - UINT32 rf = mobj->renderflags; - UINT32 q = rf & RF_DONTDRAW; - if (q != RF_DONTDRAW // visible for more than one local player - && q != (RF_DONTDRAWP1|RF_DONTDRAWP2|RF_DONTDRAWP3) - && q != (RF_DONTDRAWP4|RF_DONTDRAWP1|RF_DONTDRAWP2) - && q != (RF_DONTDRAWP4|RF_DONTDRAWP1|RF_DONTDRAWP3) - && q != (RF_DONTDRAWP4|RF_DONTDRAWP2|RF_DONTDRAWP3)) - rf &= ~q; + SYNCF(MD2_CUSVAL, mobj->cusval); + SYNCF(MD2_CVMEM, mobj->cvmem); + if (GETB(MD2_SKIN)) + { + if (save->write) + WRITEUINT16(save->p, (UINT16)((skin_t *)mobj->skin - skins)); + else + mobj->skin = &skins[READUINT16(save->p)]; + } + SYNCF(MD2_COLOR, mobj->color); + SYNCF(MD2_EXTVAL1, mobj->extravalue1); + SYNCF(MD2_EXTVAL2, mobj->extravalue2); + SYNCF(MD2_HNEXT, mobj->hnext); + SYNCF(MD2_HPREV, mobj->hprev); + SYNCF(MD2_ITNEXT, mobj->itnext); + if (GETB(MD2_SLOPE)) + { + if (save->write) + WRITEUINT16(save->p, mobj->standingslope->id); + else + mobj->standingslope = P_SlopeById(READUINT16(save->p)); + } + SYNCFB(MD2_COLORIZED, mobj->colorized); + SYNCFB(MD2_MIRRORED, mobj->mirrored); + SYNCF(MD2_ROLLANGLE, mobj->rollangle); + SYNCF(MD2_SHADOWSCALE, mobj->shadowscale); + SYNCFB(MD2_SHADOWSCALE, mobj->whiteshadow); + SYNCF(MD2_SHADOWSCALE, mobj->shadowcolor); + if (GETB(MD2_RENDERFLAGS)) + { + if (save->write) + { + UINT32 rf = mobj->renderflags; + UINT32 q = rf & RF_DONTDRAW; - WRITEUINT32(save->p, rf); + if (q != RF_DONTDRAW // visible for more than one local player + && q != (RF_DONTDRAWP1|RF_DONTDRAWP2|RF_DONTDRAWP3) + && q != (RF_DONTDRAWP4|RF_DONTDRAWP1|RF_DONTDRAWP2) + && q != (RF_DONTDRAWP4|RF_DONTDRAWP1|RF_DONTDRAWP3) + && q != (RF_DONTDRAWP4|RF_DONTDRAWP2|RF_DONTDRAWP3)) + rf &= ~q; + + WRITEUINT32(save->p, rf); + } + else + { + mobj->renderflags = READUINT32(save->p); + } } - if (diff2 & MD2_TID) - WRITEINT16(save->p, mobj->tid); - if (diff2 & MD2_SPRITESCALE) + SYNCF(MD2_TID, mobj->tid); + SYNCDEF(MD2_SPRITESCALE, mobj->spritexscale, FRACUNIT); + SYNCDEF(MD2_SPRITESCALE, mobj->spriteyscale, FRACUNIT); + SYNCDEF(MD2_SPRITEOFFSET, mobj->spritexoffset, FRACUNIT); + SYNCDEF(MD2_SPRITEOFFSET, mobj->spriteyoffset, FRACUNIT); + SYNCDEF(MD2_SPRITEOFFSET, mobj->rollingxoffset, 0); + SYNCDEF(MD2_SPRITEOFFSET, mobj->rollingyoffset, 0); + SYNCF(MD2_WORLDOFFSET, mobj->sprxoff); + SYNCF(MD2_WORLDOFFSET, mobj->spryoff); + SYNCF(MD2_WORLDOFFSET, mobj->sprzoff); + + if (GETB(MD2_SPECIAL)) { - WRITEFIXED(save->p, mobj->spritexscale); - WRITEFIXED(save->p, mobj->spriteyscale); - } - if (diff2 & MD2_SPRITEOFFSET) - { - WRITEFIXED(save->p, mobj->spritexoffset); - WRITEFIXED(save->p, mobj->spriteyoffset); - WRITEINT16(save->p, mobj->rollingxoffset); - WRITEINT16(save->p, mobj->rollingyoffset); - } - if (diff2 & MD2_WORLDOFFSET) - { - WRITEFIXED(save->p, mobj->sprxoff); - WRITEFIXED(save->p, mobj->spryoff); - WRITEFIXED(save->p, mobj->sprzoff); - } - if (diff2 & MD2_SPECIAL) - { - WRITEINT16(save->p, mobj->special); + SYNC(mobj->special); for (j = 0; j < NUM_SCRIPT_ARGS; j++) - WRITEINT32(save->p, mobj->script_args[j]); + SYNC(mobj->script_args[j]); for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) { - size_t len, k; - - if (!mobj->script_stringargs[j]) + size_t len = P_SyncINT32(save, mobj->script_stringargs[j] ? strlen(mobj->script_stringargs[j]) : 0); + if (!len) { - WRITEINT32(save->p, 0); + if (!save->write) + { + Z_Free(mobj->script_stringargs[j]); + mobj->script_stringargs[j] = NULL; + } continue; } - len = strlen(mobj->script_stringargs[j]); - WRITEINT32(save->p, len); - for (k = 0; k < len; k++) - WRITECHAR(save->p, mobj->script_stringargs[j][k]); + if (!save->write) + mobj->script_stringargs[j] = Z_Realloc(mobj->script_stringargs[j], len + 1, PU_LEVEL, NULL); + P_SyncMem(save, mobj->script_stringargs[j], len); + mobj->script_stringargs[j][len] = '\0'; } } - if (diff2 & MD2_FLOORSPRITESLOPE) + if (GETB(MD2_FLOORSPRITESLOPE)) { pslope_t *slope = mobj->floorspriteslope; + if (!save->write) + slope = (pslope_t *)P_CreateFloorSpriteSlope(mobj); - WRITEFIXED(save->p, slope->zdelta); - WRITEANGLE(save->p, slope->zangle); - WRITEANGLE(save->p, slope->xydirection); + SYNC(slope->zdelta); + SYNC(slope->zangle); + SYNC(slope->xydirection); - WRITEFIXED(save->p, slope->o.x); - WRITEFIXED(save->p, slope->o.y); - WRITEFIXED(save->p, slope->o.z); + SYNC(slope->o.x); + SYNC(slope->o.y); + SYNC(slope->o.z); - WRITEFIXED(save->p, slope->d.x); - WRITEFIXED(save->p, slope->d.y); + SYNC(slope->d.x); + SYNC(slope->d.y); - WRITEFIXED(save->p, slope->normal.x); - WRITEFIXED(save->p, slope->normal.y); - WRITEFIXED(save->p, slope->normal.z); - + SYNC(slope->normal.x); + SYNC(slope->normal.y); + SYNC(slope->normal.z); + + if (!save->write) + P_UpdateSlopeLightOffset(slope); } - if (diff2 & MD2_LIGHTLEVEL) + SYNCF(MD2_LIGHTLEVEL, mobj->lightlevel); + SYNCDEF(MD2_DISPOFFSET, mobj->dispoffset, mobj->info->dispoffset); + SYNCF(MD2_LASTMOMZ, mobj->lastmomz); + + if (GETB(MD2_TERRAIN)) { - WRITEINT16(save->p, mobj->lightlevel); + if (save->write) + { + WRITEUINT32(save->p, K_GetTerrainHeapIndex(mobj->terrain) + 1); + WRITEUINT32(save->p, SaveMobjnum(mobj->terrainOverlay)); + } + else + { + UINT32 terrain_index = READUINT32(save->p); + if (terrain_index > 0) + mobj->terrain = K_GetTerrainByIndex(terrain_index - 1); + mobj->terrainOverlay = (mobj_t *)(size_t)READUINT32(save->p); + } } - if (diff2 & MD2_DISPOFFSET) + SYNCDEF(MD3_GRAVITY, mobj->gravity, FRACUNIT); + SYNCF(MD3_BAKEDOFFSET, mobj->bakexoff); + SYNCF(MD3_BAKEDOFFSET, mobj->bakeyoff); + SYNCF(MD3_BAKEDOFFSET, mobj->bakezoff); + SYNCF(MD3_BAKEDOFFSET, mobj->bakexpiv); + SYNCF(MD3_BAKEDOFFSET, mobj->bakeypiv); + SYNCF(MD3_BAKEDOFFSET, mobj->bakezpiv); + SYNCF(MD3_EXTVAL3, mobj->extravalue3); + SYNCF(MD3_SHIELDTRACER, mobj->shieldtracer); + + if (!save->write) { - WRITEINT32(save->p, mobj->dispoffset); - } - if (diff2 & MD2_LASTMOMZ) - { - WRITEINT32(save->p, mobj->lastmomz); - } - if (diff2 & MD2_TERRAIN) - { - WRITEUINT32(save->p, K_GetTerrainHeapIndex(mobj->terrain) + 1); - WRITEUINT32(save->p, SaveMobjnum(mobj->terrainOverlay)); - } - if (diff3 & MD3_GRAVITY) - { - WRITEFIXED(save->p, mobj->gravity); - } - if (diff3 & MD3_BAKEDOFFSET) - { - WRITEFIXED(save->p, mobj->bakexoff); - WRITEFIXED(save->p, mobj->bakeyoff); - WRITEFIXED(save->p, mobj->bakezoff); - WRITEFIXED(save->p, mobj->bakexpiv); - WRITEFIXED(save->p, mobj->bakeypiv); - WRITEFIXED(save->p, mobj->bakezpiv); - } - if (diff3 & MD3_EXTVAL3) - { - WRITEINT32(save->p, mobj->extravalue3); - } - if (diff3 & MD3_SHIELDTRACER) - { - WRITEUINT32(save->p, mobj->shieldtracer->mobjnum); + // Reset some non-synch values + mobj->sloperoll = 0; + mobj->slopepitch = 0; + + // link tid set earlier + P_AddThingTID(mobj); + + // set sprev, snext, bprev, bnext, subsector + P_SetThingPosition(mobj); } - WRITEUINT32(save->p, mobj->mobjnum); + SYNC(mobj->mobjnum); + + if (!save->write) + { + if (mobj->player) + { + if (mobj->eflags & MFE_VERTICALFLIP) + mobj->player->viewz = mobj->z + mobj->height - mobj->player->viewheight; + else + mobj->player->viewz = mobj->player->mo->z + mobj->player->viewheight; + } + + if (mobj->type == MT_SKYBOX && mobj->spawnpoint) + { + P_InitSkyboxPoint(mobj, mobj->spawnpoint); + } + + if (GETB(MD2_BOSS3CAP)) + P_SetTarget(&boss3cap, mobj); + + if (GETB(MD2_WAYPOINTCAP)) + P_SetTarget(&waypointcap, mobj); + + if (GETB(MD2_KITEMCAP)) + P_SetTarget(&kitemcap, mobj); + + if (GETB(MD3_MISCCAP)) + P_SetTarget(&misccap, mobj); + + R_AddMobjInterpolator(mobj); + } + + // don't allow the mobj's refcount to be reset by P_AddThinker + // we might've already called P_SetTarget! + return &mobj->thinker; } -static void SaveNoEnemiesThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncNoEnemiesThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const noenemies_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveLine(ht->sourceline)); + noenemies_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + ht->sourceline = SyncLine(save, ht->sourceline); + return &ht->thinker; } -static void SaveBounceCheeseThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncBounceCheeseThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const bouncecheese_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveLine(ht->sourceline)); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEFIXED(save->p, ht->speed); - WRITEFIXED(save->p, ht->distance); - WRITEFIXED(save->p, ht->floorwasheight); - WRITEFIXED(save->p, ht->ceilingwasheight); - WRITECHAR(save->p, ht->low); + bouncecheese_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->sourceline = SyncLine(save, ht->sourceline); + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->speed); + SYNC(ht->distance); + SYNC(ht->floorwasheight); + SYNC(ht->ceilingwasheight); + SYNCBOOLEAN(ht->low); + if (!save->write && ht->sector) + ht->sector->ceilingdata = ht; + return &ht->thinker; } -static void SaveContinuousFallThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncContinuousFallThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const continuousfall_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEFIXED(save->p, ht->speed); - WRITEINT32(save->p, ht->direction); - WRITEFIXED(save->p, ht->floorstartheight); - WRITEFIXED(save->p, ht->ceilingstartheight); - WRITEFIXED(save->p, ht->destheight); + continuousfall_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->speed); + SYNC(ht->direction); + SYNC(ht->floorstartheight); + SYNC(ht->ceilingstartheight); + SYNC(ht->destheight); + if (!save->write && ht->sector) + { + ht->sector->ceilingdata = ht; + ht->sector->floordata = ht; + } + return &ht->thinker; } -static void SaveMarioBlockThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncMarioBlockThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const mariothink_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEFIXED(save->p, ht->speed); - WRITEINT32(save->p, ht->direction); - WRITEFIXED(save->p, ht->floorstartheight); - WRITEFIXED(save->p, ht->ceilingstartheight); - WRITEINT16(save->p, ht->tag); + mariothink_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->speed); + SYNC(ht->direction); + SYNC(ht->floorstartheight); + SYNC(ht->ceilingstartheight); + SYNC(ht->tag); + if (!save->write && ht->sector) + { + ht->sector->ceilingdata = ht; + ht->sector->floordata = ht; + } + return &ht->thinker; } -static void SaveMarioCheckThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncMarioCheckThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const mariocheck_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveLine(ht->sourceline)); - WRITEUINT32(save->p, SaveSector(ht->sector)); + mariocheck_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->sourceline = SyncLine(save, ht->sourceline); + ht->sector = SyncSector(save, ht->sector); + return &ht->thinker; } -static void SaveThwompThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncThwompThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const thwomp_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveLine(ht->sourceline)); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEFIXED(save->p, ht->crushspeed); - WRITEFIXED(save->p, ht->retractspeed); - WRITEINT32(save->p, ht->direction); - WRITEFIXED(save->p, ht->floorstartheight); - WRITEFIXED(save->p, ht->ceilingstartheight); - WRITEINT32(save->p, ht->delay); - WRITEINT16(save->p, ht->tag); - WRITEUINT16(save->p, ht->sound); - WRITEINT32(save->p, ht->initDelay); + thwomp_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->sourceline = SyncLine(save, ht->sourceline); + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->crushspeed); + SYNC(ht->retractspeed); + SYNC(ht->direction); + SYNC(ht->floorstartheight); + SYNC(ht->ceilingstartheight); + SYNC(ht->delay); + SYNC(ht->tag); + SYNC(ht->sound); + SYNC(ht->initDelay); + if (ht->sector) + { + ht->sector->ceilingdata = ht; + ht->sector->floordata = ht; + } + return &ht->thinker; } -static void SaveFloatThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncFloatThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const floatthink_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveLine(ht->sourceline)); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEINT16(save->p, ht->tag); + floatthink_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->sourceline = SyncLine(save, ht->sourceline); + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->tag); + return &ht->thinker; } -static void SaveEachTimeThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncEachTimeThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const eachtime_t *ht = (const void *)th; + eachtime_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + size_t i; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveLine(ht->sourceline)); + ht->sourceline = SyncLine(save, ht->sourceline); for (i = 0; i < MAXPLAYERS; i++) { - WRITECHAR(save->p, ht->playersInArea[i]); + SYNCBOOLEAN(ht->playersInArea[i]); } - WRITECHAR(save->p, ht->triggerOnExit); + SYNCBOOLEAN(ht->triggerOnExit); + return &ht->thinker; } -static void SaveRaiseThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncRaiseThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const raise_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEINT16(save->p, ht->tag); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEFIXED(save->p, ht->ceilingbottom); - WRITEFIXED(save->p, ht->ceilingtop); - WRITEFIXED(save->p, ht->basespeed); - WRITEFIXED(save->p, ht->extraspeed); - WRITEUINT8(save->p, ht->shaketimer); - WRITEUINT8(save->p, ht->flags); + raise_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->tag); + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->ceilingbottom); + SYNC(ht->ceilingtop); + SYNC(ht->basespeed); + SYNC(ht->extraspeed); + SYNC(ht->shaketimer); + SYNC(ht->flags); + return &ht->thinker; } -static void SaveCeilingThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncCeilingThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const ceiling_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT8(save->p, ht->type); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEFIXED(save->p, ht->bottomheight); - WRITEFIXED(save->p, ht->topheight); - WRITEFIXED(save->p, ht->speed); - WRITEFIXED(save->p, ht->delay); - WRITEFIXED(save->p, ht->delaytimer); - WRITEUINT8(save->p, ht->crush); - WRITEINT32(save->p, ht->texture); - WRITEINT32(save->p, ht->direction); - WRITEINT16(save->p, ht->tag); - WRITEFIXED(save->p, ht->sourceline); - WRITEFIXED(save->p, ht->origspeed); - WRITEFIXED(save->p, ht->crushHeight); - WRITEFIXED(save->p, ht->crushSpeed); - WRITEFIXED(save->p, ht->returnHeight); - WRITEFIXED(save->p, ht->returnSpeed); + ceiling_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->type); + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->bottomheight); + SYNC(ht->topheight); + SYNC(ht->speed); + SYNC(ht->delay); + SYNC(ht->delaytimer); + SYNC(ht->crush); + SYNC(ht->texture); + SYNC(ht->direction); + SYNC(ht->tag); + SYNC(ht->sourceline); + SYNC(ht->origspeed); + SYNC(ht->crushHeight); + SYNC(ht->crushSpeed); + SYNC(ht->returnHeight); + SYNC(ht->returnSpeed); + if (!save->write && ht->sector) + ht->sector->ceilingdata = ht; + + return &ht->thinker; } -static void SaveFloormoveThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncFloormoveThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const floormove_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT8(save->p, ht->type); - WRITEUINT8(save->p, ht->crush); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEINT32(save->p, ht->direction); - WRITEINT32(save->p, ht->texture); - WRITEFIXED(save->p, ht->floordestheight); - WRITEFIXED(save->p, ht->speed); - WRITEFIXED(save->p, ht->origspeed); - WRITEFIXED(save->p, ht->delay); - WRITEFIXED(save->p, ht->delaytimer); - WRITEINT16(save->p, ht->tag); - WRITEFIXED(save->p, ht->sourceline); - WRITEFIXED(save->p, ht->crushHeight); - WRITEFIXED(save->p, ht->crushSpeed); - WRITEFIXED(save->p, ht->returnHeight); - WRITEFIXED(save->p, ht->returnSpeed); + floormove_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->crush); + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->direction); + SYNC(ht->texture); + SYNC(ht->floordestheight); + SYNC(ht->speed); + SYNC(ht->origspeed); + SYNC(ht->delay); + SYNC(ht->delaytimer); + SYNC(ht->tag); + SYNC(ht->sourceline); + SYNC(ht->crushHeight); + SYNC(ht->crushSpeed); + SYNC(ht->returnHeight); + SYNC(ht->returnSpeed); + return &ht->thinker; } -static void SaveLightflashThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncLightflashThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const lightflash_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEINT32(save->p, ht->maxlight); - WRITEINT32(save->p, ht->minlight); + lightflash_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->maxlight); + SYNC(ht->minlight); + if (!save->write && ht->sector) + ht->sector->lightingdata = ht; + return &ht->thinker; } -static void SaveStrobeThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncStrobeThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const strobe_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEINT32(save->p, ht->count); - WRITEINT16(save->p, ht->minlight); - WRITEINT16(save->p, ht->maxlight); - WRITEINT32(save->p, ht->darktime); - WRITEINT32(save->p, ht->brighttime); + strobe_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->count); + SYNC(ht->minlight); + SYNC(ht->maxlight); + SYNC(ht->darktime); + SYNC(ht->brighttime); + if (!save->write && ht->sector) + ht->sector->lightingdata = ht; + return &ht->thinker; } -static void SaveGlowThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncGlowThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const glow_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEINT16(save->p, ht->minlight); - WRITEINT16(save->p, ht->maxlight); - WRITEINT16(save->p, ht->direction); - WRITEINT16(save->p, ht->speed); + glow_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->minlight); + SYNC(ht->maxlight); + SYNC(ht->direction); + SYNC(ht->speed); + if (!save->write && ht->sector) + ht->sector->lightingdata = ht; + return &ht->thinker; } -static inline void SaveFireflickerThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncFireflickerThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const fireflicker_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEINT32(save->p, ht->count); - WRITEINT32(save->p, ht->resetcount); - WRITEINT16(save->p, ht->maxlight); - WRITEINT16(save->p, ht->minlight); + fireflicker_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->count); + SYNC(ht->resetcount); + SYNC(ht->maxlight); + SYNC(ht->minlight); + if (!save->write && ht->sector) + ht->sector->lightingdata = ht; + return &ht->thinker; } -static void SaveElevatorThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncElevatorThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const elevator_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT8(save->p, ht->type); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEUINT32(save->p, SaveSector(ht->actionsector)); - WRITEINT32(save->p, ht->direction); - WRITEFIXED(save->p, ht->floordestheight); - WRITEFIXED(save->p, ht->ceilingdestheight); - WRITEFIXED(save->p, ht->speed); - WRITEFIXED(save->p, ht->origspeed); - WRITEFIXED(save->p, ht->low); - WRITEFIXED(save->p, ht->high); - WRITEFIXED(save->p, ht->distance); - WRITEFIXED(save->p, ht->delay); - WRITEFIXED(save->p, ht->delaytimer); - WRITEFIXED(save->p, ht->floorwasheight); - WRITEFIXED(save->p, ht->ceilingwasheight); + boolean setplanedata = thinker == (actionf_p1)T_MoveElevator; + elevator_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->type); + ht->sector = SyncSector(save, ht->sector); + ht->actionsector = SyncSector(save, ht->actionsector); + SYNC(ht->direction); + SYNC(ht->floordestheight); + SYNC(ht->ceilingdestheight); + SYNC(ht->speed); + SYNC(ht->origspeed); + SYNC(ht->low); + SYNC(ht->high); + SYNC(ht->distance); + SYNC(ht->delay); + SYNC(ht->delaytimer); + SYNC(ht->floorwasheight); + SYNC(ht->ceilingwasheight); + + if (!save->write && ht->sector && setplanedata) + { + ht->sector->ceilingdata = ht; + ht->sector->floordata = ht; + } + return &ht->thinker; } -static void SaveCrumbleThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncCrumbleThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const crumble_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveLine(ht->sourceline)); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEUINT32(save->p, SaveSector(ht->actionsector)); - WRITEUINT32(save->p, SavePlayer(ht->player)); // was dummy - WRITEINT32(save->p, ht->direction); - WRITEINT32(save->p, ht->origalpha); - WRITEINT32(save->p, ht->timer); - WRITEFIXED(save->p, ht->speed); - WRITEFIXED(save->p, ht->floorwasheight); - WRITEFIXED(save->p, ht->ceilingwasheight); - WRITEUINT8(save->p, ht->flags); + crumble_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->sourceline = SyncLine(save, ht->sourceline); + ht->sector = SyncSector(save, ht->sector); + ht->actionsector = SyncSector(save, ht->actionsector); + ht->player = LoadPlayer(P_SyncUINT32(save, SavePlayer(ht->player))); // was dummy + SYNC(ht->direction); + SYNC(ht->origalpha); + SYNC(ht->timer); + SYNC(ht->speed); + SYNC(ht->floorwasheight); + SYNC(ht->ceilingwasheight); + SYNC(ht->flags); + if (!save->write && ht->sector) + ht->sector->lightingdata = ht; + if (!save->write && ht->actionsector) + ht->actionsector->lightingdata = ht; + return &ht->thinker; } -static inline void SaveScrollThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncScrollThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const scroll_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEFIXED(save->p, ht->dx); - WRITEFIXED(save->p, ht->dy); - WRITEINT32(save->p, ht->affectee); - WRITEINT32(save->p, ht->control); - WRITEFIXED(save->p, ht->last_height); - WRITEFIXED(save->p, ht->vdx); - WRITEFIXED(save->p, ht->vdy); - WRITEINT32(save->p, ht->accel); - WRITEINT32(save->p, ht->exclusive); - WRITEUINT8(save->p, ht->type); + scroll_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->dx); + SYNC(ht->dy); + SYNC(ht->affectee); + SYNC(ht->control); + SYNC(ht->last_height); + SYNC(ht->vdx); + SYNC(ht->vdy); + SYNC(ht->accel); + SYNC(ht->exclusive); + SYNC(ht->type); + return &ht->thinker; } -static inline void SaveFrictionThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncFrictionThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const friction_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEINT32(save->p, ht->friction); - WRITEINT32(save->p, ht->movefactor); - WRITEINT32(save->p, ht->affectee); - WRITEINT32(save->p, ht->referrer); - WRITEUINT8(save->p, ht->roverfriction); + friction_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->friction); + SYNC(ht->movefactor); + SYNC(ht->affectee); + SYNC(ht->referrer); + SYNC(ht->roverfriction); + return &ht->thinker; } -static inline void SavePusherThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncPusherThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const pusher_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT8(save->p, ht->type); - WRITEFIXED(save->p, ht->x_mag); - WRITEFIXED(save->p, ht->y_mag); - WRITEFIXED(save->p, ht->z_mag); - WRITEINT32(save->p, ht->affectee); - WRITEUINT8(save->p, ht->roverpusher); - WRITEINT32(save->p, ht->referrer); - WRITEINT32(save->p, ht->exclusive); - WRITEINT32(save->p, ht->slider); + pusher_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->type); + SYNC(ht->x_mag); + SYNC(ht->y_mag); + SYNC(ht->z_mag); + SYNC(ht->affectee); + SYNC(ht->roverpusher); + SYNC(ht->referrer); + SYNC(ht->exclusive); + SYNC(ht->slider); + return &ht->thinker; } -static void SaveLaserThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncLaserThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const laserthink_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEINT16(save->p, ht->tag); - WRITEUINT32(save->p, SaveLine(ht->sourceline)); - WRITEUINT8(save->p, ht->nobosses); + laserthink_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->tag); + ht->sourceline = SyncLine(save, ht->sourceline); + SYNC(ht->nobosses); + return &ht->thinker; } -static void SaveLightlevelThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncLightlevelThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const lightlevel_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEINT16(save->p, ht->sourcelevel); - WRITEINT16(save->p, ht->destlevel); - WRITEFIXED(save->p, ht->fixedcurlevel); - WRITEFIXED(save->p, ht->fixedpertic); - WRITEINT32(save->p, ht->timer); + lightlevel_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->sourcelevel); + SYNC(ht->destlevel); + SYNC(ht->fixedcurlevel); + SYNC(ht->fixedpertic); + SYNC(ht->timer); + if (!save->write && ht->sector) + ht->sector->lightingdata = ht; + return &ht->thinker; } -static void SaveExecutorThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncExecutorThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const executor_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveLine(ht->line)); - WRITEUINT32(save->p, SaveMobjnum(ht->caller)); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEINT32(save->p, ht->timer); + executor_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->line = SyncLine(save, ht->line); + ht->caller = SyncMobj(save, ht->caller); + ht->sector = SyncSector(save, ht->sector); + SYNC(ht->timer); + return &ht->thinker; } -static void SaveDisappearThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncDisappearThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const disappear_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, ht->appeartime); - WRITEUINT32(save->p, ht->disappeartime); - WRITEUINT32(save->p, ht->offset); - WRITEUINT32(save->p, ht->timer); - WRITEINT32(save->p, ht->affectee); - WRITEINT32(save->p, ht->sourceline); - WRITEINT32(save->p, ht->exists); + disappear_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->appeartime); + SYNC(ht->disappeartime); + SYNC(ht->offset); + SYNC(ht->timer); + SYNC(ht->affectee); + SYNC(ht->sourceline); + SYNC(ht->exists); + return &ht->thinker; } -static void SaveFadeThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncFadeThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const fade_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, CheckAddNetColormapToList(ht->dest_exc)); - WRITEUINT32(save->p, ht->sectornum); - WRITEUINT32(save->p, ht->ffloornum); - WRITEINT32(save->p, ht->alpha); - WRITEINT16(save->p, ht->sourcevalue); - WRITEINT16(save->p, ht->destvalue); - WRITEINT16(save->p, ht->destlightlevel); - WRITEINT16(save->p, ht->speed); - WRITEUINT8(save->p, (UINT8)ht->ticbased); - WRITEINT32(save->p, ht->timer); - WRITEUINT8(save->p, ht->doexists); - WRITEUINT8(save->p, ht->dotranslucent); - WRITEUINT8(save->p, ht->dolighting); - WRITEUINT8(save->p, ht->docolormap); - WRITEUINT8(save->p, ht->docollision); - WRITEUINT8(save->p, ht->doghostfade); - WRITEUINT8(save->p, ht->exactalpha); + fade_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->dest_exc = GetNetColormapFromList(P_SyncUINT32(save, CheckAddNetColormapToList(ht->dest_exc))); + SYNC(ht->sectornum); + SYNC(ht->ffloornum); + SYNC(ht->alpha); + SYNC(ht->sourcevalue); + SYNC(ht->destvalue); + SYNC(ht->destlightlevel); + SYNC(ht->speed); + SYNCBOOLEAN(ht->ticbased); + SYNC(ht->timer); + SYNC(ht->doexists); + SYNC(ht->dotranslucent); + SYNC(ht->dolighting); + SYNC(ht->docolormap); + SYNCBOOLEAN(ht->docollision); + SYNCBOOLEAN(ht->doghostfade); + SYNC(ht->exactalpha); + + if (!save->write) + { + sector_t *ss = LoadSector(ht->sectornum); + if (ss) + { + size_t j = 0; // ss->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc + ffloor_t *rover; + for (rover = ss->ffloors; rover; rover = rover->next) + { + if (j == ht->ffloornum) + { + ht->rover = rover; + rover->fadingdata = ht; + break; + } + j++; + } + } + } + return &ht->thinker; } -static void SaveFadeColormapThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncFadeColormapThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const fadecolormap_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveSector(ht->sector)); - WRITEUINT32(save->p, CheckAddNetColormapToList(ht->source_exc)); - WRITEUINT32(save->p, CheckAddNetColormapToList(ht->dest_exc)); - WRITEUINT8(save->p, (UINT8)ht->ticbased); - WRITEINT32(save->p, ht->duration); - WRITEINT32(save->p, ht->timer); + fadecolormap_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + ht->sector = SyncSector(save, ht->sector); + ht->source_exc = GetNetColormapFromList(P_SyncUINT32(save, CheckAddNetColormapToList(ht->source_exc))); + ht->dest_exc = GetNetColormapFromList(P_SyncUINT32(save, CheckAddNetColormapToList(ht->dest_exc))); + SYNCBOOLEAN(ht->ticbased); + SYNC(ht->duration); + SYNC(ht->timer); + if (ht->sector) + ht->sector->fadecolormapdata = ht; + return &ht->thinker; } -static void SavePlaneDisplaceThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncPlaneDisplaceThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const planedisplace_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEINT32(save->p, ht->affectee); - WRITEINT32(save->p, ht->control); - WRITEFIXED(save->p, ht->last_height); - WRITEFIXED(save->p, ht->speed); - WRITEUINT8(save->p, ht->type); + planedisplace_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->affectee); + SYNC(ht->control); + SYNC(ht->last_height); + SYNC(ht->speed); + SYNC(ht->type); + return &ht->thinker; } -static inline void SaveDynamicLineSlopeThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncDynamicLineSlopeThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const dynlineplanethink_t* ht = (const void*)th; + dynlineplanethink_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } - WRITEUINT8(save->p, type); - WRITEUINT8(save->p, ht->type); - WRITEUINT32(save->p, SaveSlope(ht->slope)); - WRITEUINT32(save->p, SaveLine(ht->sourceline)); - WRITEFIXED(save->p, ht->extent); + SYNC(ht->type); + ht->slope = SyncSlope(save, ht->slope); + ht->sourceline = SyncLine(save, ht->sourceline); + SYNC(ht->extent); + return &ht->thinker; } -static inline void SaveDynamicVertexSlopeThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncDynamicVertexSlopeThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { size_t i; - const dynvertexplanethink_t* ht = (const void*)th; + dynvertexplanethink_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } - WRITEUINT8(save->p, type); - WRITEUINT32(save->p, SaveSlope(ht->slope)); + ht->slope = SyncSlope(save, ht->slope); for (i = 0; i < 3; i++) - WRITEUINT32(save->p, SaveSector(ht->secs[i])); - WRITEMEM(save->p, ht->vex, sizeof(ht->vex)); - WRITEMEM(save->p, ht->origsecheights, sizeof(ht->origsecheights)); - WRITEMEM(save->p, ht->origvecheights, sizeof(ht->origvecheights)); - WRITEUINT8(save->p, ht->relative); + ht->secs[i] = SyncSector(save, ht->secs[i]); + P_SyncMem(save, ht->vex, sizeof(ht->vex)); + P_SyncMem(save, ht->origsecheights, sizeof(ht->origsecheights)); + P_SyncMem(save, ht->origvecheights, sizeof(ht->origvecheights)); + SYNC(ht->relative); + return &ht->thinker; } -static inline void SavePolyrotatetThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncPolyrotatetThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const polyrotate_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEINT32(save->p, ht->polyObjNum); - WRITEINT32(save->p, ht->speed); - WRITEINT32(save->p, ht->distance); - WRITEUINT8(save->p, ht->turnobjs); + polyrotate_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->polyObjNum); + SYNC(ht->speed); + SYNC(ht->distance); + SYNC(ht->turnobjs); + return &ht->thinker; } -static void SavePolymoveThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncPolymoveThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const polymove_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEINT32(save->p, ht->polyObjNum); - WRITEINT32(save->p, ht->speed); - WRITEFIXED(save->p, ht->momx); - WRITEFIXED(save->p, ht->momy); - WRITEINT32(save->p, ht->distance); - WRITEANGLE(save->p, ht->angle); + polymove_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->polyObjNum); + SYNC(ht->speed); + SYNC(ht->momx); + SYNC(ht->momy); + SYNC(ht->distance); + SYNC(ht->angle); + return &ht->thinker; } -static void SavePolywaypointThinker(savebuffer_t *save, const thinker_t *th, UINT8 type) +static thinker_t *SyncPolywaypointThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const polywaypoint_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEINT32(save->p, ht->polyObjNum); - WRITEINT32(save->p, ht->speed); - WRITEINT32(save->p, ht->sequence); - WRITEINT32(save->p, ht->pointnum); - WRITEINT32(save->p, ht->direction); - WRITEUINT8(save->p, ht->returnbehavior); - WRITEUINT8(save->p, ht->continuous); - WRITEUINT8(save->p, ht->stophere); + polywaypoint_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->polyObjNum); + SYNC(ht->speed); + SYNC(ht->sequence); + SYNC(ht->pointnum); + SYNC(ht->direction); + SYNC(ht->returnbehavior); + SYNC(ht->continuous); + SYNC(ht->stophere); + return &ht->thinker; } -static void SavePolyslidedoorThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncPolyslidedoorThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const polyslidedoor_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEINT32(save->p, ht->polyObjNum); - WRITEINT32(save->p, ht->delay); - WRITEINT32(save->p, ht->delayCount); - WRITEINT32(save->p, ht->initSpeed); - WRITEINT32(save->p, ht->speed); - WRITEINT32(save->p, ht->initDistance); - WRITEINT32(save->p, ht->distance); - WRITEUINT32(save->p, ht->initAngle); - WRITEUINT32(save->p, ht->angle); - WRITEUINT32(save->p, ht->revAngle); - WRITEFIXED(save->p, ht->momx); - WRITEFIXED(save->p, ht->momy); - WRITEUINT8(save->p, ht->closing); + polyslidedoor_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->polyObjNum); + SYNC(ht->delay); + SYNC(ht->delayCount); + SYNC(ht->initSpeed); + SYNC(ht->speed); + SYNC(ht->initDistance); + SYNC(ht->distance); + SYNC(ht->initAngle); + SYNC(ht->angle); + SYNC(ht->revAngle); + SYNC(ht->momx); + SYNC(ht->momy); + SYNC(ht->closing); + return &ht->thinker; } -static void SavePolyswingdoorThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncPolyswingdoorThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const polyswingdoor_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEINT32(save->p, ht->polyObjNum); - WRITEINT32(save->p, ht->delay); - WRITEINT32(save->p, ht->delayCount); - WRITEINT32(save->p, ht->initSpeed); - WRITEINT32(save->p, ht->speed); - WRITEINT32(save->p, ht->initDistance); - WRITEINT32(save->p, ht->distance); - WRITEUINT8(save->p, ht->closing); + polyswingdoor_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->polyObjNum); + SYNC(ht->delay); + SYNC(ht->delayCount); + SYNC(ht->initSpeed); + SYNC(ht->speed); + SYNC(ht->initDistance); + SYNC(ht->distance); + SYNC(ht->closing); + return &ht->thinker; } -static void SavePolydisplaceThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncPolydisplaceThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const polydisplace_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEINT32(save->p, ht->polyObjNum); - WRITEUINT32(save->p, SaveSector(ht->controlSector)); - WRITEFIXED(save->p, ht->dx); - WRITEFIXED(save->p, ht->dy); - WRITEFIXED(save->p, ht->oldHeights); + polydisplace_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->polyObjNum); + ht->controlSector = SyncSector(save, ht->controlSector); + SYNC(ht->dx); + SYNC(ht->dy); + SYNC(ht->oldHeights); + return &ht->thinker; } -static void SavePolyrotdisplaceThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncPolyrotdisplaceThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const polyrotdisplace_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEINT32(save->p, ht->polyObjNum); - WRITEUINT32(save->p, SaveSector(ht->controlSector)); - WRITEFIXED(save->p, ht->rotscale); - WRITEUINT8(save->p, ht->turnobjs); - WRITEFIXED(save->p, ht->oldHeights); + polyrotdisplace_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->polyObjNum); + ht->controlSector = SyncSector(save, ht->controlSector); + SYNC(ht->rotscale); + SYNC( ht->turnobjs); + SYNC(ht->oldHeights); + return &ht->thinker; } -static void SavePolyfadeThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) +static thinker_t *SyncPolyfadeThinker(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type) { - const polyfade_t *ht = (const void *)th; - WRITEUINT8(save->p, type); - WRITEINT32(save->p, ht->polyObjNum); - WRITEINT32(save->p, ht->sourcevalue); - WRITEINT32(save->p, ht->destvalue); - WRITEUINT8(save->p, (UINT8)ht->docollision); - WRITEUINT8(save->p, (UINT8)ht->doghostfade); - WRITEUINT8(save->p, (UINT8)ht->ticbased); - WRITEINT32(save->p, ht->duration); - WRITEINT32(save->p, ht->timer); + polyfade_t *ht = (void *)th; + if (save->write) + { + WRITEUINT8(save->p, type); + } + else + { + ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + } + + SYNC(ht->polyObjNum); + SYNC(ht->sourcevalue); + SYNC(ht->destvalue); + SYNCBOOLEAN(ht->docollision); + SYNCBOOLEAN(ht->doghostfade); + SYNCBOOLEAN(ht->ticbased); + SYNC(ht->duration); + SYNC(ht->timer); + return &ht->thinker; } -static void P_NetArchiveThinkers(savebuffer_t *save) +typedef thinker_t *thinkersync_f(savebuffer_t *save, actionf_p1 thinker, thinker_t *th, UINT8 type); + +#define ITER_THINKERS \ + _(P_MobjThinker, SyncMobjThinker, tc_mobj) \ + _(T_MoveCeiling, SyncCeilingThinker, tc_ceiling) \ + _(T_MoveFloor, SyncFloormoveThinker, tc_floor) \ + _(T_LightningFlash, SyncLightflashThinker, tc_flash) \ + _(T_StrobeFlash, SyncStrobeThinker, tc_strobe) \ + _(T_Glow, SyncGlowThinker, tc_glow) \ + _(T_FireFlicker, SyncFireflickerThinker, tc_fireflicker) \ + _(T_ThwompSector, SyncThwompThinker, tc_thwomp) \ + _(T_CameraScanner, SyncElevatorThinker, tc_camerascanner) \ + _(T_MoveElevator, SyncElevatorThinker, tc_elevator) \ + _(T_ContinuousFalling, SyncContinuousFallThinker, tc_continuousfalling) \ + _(T_BounceCheese, SyncBounceCheeseThinker, tc_bouncecheese) \ + _(T_StartCrumble, SyncCrumbleThinker, tc_startcrumble) \ + _(T_MarioBlock, SyncMarioBlockThinker, tc_marioblock) \ + _(T_MarioBlockChecker, SyncMarioCheckThinker, tc_marioblockchecker) \ + _(T_FloatSector, SyncFloatThinker, tc_floatsector) \ + _(T_CrushCeiling, SyncCeilingThinker, tc_crushceiling) \ + _(T_Scroll, SyncScrollThinker, tc_scroll) \ + _(T_Friction, SyncFrictionThinker, tc_friction) \ + _(T_Pusher, SyncPusherThinker, tc_pusher) \ + _(T_LaserFlash, SyncLaserThinker, tc_laserflash) \ + _(T_LightFade, SyncLightlevelThinker, tc_lightfade) \ + _(T_ExecutorDelay, SyncExecutorThinker, tc_executor) \ + _(T_RaiseSector, SyncRaiseThinker, tc_raisesector) \ + _(T_NoEnemiesSector, SyncNoEnemiesThinker, tc_noenemies) \ + _(T_EachTimeThinker, SyncEachTimeThinker, tc_eachtime) \ + _(T_Disappear, SyncDisappearThinker, tc_disappear) \ + _(T_Fade, SyncFadeThinker, tc_fade) \ + _(T_FadeColormap, SyncFadeColormapThinker, tc_fadecolormap) \ + _(T_PlaneDisplace, SyncPlaneDisplaceThinker, tc_planedisplace) \ + _(T_DynamicSlopeLine, SyncDynamicLineSlopeThinker, tc_dynslopeline) \ + _(T_DynamicSlopeVert, SyncDynamicVertexSlopeThinker, tc_dynslopevert) \ + _(T_PolyObjRotate, SyncPolyrotatetThinker, tc_polyrotate) \ + _(T_PolyObjMove, SyncPolymoveThinker, tc_polymove) \ + _(T_PolyObjWaypoint, SyncPolywaypointThinker, tc_polywaypoint) \ + _(T_PolyDoorSlide, SyncPolyslidedoorThinker, tc_polyslidedoor) \ + _(T_PolyDoorSwing, SyncPolyswingdoorThinker, tc_polyswingdoor) \ + _(T_PolyObjFlag, SyncPolymoveThinker, tc_polyflag) \ + _(T_PolyObjDisplace, SyncPolydisplaceThinker, tc_polydisplace) \ + _(T_PolyObjRotDisplace, SyncPolyrotdisplaceThinker, tc_polyrotdisplace) \ + _(T_PolyObjFade, SyncPolyfadeThinker, tc_polyfade ) \ + +typedef enum +{ +#define _(think, sync, tc) tc, + ITER_THINKERS +#undef _ + tc_end +} specials_e; + +static const actionf_p1 actionspecials[tc_end] = +{ +#define _(think, sync, tc) (actionf_p1)think, + ITER_THINKERS +#undef _ +}; + +static void P_NetSyncThinkers(savebuffer_t *save) { TracyCZone(__zone, true); - const thinker_t *th; + thinker_t *currentthinker; + thinker_t *next; + boolean restoreNum = false; UINT32 i; - WRITEUINT32(save->p, ARCHIVEBLOCK_THINKERS); + if (P_SyncUINT32(save, ARCHIVEBLOCK_THINKERS) != ARCHIVEBLOCK_THINKERS) + I_Error("Bad $$$.sav at archive block Thinkers"); + + if (!save->write) + { + // Pre-calculate this lookup, because it was wasting + // a shit ton of time loading mobj thinkers. + CalculateDoomednumToMobjtype(); + + // remove all the current thinkers + for (i = 0; i < NUM_THINKERLISTS; i++) + { + for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = next) + { + next = currentthinker->next; + + currentthinker->references = 0; // Heinous but this is the only place the assertion in P_UnlinkThinkers is wrong + + if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker || currentthinker->function.acp1 == (actionf_p1)P_NullPrecipThinker) + P_RemoveSavegameMobj((mobj_t *)currentthinker); // item isn't saved, don't remove it + else + { + (next->prev = currentthinker->prev)->next = next; + R_DestroyLevelInterpolators(currentthinker); + Z_Free(currentthinker); + } + } + } + + // we don't want the removed mobjs to come back + P_InitThinkers(); + + // clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity + for (i = 0; i < numsectors; i++) + { + sectors[i].floordata = sectors[i].ceilingdata = sectors[i].lightingdata = sectors[i].fadecolormapdata = NULL; + } + } for (i = 0; i < NUM_THINKERLISTS; i++) { - UINT32 numsaved = 0; - // save off the current thinkers - for (th = thlist[i].next; th != &thlist[i]; th = th->next) + thinker_t* th = &thlist[i]; + UINT32 numloaded = 0; + for (;;) { - if (!(th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed - || th->function.acp1 == (actionf_p1)P_NullPrecipThinker)) - numsaved++; + actionf_p1 acp; + if (save->write) + { + th = th->next; + if (th == &thlist[i]) + { + WRITEUINT8(save->p, tc_end); + break; + } - if (th->function.acp1 == (actionf_p1)P_MobjThinker) - { - SaveMobjThinker(save, th, tc_mobj); - continue; + acp = th->function.acp1; + if (acp == (actionf_p1)P_NullPrecipThinker || acp == (actionf_p1)P_RemoveThinkerDelayed) + continue; } - #ifdef PARANOIA - else if (th->function.acp1 == (actionf_p1)P_NullPrecipThinker); - #endif - else if (th->function.acp1 == (actionf_p1)T_MoveCeiling) - { - SaveCeilingThinker(save, th, tc_ceiling); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_CrushCeiling) - { - SaveCeilingThinker(save, th, tc_crushceiling); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_MoveFloor) - { - SaveFloormoveThinker(save, th, tc_floor); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_LightningFlash) - { - SaveLightflashThinker(save, th, tc_flash); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_StrobeFlash) - { - SaveStrobeThinker(save, th, tc_strobe); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_Glow) - { - SaveGlowThinker(save, th, tc_glow); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_FireFlicker) - { - SaveFireflickerThinker(save, th, tc_fireflicker); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_MoveElevator) - { - SaveElevatorThinker(save, th, tc_elevator); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_ContinuousFalling) - { - SaveContinuousFallThinker(save, th, tc_continuousfalling); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_ThwompSector) - { - SaveThwompThinker(save, th, tc_thwomp); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_NoEnemiesSector) - { - SaveNoEnemiesThinker(save, th, tc_noenemies); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_EachTimeThinker) - { - SaveEachTimeThinker(save, th, tc_eachtime); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_RaiseSector) - { - SaveRaiseThinker(save, th, tc_raisesector); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_CameraScanner) - { - SaveElevatorThinker(save, th, tc_camerascanner); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_Scroll) - { - SaveScrollThinker(save, th, tc_scroll); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_Friction) - { - SaveFrictionThinker(save, th, tc_friction); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_Pusher) - { - SavePusherThinker(save, th, tc_pusher); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_BounceCheese) - { - SaveBounceCheeseThinker(save, th, tc_bouncecheese); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_StartCrumble) - { - SaveCrumbleThinker(save, th, tc_startcrumble); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_MarioBlock) - { - SaveMarioBlockThinker(save, th, tc_marioblock); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_MarioBlockChecker) - { - SaveMarioCheckThinker(save, th, tc_marioblockchecker); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_FloatSector) - { - SaveFloatThinker(save, th, tc_floatsector); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_LaserFlash) - { - SaveLaserThinker(save, th, tc_laserflash); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_LightFade) - { - SaveLightlevelThinker(save, th, tc_lightfade); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_ExecutorDelay) - { - SaveExecutorThinker(save, th, tc_executor); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_Disappear) - { - SaveDisappearThinker(save, th, tc_disappear); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_Fade) - { - SaveFadeThinker(save, th, tc_fade); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_FadeColormap) - { - SaveFadeColormapThinker(save, th, tc_fadecolormap); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_PlaneDisplace) - { - SavePlaneDisplaceThinker(save, th, tc_planedisplace); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_PolyObjRotate) - { - SavePolyrotatetThinker(save, th, tc_polyrotate); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_PolyObjMove) - { - SavePolymoveThinker(save, th, tc_polymove); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_PolyObjWaypoint) - { - SavePolywaypointThinker(save, th, tc_polywaypoint); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_PolyDoorSlide) - { - SavePolyslidedoorThinker(save, th, tc_polyslidedoor); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_PolyDoorSwing) - { - SavePolyswingdoorThinker(save, th, tc_polyswingdoor); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_PolyObjFlag) - { - SavePolymoveThinker(save, th, tc_polyflag); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_PolyObjDisplace) - { - SavePolydisplaceThinker(save, th, tc_polydisplace); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_PolyObjRotDisplace) - { - SavePolyrotdisplaceThinker(save, th, tc_polyrotdisplace); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_PolyObjFade) - { - SavePolyfadeThinker(save, th, tc_polyfade); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeLine) - { - SaveDynamicLineSlopeThinker(save, th, tc_dynslopeline); - continue; - } - else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeVert) - { - SaveDynamicVertexSlopeThinker(save, th, tc_dynslopevert); - continue; - } -#ifdef PARANOIA else - I_Assert(th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed); // wait garbage collection -#endif + { + UINT8 tclass = READUINT8(save->p); // NOTE: this is normally written within the sync functions + if (tclass == tc_end) + break; + else if (tclass > tc_end) + I_Error("Invalid thinker class %d", tclass); + + th = NULL; + acp = actionspecials[tclass]; + if (acp == (actionf_p1)T_ExecutorDelay) + restoreNum = true; + else if (acp == (actionf_p1)P_MobjThinker && i != THINK_MOBJ) + I_Error("P_MobjThinker in non-THINK_MOBJ list"); + } + + if (false); +#define _(think, sync, tc) else if (acp == (actionf_p1)think) th = sync(save, acp, th, tc); + ITER_THINKERS +#undef _ + else + I_Error("Unknown thinker type"); + + numloaded++; + + if (!save->write && th && acp != (actionf_p1)P_MobjThinker) + P_AddThinker(i, th); } - CONS_Debug(DBG_NETPLAY, "%u thinkers saved in list %d\n", numsaved, i); - - WRITEUINT8(save->p, tc_end); + CONS_Debug(DBG_NETPLAY, "%u thinkers synchronized in list %d\n", numloaded, i); } + + if (!save->write) + { + // Set each skyboxmo to the first skybox (or NULL) + skyboxmo[0] = skyboxviewpnts[0]; + skyboxmo[1] = skyboxcenterpnts[0]; + + if (restoreNum) + { + executor_t *delay = NULL; + UINT32 mobjnum; + for (currentthinker = thlist[THINK_MAIN].next; currentthinker != &thlist[THINK_MAIN]; currentthinker = currentthinker->next) + { + if (currentthinker->function.acp1 != (actionf_p1)T_ExecutorDelay) + continue; + delay = (void *)currentthinker; + if (!(mobjnum = (UINT32)(size_t)delay->caller)) + continue; + delay->caller = P_FindNewPosition(mobjnum); + } + } + } + TracyCZoneEnd(__zone); } -static void P_NetArchiveWaypoints(savebuffer_t *save) +static void P_NetSyncWaypoints(savebuffer_t *save) { TracyCZone(__zone, true); waypoint_t *waypoint; - size_t i; - size_t numWaypoints = K_GetNumWaypoints(); + UINT32 i; + UINT32 numWaypoints = K_GetNumWaypoints(); - WRITEUINT32(save->p, ARCHIVEBLOCK_WAYPOINTS); - WRITEUINT32(save->p, numWaypoints); + if (P_SyncUINT32(save, ARCHIVEBLOCK_WAYPOINTS) != ARCHIVEBLOCK_WAYPOINTS) + I_Error("Bad $$$.sav at archive block Waypoints"); - for (i = 0U; i < numWaypoints; i++) { - waypoint = K_GetWaypointFromIndex(i); + SYNC(numWaypoints); - // The only thing we save for each waypoint is the mobj. - // Waypoints should NEVER be completely created or destroyed mid-race as a result of this - WRITEUINT32(save->p, waypoint->mobj->mobjnum); + if (save->write) + { + for (i = 0U; i < numWaypoints; i++) { + waypoint = K_GetWaypointFromIndex(i); + + // The only thing we save for each waypoint is the mobj. + // Waypoints should NEVER be completely created or destroyed mid-race as a result of this + WRITEUINT32(save->p, waypoint->mobj->mobjnum); + } } - TracyCZoneEnd(__zone); -} - -static void P_NetUnArchiveWaypoints(savebuffer_t *save) -{ - TracyCZone(__zone, true); - - if (READUINT32(save->p) != ARCHIVEBLOCK_WAYPOINTS) - I_Error("Bad $$$.sav at archive block Waypoints!"); - else { - UINT32 numArchiveWaypoints = READUINT32(save->p); + else + { size_t numSpawnedWaypoints = K_GetNumWaypoints(); - if (numArchiveWaypoints != numSpawnedWaypoints) { + if (numWaypoints != numSpawnedWaypoints) { I_Error("Bad $$$.sav: More saved waypoints than created!"); - } else { + } + else + { waypoint_t *waypoint; UINT32 i; UINT32 temp; - for (i = 0U; i < numArchiveWaypoints; i++) { + for (i = 0U; i < numWaypoints; i++) { waypoint = K_GetWaypointFromIndex(i); temp = READUINT32(save->p); waypoint->mobj = NULL; @@ -3517,39 +3529,19 @@ static void P_NetUnArchiveWaypoints(savebuffer_t *save) } } } - TracyCZoneEnd(__zone); } -static void P_NetArchiveTubeWaypoints(savebuffer_t *save) +static void P_NetSyncTubeWaypoints(savebuffer_t *save) { TracyCZone(__zone, true); INT32 i, j; for (i = 0; i < NUMTUBEWAYPOINTSEQUENCES; i++) { - WRITEUINT16(save->p, numtubewaypoints[i]); + SYNC(numtubewaypoints[i]); for (j = 0; j < numtubewaypoints[i]; j++) - WRITEUINT32(save->p, tubewaypoints[i][j] ? tubewaypoints[i][j]->mobjnum : 0); - } - TracyCZoneEnd(__zone); -} - -static void P_NetUnArchiveTubeWaypoints(savebuffer_t *save) -{ - TracyCZone(__zone, true); - - INT32 i, j; - UINT32 mobjnum; - - for (i = 0; i < NUMTUBEWAYPOINTSEQUENCES; i++) - { - numtubewaypoints[i] = READUINT16(save->p); - for (j = 0; j < numtubewaypoints[i]; j++) - { - mobjnum = READUINT32(save->p); - tubewaypoints[i][j] = (mobjnum == 0) ? NULL : P_FindNewPosition(mobjnum); - } + SYNCRELINK(tubewaypoints[i][j]); } TracyCZoneEnd(__zone); } @@ -3578,1477 +3570,79 @@ mobj_t *P_FindNewPosition(UINT32 oldposition) return NULL; } -static inline mobj_t *LoadMobj(UINT32 mobjnum) -{ - if (mobjnum == 0) return NULL; - return (mobj_t *)(size_t)mobjnum; -} - -static sector_t *LoadSector(UINT32 sector) -{ - if (sector >= numsectors) return NULL; - return §ors[sector]; -} - -static line_t *LoadLine(UINT32 line) -{ - if (line >= numlines) return NULL; - return &lines[line]; -} - -static inline player_t *LoadPlayer(UINT32 player) -{ - if (player >= MAXPLAYERS) return NULL; - return &players[player]; -} - -static inline pslope_t *LoadSlope(UINT32 slopeid) -{ - pslope_t *p = slopelist; - if (slopeid > slopecount) return NULL; - do - { - if (p->id == slopeid) - return p; - } while ((p = p->next)); - return NULL; -} - -static mobjtype_t g_doomednum_to_mobjtype[UINT16_MAX]; - -static void CalculateDoomednumToMobjtype(void) -{ - memset(g_doomednum_to_mobjtype, MT_NULL, sizeof(g_doomednum_to_mobjtype)); - - for (size_t i = MT_NULL+1; i < NUMMOBJTYPES; i++) - { - if (mobjinfo[i].doomednum > 0 && mobjinfo[i].doomednum <= UINT16_MAX) - { - g_doomednum_to_mobjtype[ mobjinfo[i].doomednum ] = i; - } - } -} - -static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker, UINT8 tclass) -{ - mobj_t *mobj; - UINT32 diff; - UINT32 diff2; - UINT32 diff3; - INT32 i; - fixed_t z, floorz, ceilingz; - ffloor_t *floorrover = NULL, *ceilingrover = NULL; - size_t j; - - diff = READUINT32(save->p); - if (diff & MD_MORE) - diff2 = READUINT32(save->p); - else - diff2 = 0; - - if (diff2 & MD2_MORE) - diff3 = READUINT32(save->p); - else - diff3 = 0; - - z = READFIXED(save->p); // Force this so 3dfloor problems don't arise. - floorz = READFIXED(save->p); - ceilingz = READFIXED(save->p); - - if (diff2 & MD2_FLOORROVER) - { - sector_t *sec = LoadSector(READUINT32(save->p)); - UINT16 id = READUINT16(save->p); - floorrover = P_GetFFloorByID(sec, id); - } - - if (diff2 & MD2_CEILINGROVER) - { - sector_t *sec = LoadSector(READUINT32(save->p)); - UINT16 id = READUINT16(save->p); - ceilingrover = P_GetFFloorByID(sec, id); - } - - if (diff & MD_SPAWNPOINT) - { - UINT16 spawnpointnum = READUINT16(save->p); - - if (mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case - { - P_SpawnHoop(&mapthings[spawnpointnum]); - return NULL; - } - - mobj = P_AllocateMobj(); - - mobj->spawnpoint = &mapthings[spawnpointnum]; - mapthings[spawnpointnum].mobj = mobj; - } - else - mobj = P_AllocateMobj(); - - // declare this as a valid mobj as soon as possible. - mobj->thinker.function.acp1 = thinker; - - // manually link to thinkerlist, since the thinker isn't returned anymore - P_AddThinker(tclass, &mobj->thinker); - - mobj->z = z; - mobj->floorz = floorz; - mobj->ceilingz = ceilingz; - mobj->floorrover = floorrover; - mobj->ceilingrover = ceilingrover; - - if (diff & MD_TYPE) - mobj->type = READUINT32(save->p); - else - { - mobjtype_t new_type = MT_NULL; - if (mobj->spawnpoint) - { - new_type = g_doomednum_to_mobjtype[mobj->spawnpoint->type]; - } - - if (new_type <= MT_NULL || new_type >= NUMMOBJTYPES) - { - if (mobj->spawnpoint) - CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing doomednum %d\n", mobj->spawnpoint->type); - else - CONS_Alert(CONS_ERROR, "Found mobj with unknown map thing doomednum NULL\n"); - - I_Error("Netsave corrupted"); - } - - mobj->type = new_type; - } - mobj->info = &mobjinfo[mobj->type]; - - if (diff & MD_POS) - { - mobj->x = mobj->old_x = READFIXED(save->p); - mobj->y = mobj->old_y = READFIXED(save->p); - mobj->angle = mobj->old_angle = READANGLE(save->p); - mobj->pitch = mobj->old_pitch = READANGLE(save->p); - mobj->roll = mobj->old_roll = READANGLE(save->p); - } - else - { - mobj->x = mobj->old_x = mobj->spawnpoint->x << FRACBITS; - mobj->y = mobj->old_y = mobj->spawnpoint->y << FRACBITS; - mobj->angle = mobj->old_angle = FixedAngle(mobj->spawnpoint->angle*FRACUNIT); - mobj->pitch = mobj->old_pitch = FixedAngle(mobj->spawnpoint->pitch*FRACUNIT); - mobj->roll = mobj->old_roll = FixedAngle(mobj->spawnpoint->roll*FRACUNIT); - } - if (diff & MD_MOM) - { - mobj->momx = READFIXED(save->p); - mobj->momy = READFIXED(save->p); - mobj->momz = READFIXED(save->p); - mobj->pmomz = READFIXED(save->p); - } // otherwise they're zero, and the memset took care of it - - if (diff & MD_RADIUS) - mobj->radius = READFIXED(save->p); - else - mobj->radius = FixedMul(mobj->info->radius, mapobjectscale); - if (diff & MD_HEIGHT) - mobj->height = READFIXED(save->p); - else - mobj->height = FixedMul(mobj->info->height, mapobjectscale); - if (diff & MD_FLAGS) - mobj->flags = READUINT32(save->p); - else - mobj->flags = mobj->info->flags; - if (diff & MD_FLAGS2) - mobj->flags2 = READUINT32(save->p); - if (diff & MD_HEALTH) - mobj->health = READINT32(save->p); - else - mobj->health = mobj->info->spawnhealth; - if (diff & MD_RTIME) - mobj->reactiontime = READINT32(save->p); - else - mobj->reactiontime = mobj->info->reactiontime; - - if (diff & MD_STATE) - mobj->state = &states[READUINT16(save->p)]; - else - mobj->state = &states[mobj->info->spawnstate]; - if (diff & MD_TICS) - mobj->tics = READINT32(save->p); - else - mobj->tics = mobj->state->tics; - if (diff & MD_SPRITE) { - mobj->sprite = READUINT16(save->p); - if (mobj->sprite == SPR_PLAY) - mobj->sprite2 = READUINT8(save->p); - } - else { - mobj->sprite = mobj->state->sprite; - if (mobj->sprite == SPR_PLAY) - mobj->sprite2 = mobj->state->frame&FF_FRAMEMASK; - } - if (diff & MD_FRAME) - { - mobj->frame = READUINT32(save->p); - mobj->anim_duration = READUINT16(save->p); - } - else - { - mobj->frame = mobj->state->frame; - mobj->anim_duration = (UINT16)mobj->state->var2; - } - if (diff & MD_EFLAGS) - mobj->eflags = READUINT16(save->p); - if (diff & MD_PLAYER) - { - i = READUINT8(save->p); - mobj->player = &players[i]; - mobj->player->mo = mobj; - } - if (diff & MD_MOVEDIR) - mobj->movedir = READANGLE(save->p); - if (diff & MD_MOVECOUNT) - mobj->movecount = READINT32(save->p); - if (diff & MD_THRESHOLD) - mobj->threshold = READINT32(save->p); - if (diff & MD_LASTLOOK) - mobj->lastlook = READINT32(save->p); - else - mobj->lastlook = -1; - if (diff & MD_TARGET) - mobj->target = (mobj_t *)(size_t)READUINT32(save->p); - if (diff & MD_TRACER) - mobj->tracer = (mobj_t *)(size_t)READUINT32(save->p); - if (diff & MD_FRICTION) - mobj->friction = READFIXED(save->p); - else - mobj->friction = ORIG_FRICTION; - if (diff & MD_MOVEFACTOR) - mobj->movefactor = READFIXED(save->p); - else - mobj->movefactor = FRACUNIT; - if (diff & MD_FUSE) - mobj->fuse = READINT32(save->p); - if (diff & MD_WATERTOP) - mobj->watertop = READFIXED(save->p); - else - mobj->watertop = INT32_MAX; - if (diff & MD_WATERBOTTOM) - mobj->waterbottom = READFIXED(save->p); - if (diff & MD_SCALE) - mobj->scale = READFIXED(save->p); - else - mobj->scale = mapobjectscale; - if (diff & MD_DSCALE) - mobj->destscale = READFIXED(save->p); - else - mobj->destscale = mobj->scale; - if (diff2 & MD2_SCALESPEED) - mobj->scalespeed = READFIXED(save->p); - else - mobj->scalespeed = mapobjectscale/12; - if (diff & MD_ARGS) - { - for (j = 0; j < NUM_MAPTHING_ARGS; j++) - mobj->args[j] = READINT32(save->p); - } - if (diff & MD_STRINGARGS) - { - for (j = 0; j < NUM_MAPTHING_STRINGARGS; j++) - { - size_t len = READINT32(save->p); - size_t k; - - if (!len) - { - Z_Free(mobj->stringargs[j]); - mobj->stringargs[j] = NULL; - continue; - } - - mobj->stringargs[j] = Z_Realloc(mobj->stringargs[j], len + 1, PU_LEVEL, NULL); - for (k = 0; k < len; k++) - mobj->stringargs[j][k] = READCHAR(save->p); - mobj->stringargs[j][len] = '\0'; - } - } - if (diff2 & MD2_CUSVAL) - mobj->cusval = READINT32(save->p); - if (diff2 & MD2_CVMEM) - mobj->cvmem = READINT32(save->p); - if (diff2 & MD2_SKIN) - mobj->skin = &skins[READUINT16(save->p)]; - if (diff2 & MD2_COLOR) - mobj->color = READUINT16(save->p); - if (diff2 & MD2_EXTVAL1) - mobj->extravalue1 = READINT32(save->p); - if (diff2 & MD2_EXTVAL2) - mobj->extravalue2 = READINT32(save->p); - if (diff2 & MD2_HNEXT) - mobj->hnext = (mobj_t *)(size_t)READUINT32(save->p); - if (diff2 & MD2_HPREV) - mobj->hprev = (mobj_t *)(size_t)READUINT32(save->p); - if (diff2 & MD2_ITNEXT) - mobj->itnext = (mobj_t *)(size_t)READUINT32(save->p); - if (diff2 & MD2_SLOPE) - mobj->standingslope = P_SlopeById(READUINT16(save->p)); - if (diff2 & MD2_COLORIZED) - mobj->colorized = READUINT8(save->p); - if (diff2 & MD2_MIRRORED) - mobj->mirrored = READUINT8(save->p); - if (diff2 & MD2_ROLLANGLE) - mobj->rollangle = READANGLE(save->p); - if (diff2 & MD2_SHADOWSCALE) - { - mobj->shadowscale = READFIXED(save->p); - mobj->whiteshadow = READUINT8(save->p); - mobj->shadowcolor = READUINT8(save->p); - } - if (diff2 & MD2_RENDERFLAGS) - mobj->renderflags = READUINT32(save->p); - if (diff2 & MD2_TID) - mobj->tid = READINT16(save->p); - if (diff2 & MD2_SPRITESCALE) - { - mobj->spritexscale = READFIXED(save->p); - mobj->spriteyscale = READFIXED(save->p); - } - else - { - mobj->spritexscale = mobj->spriteyscale = FRACUNIT; - } - if (diff2 & MD2_SPRITEOFFSET) - { - mobj->spritexoffset = READFIXED(save->p); - mobj->spriteyoffset = READFIXED(save->p); - mobj->rollingxoffset = READINT16(save->p); - mobj->rollingyoffset = READINT16(save->p); - } - else - { - mobj->spritexoffset = mobj->spriteyoffset = 0; - mobj->rollingxoffset = mobj->rollingyoffset = 0; - } - if (diff2 & MD2_WORLDOFFSET) - { - mobj->sprxoff = READFIXED(save->p); - mobj->spryoff = READFIXED(save->p); - mobj->sprzoff = READFIXED(save->p); - } - else - { - mobj->sprxoff = mobj->spryoff = mobj->sprzoff = 0; - } - if (diff2 & MD2_SPECIAL) - { - mobj->special = READINT16(save->p); - - for (j = 0; j < NUM_SCRIPT_ARGS; j++) - mobj->script_args[j] = READINT32(save->p); - - for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) - { - size_t len = READINT32(save->p); - size_t k; - - if (!len) - { - Z_Free(mobj->script_stringargs[j]); - mobj->script_stringargs[j] = NULL; - continue; - } - - mobj->script_stringargs[j] = Z_Realloc(mobj->script_stringargs[j], len + 1, PU_LEVEL, NULL); - for (k = 0; k < len; k++) - mobj->script_stringargs[j][k] = READCHAR(save->p); - mobj->script_stringargs[j][len] = '\0'; - } - } - if (diff2 & MD2_FLOORSPRITESLOPE) - { - pslope_t *slope = (pslope_t *)P_CreateFloorSpriteSlope(mobj); - - slope->zdelta = READFIXED(save->p); - slope->zangle = READANGLE(save->p); - slope->xydirection = READANGLE(save->p); - - slope->o.x = READFIXED(save->p); - slope->o.y = READFIXED(save->p); - slope->o.z = READFIXED(save->p); - - slope->d.x = READFIXED(save->p); - slope->d.y = READFIXED(save->p); - - slope->normal.x = READFIXED(save->p); - slope->normal.y = READFIXED(save->p); - slope->normal.z = READFIXED(save->p); - - P_UpdateSlopeLightOffset(slope); - } - if (diff2 & MD2_LIGHTLEVEL) - { - mobj->lightlevel = READINT16(save->p); - } - if (diff2 & MD2_DISPOFFSET) - { - mobj->dispoffset = READINT32(save->p); - } - if (diff2 & MD2_LASTMOMZ) - { - mobj->lastmomz = READINT32(save->p); - } - if (diff2 & MD2_TERRAIN) - { - UINT32 terrain_index = READUINT32(save->p); - if (terrain_index > 0) - mobj->terrain = K_GetTerrainByIndex(terrain_index - 1); - mobj->terrainOverlay = (mobj_t *)(size_t)READUINT32(save->p); - } - else - { - mobj->terrain = NULL; - } - if (diff3 & MD3_GRAVITY) - { - mobj->gravity = READFIXED(save->p); - } - else - { - mobj->gravity = FRACUNIT; - } - if (diff3 & MD3_BAKEDOFFSET) - { - mobj->bakexoff = READFIXED(save->p); - mobj->bakeyoff = READFIXED(save->p); - mobj->bakezoff = READFIXED(save->p); - mobj->bakexpiv = READFIXED(save->p); - mobj->bakeypiv = READFIXED(save->p); - mobj->bakezpiv = READFIXED(save->p); - } - else - { - mobj->bakexoff = mobj->bakeyoff = mobj->bakezoff = 0; - mobj->bakexpiv = mobj->bakeypiv = mobj->bakezpiv = 0; - } - if (diff3 & MD3_EXTVAL3) - { - mobj->extravalue3 = READINT32(save->p); - } - if (diff3 & MD3_SHIELDTRACER) - { - mobj->shieldtracer = (mobj_t *)(size_t)READUINT32(save->p); - } - - // Reset some non-synch values - mobj->sloperoll = 0; - mobj->slopepitch = 0; - - // link tid set earlier - P_AddThingTID(mobj); - - // set sprev, snext, bprev, bnext, subsector - P_SetThingPosition(mobj); - - mobj->mobjnum = READUINT32(save->p); - - if (mobj->player) - { - if (mobj->eflags & MFE_VERTICALFLIP) - mobj->player->viewz = mobj->z + mobj->height - mobj->player->viewheight; - else - mobj->player->viewz = mobj->player->mo->z + mobj->player->viewheight; - } - - if (mobj->type == MT_SKYBOX && mobj->spawnpoint) - { - P_InitSkyboxPoint(mobj, mobj->spawnpoint); - } - - if (diff2 & MD2_BOSS3CAP) - P_SetTarget(&boss3cap, mobj); - - if (diff2 & MD2_WAYPOINTCAP) - P_SetTarget(&waypointcap, mobj); - - if (diff2 & MD2_KITEMCAP) - P_SetTarget(&kitemcap, mobj); - - if (diff3 & MD3_MISCCAP) - P_SetTarget(&misccap, mobj); - - R_AddMobjInterpolator(mobj); - - // don't allow the mobj's refcount to be reset by P_AddThinker - // we might've already called P_SetTarget! - return NULL;//&mobj->thinker; -} - -static thinker_t* LoadNoEnemiesThinker(savebuffer_t *save, actionf_p1 thinker) -{ - noenemies_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save->p)); - return &ht->thinker; -} - -static thinker_t* LoadBounceCheeseThinker(savebuffer_t *save, actionf_p1 thinker) -{ - bouncecheese_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save->p)); - ht->sector = LoadSector(READUINT32(save->p)); - ht->speed = READFIXED(save->p); - ht->distance = READFIXED(save->p); - ht->floorwasheight = READFIXED(save->p); - ht->ceilingwasheight = READFIXED(save->p); - ht->low = READCHAR(save->p); - - if (ht->sector) - ht->sector->ceilingdata = ht; - - return &ht->thinker; -} - -static thinker_t* LoadContinuousFallThinker(savebuffer_t *save, actionf_p1 thinker) -{ - continuousfall_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save->p)); - ht->speed = READFIXED(save->p); - ht->direction = READINT32(save->p); - ht->floorstartheight = READFIXED(save->p); - ht->ceilingstartheight = READFIXED(save->p); - ht->destheight = READFIXED(save->p); - - if (ht->sector) - { - ht->sector->ceilingdata = ht; - ht->sector->floordata = ht; - } - - return &ht->thinker; -} - -static thinker_t* LoadMarioBlockThinker(savebuffer_t *save, actionf_p1 thinker) -{ - mariothink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save->p)); - ht->speed = READFIXED(save->p); - ht->direction = READINT32(save->p); - ht->floorstartheight = READFIXED(save->p); - ht->ceilingstartheight = READFIXED(save->p); - ht->tag = READINT16(save->p); - - if (ht->sector) - { - ht->sector->ceilingdata = ht; - ht->sector->floordata = ht; - } - - return &ht->thinker; -} - -static thinker_t* LoadMarioCheckThinker(savebuffer_t *save, actionf_p1 thinker) -{ - mariocheck_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save->p)); - ht->sector = LoadSector(READUINT32(save->p)); - return &ht->thinker; -} - -static thinker_t* LoadThwompThinker(savebuffer_t *save, actionf_p1 thinker) -{ - thwomp_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save->p)); - ht->sector = LoadSector(READUINT32(save->p)); - ht->crushspeed = READFIXED(save->p); - ht->retractspeed = READFIXED(save->p); - ht->direction = READINT32(save->p); - ht->floorstartheight = READFIXED(save->p); - ht->ceilingstartheight = READFIXED(save->p); - ht->delay = READINT32(save->p); - ht->tag = READINT16(save->p); - ht->sound = READUINT16(save->p); - ht->initDelay = READINT32(save->p); - - if (ht->sector) - { - ht->sector->ceilingdata = ht; - ht->sector->floordata = ht; - } - - return &ht->thinker; -} - -static thinker_t* LoadFloatThinker(savebuffer_t *save, actionf_p1 thinker) -{ - floatthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save->p)); - ht->sector = LoadSector(READUINT32(save->p)); - ht->tag = READINT16(save->p); - return &ht->thinker; -} - -static thinker_t* LoadEachTimeThinker(savebuffer_t *save, actionf_p1 thinker) -{ - size_t i; - eachtime_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save->p)); - for (i = 0; i < MAXPLAYERS; i++) - { - ht->playersInArea[i] = READCHAR(save->p); - } - ht->triggerOnExit = READCHAR(save->p); - return &ht->thinker; -} - -static thinker_t* LoadRaiseThinker(savebuffer_t *save, actionf_p1 thinker) -{ - raise_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->tag = READINT16(save->p); - ht->sector = LoadSector(READUINT32(save->p)); - ht->ceilingbottom = READFIXED(save->p); - ht->ceilingtop = READFIXED(save->p); - ht->basespeed = READFIXED(save->p); - ht->extraspeed = READFIXED(save->p); - ht->shaketimer = READUINT8(save->p); - ht->flags = READUINT8(save->p); - return &ht->thinker; -} - -static thinker_t* LoadCeilingThinker(savebuffer_t *save, actionf_p1 thinker) -{ - ceiling_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->type = READUINT8(save->p); - ht->sector = LoadSector(READUINT32(save->p)); - ht->bottomheight = READFIXED(save->p); - ht->topheight = READFIXED(save->p); - ht->speed = READFIXED(save->p); - ht->delay = READFIXED(save->p); - ht->delaytimer = READFIXED(save->p); - ht->crush = READUINT8(save->p); - ht->texture = READINT32(save->p); - ht->direction = READINT32(save->p); - ht->tag = READINT16(save->p); - ht->sourceline = READFIXED(save->p); - ht->origspeed = READFIXED(save->p); - ht->crushHeight = READFIXED(save->p); - ht->crushSpeed = READFIXED(save->p); - ht->returnHeight = READFIXED(save->p); - ht->returnSpeed = READFIXED(save->p); - if (ht->sector) - ht->sector->ceilingdata = ht; - return &ht->thinker; -} - -static thinker_t* LoadFloormoveThinker(savebuffer_t *save, actionf_p1 thinker) -{ - floormove_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->type = READUINT8(save->p); - ht->crush = READUINT8(save->p); - ht->sector = LoadSector(READUINT32(save->p)); - ht->direction = READINT32(save->p); - ht->texture = READINT32(save->p); - ht->floordestheight = READFIXED(save->p); - ht->speed = READFIXED(save->p); - ht->origspeed = READFIXED(save->p); - ht->delay = READFIXED(save->p); - ht->delaytimer = READFIXED(save->p); - ht->tag = READINT16(save->p); - ht->sourceline = READFIXED(save->p); - ht->crushHeight = READFIXED(save->p); - ht->crushSpeed = READFIXED(save->p); - ht->returnHeight = READFIXED(save->p); - ht->returnSpeed = READFIXED(save->p); - if (ht->sector) - ht->sector->floordata = ht; - return &ht->thinker; -} - -static thinker_t* LoadLightflashThinker(savebuffer_t *save, actionf_p1 thinker) -{ - lightflash_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save->p)); - ht->maxlight = READINT32(save->p); - ht->minlight = READINT32(save->p); - if (ht->sector) - ht->sector->lightingdata = ht; - return &ht->thinker; -} - -static thinker_t* LoadStrobeThinker(savebuffer_t *save, actionf_p1 thinker) -{ - strobe_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save->p)); - ht->count = READINT32(save->p); - ht->minlight = READINT16(save->p); - ht->maxlight = READINT16(save->p); - ht->darktime = READINT32(save->p); - ht->brighttime = READINT32(save->p); - if (ht->sector) - ht->sector->lightingdata = ht; - return &ht->thinker; -} - -static thinker_t* LoadGlowThinker(savebuffer_t *save, actionf_p1 thinker) -{ - glow_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save->p)); - ht->minlight = READINT16(save->p); - ht->maxlight = READINT16(save->p); - ht->direction = READINT16(save->p); - ht->speed = READINT16(save->p); - if (ht->sector) - ht->sector->lightingdata = ht; - return &ht->thinker; -} - -static thinker_t* LoadFireflickerThinker(savebuffer_t *save, actionf_p1 thinker) -{ - fireflicker_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save->p)); - ht->count = READINT32(save->p); - ht->resetcount = READINT32(save->p); - ht->maxlight = READINT16(save->p); - ht->minlight = READINT16(save->p); - if (ht->sector) - ht->sector->lightingdata = ht; - return &ht->thinker; -} - -static thinker_t* LoadElevatorThinker(savebuffer_t *save, actionf_p1 thinker, boolean setplanedata) -{ - elevator_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->type = READUINT8(save->p); - ht->sector = LoadSector(READUINT32(save->p)); - ht->actionsector = LoadSector(READUINT32(save->p)); - ht->direction = READINT32(save->p); - ht->floordestheight = READFIXED(save->p); - ht->ceilingdestheight = READFIXED(save->p); - ht->speed = READFIXED(save->p); - ht->origspeed = READFIXED(save->p); - ht->low = READFIXED(save->p); - ht->high = READFIXED(save->p); - ht->distance = READFIXED(save->p); - ht->delay = READFIXED(save->p); - ht->delaytimer = READFIXED(save->p); - ht->floorwasheight = READFIXED(save->p); - ht->ceilingwasheight = READFIXED(save->p); - - if (ht->sector && setplanedata) - { - ht->sector->ceilingdata = ht; - ht->sector->floordata = ht; - } - - return &ht->thinker; -} - -static thinker_t* LoadCrumbleThinker(savebuffer_t *save, actionf_p1 thinker) -{ - crumble_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save->p)); - ht->sector = LoadSector(READUINT32(save->p)); - ht->actionsector = LoadSector(READUINT32(save->p)); - ht->player = LoadPlayer(READUINT32(save->p)); - ht->direction = READINT32(save->p); - ht->origalpha = READINT32(save->p); - ht->timer = READINT32(save->p); - ht->speed = READFIXED(save->p); - ht->floorwasheight = READFIXED(save->p); - ht->ceilingwasheight = READFIXED(save->p); - ht->flags = READUINT8(save->p); - - if (ht->sector) - ht->sector->floordata = ht; - - return &ht->thinker; -} - -static thinker_t* LoadScrollThinker(savebuffer_t *save, actionf_p1 thinker) -{ - scroll_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->dx = READFIXED(save->p); - ht->dy = READFIXED(save->p); - ht->affectee = READINT32(save->p); - ht->control = READINT32(save->p); - ht->last_height = READFIXED(save->p); - ht->vdx = READFIXED(save->p); - ht->vdy = READFIXED(save->p); - ht->accel = READINT32(save->p); - ht->exclusive = READINT32(save->p); - ht->type = READUINT8(save->p); - return &ht->thinker; -} - -static inline thinker_t* LoadFrictionThinker(savebuffer_t *save, actionf_p1 thinker) -{ - friction_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->friction = READINT32(save->p); - ht->movefactor = READINT32(save->p); - ht->affectee = READINT32(save->p); - ht->referrer = READINT32(save->p); - ht->roverfriction = READUINT8(save->p); - return &ht->thinker; -} - -static thinker_t* LoadPusherThinker(savebuffer_t *save, actionf_p1 thinker) -{ - pusher_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->type = READUINT8(save->p); - ht->x_mag = READFIXED(save->p); - ht->y_mag = READFIXED(save->p); - ht->z_mag = READFIXED(save->p); - ht->affectee = READINT32(save->p); - ht->roverpusher = READUINT8(save->p); - ht->referrer = READINT32(save->p); - ht->exclusive = READINT32(save->p); - ht->slider = READINT32(save->p); - return &ht->thinker; -} - -static inline thinker_t* LoadLaserThinker(savebuffer_t *save, actionf_p1 thinker) -{ - laserthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->tag = READINT16(save->p); - ht->sourceline = LoadLine(READUINT32(save->p)); - ht->nobosses = READUINT8(save->p); - return &ht->thinker; -} - -static inline thinker_t* LoadLightlevelThinker(savebuffer_t *save, actionf_p1 thinker) -{ - lightlevel_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save->p)); - ht->sourcelevel = READINT16(save->p); - ht->destlevel = READINT16(save->p); - ht->fixedcurlevel = READFIXED(save->p); - ht->fixedpertic = READFIXED(save->p); - ht->timer = READINT32(save->p); - if (ht->sector) - ht->sector->lightingdata = ht; - return &ht->thinker; -} - -static inline thinker_t* LoadExecutorThinker(savebuffer_t *save, actionf_p1 thinker) -{ - executor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->line = LoadLine(READUINT32(save->p)); - ht->caller = LoadMobj(READUINT32(save->p)); - ht->sector = LoadSector(READUINT32(save->p)); - ht->timer = READINT32(save->p); - return &ht->thinker; -} - -static inline thinker_t* LoadDisappearThinker(savebuffer_t *save, actionf_p1 thinker) -{ - disappear_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->appeartime = READUINT32(save->p); - ht->disappeartime = READUINT32(save->p); - ht->offset = READUINT32(save->p); - ht->timer = READUINT32(save->p); - ht->affectee = READINT32(save->p); - ht->sourceline = READINT32(save->p); - ht->exists = READINT32(save->p); - return &ht->thinker; -} - -static inline thinker_t* LoadFadeThinker(savebuffer_t *save, actionf_p1 thinker) -{ - sector_t *ss; - fade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->dest_exc = GetNetColormapFromList(READUINT32(save->p)); - ht->sectornum = READUINT32(save->p); - ht->ffloornum = READUINT32(save->p); - ht->alpha = READINT32(save->p); - ht->sourcevalue = READINT16(save->p); - ht->destvalue = READINT16(save->p); - ht->destlightlevel = READINT16(save->p); - ht->speed = READINT16(save->p); - ht->ticbased = (boolean)READUINT8(save->p); - ht->timer = READINT32(save->p); - ht->doexists = READUINT8(save->p); - ht->dotranslucent = READUINT8(save->p); - ht->dolighting = READUINT8(save->p); - ht->docolormap = READUINT8(save->p); - ht->docollision = READUINT8(save->p); - ht->doghostfade = READUINT8(save->p); - ht->exactalpha = READUINT8(save->p); - - ss = LoadSector(ht->sectornum); - if (ss) - { - size_t j = 0; // ss->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc - ffloor_t *rover; - for (rover = ss->ffloors; rover; rover = rover->next) - { - if (j == ht->ffloornum) - { - ht->rover = rover; - rover->fadingdata = ht; - break; - } - j++; - } - } - return &ht->thinker; -} - -static inline thinker_t* LoadFadeColormapThinker(savebuffer_t *save, actionf_p1 thinker) -{ - fadecolormap_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save->p)); - ht->source_exc = GetNetColormapFromList(READUINT32(save->p)); - ht->dest_exc = GetNetColormapFromList(READUINT32(save->p)); - ht->ticbased = (boolean)READUINT8(save->p); - ht->duration = READINT32(save->p); - ht->timer = READINT32(save->p); - if (ht->sector) - ht->sector->fadecolormapdata = ht; - return &ht->thinker; -} - -static inline thinker_t* LoadPlaneDisplaceThinker(savebuffer_t *save, actionf_p1 thinker) -{ - planedisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - - ht->affectee = READINT32(save->p); - ht->control = READINT32(save->p); - ht->last_height = READFIXED(save->p); - ht->speed = READFIXED(save->p); - ht->type = READUINT8(save->p); - return &ht->thinker; -} - -static inline thinker_t* LoadDynamicLineSlopeThinker(savebuffer_t *save, actionf_p1 thinker) -{ - dynlineplanethink_t* ht = Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - - ht->type = READUINT8(save->p); - ht->slope = LoadSlope(READUINT32(save->p)); - ht->sourceline = LoadLine(READUINT32(save->p)); - ht->extent = READFIXED(save->p); - return &ht->thinker; -} - -static inline thinker_t* LoadDynamicVertexSlopeThinker(savebuffer_t *save, actionf_p1 thinker) -{ - size_t i; - dynvertexplanethink_t* ht = Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - - ht->slope = LoadSlope(READUINT32(save->p)); - for (i = 0; i < 3; i++) - ht->secs[i] = LoadSector(READUINT32(save->p)); - READMEM(save->p, ht->vex, sizeof(ht->vex)); - READMEM(save->p, ht->origsecheights, sizeof(ht->origsecheights)); - READMEM(save->p, ht->origvecheights, sizeof(ht->origvecheights)); - ht->relative = READUINT8(save->p); - return &ht->thinker; -} - -static inline thinker_t* LoadPolyrotatetThinker(savebuffer_t *save, actionf_p1 thinker) -{ - polyrotate_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save->p); - ht->speed = READINT32(save->p); - ht->distance = READINT32(save->p); - ht->turnobjs = READUINT8(save->p); - return &ht->thinker; -} - -static thinker_t* LoadPolymoveThinker(savebuffer_t *save, actionf_p1 thinker) -{ - polymove_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save->p); - ht->speed = READINT32(save->p); - ht->momx = READFIXED(save->p); - ht->momy = READFIXED(save->p); - ht->distance = READINT32(save->p); - ht->angle = READANGLE(save->p); - return &ht->thinker; -} - -static inline thinker_t* LoadPolywaypointThinker(savebuffer_t *save, actionf_p1 thinker) -{ - polywaypoint_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save->p); - ht->speed = READINT32(save->p); - ht->sequence = READINT32(save->p); - ht->pointnum = READINT32(save->p); - ht->direction = READINT32(save->p); - ht->returnbehavior = READUINT8(save->p); - ht->continuous = READUINT8(save->p); - ht->stophere = READUINT8(save->p); - return &ht->thinker; -} - -static inline thinker_t* LoadPolyslidedoorThinker(savebuffer_t *save, actionf_p1 thinker) -{ - polyslidedoor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save->p); - ht->delay = READINT32(save->p); - ht->delayCount = READINT32(save->p); - ht->initSpeed = READINT32(save->p); - ht->speed = READINT32(save->p); - ht->initDistance = READINT32(save->p); - ht->distance = READINT32(save->p); - ht->initAngle = READUINT32(save->p); - ht->angle = READUINT32(save->p); - ht->revAngle = READUINT32(save->p); - ht->momx = READFIXED(save->p); - ht->momy = READFIXED(save->p); - ht->closing = READUINT8(save->p); - return &ht->thinker; -} - -static inline thinker_t* LoadPolyswingdoorThinker(savebuffer_t *save, actionf_p1 thinker) -{ - polyswingdoor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save->p); - ht->delay = READINT32(save->p); - ht->delayCount = READINT32(save->p); - ht->initSpeed = READINT32(save->p); - ht->speed = READINT32(save->p); - ht->initDistance = READINT32(save->p); - ht->distance = READINT32(save->p); - ht->closing = READUINT8(save->p); - return &ht->thinker; -} - -static inline thinker_t* LoadPolydisplaceThinker(savebuffer_t *save, actionf_p1 thinker) -{ - polydisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save->p); - ht->controlSector = LoadSector(READUINT32(save->p)); - ht->dx = READFIXED(save->p); - ht->dy = READFIXED(save->p); - ht->oldHeights = READFIXED(save->p); - return &ht->thinker; -} - -static inline thinker_t* LoadPolyrotdisplaceThinker(savebuffer_t *save, actionf_p1 thinker) -{ - polyrotdisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save->p); - ht->controlSector = LoadSector(READUINT32(save->p)); - ht->rotscale = READFIXED(save->p); - ht->turnobjs = READUINT8(save->p); - ht->oldHeights = READFIXED(save->p); - return &ht->thinker; -} - -static thinker_t* LoadPolyfadeThinker(savebuffer_t *save, actionf_p1 thinker) -{ - polyfade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); - ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save->p); - ht->sourcevalue = READINT32(save->p); - ht->destvalue = READINT32(save->p); - ht->docollision = (boolean)READUINT8(save->p); - ht->doghostfade = (boolean)READUINT8(save->p); - ht->ticbased = (boolean)READUINT8(save->p); - ht->duration = READINT32(save->p); - ht->timer = READINT32(save->p); - return &ht->thinker; -} - -static void P_NetUnArchiveThinkers(savebuffer_t *save) -{ - TracyCZone(__zone, true); - - thinker_t *currentthinker; - thinker_t *next; - UINT8 tclass; - UINT8 restoreNum = false; - UINT32 i; - UINT32 numloaded = 0; - - if (READUINT32(save->p) != ARCHIVEBLOCK_THINKERS) - I_Error("Bad $$$.sav at archive block Thinkers"); - - // Pre-calculate this lookup, because it was wasting - // a shit ton of time loading mobj thinkers. - CalculateDoomednumToMobjtype(); - - // remove all the current thinkers - for (i = 0; i < NUM_THINKERLISTS; i++) - { - for (currentthinker = thlist[i].next; currentthinker != &thlist[i]; currentthinker = next) - { - next = currentthinker->next; - - currentthinker->references = 0; // Heinous but this is the only place the assertion in P_UnlinkThinkers is wrong - - if (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker || currentthinker->function.acp1 == (actionf_p1)P_NullPrecipThinker) - P_RemoveSavegameMobj((mobj_t *)currentthinker); // item isn't saved, don't remove it - else - { - (next->prev = currentthinker->prev)->next = next; - R_DestroyLevelInterpolators(currentthinker); - Z_Free(currentthinker); - } - } - } - - // we don't want the removed mobjs to come back - P_InitThinkers(); - - // clear sector thinker pointers so they don't point to non-existant thinkers for all of eternity - for (i = 0; i < numsectors; i++) - { - sectors[i].floordata = sectors[i].ceilingdata = sectors[i].lightingdata = sectors[i].fadecolormapdata = NULL; - } - - // read in saved thinkers - for (i = 0; i < NUM_THINKERLISTS; i++) - { - for (;;) - { - thinker_t* th = NULL; - tclass = READUINT8(save->p); - - if (tclass == tc_end) - break; // leave the saved thinker reading loop - numloaded++; - - switch (tclass) - { - case tc_mobj: - th = LoadMobjThinker(save, (actionf_p1)P_MobjThinker, i); - break; - - case tc_ceiling: - th = LoadCeilingThinker(save, (actionf_p1)T_MoveCeiling); - break; - - case tc_crushceiling: - th = LoadCeilingThinker(save, (actionf_p1)T_CrushCeiling); - break; - - case tc_floor: - th = LoadFloormoveThinker(save, (actionf_p1)T_MoveFloor); - break; - - case tc_flash: - th = LoadLightflashThinker(save, (actionf_p1)T_LightningFlash); - break; - - case tc_strobe: - th = LoadStrobeThinker(save, (actionf_p1)T_StrobeFlash); - break; - - case tc_glow: - th = LoadGlowThinker(save, (actionf_p1)T_Glow); - break; - - case tc_fireflicker: - th = LoadFireflickerThinker(save, (actionf_p1)T_FireFlicker); - break; - - case tc_elevator: - th = LoadElevatorThinker(save, (actionf_p1)T_MoveElevator, true); - break; - - case tc_continuousfalling: - th = LoadContinuousFallThinker(save, (actionf_p1)T_ContinuousFalling); - break; - - case tc_thwomp: - th = LoadThwompThinker(save, (actionf_p1)T_ThwompSector); - break; - - case tc_noenemies: - th = LoadNoEnemiesThinker(save, (actionf_p1)T_NoEnemiesSector); - break; - - case tc_eachtime: - th = LoadEachTimeThinker(save, (actionf_p1)T_EachTimeThinker); - break; - - case tc_raisesector: - th = LoadRaiseThinker(save, (actionf_p1)T_RaiseSector); - break; - - case tc_camerascanner: - th = LoadElevatorThinker(save, (actionf_p1)T_CameraScanner, false); - break; - - case tc_bouncecheese: - th = LoadBounceCheeseThinker(save, (actionf_p1)T_BounceCheese); - break; - - case tc_startcrumble: - th = LoadCrumbleThinker(save, (actionf_p1)T_StartCrumble); - break; - - case tc_marioblock: - th = LoadMarioBlockThinker(save, (actionf_p1)T_MarioBlock); - break; - - case tc_marioblockchecker: - th = LoadMarioCheckThinker(save, (actionf_p1)T_MarioBlockChecker); - break; - - case tc_floatsector: - th = LoadFloatThinker(save, (actionf_p1)T_FloatSector); - break; - - case tc_laserflash: - th = LoadLaserThinker(save, (actionf_p1)T_LaserFlash); - break; - - case tc_lightfade: - th = LoadLightlevelThinker(save, (actionf_p1)T_LightFade); - break; - - case tc_executor: - th = LoadExecutorThinker(save, (actionf_p1)T_ExecutorDelay); - restoreNum = true; - break; - - case tc_disappear: - th = LoadDisappearThinker(save, (actionf_p1)T_Disappear); - break; - - case tc_fade: - th = LoadFadeThinker(save, (actionf_p1)T_Fade); - break; - - case tc_fadecolormap: - th = LoadFadeColormapThinker(save, (actionf_p1)T_FadeColormap); - break; - - case tc_planedisplace: - th = LoadPlaneDisplaceThinker(save, (actionf_p1)T_PlaneDisplace); - break; - case tc_polyrotate: - th = LoadPolyrotatetThinker(save, (actionf_p1)T_PolyObjRotate); - break; - - case tc_polymove: - th = LoadPolymoveThinker(save, (actionf_p1)T_PolyObjMove); - break; - - case tc_polywaypoint: - th = LoadPolywaypointThinker(save, (actionf_p1)T_PolyObjWaypoint); - break; - - case tc_polyslidedoor: - th = LoadPolyslidedoorThinker(save, (actionf_p1)T_PolyDoorSlide); - break; - - case tc_polyswingdoor: - th = LoadPolyswingdoorThinker(save, (actionf_p1)T_PolyDoorSwing); - break; - - case tc_polyflag: - th = LoadPolymoveThinker(save, (actionf_p1)T_PolyObjFlag); - break; - - case tc_polydisplace: - th = LoadPolydisplaceThinker(save, (actionf_p1)T_PolyObjDisplace); - break; - - case tc_polyrotdisplace: - th = LoadPolyrotdisplaceThinker(save, (actionf_p1)T_PolyObjRotDisplace); - break; - - case tc_polyfade: - th = LoadPolyfadeThinker(save, (actionf_p1)T_PolyObjFade); - break; - - case tc_dynslopeline: - th = LoadDynamicLineSlopeThinker(save, (actionf_p1)T_DynamicSlopeLine); - break; - - case tc_dynslopevert: - th = LoadDynamicVertexSlopeThinker(save, (actionf_p1)T_DynamicSlopeVert); - break; - - case tc_scroll: - th = LoadScrollThinker(save, (actionf_p1)T_Scroll); - break; - - case tc_friction: - th = LoadFrictionThinker(save, (actionf_p1)T_Friction); - break; - - case tc_pusher: - th = LoadPusherThinker(save, (actionf_p1)T_Pusher); - break; - - default: - I_Error("P_UnarchiveSpecials: Unknown tclass %d in savegame", tclass); - } - if (th) - P_AddThinker(i, th); - } - - CONS_Debug(DBG_NETPLAY, "%u thinkers loaded in list %d\n", numloaded, i); - } - - // Set each skyboxmo to the first skybox (or NULL) - skyboxmo[0] = skyboxviewpnts[0]; - skyboxmo[1] = skyboxcenterpnts[0]; - - if (restoreNum) - { - executor_t *delay = NULL; - UINT32 mobjnum; - for (currentthinker = thlist[THINK_MAIN].next; currentthinker != &thlist[THINK_MAIN]; currentthinker = currentthinker->next) - { - if (currentthinker->function.acp1 != (actionf_p1)T_ExecutorDelay) - continue; - delay = (void *)currentthinker; - if (!(mobjnum = (UINT32)(size_t)delay->caller)) - continue; - delay->caller = P_FindNewPosition(mobjnum); - } - } - TracyCZoneEnd(__zone); -} - /////////////////////////////////////////////////////////////////////////////// // // haleyjd 03/26/06: PolyObject saving code // -#define PD_FLAGS 0x01 -#define PD_TRANS 0x02 -static inline void P_ArchivePolyObj(savebuffer_t *save, polyobj_t *po) +enum pobj_diff_t { - TracyCZone(__zone, true); + PD_FLAGS, + PD_TRANS, + PD__MAX +}; - UINT8 diff = 0; - WRITEINT32(save->p, po->id); - WRITEANGLE(save->p, po->angle); - - WRITEFIXED(save->p, po->spawnSpot.x); - WRITEFIXED(save->p, po->spawnSpot.y); - - if (po->flags != po->spawnflags) - diff |= PD_FLAGS; - if (po->translucency != po->spawntrans) - diff |= PD_TRANS; - - WRITEUINT8(save->p, diff); - - if (diff & PD_FLAGS) - WRITEINT32(save->p, po->flags); - if (diff & PD_TRANS) - WRITEINT32(save->p, po->translucency); - - TracyCZoneEnd(__zone); -} - -static inline void P_UnArchivePolyObj(savebuffer_t *save, polyobj_t *po) +static inline void P_SynchPolyObj(savebuffer_t *save, polyobj_t *po) { - TracyCZone(__zone, true); - INT32 id; UINT32 angle; fixed_t x, y; - UINT8 diff; + UINT8 diff[(PD__MAX>>3) + 1] = {0}; + INT32 j = 0; - // nullify all polyobject thinker pointers; - // the thinkers themselves will fight over who gets the field - // when they first start to run. - po->thinker = NULL; + if (save->write) + { + DIFF(po->flags != po->spawnflags, PD_FLAGS); + DIFF(po->translucency != po->spawntrans, PD_FLAGS); + } + else + { + // nullify all polyobject thinker pointers; + // the thinkers themselves will fight over who gets the field + // when they first start to run. + po->thinker = NULL; + } - id = READINT32(save->p); + id = P_SyncINT32(save, po->id); - angle = READANGLE(save->p); + angle = P_SyncAngle(save, po->angle); - x = READFIXED(save->p); - y = READFIXED(save->p); + x = P_SyncFixed(save, po->spawnSpot.x); + y = P_SyncFixed(save, po->spawnSpot.y); - diff = READUINT8(save->p); + do + SYNC(diff[j]); + while (diff[j++] & 0x80); - if (diff & PD_FLAGS) - po->flags = READINT32(save->p); - if (diff & PD_TRANS) - po->translucency = READINT32(save->p); + SYNCF(PD_FLAGS, po->flags); + SYNCF(PD_TRANS, po->translucency); - // if the object is bad or isn't in the id hash, we can do nothing more - // with it, so return now - if (po->isBad || po != Polyobj_GetForNum(id)) - return; + if (!save->write) + { + // if the object is bad or isn't in the id hash, we can do nothing more + // with it, so return now + if (po->isBad || po != Polyobj_GetForNum(id)) + return; - // rotate and translate polyobject - Polyobj_MoveOnLoad(po, angle, x, y); - - TracyCZoneEnd(__zone); + // rotate and translate polyobject + Polyobj_MoveOnLoad(po, angle, x, y); + } } -static inline void P_ArchivePolyObjects(savebuffer_t *save) +static inline void P_SyncPolyObjects(savebuffer_t *save) { - TracyCZone(__zone, true); - - INT32 i; - - WRITEUINT32(save->p, ARCHIVEBLOCK_POBJS); - - // save number of polyobjects - WRITEINT32(save->p, numPolyObjects); - - for (i = 0; i < numPolyObjects; ++i) - P_ArchivePolyObj(save, &PolyObjects[i]); - - TracyCZoneEnd(__zone); -} - -static inline void P_UnArchivePolyObjects(savebuffer_t *save) -{ - TracyCZone(__zone, true); - INT32 i, numSavedPolys; - if (READUINT32(save->p) != ARCHIVEBLOCK_POBJS) + if (P_SyncUINT32(save, ARCHIVEBLOCK_POBJS) != ARCHIVEBLOCK_POBJS) I_Error("Bad $$$.sav at archive block Pobjs"); - numSavedPolys = READINT32(save->p); + numSavedPolys = P_SyncINT32(save, numPolyObjects); if (numSavedPolys != numPolyObjects) - I_Error("P_UnArchivePolyObjects: polyobj count inconsistency\n"); + I_Error("P_SynchronizePolyObjects: polyobj count inconsistency\n"); for (i = 0; i < numSavedPolys; ++i) - P_UnArchivePolyObj(save, &PolyObjects[i]); - - TracyCZoneEnd(__zone); + P_SynchPolyObj(save, &PolyObjects[i]); } static mobj_t *RelinkMobj(mobj_t **ptr) @@ -5154,89 +3748,88 @@ static void P_RelinkPointers(void) } } -static inline void P_NetArchiveSpecials(savebuffer_t *save) +static inline void P_NetSyncSpecials(savebuffer_t *save) { TracyCZone(__zone, true); size_t i, z; - - WRITEUINT32(save->p, ARCHIVEBLOCK_SPECIALS); - - // itemrespawn queue for deathmatch - i = iquetail; - while (iquehead != i) - { - for (z = 0; z < nummapthings; z++) - { - if (&mapthings[z] == itemrespawnque[i]) - { - WRITEUINT32(save->p, z); - break; - } - } - WRITEUINT32(save->p, itemrespawntime[i]); - i = (i + 1) & (ITEMQUESIZE-1); - } - - // end delimiter - WRITEUINT32(save->p, 0xffffffff); - - // Sky number - WRITESTRINGN(save->p, globallevelskytexture, 9); - - // Current global weather type - WRITEUINT8(save->p, globalweather); - - if (metalplayback) // Is metal sonic running? - { - WRITEUINT8(save->p, 0x01); - G_SaveMetal(&save->p); - } - else - WRITEUINT8(save->p, 0x00); - TracyCZoneEnd(__zone); -} - -static void P_NetUnArchiveSpecials(savebuffer_t *save) -{ - TracyCZone(__zone, true); - char skytex[9]; - size_t i; - if (READUINT32(save->p) != ARCHIVEBLOCK_SPECIALS) + if (P_SyncUINT32(save, ARCHIVEBLOCK_SPECIALS) != ARCHIVEBLOCK_SPECIALS) I_Error("Bad $$$.sav at archive block Specials"); - // BP: added save itemrespawn queue for deathmatch - iquetail = iquehead = 0; - while ((i = READUINT32(save->p)) != 0xffffffff) + if (save->write) { - itemrespawnque[iquehead] = &mapthings[i]; - itemrespawntime[iquehead++] = READINT32(save->p); + // itemrespawn queue for deathmatch + i = iquetail; + while (iquehead != i) + { + for (z = 0; z < nummapthings; z++) + { + if (&mapthings[z] == itemrespawnque[i]) + { + WRITEUINT32(save->p, z); + break; + } + } + WRITEUINT32(save->p, itemrespawntime[i]); + i = (i + 1) & (ITEMQUESIZE-1); + } + + // end delimiter + WRITEUINT32(save->p, 0xffffffff); + } + else + { + // BP: added save itemrespawn queue for deathmatch + iquetail = iquehead = 0; + while ((i = READUINT32(save->p)) != 0xffffffff) + { + itemrespawnque[iquehead] = &mapthings[i]; + itemrespawntime[iquehead++] = READINT32(save->p); + } } - READSTRINGN(save->p, skytex, sizeof(skytex)); - if (strcmp(skytex, globallevelskytexture)) + // Sky number + P_SyncStringN(save, globallevelskytexture, 9); + + if (!save->write && strcmp(skytex, globallevelskytexture)) P_SetupLevelSky(skytex, true); - globalweather = READUINT8(save->p); + // Current global weather type + SYNC(globalweather); - if (globalweather) + if (!save->write) { - if (curWeather == globalweather) - curWeather = PRECIP_NONE; + if (globalweather) + { + if (curWeather == globalweather) + curWeather = PRECIP_NONE; - P_SwitchWeather(globalweather); - } - else // PRECIP_NONE - { - if (curWeather != PRECIP_NONE) P_SwitchWeather(globalweather); + } + else // PRECIP_NONE + { + if (curWeather != PRECIP_NONE) + P_SwitchWeather(globalweather); + } } - if (READUINT8(save->p) == 0x01) // metal sonic - G_LoadMetal(&save->p); - + if (save->write) + { + if (metalplayback) // Is metal sonic running? + { + WRITEUINT8(save->p, 0x01); + G_SaveMetal(&save->p); + } + else + WRITEUINT8(save->p, 0x00); + } + else + { + if (READUINT8(save->p) == 0x01) // metal sonic + G_LoadMetal(&save->p); + } TracyCZoneEnd(__zone); } @@ -5305,211 +3898,51 @@ static inline void P_UnArchiveSPGame(savebuffer_t *save, INT16 mapoverride) TracyCZoneEnd(__zone); } -static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) +static boolean P_NetSyncMisc(savebuffer_t *save, boolean resending) { TracyCZone(__zone, true); - size_t i; + size_t i, j; + size_t numTasks; + const INT16 prevgamemap = gamemap; - WRITEUINT32(save->p, ARCHIVEBLOCK_MISC); + if (P_SyncUINT32(save, ARCHIVEBLOCK_MISC) != ARCHIVEBLOCK_MISC) + I_Error("Bad $$$.sav at archive block Misc"); if (resending) - WRITEUINT32(save->p, gametic); - WRITEINT16(save->p, gamemap); + SYNC(gametic); - if (gamestate != GS_LEVEL) - WRITEINT16(save->p, GS_WAITINGPLAYERS); // nice hack to put people back into waitingplayers + SYNC(gamemap); + + if (save->write) + { + if (gamestate != GS_LEVEL) + WRITEINT16(save->p, GS_WAITINGPLAYERS); // nice hack to put people back into waitingplayers + else + WRITEINT16(save->p, gamestate); + } else - WRITEINT16(save->p, gamestate); - WRITEINT16(save->p, gametype); + { + if (!gamemap || gamemap > nummapheaders || !mapheaderinfo[gamemap-1]) + I_Error("P_NetUnArchiveMisc: Internal map ID %d not found (nummapheaders = %d)", gamemap-1, nummapheaders); + // tell the sound code to reset the music since we're skipping what + // normally sets this flag + if (!resending) + mapmusflags |= MUSIC_RELOADRESET; + G_SetGamestate(READINT16(save->p)); + } + + SYNC(gametype); + + if (save->write) { UINT32 pig = 0; for (i = 0; i < MAXPLAYERS; i++) pig |= (playeringame[i] != 0)<p, pig); } - - WRITEUINT32(save->p, P_GetRandSeed()); - - WRITEUINT32(save->p, tokenlist); - - WRITEUINT8(save->p, encoremode); - WRITEUINT8(save->p, mapmusrng); - - WRITEUINT32(save->p, leveltime); - WRITEINT16(save->p, lastmap); - WRITEUINT16(save->p, bossdisabled); - WRITEUINT8(save->p, ringsactive); - WRITEUINT8(save->p, stackingactive); - WRITEUINT8(save->p, chainingactive); - WRITEUINT8(save->p, slipdashactive); - WRITEUINT8(save->p, purpledriftactive); - WRITEUINT8(save->p, slopeboostactive); - WRITEUINT8(save->p, draftingactive); - WRITEUINT8(save->p, airdropactive); - WRITEUINT8(save->p, bumpsparkactive); - - for (i = 0; i < 12; i++) - { - WRITEINT16(save->p, votelevels[i][0]); - WRITEINT16(save->p, votelevels[i][1]); - } - - for (i = 0; i < MAXPLAYERS; i++) - WRITESINT8(save->p, votes[i]); - - WRITESINT8(save->p, pickedvote); - - WRITEUINT16(save->p, emeralds); - { - UINT8 globools = 0; - if (stagefailed) - globools |= 1; - if (stoppedclock) - globools |= (1<<1); - WRITEUINT8(save->p, globools); - } - - WRITEUINT32(save->p, token); - WRITEUINT32(save->p, bluescore); - WRITEUINT32(save->p, redscore); - - WRITEUINT16(save->p, skincolor_redteam); - WRITEUINT16(save->p, skincolor_blueteam); - WRITEUINT16(save->p, skincolor_redring); - WRITEUINT16(save->p, skincolor_bluering); - - WRITEINT32(save->p, modulothing); - - WRITEINT16(save->p, autobalance); - WRITEINT16(save->p, teamscramble); - - for (i = 0; i < MAXPLAYERS; i++) - WRITEINT16(save->p, scrambleplayers[i]); - - for (i = 0; i < MAXPLAYERS; i++) - WRITEINT16(save->p, scrambleteams[i]); - - WRITEINT16(save->p, scrambletotal); - WRITEINT16(save->p, scramblecount); - - WRITEUINT32(save->p, racecountdown); - WRITEUINT32(save->p, exitcountdown); - - // exitcondition_t - WRITEUINT8(save->p, g_exit.losing); - WRITEUINT8(save->p, g_exit.retry); - WRITEUINT8(save->p, g_exit.hasfinished); - - WRITEFIXED(save->p, gravity); - WRITEFIXED(save->p, mapobjectscale); - - // SRB2kart - WRITEINT32(save->p, nummapboxes); - WRITEINT32(save->p, numgotboxes); - WRITEUINT8(save->p, numtargets); - WRITEUINT8(save->p, itembreaker); - - WRITEUINT8(save->p, gamespeed); - WRITEUINT8(save->p, numlaps); - WRITEUINT8(save->p, franticitems); - WRITEUINT8(save->p, comeback); - - WRITESINT8(save->p, speedscramble); - WRITESINT8(save->p, encorescramble); - - - // WANTED system - WRITESINT8(save->p, mostwanted); - for (i = 0; i < 4; i++) - WRITESINT8(save->p, battlewanted[i]); - - WRITEUINT32(save->p, wantedcalcdelay); - WRITEUINT32(save->p, indirectitemcooldown); - WRITEUINT32(save->p, hyubgone); - WRITEUINT32(save->p, mapreset); - - WRITEUINT8(save->p, spectateGriefed); - - WRITEUINT8(save->p, thwompsactive); - WRITEUINT8(save->p, lastLowestLap); - WRITESINT8(save->p, spbplace); - WRITEUINT8(save->p, startedInFreePlay); - - WRITEUINT32(save->p, introtime); - WRITEUINT32(save->p, starttime); - - WRITEINT32(save->p, hyudorotime); - WRITEINT32(save->p, stealtime); - WRITEINT32(save->p, sneakertime); - WRITEINT32(save->p, waterpaneltime); - WRITEINT32(save->p, itemtime); - WRITEINT32(save->p, bubbletime); - WRITEINT32(save->p, comebacktime); - WRITEINT32(save->p, bumptime); - WRITEINT32(save->p, greasetics); - WRITEINT32(save->p, wipeoutslowtime); - WRITEINT32(save->p, wantedreduce); - WRITEINT32(save->p, wantedfrequency); - - WRITEUINT32(save->p, timelimitintics); - WRITEUINT32(save->p, extratimeintics); - WRITEUINT32(save->p, secretextratime); - - // Is it paused? - if (paused) - WRITEUINT8(save->p, 0x2f); else - WRITEUINT8(save->p, 0x2e); - - // Only the server uses this, but it - // needs synched for remote admins anyway. - WRITEUINT32(save->p, schedule_len); - for (i = 0; i < schedule_len; i++) - { - scheduleTask_t *task = schedule[i]; - WRITEINT16(save->p, task->basetime); - WRITEINT16(save->p, task->timer); - WRITESTRING(save->p, task->command); - } - - WRITEUINT32(save->p, cht_debug); - - TracyCZoneEnd(__zone); -} - -FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) -{ - TracyCZone(__zone, true); - - size_t i, j; - size_t numTasks; - - const INT16 prevgamemap = gamemap; - - if (READUINT32(save->p) != ARCHIVEBLOCK_MISC) - I_Error("Bad $$$.sav at archive block Misc"); - - if (reloading) - gametic = READUINT32(save->p); - - gamemap = READINT16(save->p); - - // gamemap changed; we assume that its map header is always valid, - // so make it so - if (!gamemap || gamemap > nummapheaders || !mapheaderinfo[gamemap-1]) - I_Error("P_NetUnArchiveMisc: Internal map ID %d not found (nummapheaders = %d)", gamemap-1, nummapheaders); - - // tell the sound code to reset the music since we're skipping what - // normally sets this flag - if (!reloading) - mapmusflags |= MUSIC_RELOADRESET; - - G_SetGamestate(READINT16(save->p)); - - gametype = READINT16(save->p); - { UINT32 pig = READUINT32(save->p); for (i = 0; i < MAXPLAYERS; i++) @@ -5519,359 +3952,385 @@ FUNCINLINE static ATTRINLINE boolean P_NetUnArchiveMisc(savebuffer_t *save, bool } } - P_SetRandSeed(READUINT32(save->p)); + P_SetRandSeed(P_SyncUINT32(save, P_GetRandSeed())); - tokenlist = READUINT32(save->p); + SYNC(tokenlist); - encoremode = (boolean)READUINT8(save->p); - - mapmusrng = READUINT8(save->p); + SYNCBOOLEAN(encoremode); + SYNC(mapmusrng); - // Only reload the level during a gamestate reload - // if the map is horribly mismatched somehow. Minor - // differences in level state are already handled - // by other parts of the reload, so doing this - // on *every* reload wastes lots of time that we - // will need for rollback down the road. - if (!reloading || prevgamemap != gamemap) + if (!save->write) { - if (!P_LoadLevel(true, reloading)) + // Only reload the level during a gamestate reload + // if the map is horribly mismatched somehow. Minor + // differences in level state are already handled + // by other parts of the reload, so doing this + // on *every* reload wastes lots of time that we + // will need for rollback down the road. + if (!resending || prevgamemap != gamemap) { - CONS_Alert(CONS_ERROR, M_GetText("Can't load the level!\n")); - return false; + if (!P_LoadLevel(true, resending)) + { + CONS_Alert(CONS_ERROR, M_GetText("Can't load the level!\n")); + return false; + } + } + else + { + // Only reload stuff that can we modify in the save states themselves. + // This is still orders of magnitude faster than a full level reload. + // Considered memcpy, but it's complicated -- save that for local saves. + + sector_t *ss = sectors; + sector_t *spawnss = spawnsectors; + for (i = 0; i < numsectors; i++, ss++, spawnss++) + { + ss->floorheight = spawnss->floorheight; + ss->ceilingheight = spawnss->ceilingheight; + ss->floorpic = spawnss->floorpic; + ss->ceilingpic = spawnss->ceilingpic; + ss->lightlevel = spawnss->lightlevel; + ss->special = spawnss->special; + ss->floor_xoffs = spawnss->floor_xoffs; + ss->floor_yoffs = spawnss->floor_yoffs; + ss->ceiling_xoffs = spawnss->ceiling_xoffs; + ss->ceiling_yoffs = spawnss->ceiling_yoffs; + ss->floorpic_angle = spawnss->floorpic_angle; + ss->ceilingpic_angle = spawnss->ceilingpic_angle; + + if (Tag_Compare(&ss->tags, &spawnss->tags) == false) + { + if (spawnss->tags.count) + { + ss->tags.count = spawnss->tags.count; + ss->tags.tags = + memcpy( + Z_Realloc( + ss->tags.tags, + spawnss->tags.count * sizeof(mtag_t), + PU_LEVEL, + NULL + ), + spawnss->tags.tags, + spawnss->tags.count * sizeof(mtag_t) + ); + } + else + { + ss->tags.count = 0; + Z_Free(ss->tags.tags); + } + } + + ss->extra_colormap = ss->spawn_extra_colormap; + ss->crumblestate = CRUMBLE_NONE; + ss->floorlightlevel = spawnss->floorlightlevel; + ss->floorlightabsolute = spawnss->floorlightabsolute; + ss->ceilinglightlevel = spawnss->ceilinglightlevel; + ss->ceilinglightabsolute = spawnss->ceilinglightabsolute; + ss->flags = spawnss->flags; + ss->specialflags = spawnss->specialflags; + ss->damagetype = spawnss->damagetype; + ss->triggertag = spawnss->triggertag; + ss->triggerer = spawnss->triggerer; + ss->gravity = spawnss->gravity; + ss->action = spawnss->action; + + memcpy(ss->args, spawnss->args, NUM_SCRIPT_ARGS * sizeof(*ss->args)); + + for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) + { + size_t len = 0; + + if (spawnss->stringargs[j]) + { + len = strlen(spawnss->stringargs[j]); + } + + if (!len) + { + Z_Free(ss->stringargs[j]); + ss->stringargs[j] = NULL; + } + else + { + ss->stringargs[j] = Z_Realloc(ss->stringargs[j], len + 1, PU_LEVEL, NULL); + M_Memcpy(ss->stringargs[j], spawnss->stringargs[j], len); + ss->stringargs[j][len] = '\0'; + } + } + + ss->activation = spawnss->activation; + ss->botController.flags = spawnss->botController.flags; + ss->botController.forceAngle = spawnss->botController.forceAngle; + + if (ss->ffloors) + { + ffloor_t *rover; + for (rover = ss->ffloors; rover; rover = rover->next) + { + rover->fofflags = rover->spawnflags; + rover->alpha = rover->spawnalpha; + } + } + } + + line_t *li = lines; + line_t *spawnli = spawnlines; + side_t *si = NULL; + side_t *spawnsi = NULL; + for (i = 0; i < numlines; i++, spawnli++, li++) + { + li->flags = spawnli->flags; + li->special = spawnli->special; + li->callcount = 0; + + if (Tag_Compare(&li->tags, &spawnli->tags) == false) + { + if (spawnli->tags.count) + { + li->tags.count = spawnli->tags.count; + li->tags.tags = + memcpy( + Z_Realloc( + li->tags.tags, + spawnli->tags.count * sizeof(mtag_t), + PU_LEVEL, + NULL + ), + spawnli->tags.tags, + spawnli->tags.count * sizeof(mtag_t) + ); + + } + else + { + li->tags.count = 0; + Z_Free(li->tags.tags); + } + } + + memcpy(li->args, spawnli->args, NUM_SCRIPT_ARGS * sizeof(*li->args)); + + for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) + { + size_t len = 0; + + if (spawnli->stringargs[j]) + { + len = strlen(spawnli->stringargs[j]); + } + + if (!len) + { + Z_Free(li->stringargs[j]); + li->stringargs[j] = NULL; + } + else + { + li->stringargs[j] = Z_Realloc(li->stringargs[j], len + 1, PU_LEVEL, NULL); + M_Memcpy(li->stringargs[j], spawnli->stringargs[j], len); + li->stringargs[j][len] = '\0'; + } + } + + li->executordelay = spawnli->executordelay; + li->activation = spawnli->activation; + + if (li->sidenum[0] != 0xffff) + { + si = &sides[li->sidenum[0]]; + spawnsi = &spawnsides[li->sidenum[0]]; + + si->textureoffset = spawnsi->textureoffset; + si->toptexture = spawnsi->toptexture; + si->bottomtexture = spawnsi->bottomtexture; + si->midtexture = spawnsi->midtexture; + } + + if (li->sidenum[1] != 0xffff) + { + si = &sides[li->sidenum[1]]; + spawnsi = &spawnsides[li->sidenum[1]]; + + si->textureoffset = spawnsi->textureoffset; + si->toptexture = spawnsi->toptexture; + si->bottomtexture = spawnsi->bottomtexture; + si->midtexture = spawnsi->midtexture; + } + } + + Taglist_InitGlobalTables(); } } - else + + SYNC(leveltime); + SYNC(lastmap); + SYNC(bossdisabled); + SYNCBOOLEAN(ringsactive); + SYNCBOOLEAN(stackingactive); + SYNCBOOLEAN(chainingactive); + SYNCBOOLEAN(slipdashactive); + SYNCBOOLEAN(purpledriftactive); + SYNCBOOLEAN(slopeboostactive); + SYNCBOOLEAN(draftingactive); + SYNCBOOLEAN(airdropactive); + SYNC(bumpsparkactive); + SYNC(invintype); + + for (i = 0; i < sizeof(votelevels)/sizeof(*votelevels); i++) { - // Only reload stuff that can we modify in the save states themselves. - // This is still orders of magnitude faster than a full level reload. - // Considered memcpy, but it's complicated -- save that for local saves. - - sector_t *ss = sectors; - sector_t *spawnss = spawnsectors; - for (i = 0; i < numsectors; i++, ss++, spawnss++) - { - ss->floorheight = spawnss->floorheight; - ss->ceilingheight = spawnss->ceilingheight; - ss->floorpic = spawnss->floorpic; - ss->ceilingpic = spawnss->ceilingpic; - ss->lightlevel = spawnss->lightlevel; - ss->special = spawnss->special; - ss->floor_xoffs = spawnss->floor_xoffs; - ss->floor_yoffs = spawnss->floor_yoffs; - ss->ceiling_xoffs = spawnss->ceiling_xoffs; - ss->ceiling_yoffs = spawnss->ceiling_yoffs; - ss->floorpic_angle = spawnss->floorpic_angle; - ss->ceilingpic_angle = spawnss->ceilingpic_angle; - - if (Tag_Compare(&ss->tags, &spawnss->tags) == false) - { - if (spawnss->tags.count) - { - ss->tags.count = spawnss->tags.count; - ss->tags.tags = - memcpy( - Z_Realloc( - ss->tags.tags, - spawnss->tags.count * sizeof(mtag_t), - PU_LEVEL, - NULL - ), - spawnss->tags.tags, - spawnss->tags.count * sizeof(mtag_t) - ); - } - else - { - ss->tags.count = 0; - Z_Free(ss->tags.tags); - } - } - - ss->extra_colormap = ss->spawn_extra_colormap; - ss->crumblestate = CRUMBLE_NONE; - ss->floorlightlevel = spawnss->floorlightlevel; - ss->floorlightabsolute = spawnss->floorlightabsolute; - ss->ceilinglightlevel = spawnss->ceilinglightlevel; - ss->ceilinglightabsolute = spawnss->ceilinglightabsolute; - ss->flags = spawnss->flags; - ss->specialflags = spawnss->specialflags; - ss->damagetype = spawnss->damagetype; - ss->triggertag = spawnss->triggertag; - ss->triggerer = spawnss->triggerer; - ss->gravity = spawnss->gravity; - ss->action = spawnss->action; - - memcpy(ss->args, spawnss->args, NUM_SCRIPT_ARGS * sizeof(*ss->args)); - - for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) - { - size_t len = 0; - - if (spawnss->stringargs[j]) - { - len = strlen(spawnss->stringargs[j]); - } - - if (!len) - { - Z_Free(ss->stringargs[j]); - ss->stringargs[j] = NULL; - } - else - { - ss->stringargs[j] = Z_Realloc(ss->stringargs[j], len + 1, PU_LEVEL, NULL); - M_Memcpy(ss->stringargs[j], spawnss->stringargs[j], len); - ss->stringargs[j][len] = '\0'; - } - } - - ss->activation = spawnss->activation; - ss->botController.flags = spawnss->botController.flags; - ss->botController.forceAngle = spawnss->botController.forceAngle; - - if (ss->ffloors) - { - ffloor_t *rover; - for (rover = ss->ffloors; rover; rover = rover->next) - { - rover->fofflags = rover->spawnflags; - rover->alpha = rover->spawnalpha; - } - } - } - - line_t *li = lines; - line_t *spawnli = spawnlines; - side_t *si = NULL; - side_t *spawnsi = NULL; - for (i = 0; i < numlines; i++, spawnli++, li++) - { - li->flags = spawnli->flags; - li->special = spawnli->special; - li->callcount = 0; - - if (Tag_Compare(&li->tags, &spawnli->tags) == false) - { - if (spawnli->tags.count) - { - li->tags.count = spawnli->tags.count; - li->tags.tags = - memcpy( - Z_Realloc( - li->tags.tags, - spawnli->tags.count * sizeof(mtag_t), - PU_LEVEL, - NULL - ), - spawnli->tags.tags, - spawnli->tags.count * sizeof(mtag_t) - ); - - } - else - { - li->tags.count = 0; - Z_Free(li->tags.tags); - } - } - - memcpy(li->args, spawnli->args, NUM_SCRIPT_ARGS * sizeof(*li->args)); - - for (j = 0; j < NUM_SCRIPT_STRINGARGS; j++) - { - size_t len = 0; - - if (spawnli->stringargs[j]) - { - len = strlen(spawnli->stringargs[j]); - } - - if (!len) - { - Z_Free(li->stringargs[j]); - li->stringargs[j] = NULL; - } - else - { - li->stringargs[j] = Z_Realloc(li->stringargs[j], len + 1, PU_LEVEL, NULL); - M_Memcpy(li->stringargs[j], spawnli->stringargs[j], len); - li->stringargs[j][len] = '\0'; - } - } - - li->executordelay = spawnli->executordelay; - li->activation = spawnli->activation; - - if (li->sidenum[0] != 0xffff) - { - si = &sides[li->sidenum[0]]; - spawnsi = &spawnsides[li->sidenum[0]]; - - si->textureoffset = spawnsi->textureoffset; - si->toptexture = spawnsi->toptexture; - si->bottomtexture = spawnsi->bottomtexture; - si->midtexture = spawnsi->midtexture; - } - - if (li->sidenum[1] != 0xffff) - { - si = &sides[li->sidenum[1]]; - spawnsi = &spawnsides[li->sidenum[1]]; - - si->textureoffset = spawnsi->textureoffset; - si->toptexture = spawnsi->toptexture; - si->bottomtexture = spawnsi->bottomtexture; - si->midtexture = spawnsi->midtexture; - } - } - - Taglist_InitGlobalTables(); - } - - // get the time - leveltime = READUINT32(save->p); - lastmap = READINT16(save->p); - bossdisabled = READUINT16(save->p); - ringsactive = READUINT8(save->p); - stackingactive = READUINT8(save->p); - chainingactive = READUINT8(save->p); - slipdashactive = READUINT8(save->p); - purpledriftactive = READUINT8(save->p); - slopeboostactive = READUINT8(save->p); - draftingactive = READUINT8(save->p); - airdropactive = READUINT8(save->p); - bumpsparkactive = READUINT8(save->p); - - for (i = 0; i < 12; i++) - { - votelevels[i][0] = READINT16(save->p); - votelevels[i][1] = READINT16(save->p); + SYNC(votelevels[i][0]); + SYNC(votelevels[i][1]); } for (i = 0; i < MAXPLAYERS; i++) - votes[i] = READSINT8(save->p); + SYNC(votes[i]); - pickedvote = READSINT8(save->p); + SYNC(pickedvote); - emeralds = READUINT16(save->p); + SYNC(emeralds); + if (save->write) + { + UINT8 globools = 0; + if (stagefailed) + globools |= 1; + if (stoppedclock) + globools |= (1<<1); + WRITEUINT8(save->p, globools); + } + else { UINT8 globools = READUINT8(save->p); stagefailed = !!(globools & 1); stoppedclock = !!(globools & (1<<1)); } - token = READUINT32(save->p); - bluescore = READUINT32(save->p); - redscore = READUINT32(save->p); + SYNC(token); + SYNC(bluescore); + SYNC(redscore); - skincolor_redteam = READUINT16(save->p); - skincolor_blueteam = READUINT16(save->p); - skincolor_redring = READUINT16(save->p); - skincolor_bluering = READUINT16(save->p); + SYNC(skincolor_redteam); + SYNC(skincolor_blueteam); + SYNC(skincolor_redring); + SYNC(skincolor_bluering); - modulothing = READINT32(save->p); + SYNC(modulothing); - autobalance = READINT16(save->p); - teamscramble = READINT16(save->p); + SYNC(autobalance); + SYNC(teamscramble); for (i = 0; i < MAXPLAYERS; i++) - scrambleplayers[i] = READINT16(save->p); + SYNC(scrambleplayers[i]); for (i = 0; i < MAXPLAYERS; i++) - scrambleteams[i] = READINT16(save->p); + SYNC(scrambleteams[i]); - scrambletotal = READINT16(save->p); - scramblecount = READINT16(save->p); + SYNC(scrambletotal); + SYNC(scramblecount); - racecountdown = READUINT32(save->p); - exitcountdown = READUINT32(save->p); + SYNC(racecountdown); + SYNC(exitcountdown); // exitcondition_t - g_exit.losing = READUINT8(save->p); - g_exit.retry = READUINT8(save->p); - g_exit.hasfinished = READUINT8(save->p); + SYNCBOOLEAN(g_exit.losing); + SYNCBOOLEAN(g_exit.retry); + SYNCBOOLEAN(g_exit.hasfinished); - gravity = READFIXED(save->p); - mapobjectscale = READFIXED(save->p); + SYNC(gravity); + SYNC(mapobjectscale); // SRB2kart - nummapboxes = READINT32(save->p); - numgotboxes = READINT32(save->p); - numtargets = READUINT8(save->p); - itembreaker = (boolean)READUINT8(save->p); + SYNC(nummapboxes); + SYNC(numgotboxes); + SYNC(numtargets); + SYNCBOOLEAN(itembreaker); - gamespeed = READUINT8(save->p); - numlaps = READUINT8(save->p); - franticitems = (boolean)READUINT8(save->p); - comeback = (boolean)READUINT8(save->p); + SYNC(gamespeed); + SYNC(numlaps); + SYNCBOOLEAN(franticitems); + SYNCBOOLEAN(comeback); - speedscramble = READSINT8(save->p); - encorescramble = READSINT8(save->p); + SYNC(speedscramble); + SYNC(encorescramble); - mostwanted = READSINT8(save->p); - for (i = 0; i < 4; i++) - battlewanted[i] = READSINT8(save->p); + // WANTED system + SYNC(mostwanted); + for (i = 0; i < sizeof(battlewanted)/sizeof(*battlewanted); i++) + SYNC(battlewanted[i]); - wantedcalcdelay = READUINT32(save->p); - hyubgone = READUINT32(save->p); - indirectitemcooldown = READUINT32(save->p); - mapreset = READUINT32(save->p); + SYNC(wantedcalcdelay); + SYNC(indirectitemcooldown); + SYNC(hyubgone); + SYNC(mapreset); - spectateGriefed = READUINT8(save->p); + SYNC(spectateGriefed); - thwompsactive = (boolean)READUINT8(save->p); - lastLowestLap = READUINT8(save->p); - spbplace = READSINT8(save->p); - startedInFreePlay = READUINT8(save->p); + SYNCBOOLEAN(thwompsactive); + SYNC(lastLowestLap); + SYNC(spbplace); + SYNCBOOLEAN(startedInFreePlay); - introtime = READUINT32(save->p); - starttime = READUINT32(save->p); + SYNC(introtime); + SYNC(starttime); - hyudorotime = READINT32(save->p); - stealtime = READINT32(save->p); - sneakertime = READINT32(save->p); - waterpaneltime = READINT32(save->p); - itemtime = READINT32(save->p); - bubbletime = READINT32(save->p); - comebacktime = READINT32(save->p); - bumptime = READINT32(save->p); - greasetics = READINT32(save->p); - wipeoutslowtime = READINT32(save->p); - wantedreduce = READINT32(save->p); - wantedfrequency = READINT32(save->p); - - timelimitintics = READUINT32(save->p); - extratimeintics = READUINT32(save->p); - secretextratime = READUINT32(save->p); + SYNC(hyudorotime); + SYNC(stealtime); + SYNC(sneakertime); + SYNC(waterpaneltime); + SYNC(itemtime); + SYNC(bubbletime); + SYNC(comebacktime); + SYNC(bumptime); + SYNC(greasetics); + SYNC(wipeoutslowtime); + SYNC(wantedreduce); + SYNC(wantedfrequency); - // Is it paused? - if (READUINT8(save->p) == 0x2f) - paused = true; + SYNC(timelimitintics); + SYNC(extratimeintics); + SYNC(secretextratime); - // Only the server uses this, but it - // needs synched for remote admins anyway. - Schedule_Clear(); + SYNC(paused); // surprisingly not a boolean - numTasks = READUINT32(save->p); - for (i = 0; i < numTasks; i++) + if (save->write) { - INT16 basetime; - INT16 timer; - char command[MAXTEXTCMD]; + // Only the server uses this, but it + // needs synched for remote admins anyway. + WRITEUINT32(save->p, schedule_len); + for (i = 0; i < schedule_len; i++) + { + scheduleTask_t *task = schedule[i]; + WRITEINT16(save->p, task->basetime); + WRITEINT16(save->p, task->timer); + WRITESTRING(save->p, task->command); + } + } + else + { + // Only the server uses this, but it + // needs synched for remote admins anyway. + Schedule_Clear(); - basetime = READINT16(save->p); - timer = READINT16(save->p); - READSTRING(save->p, command); + numTasks = READUINT32(save->p); + for (i = 0; i < numTasks; i++) + { + INT16 basetime; + INT16 timer; + char command[MAXTEXTCMD]; - Schedule_Add(basetime, timer, command); + basetime = READINT16(save->p); + timer = READINT16(save->p); + READSTRING(save->p, command); + + Schedule_Add(basetime, timer, command); + } } - cht_debug = READUINT32(save->p); - - TracyCZoneEnd(__zone); + SYNC(cht_debug); return true; + TracyCZoneEnd(__zone); } static inline void P_ArchiveLuabanksAndConsistency(savebuffer_t *save) @@ -5944,8 +4403,10 @@ void P_SaveNetGame(savebuffer_t *save, boolean resending) mobj_t *mobj; UINT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise + save->write = true; + CV_SaveNetVars(&save->p); - P_NetArchiveMisc(save, resending); + P_NetSyncMisc(save, resending); // Assign the mobjnumber for pointer tracking if (gamestate == GS_LEVEL) @@ -5958,28 +4419,28 @@ void P_SaveNetGame(savebuffer_t *save, boolean resending) mobj = (mobj_t *)th; if (UNLIKELY(mobj->type == MT_HOOP || mobj->type == MT_HOOPCOLLIDE || mobj->type == MT_HOOPCENTER // MT_SPARK: used for debug stuff - || mobj->type == MT_SPARK)) + || mobj->type == MT_SPARK || mobj->flags2 & MF2_DONTSYNC)) continue; mobj->mobjnum = i++; } } - P_NetArchivePlayers(save); - P_NetArchiveParties(save); + P_NetSyncPlayers(save); + P_NetSyncParties(save); if (gamestate == GS_LEVEL) { - P_NetArchiveWorld(save); - P_ArchivePolyObjects(save); - P_NetArchiveThinkers(save); - P_NetArchiveSpecials(save); - P_NetArchiveColormaps(save); - P_NetArchiveTubeWaypoints(save); - P_NetArchiveWaypoints(save); + P_NetSyncWorld(save); + P_SyncPolyObjects(save); + P_NetSyncThinkers(save); + P_NetSyncSpecials(save); + P_NetSyncColormaps(save); + P_NetSyncTubeWaypoints(save); + P_NetSyncWaypoints(save); } ACS_Archive(save); - LUA_Archive(save, true); + LUA_Sync(save, true, false); P_ArchiveLuabanksAndConsistency(save); @@ -6011,26 +4472,28 @@ boolean P_LoadNetGame(savebuffer_t *save, boolean reloading) { TracyCZone(__zone, true); + save->write = false; + CV_LoadNetVars(&save->p); - if (!P_NetUnArchiveMisc(save,reloading)) + if (!P_NetSyncMisc(save,reloading)) return false; - P_NetUnArchivePlayers(save); - P_NetUnArchiveParties(save); + P_NetSyncPlayers(save); + P_NetSyncParties(save); if (gamestate == GS_LEVEL) { - P_NetUnArchiveWorld(save); - P_UnArchivePolyObjects(save); - P_NetUnArchiveThinkers(save); - P_NetUnArchiveSpecials(save); - P_NetUnArchiveColormaps(save); - P_NetUnArchiveTubeWaypoints(save); - P_NetUnArchiveWaypoints(save); + P_NetSyncWorld(save); + P_SyncPolyObjects(save); + P_NetSyncThinkers(save); + P_NetSyncSpecials(save); + P_NetSyncColormaps(save); + P_NetSyncTubeWaypoints(save); + P_NetSyncWaypoints(save); P_RelinkPointers(); } ACS_UnArchive(save); - LUA_UnArchive(save, true, false); + LUA_Sync(save, true, false); // This is stupid and hacky, but maybe it'll work! P_SetRandSeed(P_GetInitSeed()); diff --git a/src/p_saveg.h b/src/p_saveg.h index ef35872cc..a57578bc2 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -51,6 +51,7 @@ struct savebuffer_t UINT8 *p; UINT8 *end; size_t size; + boolean write; }; boolean P_SaveBufferZAlloc(savebuffer_t *save, size_t alloc_size, INT32 tag, void *user);