Merge branch 'next' into 2214

This commit is contained in:
spherallic 2024-09-13 15:50:12 +02:00
commit 3c1a43f141
18 changed files with 2457 additions and 2163 deletions

View file

@ -1722,8 +1722,7 @@ badinput:
static boolean serverloading = false; static boolean serverloading = false;
static consvar_t * static consvar_t *ReadNetVar(save_t *p, char **return_value, boolean *return_stealth)
ReadNetVar (UINT8 **p, char **return_value, boolean *return_stealth)
{ {
UINT16 netid; UINT16 netid;
char *val; char *val;
@ -1731,10 +1730,10 @@ ReadNetVar (UINT8 **p, char **return_value, boolean *return_stealth)
consvar_t *cvar; consvar_t *cvar;
netid = READUINT16 (*p); netid = P_ReadUINT16(p);
val = (char *)*p; val = (char *)&p->buf[p->pos];
SKIPSTRING (*p); P_SkipString(p);
stealth = READUINT8 (*p); stealth = P_ReadUINT8(p);
cvar = CV_FindNetVar(netid); cvar = CV_FindNetVar(netid);
@ -1752,8 +1751,7 @@ ReadNetVar (UINT8 **p, char **return_value, boolean *return_stealth)
} }
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
static consvar_t * static consvar_t *ReadOldDemoVar(save_t *p, char **return_value, boolean *return_stealth)
ReadOldDemoVar (UINT8 **p, char **return_value, boolean *return_stealth)
{ {
UINT16 id; UINT16 id;
char *val; char *val;
@ -1761,10 +1759,10 @@ ReadOldDemoVar (UINT8 **p, char **return_value, boolean *return_stealth)
old_demo_var_t *demovar; old_demo_var_t *demovar;
id = READUINT16 (*p); id = P_ReadUINT16(p);
val = (char *)*p; val = (char *)&p->buf[p->pos];
SKIPSTRING (*p); P_SkipString(p);
stealth = READUINT8 (*p); stealth = P_ReadUINT8(p);
demovar = CV_FindOldDemoVar(id); demovar = CV_FindOldDemoVar(id);
@ -1783,8 +1781,7 @@ ReadOldDemoVar (UINT8 **p, char **return_value, boolean *return_stealth)
} }
#endif/*OLD22DEMOCOMPAT*/ #endif/*OLD22DEMOCOMPAT*/
static consvar_t * static consvar_t *ReadDemoVar(save_t *p, char **return_value, boolean *return_stealth)
ReadDemoVar (UINT8 **p, char **return_value, boolean *return_stealth)
{ {
char *name; char *name;
char *val; char *val;
@ -1792,11 +1789,11 @@ ReadDemoVar (UINT8 **p, char **return_value, boolean *return_stealth)
consvar_t *cvar; consvar_t *cvar;
name = (char *)*p; name = (char *)&p->buf[p->pos];
SKIPSTRING (*p); P_SkipString(p);
val = (char *)*p; val = (char *)&p->buf[p->pos];
SKIPSTRING (*p); P_SkipString(p);
stealth = READUINT8 (*p); stealth = P_ReadUINT8(p);
cvar = CV_FindVar(name); cvar = CV_FindVar(name);
@ -1826,41 +1823,46 @@ static void Got_NetVar(UINT8 **p, INT32 playernum)
return; return;
} }
cvar = ReadNetVar(p, &svalue, &stealth); save_t save_p;
save_p.buf = *p;
save_p.size = MAXTEXTCMD;
save_p.pos = 0;
cvar = ReadNetVar(&save_p, &svalue, &stealth);
*p = &save_p.buf[save_p.pos];
if (cvar) if (cvar)
Setvalue(cvar, svalue, stealth); Setvalue(cvar, svalue, stealth);
} }
void CV_SaveVars(UINT8 **p, boolean in_demo) void CV_SaveVars(save_t *p, boolean in_demo)
{ {
consvar_t *cvar; consvar_t *cvar;
UINT8 *count_p = *p; UINT8 *count_p = &p->buf[p->pos];
UINT16 count = 0; UINT16 count = 0;
// send only changed cvars ... // send only changed cvars ...
// the client will reset all netvars to default before loading // the client will reset all netvars to default before loading
WRITEUINT16(*p, 0x0000); P_WriteUINT16(p, 0x0000);
for (cvar = consvar_vars; cvar; cvar = cvar->next) for (cvar = consvar_vars; cvar; cvar = cvar->next)
if ((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar)) if ((cvar->flags & CV_NETVAR) && !CV_IsSetToDefault(cvar))
{ {
if (in_demo) if (in_demo)
{ {
WRITESTRING(*p, cvar->name); P_WriteString(p, cvar->name);
} }
else else
{ {
WRITEUINT16(*p, cvar->netid); P_WriteUINT16(p, cvar->netid);
} }
WRITESTRING(*p, cvar->string); P_WriteString(p, cvar->string);
WRITEUINT8(*p, false); P_WriteUINT8(p, false);
++count; ++count;
} }
WRITEUINT16(count_p, count); WRITEUINT16(count_p, count);
} }
static void CV_LoadVars(UINT8 **p, static void CV_LoadVars(save_t *p,
consvar_t *(*got)(UINT8 **p, char **ret_value, boolean *ret_stealth)) consvar_t *(*got)(save_t *p, char **ret_value, boolean *ret_stealth))
{ {
const boolean store = (client || demoplayback); const boolean store = (client || demoplayback);
@ -1888,7 +1890,7 @@ static void CV_LoadVars(UINT8 **p,
} }
} }
count = READUINT16(*p); count = P_ReadUINT16(p);
while (count--) while (count--)
{ {
cvar = (*got)(p, &val, &stealth); cvar = (*got)(p, &val, &stealth);
@ -1921,19 +1923,19 @@ void CV_RevertNetVars(void)
} }
} }
void CV_LoadNetVars(UINT8 **p) void CV_LoadNetVars(save_t *p)
{ {
CV_LoadVars(p, ReadNetVar); CV_LoadVars(p, ReadNetVar);
} }
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
void CV_LoadOldDemoVars(UINT8 **p) void CV_LoadOldDemoVars(save_t *p)
{ {
CV_LoadVars(p, ReadOldDemoVar); CV_LoadVars(p, ReadOldDemoVar);
} }
#endif #endif
void CV_LoadDemoVars(UINT8 **p) void CV_LoadDemoVars(save_t *p)
{ {
CV_LoadVars(p, ReadDemoVar); CV_LoadVars(p, ReadDemoVar);
} }

View file

@ -15,6 +15,7 @@
#include <stdio.h> #include <stdio.h>
#include "doomdef.h" #include "doomdef.h"
#include "p_saveg.h"
//=================================== //===================================
// Command buffer & command execution // Command buffer & command execution
@ -218,19 +219,19 @@ void CV_AddValue(consvar_t *var, INT32 increment);
void CV_SaveVariables(FILE *f); void CV_SaveVariables(FILE *f);
// load/save gamesate (load and save option and for network join in game) // load/save gamesate (load and save option and for network join in game)
void CV_SaveVars(UINT8 **p, boolean in_demo); void CV_SaveVars(save_t *p, boolean in_demo);
#define CV_SaveNetVars(p) CV_SaveVars(p, false) #define CV_SaveNetVars(p) CV_SaveVars(p, false)
void CV_LoadNetVars(UINT8 **p); void CV_LoadNetVars(save_t *p);
// then revert after leaving a netgame // then revert after leaving a netgame
void CV_RevertNetVars(void); void CV_RevertNetVars(void);
#define CV_SaveDemoVars(p) CV_SaveVars(p, true) #define CV_SaveDemoVars(p) CV_SaveVars(p, true)
void CV_LoadDemoVars(UINT8 **p); void CV_LoadDemoVars(save_t *p);
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
void CV_LoadOldDemoVars(UINT8 **p); void CV_LoadOldDemoVars(save_t *p);
#endif #endif
// reset cheat netvars after cheats is deactivated // reset cheat netvars after cheats is deactivated

View file

@ -1065,12 +1065,12 @@ static const char *credits[] = {
"Julio \"Chaos Zero 64\" Guir", "Julio \"Chaos Zero 64\" Guir",
"\"Hanicef\"", "\"Hanicef\"",
"\"Hannu_Hanhi\"", // For many OpenGL performance improvements! "\"Hannu_Hanhi\"", // For many OpenGL performance improvements!
"\"hazepastel\"",
"Kepa \"Nev3r\" Iceta", "Kepa \"Nev3r\" Iceta",
"Thomas \"Shadow Hog\" Igoe", "Thomas \"Shadow Hog\" Igoe",
"Iestyn \"Monster Iestyn\" Jealous", "Iestyn \"Monster Iestyn\" Jealous",
"\"Kaito Sinclaire\"", "\"Kaito Sinclaire\"",
"\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog "\"Kalaron\"", // Coded some of Sryder13's collection of OpenGL fixes, especially fog
"\"katsy\"",
"Ronald \"Furyhunter\" Kinard", // The SDL2 port "Ronald \"Furyhunter\" Kinard", // The SDL2 port
"\"Lat'\"", // SRB2-CHAT, the chat window from Kart "\"Lat'\"", // SRB2-CHAT, the chat window from Kart
"\"LZA\"", "\"LZA\"",

View file

@ -1454,6 +1454,7 @@ void G_BeginRecording(void)
char *filename; char *filename;
UINT16 totalfiles; UINT16 totalfiles;
UINT8 *m; UINT8 *m;
save_t savebuffer;
if (demo_p) if (demo_p)
return; return;
@ -1603,7 +1604,11 @@ void G_BeginRecording(void)
} }
// Save netvar data // Save netvar data
CV_SaveDemoVars(&demo_p); savebuffer.buf = demo_p;
savebuffer.size = demoend - demo_p;
savebuffer.pos = 0;
CV_SaveDemoVars(&savebuffer);
demo_p = &savebuffer.buf[savebuffer.pos];
memset(&oldcmd,0,sizeof(oldcmd)); memset(&oldcmd,0,sizeof(oldcmd));
memset(&oldghost,0,sizeof(oldghost)); memset(&oldghost,0,sizeof(oldghost));
@ -2236,10 +2241,24 @@ void G_DoPlayDemo(char *defdemoname)
// net var data // net var data
#ifdef OLD22DEMOCOMPAT #ifdef OLD22DEMOCOMPAT
if (demoversion < 0x000d) if (demoversion < 0x000d)
CV_LoadOldDemoVars(&demo_p); {
save_t savebuffer;
savebuffer.buf = demo_p;
savebuffer.size = demoend - demo_p;
savebuffer.pos = 0;
CV_LoadOldDemoVars(&savebuffer);
demo_p = &savebuffer.buf[savebuffer.pos];
}
else else
#endif #endif
CV_LoadDemoVars(&demo_p); {
save_t savebuffer;
savebuffer.buf = demo_p;
savebuffer.size = demoend - demo_p;
savebuffer.pos = 0;
CV_LoadDemoVars(&savebuffer);
demo_p = &savebuffer.buf[savebuffer.pos];
}
// Sigh ... it's an empty demo. // Sigh ... it's an empty demo.
if (*demo_p == DEMOMARKER) if (*demo_p == DEMOMARKER)

View file

@ -256,8 +256,6 @@ boolean precache = true; // if true, load all graphics at start
INT16 prevmap, nextmap; INT16 prevmap, nextmap;
static UINT8 *savebuffer;
// Analog Control // Analog Control
static void UserAnalog_OnChange(void); static void UserAnalog_OnChange(void);
static void UserAnalog2_OnChange(void); static void UserAnalog2_OnChange(void);
@ -1936,6 +1934,8 @@ void G_DoLoadLevel(boolean resetplayer)
// //
void G_StartTitleCard(void) void G_StartTitleCard(void)
{ {
ST_stopTitleCard();
// The title card has been disabled for this map. // The title card has been disabled for this map.
// Oh well. // Oh well.
if (!G_IsTitleCardAvailable()) if (!G_IsTitleCardAvailable())
@ -4399,7 +4399,7 @@ void G_LoadGameSettings(void)
// Loads the main data file, which stores information such as emblems found, etc. // Loads the main data file, which stores information such as emblems found, etc.
void G_LoadGameData(gamedata_t *data) void G_LoadGameData(gamedata_t *data)
{ {
size_t length; save_t savebuffer;
INT32 i, j; INT32 i, j;
UINT32 versionID; UINT32 versionID;
@ -4441,18 +4441,18 @@ void G_LoadGameData(gamedata_t *data)
return; return;
} }
length = FIL_ReadFile(va(pandf, srb2home, gamedatafilename), &savebuffer); savebuffer.size = FIL_ReadFile(va(pandf, srb2home, gamedatafilename), &savebuffer.buf);
if (!length) if (!savebuffer.size)
{ {
// No gamedata. We can save a new one. // No gamedata. We can save a new one.
data->loaded = true; data->loaded = true;
return; return;
} }
save_p = savebuffer; savebuffer.pos = 0;
// Version check // Version check
versionID = READUINT32(save_p); versionID = P_ReadUINT32(&savebuffer);
if (versionID != GAMEDATA_ID if (versionID != GAMEDATA_ID
#ifdef COMPAT_GAMEDATA_ID // backwards compat behavior #ifdef COMPAT_GAMEDATA_ID // backwards compat behavior
&& versionID != COMPAT_GAMEDATA_ID && versionID != COMPAT_GAMEDATA_ID
@ -4463,8 +4463,7 @@ void G_LoadGameData(gamedata_t *data)
if (strcmp(srb2home,".")) if (strcmp(srb2home,"."))
gdfolder = srb2home; gdfolder = srb2home;
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = NULL;
I_Error("Game data is from another version of SRB2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); I_Error("Game data is from another version of SRB2.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder);
} }
@ -4476,14 +4475,14 @@ void G_LoadGameData(gamedata_t *data)
} }
#endif #endif
data->totalplaytime = READUINT32(save_p); data->totalplaytime = P_ReadUINT32(&savebuffer);
#ifdef COMPAT_GAMEDATA_ID #ifdef COMPAT_GAMEDATA_ID
if (versionID == COMPAT_GAMEDATA_ID) if (versionID == COMPAT_GAMEDATA_ID)
{ {
// We'll temporarily use the old condition when loading an older file. // We'll temporarily use the old condition when loading an older file.
// The proper mod-specific hash will get saved in afterwards. // The proper mod-specific hash will get saved in afterwards.
boolean modded = READUINT8(save_p); boolean modded = P_ReadUINT8(&savebuffer);
if (modded && !savemoddata) if (modded && !savemoddata)
{ {
@ -4503,13 +4502,13 @@ void G_LoadGameData(gamedata_t *data)
strcpy(currentfilename, gamedatafilename); strcpy(currentfilename, gamedatafilename);
STRBUFCPY(backupfilename, strcat(currentfilename, bak)); STRBUFCPY(backupfilename, strcat(currentfilename, bak));
FIL_WriteFile(va(pandf, srb2home, backupfilename), savebuffer, length); FIL_WriteFile(va(pandf, srb2home, backupfilename), &savebuffer.buf, savebuffer.size);
} }
else else
#endif #endif
{ {
// Quick & dirty hash for what mod this save file is for. // Quick & dirty hash for what mod this save file is for.
UINT32 modID = READUINT32(save_p); UINT32 modID = P_ReadUINT32(&savebuffer);
UINT32 expectedID = quickncasehash(timeattackfolder, sizeof timeattackfolder); UINT32 expectedID = quickncasehash(timeattackfolder, sizeof timeattackfolder);
if (modID != expectedID) if (modID != expectedID)
@ -4521,50 +4520,50 @@ void G_LoadGameData(gamedata_t *data)
// TODO put another cipher on these things? meh, I don't care... // TODO put another cipher on these things? meh, I don't care...
for (i = 0; i < NUMMAPS; i++) for (i = 0; i < NUMMAPS; i++)
if ((data->mapvisited[i] = READUINT8(save_p)) > MV_MAX) if ((data->mapvisited[i] = P_ReadUINT8(&savebuffer)) > MV_MAX)
goto datacorrupt; goto datacorrupt;
// To save space, use one bit per collected/achieved/unlocked flag // To save space, use one bit per collected/achieved/unlocked flag
for (i = 0; i < max_emblems;) for (i = 0; i < max_emblems;)
{ {
rtemp = READUINT8(save_p); rtemp = P_ReadUINT8(&savebuffer);
for (j = 0; j < 8 && j+i < max_emblems; ++j) for (j = 0; j < 8 && j+i < max_emblems; ++j)
data->collected[j+i] = ((rtemp >> j) & 1); data->collected[j+i] = ((rtemp >> j) & 1);
i += j; i += j;
} }
for (i = 0; i < max_extraemblems;) for (i = 0; i < max_extraemblems;)
{ {
rtemp = READUINT8(save_p); rtemp = P_ReadUINT8(&savebuffer);
for (j = 0; j < 8 && j+i < max_extraemblems; ++j) for (j = 0; j < 8 && j+i < max_extraemblems; ++j)
data->extraCollected[j+i] = ((rtemp >> j) & 1); data->extraCollected[j+i] = ((rtemp >> j) & 1);
i += j; i += j;
} }
for (i = 0; i < max_unlockables;) for (i = 0; i < max_unlockables;)
{ {
rtemp = READUINT8(save_p); rtemp = P_ReadUINT8(&savebuffer);
for (j = 0; j < 8 && j+i < max_unlockables; ++j) for (j = 0; j < 8 && j+i < max_unlockables; ++j)
data->unlocked[j+i] = ((rtemp >> j) & 1); data->unlocked[j+i] = ((rtemp >> j) & 1);
i += j; i += j;
} }
for (i = 0; i < max_conditionsets;) for (i = 0; i < max_conditionsets;)
{ {
rtemp = READUINT8(save_p); rtemp = P_ReadUINT8(&savebuffer);
for (j = 0; j < 8 && j+i < max_conditionsets; ++j) for (j = 0; j < 8 && j+i < max_conditionsets; ++j)
data->achieved[j+i] = ((rtemp >> j) & 1); data->achieved[j+i] = ((rtemp >> j) & 1);
i += j; i += j;
} }
data->timesBeaten = READUINT32(save_p); data->timesBeaten = P_ReadUINT32(&savebuffer);
data->timesBeatenWithEmeralds = READUINT32(save_p); data->timesBeatenWithEmeralds = P_ReadUINT32(&savebuffer);
data->timesBeatenUltimate = READUINT32(save_p); data->timesBeatenUltimate = P_ReadUINT32(&savebuffer);
// Main records // Main records
for (i = 0; i < NUMMAPS; ++i) for (i = 0; i < NUMMAPS; ++i)
{ {
recscore = READUINT32(save_p); recscore = P_ReadUINT32(&savebuffer);
rectime = (tic_t)READUINT32(save_p); rectime = (tic_t)P_ReadUINT32(&savebuffer);
recrings = READUINT16(save_p); recrings = P_ReadUINT16(&savebuffer);
save_p++; // compat P_ReadUINT8(&savebuffer); // compat
if (recrings > 10000 || recscore > MAXSCORE) if (recrings > 10000 || recscore > MAXSCORE)
goto datacorrupt; goto datacorrupt;
@ -4581,16 +4580,16 @@ void G_LoadGameData(gamedata_t *data)
// Nights records // Nights records
for (i = 0; i < NUMMAPS; ++i) for (i = 0; i < NUMMAPS; ++i)
{ {
if ((recmares = READUINT8(save_p)) == 0) if ((recmares = P_ReadUINT8(&savebuffer)) == 0)
continue; continue;
G_AllocNightsRecordData((INT16)i, data); G_AllocNightsRecordData((INT16)i, data);
for (curmare = 0; curmare < (recmares+1); ++curmare) for (curmare = 0; curmare < (recmares+1); ++curmare)
{ {
data->nightsrecords[i]->score[curmare] = READUINT32(save_p); data->nightsrecords[i]->score[curmare] = P_ReadUINT32(&savebuffer);
data->nightsrecords[i]->grade[curmare] = READUINT8(save_p); data->nightsrecords[i]->grade[curmare] = P_ReadUINT8(&savebuffer);
data->nightsrecords[i]->time[curmare] = (tic_t)READUINT32(save_p); data->nightsrecords[i]->time[curmare] = (tic_t)P_ReadUINT32(&savebuffer);
if (data->nightsrecords[i]->grade[curmare] > GRADE_S) if (data->nightsrecords[i]->grade[curmare] > GRADE_S)
{ {
@ -4602,8 +4601,7 @@ void G_LoadGameData(gamedata_t *data)
} }
// done // done
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = NULL;
// Don't consider loaded until it's a success! // Don't consider loaded until it's a success!
// It used to do this much earlier, but this would cause the gamedata to // It used to do this much earlier, but this would cause the gamedata to
@ -4624,8 +4622,7 @@ void G_LoadGameData(gamedata_t *data)
if (strcmp(srb2home,".")) if (strcmp(srb2home,"."))
gdfolder = srb2home; gdfolder = srb2home;
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = NULL;
I_Error("Corrupt game data file.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); I_Error("Corrupt game data file.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder);
} }
@ -4635,9 +4632,8 @@ void G_LoadGameData(gamedata_t *data)
// Saves the main data file, which stores information such as emblems found, etc. // Saves the main data file, which stores information such as emblems found, etc.
void G_SaveGameData(gamedata_t *data) void G_SaveGameData(gamedata_t *data)
{ {
UINT8 *data_p; save_t savebuffer;
size_t length;
INT32 i, j; INT32 i, j;
UINT8 btemp; UINT8 btemp;
@ -4649,30 +4645,31 @@ void G_SaveGameData(gamedata_t *data)
if (!data->loaded) if (!data->loaded)
return; // If never loaded (-nodata), don't save return; // If never loaded (-nodata), don't save
data_p = savebuffer = (UINT8 *)malloc(GAMEDATASIZE); savebuffer.size = GAMEDATASIZE;
if (!data_p) savebuffer.buf = (UINT8 *)malloc(savebuffer.size);
if (!savebuffer.buf)
{ {
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n")); CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n"));
return; return;
} }
savebuffer.pos = 0;
if (usedCheats) if (usedCheats)
{ {
free(savebuffer); free(savebuffer.buf);
savebuffer = NULL;
return; return;
} }
// Version test // Version test
WRITEUINT32(data_p, GAMEDATA_ID); P_WriteUINT32(&savebuffer, GAMEDATA_ID);
WRITEUINT32(data_p, data->totalplaytime); P_WriteUINT32(&savebuffer, data->totalplaytime);
WRITEUINT32(data_p, quickncasehash(timeattackfolder, sizeof timeattackfolder)); P_WriteUINT32(&savebuffer, quickncasehash(timeattackfolder, sizeof timeattackfolder));
// TODO put another cipher on these things? meh, I don't care... // TODO put another cipher on these things? meh, I don't care...
for (i = 0; i < NUMMAPS; i++) for (i = 0; i < NUMMAPS; i++)
WRITEUINT8(data_p, (data->mapvisited[i] & MV_MAX)); P_WriteUINT8(&savebuffer, (data->mapvisited[i] & MV_MAX));
// To save space, use one bit per collected/achieved/unlocked flag // To save space, use one bit per collected/achieved/unlocked flag
for (i = 0; i < MAXEMBLEMS;) for (i = 0; i < MAXEMBLEMS;)
@ -4680,7 +4677,7 @@ void G_SaveGameData(gamedata_t *data)
btemp = 0; btemp = 0;
for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j)
btemp |= (data->collected[j+i] << j); btemp |= (data->collected[j+i] << j);
WRITEUINT8(data_p, btemp); P_WriteUINT8(&savebuffer, btemp);
i += j; i += j;
} }
for (i = 0; i < MAXEXTRAEMBLEMS;) for (i = 0; i < MAXEXTRAEMBLEMS;)
@ -4688,7 +4685,7 @@ void G_SaveGameData(gamedata_t *data)
btemp = 0; btemp = 0;
for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j) for (j = 0; j < 8 && j+i < MAXEXTRAEMBLEMS; ++j)
btemp |= (data->extraCollected[j+i] << j); btemp |= (data->extraCollected[j+i] << j);
WRITEUINT8(data_p, btemp); P_WriteUINT8(&savebuffer, btemp);
i += j; i += j;
} }
for (i = 0; i < MAXUNLOCKABLES;) for (i = 0; i < MAXUNLOCKABLES;)
@ -4696,7 +4693,7 @@ void G_SaveGameData(gamedata_t *data)
btemp = 0; btemp = 0;
for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j)
btemp |= (data->unlocked[j+i] << j); btemp |= (data->unlocked[j+i] << j);
WRITEUINT8(data_p, btemp); P_WriteUINT8(&savebuffer, btemp);
i += j; i += j;
} }
for (i = 0; i < MAXCONDITIONSETS;) for (i = 0; i < MAXCONDITIONSETS;)
@ -4704,30 +4701,30 @@ void G_SaveGameData(gamedata_t *data)
btemp = 0; btemp = 0;
for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j)
btemp |= (data->achieved[j+i] << j); btemp |= (data->achieved[j+i] << j);
WRITEUINT8(data_p, btemp); P_WriteUINT8(&savebuffer, btemp);
i += j; i += j;
} }
WRITEUINT32(data_p, data->timesBeaten); P_WriteUINT32(&savebuffer, data->timesBeaten);
WRITEUINT32(data_p, data->timesBeatenWithEmeralds); P_WriteUINT32(&savebuffer, data->timesBeatenWithEmeralds);
WRITEUINT32(data_p, data->timesBeatenUltimate); P_WriteUINT32(&savebuffer, data->timesBeatenUltimate);
// Main records // Main records
for (i = 0; i < NUMMAPS; i++) for (i = 0; i < NUMMAPS; i++)
{ {
if (data->mainrecords[i]) if (data->mainrecords[i])
{ {
WRITEUINT32(data_p, data->mainrecords[i]->score); P_WriteUINT32(&savebuffer, data->mainrecords[i]->score);
WRITEUINT32(data_p, data->mainrecords[i]->time); P_WriteUINT32(&savebuffer, data->mainrecords[i]->time);
WRITEUINT16(data_p, data->mainrecords[i]->rings); P_WriteUINT16(&savebuffer, data->mainrecords[i]->rings);
} }
else else
{ {
WRITEUINT32(data_p, 0); P_WriteUINT32(&savebuffer, 0);
WRITEUINT32(data_p, 0); P_WriteUINT32(&savebuffer, 0);
WRITEUINT16(data_p, 0); P_WriteUINT16(&savebuffer, 0);
} }
WRITEUINT8(data_p, 0); // compat P_WriteUINT8(&savebuffer, 0); // compat
} }
// NiGHTS records // NiGHTS records
@ -4735,25 +4732,22 @@ void G_SaveGameData(gamedata_t *data)
{ {
if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares) if (!data->nightsrecords[i] || !data->nightsrecords[i]->nummares)
{ {
WRITEUINT8(data_p, 0); P_WriteUINT8(&savebuffer, 0);
continue; continue;
} }
WRITEUINT8(data_p, data->nightsrecords[i]->nummares); P_WriteUINT8(&savebuffer, data->nightsrecords[i]->nummares);
for (curmare = 0; curmare < (data->nightsrecords[i]->nummares + 1); ++curmare) for (curmare = 0; curmare < (data->nightsrecords[i]->nummares + 1); ++curmare)
{ {
WRITEUINT32(data_p, data->nightsrecords[i]->score[curmare]); P_WriteUINT32(&savebuffer, data->nightsrecords[i]->score[curmare]);
WRITEUINT8(data_p, data->nightsrecords[i]->grade[curmare]); P_WriteUINT8(&savebuffer, data->nightsrecords[i]->grade[curmare]);
WRITEUINT32(data_p, data->nightsrecords[i]->time[curmare]); P_WriteUINT32(&savebuffer, data->nightsrecords[i]->time[curmare]);
} }
} }
length = data_p - savebuffer; FIL_WriteFile(va(pandf, srb2home, gamedatafilename), savebuffer.buf, savebuffer.pos);
free(savebuffer.buf);
FIL_WriteFile(va(pandf, srb2home, gamedatafilename), savebuffer, length);
free(savebuffer);
savebuffer = NULL;
} }
#define VERSIONSIZE 16 #define VERSIONSIZE 16
@ -4764,7 +4758,7 @@ void G_SaveGameData(gamedata_t *data)
// //
void G_LoadGame(UINT32 slot, INT16 mapoverride) void G_LoadGame(UINT32 slot, INT16 mapoverride)
{ {
size_t length; save_t savebuffer;
char vcheck[VERSIONSIZE]; char vcheck[VERSIONSIZE];
char savename[255]; char savename[255];
@ -4781,18 +4775,18 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
else else
sprintf(savename, savegamename, slot); sprintf(savename, savegamename, slot);
length = FIL_ReadFile(savename, &savebuffer); savebuffer.size = FIL_ReadFile(savename, &savebuffer.buf);
if (!length) if (!savebuffer.size)
{ {
CONS_Printf(M_GetText("Couldn't read file %s\n"), savename); CONS_Printf(M_GetText("Couldn't read file %s\n"), savename);
return; return;
} }
save_p = savebuffer; savebuffer.pos = 0;
memset(vcheck, 0, sizeof (vcheck)); memset(vcheck, 0, sizeof (vcheck));
sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION); sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION);
if (strcmp((const char *)save_p, (const char *)vcheck)) if (strcmp((const char *)&savebuffer.buf[savebuffer.pos], (const char *)vcheck))
{ {
#ifdef SAVEGAME_OTHERVERSIONS #ifdef SAVEGAME_OTHERVERSIONS
M_StartMessage(M_GetText("Save game from different version.\nYou can load this savegame, but\nsaving afterwards will be disabled.\n\nDo you want to continue anyway?\n\n(Press 'Y' to confirm)\n"), M_StartMessage(M_GetText("Save game from different version.\nYou can load this savegame, but\nsaving afterwards will be disabled.\n\nDo you want to continue anyway?\n\n(Press 'Y' to confirm)\n"),
@ -4802,15 +4796,14 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
M_ClearMenus(true); // so ESC backs out to title M_ClearMenus(true); // so ESC backs out to title
M_StartMessage(M_GetText("Save game from different version\n\nPress ESC\n"), NULL, MM_NOTHING); M_StartMessage(M_GetText("Save game from different version\n\nPress ESC\n"), NULL, MM_NOTHING);
Command_ExitGame_f(); Command_ExitGame_f();
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = savebuffer = NULL;
// no cheating! // no cheating!
memset(&savedata, 0, sizeof(savedata)); memset(&savedata, 0, sizeof(savedata));
#endif #endif
return; // bad version return; // bad version
} }
save_p += VERSIONSIZE; savebuffer.pos += VERSIONSIZE;
// if (demoplayback) // reset game engine // if (demoplayback) // reset game engine
// G_StopDemo(); // G_StopDemo();
@ -4819,13 +4812,12 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
// automapactive = false; // automapactive = false;
// dearchive all the modifications // dearchive all the modifications
if (!P_LoadGame(mapoverride)) if (!P_LoadGame(&savebuffer, mapoverride))
{ {
M_ClearMenus(true); // so ESC backs out to title M_ClearMenus(true); // so ESC backs out to title
M_StartMessage(M_GetText("Savegame file corrupted\n\nPress ESC\n"), NULL, MM_NOTHING); M_StartMessage(M_GetText("Savegame file corrupted\n\nPress ESC\n"), NULL, MM_NOTHING);
Command_ExitGame_f(); Command_ExitGame_f();
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = savebuffer = NULL;
// no cheating! // no cheating!
memset(&savedata, 0, sizeof(savedata)); memset(&savedata, 0, sizeof(savedata));
@ -4833,13 +4825,12 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
} }
if (marathonmode) if (marathonmode)
{ {
marathontime = READUINT32(save_p); marathontime = P_ReadUINT32(&savebuffer);
marathonmode |= READUINT8(save_p); marathonmode |= P_ReadUINT8(&savebuffer);
} }
// done // done
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = savebuffer = NULL;
displayplayer = consoleplayer; displayplayer = consoleplayer;
multiplayer = splitscreen = false; multiplayer = splitscreen = false;
@ -4857,6 +4848,7 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
// //
void G_SaveGame(UINT32 slot, INT16 mapnum) void G_SaveGame(UINT32 slot, INT16 mapnum)
{ {
save_t savebuffer;
boolean saved; boolean saved;
char savename[256] = ""; char savename[256] = "";
const char *backup; const char *backup;
@ -4870,33 +4862,32 @@ void G_SaveGame(UINT32 slot, INT16 mapnum)
gameaction = ga_nothing; gameaction = ga_nothing;
{ {
char name[VERSIONSIZE]; char name[VERSIONSIZE];
size_t length;
save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); savebuffer.size = SAVEGAMESIZE;
if (!save_p) savebuffer.buf = (UINT8 *)malloc(savebuffer.size);
if (!savebuffer.buf)
{ {
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n")); CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n"));
return; return;
} }
savebuffer.pos = 0;
memset(name, 0, sizeof (name)); memset(name, 0, sizeof (name));
sprintf(name, (marathonmode ? "back-up %d" : "version %d"), VERSION); sprintf(name, (marathonmode ? "back-up %d" : "version %d"), VERSION);
WRITEMEM(save_p, name, VERSIONSIZE); P_WriteMem(&savebuffer, name, VERSIONSIZE);
P_SaveGame(mapnum); P_SaveGame(&savebuffer, mapnum);
if (marathonmode) if (marathonmode)
{ {
UINT32 writetime = marathontime; UINT32 writetime = marathontime;
if (!(marathonmode & MA_INGAME)) if (!(marathonmode & MA_INGAME))
writetime += TICRATE*5; // live event backup penalty because we don't know how long it takes to get to the next map writetime += TICRATE*5; // live event backup penalty because we don't know how long it takes to get to the next map
WRITEUINT32(save_p, writetime); P_WriteUINT32(&savebuffer, writetime);
WRITEUINT8(save_p, (marathonmode & ~MA_INIT)); P_WriteUINT8(&savebuffer, (marathonmode & ~MA_INIT));
} }
length = save_p - savebuffer; saved = FIL_WriteFile(backup, savebuffer.buf, savebuffer.pos);
saved = FIL_WriteFile(backup, savebuffer, length); free(savebuffer.buf);
free(savebuffer);
save_p = savebuffer = NULL;
} }
gameaction = ga_nothing; gameaction = ga_nothing;
@ -4908,11 +4899,10 @@ void G_SaveGame(UINT32 slot, INT16 mapnum)
} }
#define BADSAVE goto cleanup; #define BADSAVE goto cleanup;
#define CHECKPOS if (save_p >= end_p) BADSAVE
void G_SaveGameOver(UINT32 slot, boolean modifylives) void G_SaveGameOver(UINT32 slot, boolean modifylives)
{ {
save_t savebuffer;
boolean saved = false; boolean saved = false;
size_t length;
char vcheck[VERSIONSIZE]; char vcheck[VERSIONSIZE];
char savename[255]; char savename[255];
const char *backup; const char *backup;
@ -4923,42 +4913,38 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives)
sprintf(savename, savegamename, slot); sprintf(savename, savegamename, slot);
backup = va("%s",savename); backup = va("%s",savename);
length = FIL_ReadFile(savename, &savebuffer); savebuffer.size = FIL_ReadFile(savename, &savebuffer.buf);
if (!length) if (!savebuffer.size)
{ {
CONS_Printf(M_GetText("Couldn't read file %s\n"), savename); CONS_Printf(M_GetText("Couldn't read file %s\n"), savename);
return; return;
} }
savebuffer.pos = 0;
{ {
char temp[sizeof(timeattackfolder)]; char temp[sizeof(timeattackfolder)];
UINT8 *end_p = savebuffer + length;
UINT8 *lives_p; UINT8 *lives_p;
SINT8 pllives; SINT8 pllives;
#ifdef NEWSKINSAVES #ifdef NEWSKINSAVES
INT16 backwardsCompat = 0; INT16 backwardsCompat = 0;
#endif #endif
save_p = savebuffer;
// Version check // Version check
memset(vcheck, 0, sizeof (vcheck)); memset(vcheck, 0, sizeof (vcheck));
sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION); sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION);
if (strcmp((const char *)save_p, (const char *)vcheck)) BADSAVE if (strcmp((const char *)&savebuffer.buf[savebuffer.pos], (const char *)vcheck)) BADSAVE
save_p += VERSIONSIZE; savebuffer.pos += VERSIONSIZE;
// P_UnArchiveMisc() // P_UnArchiveMisc()
(void)READINT16(save_p); (void)P_ReadINT16(&savebuffer);
CHECKPOS (void)P_ReadUINT16(&savebuffer); // emeralds
(void)READUINT16(save_p); // emeralds P_ReadStringN(&savebuffer, temp, sizeof(temp)); // mod it belongs to
CHECKPOS
READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to
if (strcmp(temp, timeattackfolder)) BADSAVE if (strcmp(temp, timeattackfolder)) BADSAVE
// P_UnArchivePlayer() // P_UnArchivePlayer()
CHECKPOS
#ifdef NEWSKINSAVES #ifdef NEWSKINSAVES
backwardsCompat = READUINT16(save_p); backwardsCompat = P_ReadUINT16(&savebuffer);
CHECKPOS
if (backwardsCompat == NEWSKINSAVES) // New save, read skin names if (backwardsCompat == NEWSKINSAVES) // New save, read skin names
#endif #endif
@ -4966,47 +4952,37 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives)
char ourSkinName[SKINNAMESIZE+1]; char ourSkinName[SKINNAMESIZE+1];
char botSkinName[SKINNAMESIZE+1]; char botSkinName[SKINNAMESIZE+1];
READSTRINGN(save_p, ourSkinName, SKINNAMESIZE); P_ReadStringN(&savebuffer, ourSkinName, SKINNAMESIZE);
CHECKPOS
READSTRINGN(save_p, botSkinName, SKINNAMESIZE); P_ReadStringN(&savebuffer, botSkinName, SKINNAMESIZE);
CHECKPOS
} }
WRITEUINT8(save_p, numgameovers); P_WriteUINT8(&savebuffer, numgameovers);
CHECKPOS
lives_p = save_p; lives_p = &savebuffer.buf[savebuffer.pos];
pllives = READSINT8(save_p); // lives pllives = P_ReadSINT8(&savebuffer); // lives
CHECKPOS
if (modifylives && pllives < startinglivesbalance[numgameovers]) if (modifylives && pllives < startinglivesbalance[numgameovers])
{ {
pllives = startinglivesbalance[numgameovers]; *lives_p = startinglivesbalance[numgameovers];
WRITESINT8(lives_p, pllives);
} }
(void)READINT32(save_p); // Score (void)P_ReadINT32(&savebuffer); // Score
CHECKPOS (void)P_ReadINT32(&savebuffer); // continues
(void)READINT32(save_p); // continues
// File end marker check // File end marker check
CHECKPOS switch (P_ReadUINT8(&savebuffer))
switch (READUINT8(save_p))
{ {
case 0xb7: case 0xb7:
{ {
UINT8 i, banksinuse; UINT8 i, banksinuse;
CHECKPOS banksinuse = P_ReadUINT8(&savebuffer);
banksinuse = READUINT8(save_p);
CHECKPOS
if (banksinuse > NUM_LUABANKS) if (banksinuse > NUM_LUABANKS)
BADSAVE BADSAVE
for (i = 0; i < banksinuse; i++) for (i = 0; i < banksinuse; i++)
{ {
(void)READINT32(save_p); (void)P_ReadINT32(&savebuffer);
CHECKPOS
} }
if (READUINT8(save_p) != 0x1d) if (P_ReadUINT8(&savebuffer) != 0x1d)
BADSAVE BADSAVE
} }
case 0x1d: case 0x1d:
@ -5016,7 +4992,7 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives)
} }
// done // done
saved = FIL_WriteFile(backup, savebuffer, length); saved = FIL_WriteFile(backup, savebuffer.buf, savebuffer.size);
} }
cleanup: cleanup:
@ -5024,11 +5000,9 @@ cleanup:
CONS_Printf(M_GetText("Game saved.\n")); CONS_Printf(M_GetText("Game saved.\n"));
else if (!saved) else if (!saved)
CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, (marathonmode ? liveeventbackup : savegamename)); CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, (marathonmode ? liveeventbackup : savegamename));
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = savebuffer = NULL;
} }
#undef CHECKPOS
#undef BADSAVE #undef BADSAVE
// //

View file

@ -587,8 +587,8 @@ static void Command_CSay_f(void)
DoSayCommand(0, 1, HU_CSAY); DoSayCommand(0, 1, HU_CSAY);
} }
static tic_t spam_tokens[MAXPLAYERS] = { 1 }; // fill the buffer with 1 so the motd can be sent. UINT8 spam_tokens[MAXPLAYERS] = { 1 }; // fill the buffer with 1 so the motd can be sent.
static tic_t spam_tics[MAXPLAYERS]; tic_t spam_tics[MAXPLAYERS];
/** Receives a message, processing an ::XD_SAY command. /** Receives a message, processing an ::XD_SAY command.
* \sa DoSayCommand * \sa DoSayCommand
@ -650,14 +650,12 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum)
else else
spam_tokens[playernum] -= 1; spam_tokens[playernum] -= 1;
// run the lua hook even if we were supposed to eat the msg, netgame consistency goes first. if (spam_eatmsg)
return; // don't proceed if we were supposed to eat the message.
if (LUA_HookPlayerMsg(playernum, target, flags, msg)) if (LUA_HookPlayerMsg(playernum, target, flags, msg))
return; return;
if (spam_eatmsg)
return; // don't proceed if we were supposed to eat the message.
// If it's a CSAY, just CECHO and be done with it. // If it's a CSAY, just CECHO and be done with it.
if (flags & HU_CSAY) if (flags & HU_CSAY)
{ {

View file

@ -79,6 +79,9 @@ void HU_AddChatText(const char *text, boolean playsound);
// set true when entering a chat message // set true when entering a chat message
extern boolean chat_on; extern boolean chat_on;
extern UINT8 spam_tokens[MAXPLAYERS];
extern tic_t spam_tics[MAXPLAYERS];
extern patch_t *emeraldpics[3][8]; extern patch_t *emeraldpics[3][8];
extern patch_t *rflagico; extern patch_t *rflagico;
extern patch_t *bflagico; extern patch_t *bflagico;

View file

@ -1098,7 +1098,7 @@ static UINT8 GetUserdataArchType(int index)
return ARCH_NULL; return ARCH_NULL;
} }
static UINT8 ArchiveValue(int TABLESINDEX, int myindex) static UINT8 ArchiveValue(save_t *save_p, int TABLESINDEX, int myindex)
{ {
if (myindex < 0) if (myindex < 0)
myindex = lua_gettop(gL)+1+myindex; myindex = lua_gettop(gL)+1+myindex;
@ -1106,34 +1106,34 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
case LUA_TNONE: case LUA_TNONE:
case LUA_TNIL: case LUA_TNIL:
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
break; break;
// This might be a problem. D: // This might be a problem. D:
case LUA_TLIGHTUSERDATA: case LUA_TLIGHTUSERDATA:
case LUA_TTHREAD: case LUA_TTHREAD:
case LUA_TFUNCTION: case LUA_TFUNCTION:
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
return 2; return 2;
case LUA_TBOOLEAN: case LUA_TBOOLEAN:
WRITEUINT8(save_p, lua_toboolean(gL, myindex) ? ARCH_TRUE : ARCH_FALSE); P_WriteUINT8(save_p, lua_toboolean(gL, myindex) ? ARCH_TRUE : ARCH_FALSE);
break; break;
case LUA_TNUMBER: case LUA_TNUMBER:
{ {
lua_Integer number = lua_tointeger(gL, myindex); lua_Integer number = lua_tointeger(gL, myindex);
if (number >= INT8_MIN && number <= INT8_MAX) if (number >= INT8_MIN && number <= INT8_MAX)
{ {
WRITEUINT8(save_p, ARCH_INT8); P_WriteUINT8(save_p, ARCH_INT8);
WRITESINT8(save_p, number); P_WriteSINT8(save_p, number);
} }
else if (number >= INT16_MIN && number <= INT16_MAX) else if (number >= INT16_MIN && number <= INT16_MAX)
{ {
WRITEUINT8(save_p, ARCH_INT16); P_WriteUINT8(save_p, ARCH_INT16);
WRITEINT16(save_p, number); P_WriteINT16(save_p, number);
} }
else else
{ {
WRITEUINT8(save_p, ARCH_INT32); P_WriteUINT8(save_p, ARCH_INT32);
WRITEFIXED(save_p, number); P_WriteFixed(save_p, number);
} }
break; break;
} }
@ -1144,23 +1144,23 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
UINT32 i = 0; UINT32 i = 0;
// if you're wondering why we're writing a string to save_p this way, // if you're wondering why we're writing a string to save_p this way,
// it turns out that Lua can have embedded zeros ('\0') in the strings, // it turns out that Lua can have embedded zeros ('\0') in the strings,
// so we can't use WRITESTRING as that cuts off when it finds a '\0'. // so we can't use P_WriteString as that cuts off when it finds a '\0'.
// Saving the size of the string also allows us to get the size of the string on the other end, // Saving the size of the string also allows us to get the size of the string on the other end,
// fixing the awful crashes previously encountered for reading strings longer than 1024 // fixing the awful crashes previously encountered for reading strings longer than 1024
// (yes I know that's kind of a stupid thing to care about, but it'd be evil to trim or ignore them?) // (yes I know that's kind of a stupid thing to care about, but it'd be evil to trim or ignore them?)
// -- Monster Iestyn 05/08/18 // -- Monster Iestyn 05/08/18
if (len < 255) if (len < 255)
{ {
WRITEUINT8(save_p, ARCH_SMALLSTRING); P_WriteUINT8(save_p, ARCH_SMALLSTRING);
WRITEUINT8(save_p, len); // save size of string P_WriteUINT8(save_p, len); // save size of string
} }
else else
{ {
WRITEUINT8(save_p, ARCH_LARGESTRING); P_WriteUINT8(save_p, ARCH_LARGESTRING);
WRITEUINT32(save_p, len); // save size of string P_WriteUINT32(save_p, len); // save size of string
} }
while (i < len) while (i < len)
WRITECHAR(save_p, s[i++]); // write chars individually, including the embedded zeros P_WriteChar(save_p, s[i++]); // write chars individually, including the embedded zeros
break; break;
} }
case LUA_TTABLE: case LUA_TTABLE:
@ -1186,13 +1186,13 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
if (t == 0) if (t == 0)
{ {
CONS_Alert(CONS_ERROR, "Too many tables to archive!\n"); CONS_Alert(CONS_ERROR, "Too many tables to archive!\n");
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
return 0; return 0;
} }
} }
WRITEUINT8(save_p, ARCH_TABLE); P_WriteUINT8(save_p, ARCH_TABLE);
WRITEUINT16(save_p, t); P_WriteUINT16(save_p, t);
if (!found) if (!found)
{ {
@ -1208,25 +1208,25 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
case ARCH_MOBJINFO: case ARCH_MOBJINFO:
{ {
mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex)); mobjinfo_t *info = *((mobjinfo_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_MOBJINFO); P_WriteUINT8(save_p, ARCH_MOBJINFO);
WRITEUINT16(save_p, info - mobjinfo); P_WriteUINT16(save_p, info - mobjinfo);
break; break;
} }
case ARCH_STATE: case ARCH_STATE:
{ {
state_t *state = *((state_t **)lua_touserdata(gL, myindex)); state_t *state = *((state_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_STATE); P_WriteUINT8(save_p, ARCH_STATE);
WRITEUINT16(save_p, state - states); P_WriteUINT16(save_p, state - states);
break; break;
} }
case ARCH_MOBJ: case ARCH_MOBJ:
{ {
mobj_t *mobj = *((mobj_t **)lua_touserdata(gL, myindex)); mobj_t *mobj = *((mobj_t **)lua_touserdata(gL, myindex));
if (!mobj) if (!mobj)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_MOBJ); P_WriteUINT8(save_p, ARCH_MOBJ);
WRITEUINT32(save_p, mobj->mobjnum); P_WriteUINT32(save_p, mobj->mobjnum);
} }
break; break;
} }
@ -1234,10 +1234,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
player_t *player = *((player_t **)lua_touserdata(gL, myindex)); player_t *player = *((player_t **)lua_touserdata(gL, myindex));
if (!player) if (!player)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_PLAYER); P_WriteUINT8(save_p, ARCH_PLAYER);
WRITEUINT8(save_p, player - players); P_WriteUINT8(save_p, player - players);
} }
break; break;
} }
@ -1245,10 +1245,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
mapthing_t *mapthing = *((mapthing_t **)lua_touserdata(gL, myindex)); mapthing_t *mapthing = *((mapthing_t **)lua_touserdata(gL, myindex));
if (!mapthing) if (!mapthing)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_MAPTHING); P_WriteUINT8(save_p, ARCH_MAPTHING);
WRITEUINT16(save_p, mapthing - mapthings); P_WriteUINT16(save_p, mapthing - mapthings);
} }
break; break;
} }
@ -1256,10 +1256,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
vertex_t *vertex = *((vertex_t **)lua_touserdata(gL, myindex)); vertex_t *vertex = *((vertex_t **)lua_touserdata(gL, myindex));
if (!vertex) if (!vertex)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_VERTEX); P_WriteUINT8(save_p, ARCH_VERTEX);
WRITEUINT16(save_p, vertex - vertexes); P_WriteUINT16(save_p, vertex - vertexes);
} }
break; break;
} }
@ -1267,10 +1267,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
line_t *line = *((line_t **)lua_touserdata(gL, myindex)); line_t *line = *((line_t **)lua_touserdata(gL, myindex));
if (!line) if (!line)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_LINE); P_WriteUINT8(save_p, ARCH_LINE);
WRITEUINT16(save_p, line - lines); P_WriteUINT16(save_p, line - lines);
} }
break; break;
} }
@ -1278,10 +1278,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
side_t *side = *((side_t **)lua_touserdata(gL, myindex)); side_t *side = *((side_t **)lua_touserdata(gL, myindex));
if (!side) if (!side)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SIDE); P_WriteUINT8(save_p, ARCH_SIDE);
WRITEUINT16(save_p, side - sides); P_WriteUINT16(save_p, side - sides);
} }
break; break;
} }
@ -1289,10 +1289,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
subsector_t *subsector = *((subsector_t **)lua_touserdata(gL, myindex)); subsector_t *subsector = *((subsector_t **)lua_touserdata(gL, myindex));
if (!subsector) if (!subsector)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SUBSECTOR); P_WriteUINT8(save_p, ARCH_SUBSECTOR);
WRITEUINT16(save_p, subsector - subsectors); P_WriteUINT16(save_p, subsector - subsectors);
} }
break; break;
} }
@ -1300,10 +1300,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
sector_t *sector = *((sector_t **)lua_touserdata(gL, myindex)); sector_t *sector = *((sector_t **)lua_touserdata(gL, myindex));
if (!sector) if (!sector)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SECTOR); P_WriteUINT8(save_p, ARCH_SECTOR);
WRITEUINT16(save_p, sector - sectors); P_WriteUINT16(save_p, sector - sectors);
} }
break; break;
} }
@ -1312,10 +1312,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
seg_t *seg = *((seg_t **)lua_touserdata(gL, myindex)); seg_t *seg = *((seg_t **)lua_touserdata(gL, myindex));
if (!seg) if (!seg)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SEG); P_WriteUINT8(save_p, ARCH_SEG);
WRITEUINT16(save_p, seg - segs); P_WriteUINT16(save_p, seg - segs);
} }
break; break;
} }
@ -1323,10 +1323,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
node_t *node = *((node_t **)lua_touserdata(gL, myindex)); node_t *node = *((node_t **)lua_touserdata(gL, myindex));
if (!node) if (!node)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_NODE); P_WriteUINT8(save_p, ARCH_NODE);
WRITEUINT16(save_p, node - nodes); P_WriteUINT16(save_p, node - nodes);
} }
break; break;
} }
@ -1335,16 +1335,16 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
ffloor_t *rover = *((ffloor_t **)lua_touserdata(gL, myindex)); ffloor_t *rover = *((ffloor_t **)lua_touserdata(gL, myindex));
if (!rover) if (!rover)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
UINT16 i = P_GetFFloorID(rover); UINT16 i = P_GetFFloorID(rover);
if (i == UINT16_MAX) // invalid ID if (i == UINT16_MAX) // invalid ID
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else else
{ {
WRITEUINT8(save_p, ARCH_FFLOOR); P_WriteUINT8(save_p, ARCH_FFLOOR);
WRITEUINT16(save_p, rover->target - sectors); P_WriteUINT16(save_p, rover->target - sectors);
WRITEUINT16(save_p, i); P_WriteUINT16(save_p, i);
} }
} }
break; break;
@ -1353,10 +1353,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
polyobj_t *polyobj = *((polyobj_t **)lua_touserdata(gL, myindex)); polyobj_t *polyobj = *((polyobj_t **)lua_touserdata(gL, myindex));
if (!polyobj) if (!polyobj)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_POLYOBJ); P_WriteUINT8(save_p, ARCH_POLYOBJ);
WRITEUINT16(save_p, polyobj-PolyObjects); P_WriteUINT16(save_p, polyobj-PolyObjects);
} }
break; break;
} }
@ -1364,10 +1364,10 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
pslope_t *slope = *((pslope_t **)lua_touserdata(gL, myindex)); pslope_t *slope = *((pslope_t **)lua_touserdata(gL, myindex));
if (!slope) if (!slope)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_SLOPE); P_WriteUINT8(save_p, ARCH_SLOPE);
WRITEUINT16(save_p, slope->id); P_WriteUINT16(save_p, slope->id);
} }
break; break;
} }
@ -1375,36 +1375,36 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
{ {
mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex)); mapheader_t *header = *((mapheader_t **)lua_touserdata(gL, myindex));
if (!header) if (!header)
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
else { else {
WRITEUINT8(save_p, ARCH_MAPHEADER); P_WriteUINT8(save_p, ARCH_MAPHEADER);
WRITEUINT16(save_p, header - *mapheaderinfo); P_WriteUINT16(save_p, header - *mapheaderinfo);
} }
break; break;
} }
case ARCH_SKINCOLOR: case ARCH_SKINCOLOR:
{ {
skincolor_t *info = *((skincolor_t **)lua_touserdata(gL, myindex)); skincolor_t *info = *((skincolor_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_SKINCOLOR); P_WriteUINT8(save_p, ARCH_SKINCOLOR);
WRITEUINT16(save_p, info - skincolors); P_WriteUINT16(save_p, info - skincolors);
break; break;
} }
case ARCH_MOUSE: case ARCH_MOUSE:
{ {
mouse_t *m = *((mouse_t **)lua_touserdata(gL, myindex)); mouse_t *m = *((mouse_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_MOUSE); P_WriteUINT8(save_p, ARCH_MOUSE);
WRITEUINT8(save_p, m == &mouse ? 1 : 2); P_WriteUINT8(save_p, m == &mouse ? 1 : 2);
break; break;
} }
case ARCH_SKIN: case ARCH_SKIN:
{ {
skin_t *skin = *((skin_t **)lua_touserdata(gL, myindex)); skin_t *skin = *((skin_t **)lua_touserdata(gL, myindex));
WRITEUINT8(save_p, ARCH_SKIN); P_WriteUINT8(save_p, ARCH_SKIN);
WRITEUINT8(save_p, skin->skinnum); // UINT8 because MAXSKINS must be <= 256 P_WriteUINT8(save_p, skin->skinnum); // UINT8 because MAXSKINS must be <= 256
break; break;
} }
default: default:
WRITEUINT8(save_p, ARCH_NULL); P_WriteUINT8(save_p, ARCH_NULL);
return 2; return 2;
} }
break; break;
@ -1412,14 +1412,14 @@ static UINT8 ArchiveValue(int TABLESINDEX, int myindex)
return 0; return 0;
} }
static void ArchiveExtVars(void *pointer, const char *ptype) static void ArchiveExtVars(save_t *save_p, void *pointer, const char *ptype)
{ {
int TABLESINDEX; int TABLESINDEX;
UINT16 i; UINT16 i;
if (!gL) { if (!gL) {
if (fastcmp(ptype,"player")) // players must always be included, even if no vars if (fastcmp(ptype,"player")) // players must always be included, even if no vars
WRITEUINT16(save_p, 0); P_WriteUINT16(save_p, 0);
return; return;
} }
@ -1435,7 +1435,7 @@ static void ArchiveExtVars(void *pointer, const char *ptype)
{ // no extra values table { // no extra values table
lua_pop(gL, 1); lua_pop(gL, 1);
if (fastcmp(ptype,"player")) // players must always be included, even if no vars if (fastcmp(ptype,"player")) // players must always be included, even if no vars
WRITEUINT16(save_p, 0); P_WriteUINT16(save_p, 0);
return; return;
} }
@ -1447,20 +1447,20 @@ static void ArchiveExtVars(void *pointer, const char *ptype)
if (i == 0) if (i == 0)
{ {
if (fastcmp(ptype,"player")) // always include players even if they have no extra variables if (fastcmp(ptype,"player")) // always include players even if they have no extra variables
WRITEUINT16(save_p, 0); P_WriteUINT16(save_p, 0);
lua_pop(gL, 1); lua_pop(gL, 1);
return; return;
} }
if (fastcmp(ptype,"mobj")) // mobjs must write their mobjnum as a header if (fastcmp(ptype,"mobj")) // mobjs must write their mobjnum as a header
WRITEUINT32(save_p, ((mobj_t *)pointer)->mobjnum); P_WriteUINT32(save_p, ((mobj_t *)pointer)->mobjnum);
WRITEUINT16(save_p, i); P_WriteUINT16(save_p, i);
lua_pushnil(gL); lua_pushnil(gL);
while (lua_next(gL, -2)) while (lua_next(gL, -2))
{ {
I_Assert(lua_type(gL, -2) == LUA_TSTRING); I_Assert(lua_type(gL, -2) == LUA_TSTRING);
WRITESTRING(save_p, lua_tostring(gL, -2)); P_WriteString(save_p, lua_tostring(gL, -2));
if (ArchiveValue(TABLESINDEX, -1) == 2) if (ArchiveValue(save_p, TABLESINDEX, -1) == 2)
CONS_Alert(CONS_ERROR, "Type of value for %s entry '%s' (%s) could not be archived!\n", ptype, lua_tostring(gL, -2), luaL_typename(gL, -1)); CONS_Alert(CONS_ERROR, "Type of value for %s entry '%s' (%s) could not be archived!\n", ptype, lua_tostring(gL, -2), luaL_typename(gL, -1));
lua_pop(gL, 1); lua_pop(gL, 1);
} }
@ -1468,16 +1468,19 @@ static void ArchiveExtVars(void *pointer, const char *ptype)
lua_pop(gL, 1); lua_pop(gL, 1);
} }
// FIXME: remove and pass as local variable
static save_t *lua_save_p;
static int NetArchive(lua_State *L) static int NetArchive(lua_State *L)
{ {
int TABLESINDEX = lua_upvalueindex(1); int TABLESINDEX = lua_upvalueindex(1);
int i, n = lua_gettop(L); int i, n = lua_gettop(L);
for (i = 1; i <= n; i++) for (i = 1; i <= n; i++)
ArchiveValue(TABLESINDEX, i); ArchiveValue(lua_save_p, TABLESINDEX, i);
return n; return n;
} }
static void ArchiveTables(void) static void ArchiveTables(save_t *save_p)
{ {
int TABLESINDEX; int TABLESINDEX;
UINT16 i, n; UINT16 i, n;
@ -1496,14 +1499,14 @@ static void ArchiveTables(void)
while (lua_next(gL, -2)) while (lua_next(gL, -2))
{ {
// Write key // Write key
e = ArchiveValue(TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this. e = ArchiveValue(save_p, TABLESINDEX, -2); // key should be either a number or a string, ArchiveValue can handle this.
if (e == 1) if (e == 1)
n++; // the table contained a new table we'll have to archive. :( n++; // the table contained a new table we'll have to archive. :(
else if (e == 2) // invalid key type (function, thread, lightuserdata, or anything we don't recognise) else if (e == 2) // invalid key type (function, thread, lightuserdata, or anything we don't recognise)
CONS_Alert(CONS_ERROR, "Index '%s' (%s) of table %d could not be archived!\n", lua_tostring(gL, -2), luaL_typename(gL, -2), i); CONS_Alert(CONS_ERROR, "Index '%s' (%s) of table %d could not be archived!\n", lua_tostring(gL, -2), luaL_typename(gL, -2), i);
// Write value // Write value
e = ArchiveValue(TABLESINDEX, -1); e = ArchiveValue(save_p, TABLESINDEX, -1);
if (e == 1) if (e == 1)
n++; // the table contained a new table we'll have to archive. :( n++; // the table contained a new table we'll have to archive. :(
else if (e == 2) // invalid value type else if (e == 2) // invalid value type
@ -1511,7 +1514,7 @@ static void ArchiveTables(void)
lua_pop(gL, 1); lua_pop(gL, 1);
} }
WRITEUINT8(save_p, ARCH_TEND); P_WriteUINT8(save_p, ARCH_TEND);
// Write metatable ID // Write metatable ID
if (lua_getmetatable(gL, -1)) if (lua_getmetatable(gL, -1))
@ -1520,19 +1523,19 @@ static void ArchiveTables(void)
lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES); lua_getfield(gL, LUA_REGISTRYINDEX, LREG_METATABLES);
lua_pushvalue(gL, -2); lua_pushvalue(gL, -2);
lua_gettable(gL, -2); lua_gettable(gL, -2);
WRITEUINT16(save_p, lua_isnil(gL, -1) ? 0 : lua_tointeger(gL, -1)); P_WriteUINT16(save_p, lua_isnil(gL, -1) ? 0 : lua_tointeger(gL, -1));
lua_pop(gL, 3); lua_pop(gL, 3);
} }
else else
WRITEUINT16(save_p, 0); P_WriteUINT16(save_p, 0);
lua_pop(gL, 1); lua_pop(gL, 1);
} }
} }
static UINT8 UnArchiveValue(int TABLESINDEX) static UINT8 UnArchiveValue(save_t *save_p, int TABLESINDEX)
{ {
UINT8 type = READUINT8(save_p); UINT8 type = P_ReadUINT8(save_p);
switch (type) switch (type)
{ {
case ARCH_NULL: case ARCH_NULL:
@ -1545,13 +1548,13 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
lua_pushboolean(gL, false); lua_pushboolean(gL, false);
break; break;
case ARCH_INT8: case ARCH_INT8:
lua_pushinteger(gL, READSINT8(save_p)); lua_pushinteger(gL, P_ReadSINT8(save_p));
break; break;
case ARCH_INT16: case ARCH_INT16:
lua_pushinteger(gL, READINT16(save_p)); lua_pushinteger(gL, P_ReadINT16(save_p));
break; break;
case ARCH_INT32: case ARCH_INT32:
lua_pushinteger(gL, READFIXED(save_p)); lua_pushinteger(gL, P_ReadFixed(save_p));
break; break;
case ARCH_SMALLSTRING: case ARCH_SMALLSTRING:
case ARCH_LARGESTRING: case ARCH_LARGESTRING:
@ -1562,23 +1565,23 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
// See my comments in the ArchiveValue function; // See my comments in the ArchiveValue function;
// it's much the same for reading strings as writing them! // it's much the same for reading strings as writing them!
// (i.e. we can't use READSTRING either) // (i.e. we can't use P_ReadString either)
// -- Monster Iestyn 05/08/18 // -- Monster Iestyn 05/08/18
if (type == ARCH_SMALLSTRING) if (type == ARCH_SMALLSTRING)
len = READUINT8(save_p); // length of string, including embedded zeros len = P_ReadUINT8(save_p); // length of string, including embedded zeros
else else
len = READUINT32(save_p); // length of string, including embedded zeros len = P_ReadUINT32(save_p); // length of string, including embedded zeros
value = malloc(len); // make temp buffer of size len value = malloc(len); // make temp buffer of size len
// now read the actual string // now read the actual string
while (i < len) while (i < len)
value[i++] = READCHAR(save_p); // read chars individually, including the embedded zeros value[i++] = P_ReadChar(save_p); // read chars individually, including the embedded zeros
lua_pushlstring(gL, value, len); // push the string (note: this function supports embedded zeros) lua_pushlstring(gL, value, len); // push the string (note: this function supports embedded zeros)
free(value); // free the buffer free(value); // free the buffer
break; break;
} }
case ARCH_TABLE: case ARCH_TABLE:
{ {
UINT16 tid = READUINT16(save_p); UINT16 tid = P_ReadUINT16(save_p);
lua_rawgeti(gL, TABLESINDEX, tid); lua_rawgeti(gL, TABLESINDEX, tid);
if (lua_isnil(gL, -1)) if (lua_isnil(gL, -1))
{ {
@ -1591,69 +1594,69 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
break; break;
} }
case ARCH_MOBJINFO: case ARCH_MOBJINFO:
LUA_PushUserdata(gL, &mobjinfo[READUINT16(save_p)], META_MOBJINFO); LUA_PushUserdata(gL, &mobjinfo[P_ReadUINT16(save_p)], META_MOBJINFO);
break; break;
case ARCH_STATE: case ARCH_STATE:
LUA_PushUserdata(gL, &states[READUINT16(save_p)], META_STATE); LUA_PushUserdata(gL, &states[P_ReadUINT16(save_p)], META_STATE);
break; break;
case ARCH_MOBJ: case ARCH_MOBJ:
LUA_PushUserdata(gL, P_FindNewPosition(READUINT32(save_p)), META_MOBJ); LUA_PushUserdata(gL, P_FindNewPosition(P_ReadUINT32(save_p)), META_MOBJ);
break; break;
case ARCH_PLAYER: case ARCH_PLAYER:
LUA_PushUserdata(gL, &players[READUINT8(save_p)], META_PLAYER); LUA_PushUserdata(gL, &players[P_ReadUINT8(save_p)], META_PLAYER);
break; break;
case ARCH_MAPTHING: case ARCH_MAPTHING:
LUA_PushUserdata(gL, &mapthings[READUINT16(save_p)], META_MAPTHING); LUA_PushUserdata(gL, &mapthings[P_ReadUINT16(save_p)], META_MAPTHING);
break; break;
case ARCH_VERTEX: case ARCH_VERTEX:
LUA_PushUserdata(gL, &vertexes[READUINT16(save_p)], META_VERTEX); LUA_PushUserdata(gL, &vertexes[P_ReadUINT16(save_p)], META_VERTEX);
break; break;
case ARCH_LINE: case ARCH_LINE:
LUA_PushUserdata(gL, &lines[READUINT16(save_p)], META_LINE); LUA_PushUserdata(gL, &lines[P_ReadUINT16(save_p)], META_LINE);
break; break;
case ARCH_SIDE: case ARCH_SIDE:
LUA_PushUserdata(gL, &sides[READUINT16(save_p)], META_SIDE); LUA_PushUserdata(gL, &sides[P_ReadUINT16(save_p)], META_SIDE);
break; break;
case ARCH_SUBSECTOR: case ARCH_SUBSECTOR:
LUA_PushUserdata(gL, &subsectors[READUINT16(save_p)], META_SUBSECTOR); LUA_PushUserdata(gL, &subsectors[P_ReadUINT16(save_p)], META_SUBSECTOR);
break; break;
case ARCH_SECTOR: case ARCH_SECTOR:
LUA_PushUserdata(gL, &sectors[READUINT16(save_p)], META_SECTOR); LUA_PushUserdata(gL, &sectors[P_ReadUINT16(save_p)], META_SECTOR);
break; break;
#ifdef HAVE_LUA_SEGS #ifdef HAVE_LUA_SEGS
case ARCH_SEG: case ARCH_SEG:
LUA_PushUserdata(gL, &segs[READUINT16(save_p)], META_SEG); LUA_PushUserdata(gL, &segs[P_ReadUINT16(save_p)], META_SEG);
break; break;
case ARCH_NODE: case ARCH_NODE:
LUA_PushUserdata(gL, &nodes[READUINT16(save_p)], META_NODE); LUA_PushUserdata(gL, &nodes[P_ReadUINT16(save_p)], META_NODE);
break; break;
#endif #endif
case ARCH_FFLOOR: case ARCH_FFLOOR:
{ {
sector_t *sector = &sectors[READUINT16(save_p)]; sector_t *sector = &sectors[P_ReadUINT16(save_p)];
UINT16 id = READUINT16(save_p); UINT16 id = P_ReadUINT16(save_p);
ffloor_t *rover = P_GetFFloorByID(sector, id); ffloor_t *rover = P_GetFFloorByID(sector, id);
if (rover) if (rover)
LUA_PushUserdata(gL, rover, META_FFLOOR); LUA_PushUserdata(gL, rover, META_FFLOOR);
break; break;
} }
case ARCH_POLYOBJ: case ARCH_POLYOBJ:
LUA_PushUserdata(gL, &PolyObjects[READUINT16(save_p)], META_POLYOBJ); LUA_PushUserdata(gL, &PolyObjects[P_ReadUINT16(save_p)], META_POLYOBJ);
break; break;
case ARCH_SLOPE: case ARCH_SLOPE:
LUA_PushUserdata(gL, P_SlopeById(READUINT16(save_p)), META_SLOPE); LUA_PushUserdata(gL, P_SlopeById(P_ReadUINT16(save_p)), META_SLOPE);
break; break;
case ARCH_MAPHEADER: case ARCH_MAPHEADER:
LUA_PushUserdata(gL, mapheaderinfo[READUINT16(save_p)], META_MAPHEADER); LUA_PushUserdata(gL, mapheaderinfo[P_ReadUINT16(save_p)], META_MAPHEADER);
break; break;
case ARCH_SKINCOLOR: case ARCH_SKINCOLOR:
LUA_PushUserdata(gL, &skincolors[READUINT16(save_p)], META_SKINCOLOR); LUA_PushUserdata(gL, &skincolors[P_ReadUINT16(save_p)], META_SKINCOLOR);
break; break;
case ARCH_MOUSE: case ARCH_MOUSE:
LUA_PushUserdata(gL, READUINT16(save_p) == 1 ? &mouse : &mouse2, META_MOUSE); LUA_PushUserdata(gL, P_ReadUINT16(save_p) == 1 ? &mouse : &mouse2, META_MOUSE);
break; break;
case ARCH_SKIN: case ARCH_SKIN:
LUA_PushUserdata(gL, skins[READUINT8(save_p)], META_SKIN); LUA_PushUserdata(gL, skins[P_ReadUINT8(save_p)], META_SKIN);
break; break;
case ARCH_TEND: case ARCH_TEND:
return 1; return 1;
@ -1661,10 +1664,10 @@ static UINT8 UnArchiveValue(int TABLESINDEX)
return 0; return 0;
} }
static void UnArchiveExtVars(void *pointer) static void UnArchiveExtVars(save_t *save_p, void *pointer)
{ {
int TABLESINDEX; int TABLESINDEX;
UINT16 field_count = READUINT16(save_p); UINT16 field_count = P_ReadUINT16(save_p);
UINT16 i; UINT16 i;
char field[1024]; char field[1024];
@ -1677,8 +1680,8 @@ static void UnArchiveExtVars(void *pointer)
for (i = 0; i < field_count; i++) for (i = 0; i < field_count; i++)
{ {
READSTRING(save_p, field); P_ReadString(save_p, field);
UnArchiveValue(TABLESINDEX); UnArchiveValue(save_p, TABLESINDEX);
lua_setfield(gL, -2, field); lua_setfield(gL, -2, field);
} }
@ -1695,11 +1698,11 @@ static int NetUnArchive(lua_State *L)
int TABLESINDEX = lua_upvalueindex(1); int TABLESINDEX = lua_upvalueindex(1);
int i, n = lua_gettop(L); int i, n = lua_gettop(L);
for (i = 1; i <= n; i++) for (i = 1; i <= n; i++)
UnArchiveValue(TABLESINDEX); UnArchiveValue(lua_save_p, TABLESINDEX);
return n; return n;
} }
static void UnArchiveTables(void) static void UnArchiveTables(save_t *save_p)
{ {
int TABLESINDEX; int TABLESINDEX;
UINT16 i, n; UINT16 i, n;
@ -1716,13 +1719,13 @@ static void UnArchiveTables(void)
lua_rawgeti(gL, TABLESINDEX, i); lua_rawgeti(gL, TABLESINDEX, i);
while (true) while (true)
{ {
UINT8 e = UnArchiveValue(TABLESINDEX); // read key UINT8 e = UnArchiveValue(save_p, TABLESINDEX); // read key
if (e == 1) // End of table if (e == 1) // End of table
break; break;
else if (e == 2) // Key contains a new table else if (e == 2) // Key contains a new table
n++; n++;
if (UnArchiveValue(TABLESINDEX) == 2) // read value if (UnArchiveValue(save_p, TABLESINDEX) == 2) // read value
n++; n++;
if (lua_isnil(gL, -2)) // if key is nil (if a function etc was accidentally saved) if (lua_isnil(gL, -2)) // if key is nil (if a function etc was accidentally saved)
@ -1734,7 +1737,7 @@ static void UnArchiveTables(void)
lua_rawset(gL, -3); lua_rawset(gL, -3);
} }
metatableid = READUINT16(save_p); metatableid = P_ReadUINT16(save_p);
if (metatableid) if (metatableid)
{ {
// setmetatable(table, registry.metatables[metatableid]) // setmetatable(table, registry.metatables[metatableid])
@ -1758,7 +1761,7 @@ void LUA_Step(void)
lua_gc(gL, LUA_GCSTEP, 1); lua_gc(gL, LUA_GCSTEP, 1);
} }
void LUA_Archive(void) void LUA_Archive(save_t *save_p)
{ {
INT32 i; INT32 i;
thinker_t *th; thinker_t *th;
@ -1771,7 +1774,7 @@ void LUA_Archive(void)
if (!playeringame[i] && i > 0) // dedicated servers... if (!playeringame[i] && i > 0) // dedicated servers...
continue; continue;
// all players in game will be archived, even if they just add a 0. // all players in game will be archived, even if they just add a 0.
ArchiveExtVars(&players[i], "player"); ArchiveExtVars(save_p, &players[i], "player");
} }
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
@ -1781,19 +1784,20 @@ void LUA_Archive(void)
// archive function will determine when to skip mobjs, // archive function will determine when to skip mobjs,
// and write mobjnum in otherwise. // and write mobjnum in otherwise.
ArchiveExtVars(th, "mobj"); ArchiveExtVars(save_p, th, "mobj");
} }
WRITEUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum. P_WriteUINT32(save_p, UINT32_MAX); // end of mobjs marker, replaces mobjnum.
lua_save_p = save_p;
LUA_HookNetArchive(NetArchive); // call the NetArchive hook in archive mode LUA_HookNetArchive(NetArchive); // call the NetArchive hook in archive mode
ArchiveTables(); ArchiveTables(save_p);
if (gL) if (gL)
lua_pop(gL, 1); // pop tables lua_pop(gL, 1); // pop tables
} }
void LUA_UnArchive(void) void LUA_UnArchive(save_t *save_p)
{ {
UINT32 mobjnum; UINT32 mobjnum;
INT32 i; INT32 i;
@ -1806,23 +1810,24 @@ void LUA_UnArchive(void)
{ {
if (!playeringame[i] && i > 0) // dedicated servers... if (!playeringame[i] && i > 0) // dedicated servers...
continue; continue;
UnArchiveExtVars(&players[i]); UnArchiveExtVars(save_p, &players[i]);
} }
do { do {
mobjnum = READUINT32(save_p); // read a mobjnum mobjnum = P_ReadUINT32(save_p); // read a mobjnum
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{ {
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue; continue;
if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj
continue; continue;
UnArchiveExtVars(th); // apply variables UnArchiveExtVars(save_p, th); // apply variables
} }
} while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker. } while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker.
lua_save_p = save_p;
LUA_HookNetArchive(NetUnArchive); // call the NetArchive hook in unarchive mode LUA_HookNetArchive(NetUnArchive); // call the NetArchive hook in unarchive mode
UnArchiveTables(); UnArchiveTables(save_p);
if (gL) if (gL)
lua_pop(gL, 1); // pop tables lua_pop(gL, 1); // pop tables

View file

@ -13,6 +13,7 @@
#ifndef LUA_SCRIPT_H #ifndef LUA_SCRIPT_H
#define LUA_SCRIPT_H #define LUA_SCRIPT_H
#include "p_saveg.h"
#include "m_fixed.h" #include "m_fixed.h"
#include "doomtype.h" #include "doomtype.h"
#include "d_player.h" #include "d_player.h"
@ -52,8 +53,8 @@ void LUA_DumpFile(const char *filename);
#endif #endif
fixed_t LUA_EvalMath(const char *word); fixed_t LUA_EvalMath(const char *word);
void LUA_Step(void); void LUA_Step(void);
void LUA_Archive(void); void LUA_Archive(save_t *save_p);
void LUA_UnArchive(void); void LUA_UnArchive(save_t *save_p);
int LUA_PushGlobals(lua_State *L, const char *word); int LUA_PushGlobals(lua_State *L, const char *word);
int LUA_CheckGlobals(lua_State *L, const char *word); int LUA_CheckGlobals(lua_State *L, const char *word);
void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c

View file

@ -1416,6 +1416,83 @@ static void IdleUpdate(void)
} }
} }
static void DedicatedIdleUpdate(INT32 *realtics)
{
const tic_t dedicatedidletime = cv_dedicatedidletime.value * TICRATE;
static tic_t dedicatedidletimeprev = 0;
static tic_t dedicatedidle = 0;
if (!server || !dedicated || gamestate != GS_LEVEL)
return;
if (dedicatedidletime > 0)
{
INT32 i;
boolean empty = true;
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
{
empty = false;
break;
}
if (empty)
{
if (leveltime == 2)
{
// On next tick...
dedicatedidle = dedicatedidletime - 1;
}
else if (dedicatedidle >= dedicatedidletime)
{
if (D_GetExistingTextcmd(gametic, 0) || D_GetExistingTextcmd(gametic + 1, 0))
{
CONS_Printf("DEDICATED: Awakening from idle (Netxcmd detected...)\n");
dedicatedidle = 0;
}
else
{
(*realtics) = 0;
}
}
else
{
dedicatedidle += (*realtics);
if (dedicatedidle >= dedicatedidletime)
{
const char *idlereason = "at round start";
if (leveltime > 3)
idlereason = va("for %d seconds", dedicatedidle / TICRATE);
CONS_Printf("DEDICATED: No players %s, idling...\n", idlereason);
(*realtics) = 0;
dedicatedidle = dedicatedidletime;
}
}
}
else
{
if (dedicatedidle >= dedicatedidletime)
{
CONS_Printf("DEDICATED: Awakening from idle (Player detected...)\n");
}
dedicatedidle = 0;
}
}
else
{
if (dedicatedidletimeprev > 0 && dedicatedidle >= dedicatedidletimeprev)
{
CONS_Printf("DEDICATED: Awakening from idle (Idle disabled...)\n");
}
dedicatedidle = 0;
}
dedicatedidletimeprev = dedicatedidletime;
}
// Handle timeouts to prevent definitive freezes from happenning // Handle timeouts to prevent definitive freezes from happenning
static void HandleNodeTimeouts(void) static void HandleNodeTimeouts(void)
{ {
@ -1492,69 +1569,7 @@ void NetUpdate(void)
realtics = 5; realtics = 5;
} }
if (server && dedicated && gamestate == GS_LEVEL) DedicatedIdleUpdate(&realtics);
{
const tic_t dedicatedidletime = cv_dedicatedidletime.value * TICRATE;
static tic_t dedicatedidletimeprev = 0;
static tic_t dedicatedidle = 0;
if (dedicatedidletime > 0)
{
INT32 i;
for (i = 1; i < MAXNETNODES; ++i)
if (netnodes[i].ingame)
{
if (dedicatedidle >= dedicatedidletime)
{
CONS_Printf("DEDICATED: Awakening from idle (Node %d detected...)\n", i);
dedicatedidle = 0;
}
break;
}
if (i == MAXNETNODES)
{
if (leveltime == 2)
{
// On next tick...
dedicatedidle = dedicatedidletime-1;
}
else if (dedicatedidle >= dedicatedidletime)
{
if (D_GetExistingTextcmd(gametic, 0) || D_GetExistingTextcmd(gametic+1, 0))
{
CONS_Printf("DEDICATED: Awakening from idle (Netxcmd detected...)\n");
dedicatedidle = 0;
}
else
{
realtics = 0;
}
}
else if ((dedicatedidle += realtics) >= dedicatedidletime)
{
const char *idlereason = "at round start";
if (leveltime > 3)
idlereason = va("for %d seconds", dedicatedidle/TICRATE);
CONS_Printf("DEDICATED: No nodes %s, idling...\n", idlereason);
realtics = 0;
dedicatedidle = dedicatedidletime;
}
}
}
else
{
if (dedicatedidletimeprev > 0 && dedicatedidle >= dedicatedidletimeprev)
{
CONS_Printf("DEDICATED: Awakening from idle (Idle disabled...)\n");
}
dedicatedidle = 0;
}
dedicatedidletimeprev = dedicatedidletime;
}
gametime = nowtime; gametime = nowtime;

View file

@ -4799,12 +4799,11 @@ static void Command_Togglemodified_f(void)
modifiedgame = !modifiedgame; modifiedgame = !modifiedgame;
} }
extern UINT8 *save_p;
static void Command_Archivetest_f(void) static void Command_Archivetest_f(void)
{ {
UINT8 *buf;
UINT32 i, wrote; UINT32 i, wrote;
thinker_t *th; thinker_t *th;
save_t savebuffer;
if (gamestate != GS_LEVEL) if (gamestate != GS_LEVEL)
{ {
CONS_Printf("This command only works in-game, you dummy.\n"); CONS_Printf("This command only works in-game, you dummy.\n");
@ -4818,28 +4817,29 @@ static void Command_Archivetest_f(void)
((mobj_t *)th)->mobjnum = i++; ((mobj_t *)th)->mobjnum = i++;
// allocate buffer // allocate buffer
buf = save_p = ZZ_Alloc(1024); savebuffer.size = 1024;
savebuffer.buf = malloc(savebuffer.size);
savebuffer.pos = 0;
// test archive // test archive
CONS_Printf("LUA_Archive...\n"); CONS_Printf("LUA_Archive...\n");
LUA_Archive(); LUA_Archive(&savebuffer);
WRITEUINT8(save_p, 0x7F); P_WriteUINT8(&savebuffer, 0x7F);
wrote = (UINT32)(save_p-buf); wrote = savebuffer.pos;
// clear Lua state, so we can really see what happens! // clear Lua state, so we can really see what happens!
CONS_Printf("Clearing state!\n"); CONS_Printf("Clearing state!\n");
LUA_ClearExtVars(); LUA_ClearExtVars();
// test unarchive // test unarchive
save_p = buf;
CONS_Printf("LUA_UnArchive...\n"); CONS_Printf("LUA_UnArchive...\n");
LUA_UnArchive(); LUA_UnArchive(&savebuffer);
i = READUINT8(save_p); i = P_ReadUINT8(&savebuffer);
if (i != 0x7F || wrote != (UINT32)(save_p-buf)) if (i != 0x7F || wrote != (UINT32)(savebuffer.pos))
CONS_Printf("Savegame corrupted. (write %u, read %u)\n", wrote, (UINT32)(save_p-buf)); CONS_Printf("Savegame corrupted. (write %u, read %u)\n", wrote, (UINT32)(savebuffer.pos));
// free buffer // free buffer
Z_Free(buf); free(savebuffer.buf);
CONS_Printf("Done. No crash.\n"); CONS_Printf("Done. No crash.\n");
} }
#endif #endif

View file

@ -54,30 +54,25 @@ boolean SV_ResendingSavegameToAnyone(void)
void SV_SendSaveGame(INT32 node, boolean resending) void SV_SendSaveGame(INT32 node, boolean resending)
{ {
size_t length, compressedlen; size_t length, compressedlen;
UINT8 *savebuffer; save_t savebuffer;
UINT8 *compressedsave; UINT8 *compressedsave;
UINT8 *buffertosend; UINT8 *buffertosend;
// first save it in a malloced buffer // first save it in a malloced buffer
savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); savebuffer.size = SAVEGAMESIZE;
if (!savebuffer) savebuffer.buf = (UINT8 *)malloc(savebuffer.size);
if (!savebuffer.buf)
{ {
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
return; return;
} }
// Leave room for the uncompressed length. // Leave room for the uncompressed length.
save_p = savebuffer + sizeof(UINT32); savebuffer.pos = sizeof(UINT32);
P_SaveNetGame(resending); P_SaveNetGame(&savebuffer, resending);
length = save_p - savebuffer; length = savebuffer.pos;
if (length > SAVEGAMESIZE)
{
free(savebuffer);
save_p = NULL;
I_Error("Savegame buffer overrun");
}
// Allocate space for compressed save: one byte fewer than for the // Allocate space for compressed save: one byte fewer than for the
// uncompressed data to ensure that the compression is worthwhile. // uncompressed data to ensure that the compression is worthwhile.
@ -85,15 +80,16 @@ void SV_SendSaveGame(INT32 node, boolean resending)
if (!compressedsave) if (!compressedsave)
{ {
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
free(savebuffer.buf);
return; return;
} }
// Attempt to compress it. // Attempt to compress it.
if((compressedlen = lzf_compress(savebuffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1))) if((compressedlen = lzf_compress(savebuffer.buf + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1)))
{ {
// Compressing succeeded; send compressed data // Compressing succeeded; send compressed data
free(savebuffer); free(savebuffer.buf);
// State that we're compressed. // State that we're compressed.
buffertosend = compressedsave; buffertosend = compressedsave;
@ -107,12 +103,12 @@ void SV_SendSaveGame(INT32 node, boolean resending)
free(compressedsave); free(compressedsave);
// State that we're not compressed // State that we're not compressed
buffertosend = savebuffer; buffertosend = savebuffer.buf;
WRITEUINT32(savebuffer, 0); savebuffer.pos = 0;
P_WriteUINT32(&savebuffer, 0);
} }
AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0); AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0);
save_p = NULL;
// Remember when we started sending the savegame so we can handle timeouts // Remember when we started sending the savegame so we can handle timeouts
netnodes[node].sendingsavegame = true; netnodes[node].sendingsavegame = true;
@ -125,8 +121,7 @@ static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_SA
void SV_SavedGame(void) void SV_SavedGame(void)
{ {
size_t length; save_t savebuffer;
UINT8 *savebuffer;
char tmpsave[256]; char tmpsave[256];
if (!cv_dumpconsistency.value) if (!cv_dumpconsistency.value)
@ -135,29 +130,22 @@ void SV_SavedGame(void)
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
// first save it in a malloced buffer // first save it in a malloced buffer
save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); savebuffer.size = SAVEGAMESIZE;
if (!save_p) savebuffer.buf = (UINT8 *)malloc(savebuffer.size);
if (!savebuffer.buf)
{ {
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
return; return;
} }
savebuffer.pos = 0;
P_SaveNetGame(false); P_SaveNetGame(&savebuffer, false);
length = save_p - savebuffer;
if (length > SAVEGAMESIZE)
{
free(savebuffer);
save_p = NULL;
I_Error("Savegame buffer overrun");
}
// then save it! // then save it!
if (!FIL_WriteFile(tmpsave, savebuffer, length)) if (!FIL_WriteFile(tmpsave, savebuffer.buf, savebuffer.pos))
CONS_Printf(M_GetText("Didn't save %s for netgame"), tmpsave); CONS_Printf(M_GetText("Didn't save %s for netgame"), tmpsave);
free(savebuffer); free(savebuffer.pos);
save_p = NULL;
} }
#undef TMPSAVENAME #undef TMPSAVENAME
@ -167,33 +155,34 @@ void SV_SavedGame(void)
void CL_LoadReceivedSavegame(boolean reloading) void CL_LoadReceivedSavegame(boolean reloading)
{ {
UINT8 *savebuffer = NULL; save_t savebuffer;
size_t length, decompressedlen; size_t decompressedlen;
char tmpsave[256]; char tmpsave[256];
FreeFileNeeded(); FreeFileNeeded();
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
length = FIL_ReadFile(tmpsave, &savebuffer); savebuffer.size = FIL_ReadFile(tmpsave, &savebuffer.buf);
savebuffer.pos = 0;
CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length)); CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(savebuffer.size));
if (!length) if (!savebuffer.size)
{ {
I_Error("Can't read savegame sent"); I_Error("Can't read savegame sent");
return; return;
} }
save_p = savebuffer;
// Decompress saved game if necessary. // Decompress saved game if necessary.
decompressedlen = READUINT32(save_p); decompressedlen = P_ReadUINT32(&savebuffer);
if(decompressedlen > 0) if(decompressedlen > 0)
{ {
UINT8 *decompressedbuffer = Z_Malloc(decompressedlen, PU_STATIC, NULL); UINT8 *decompressedbuffer = Z_Malloc(decompressedlen, PU_STATIC, NULL);
lzf_decompress(save_p, length - sizeof(UINT32), decompressedbuffer, decompressedlen); lzf_decompress(savebuffer.buf + sizeof(UINT32), savebuffer.size - sizeof(UINT32), decompressedbuffer, decompressedlen);
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = savebuffer = decompressedbuffer; savebuffer.buf = decompressedbuffer;
savebuffer.size = decompressedlen;
savebuffer.pos = 0;
} }
paused = false; paused = false;
@ -203,7 +192,7 @@ void CL_LoadReceivedSavegame(boolean reloading)
automapactive = false; automapactive = false;
// load a base level // load a base level
if (P_LoadNetGame(reloading)) if (P_LoadNetGame(&savebuffer, reloading))
{ {
const UINT8 actnum = mapheaderinfo[gamemap-1]->actnum; const UINT8 actnum = mapheaderinfo[gamemap-1]->actnum;
CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap)); CONS_Printf(M_GetText("Map is now \"%s"), G_BuildMapName(gamemap));
@ -219,8 +208,7 @@ void CL_LoadReceivedSavegame(boolean reloading)
} }
// done // done
Z_Free(savebuffer); Z_Free(savebuffer.buf);
save_p = NULL;
if (unlink(tmpsave) == -1) if (unlink(tmpsave) == -1)
CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave); CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave);
consistancy[gametic%BACKUPTICS] = Consistancy(); consistancy[gametic%BACKUPTICS] = Consistancy();

View file

@ -539,6 +539,8 @@ boolean P_SceneryZMovement(mobj_t *mo);
void P_PlayerZMovement(mobj_t *mo); void P_PlayerZMovement(mobj_t *mo);
void P_EmeraldManager(void); void P_EmeraldManager(void);
mobj_t *P_FindNewPosition(UINT32 oldposition);
extern INT32 modulothing; extern INT32 modulothing;
#define MAXHUNTEMERALDS 64 #define MAXHUNTEMERALDS 64

File diff suppressed because it is too large Load diff

View file

@ -18,17 +18,24 @@
#pragma interface #pragma interface
#endif #endif
#include "tables.h"
#define NEWSKINSAVES (INT16_MAX) // TODO: 2.3: Delete (Purely for backwards compatibility) #define NEWSKINSAVES (INT16_MAX) // TODO: 2.3: Delete (Purely for backwards compatibility)
// Persistent storage/archiving. // Persistent storage/archiving.
// These are the load / save game routines. // These are the load / save game routines.
void P_SaveGame(INT16 mapnum); typedef struct
void P_SaveNetGame(boolean resending); {
boolean P_LoadGame(INT16 mapoverride); unsigned char *buf;
boolean P_LoadNetGame(boolean reloading); size_t size;
size_t pos;
} save_t;
mobj_t *P_FindNewPosition(UINT32 oldposition); void P_SaveGame(save_t *save_p, INT16 mapnum);
void P_SaveNetGame(save_t *save_p, boolean resending);
boolean P_LoadGame(save_t *save_p, INT16 mapoverride);
boolean P_LoadNetGame(save_t *save_p, boolean reloading);
typedef struct typedef struct
{ {
@ -42,6 +49,37 @@ typedef struct
} savedata_t; } savedata_t;
extern savedata_t savedata; extern savedata_t savedata;
extern UINT8 *save_p;
void P_WriteUINT8(save_t *p, UINT8 v);
void P_WriteSINT8(save_t *p, SINT8 v);
void P_WriteUINT16(save_t *p, UINT16 v);
void P_WriteINT16(save_t *p, INT16 v);
void P_WriteUINT32(save_t *p, UINT32 v);
void P_WriteINT32(save_t *p, INT32 v);
void P_WriteChar(save_t *p, char v);
void P_WriteFixed(save_t *p, fixed_t v);
void P_WriteAngle(save_t *p, angle_t v);
void P_WriteStringN(save_t *p, char const *s, size_t n);
void P_WriteStringL(save_t *p, char const *s, size_t n);
void P_WriteString(save_t *p, char const *s);
void P_WriteMem(save_t *p, void const *s, size_t n);
void P_SkipStringN(save_t *p, size_t n);
void P_SkipStringL(save_t *p, size_t n);
void P_SkipString(save_t *p);
UINT8 P_ReadUINT8(save_t *p);
SINT8 P_ReadSINT8(save_t *p);
UINT16 P_ReadUINT16(save_t *p);
INT16 P_ReadINT16(save_t *p);
UINT32 P_ReadUINT32(save_t *p);
INT32 P_ReadINT32(save_t *p);
char P_ReadChar(save_t *p);
fixed_t P_ReadFixed(save_t *p);
angle_t P_ReadAngle(save_t *p);
void P_ReadStringN(save_t *p, char *s, size_t n);
void P_ReadStringL(save_t *p, char *s, size_t n);
void P_ReadString(save_t *p, char *s);
void P_ReadMem(save_t *p, void *s, size_t n);
#endif #endif

View file

@ -379,7 +379,7 @@ static void MirrorMissingRotations(void)
UINT8 baserotation = GetOppositeRotation(rotation, frame->rotate); UINT8 baserotation = GetOppositeRotation(rotation, frame->rotate);
UINT32 lumpnum = frame->lumppat[baserotation - 1]; UINT32 lumpnum = frame->lumppat[baserotation - 1];
R_InstallSpriteLump(WADFILENUM(lumpnum), LUMPNUM(lumpnum), frame->lumpid[baserotation], framenum, rotation, 1); R_InstallSpriteLump(WADFILENUM(lumpnum), LUMPNUM(lumpnum), frame->lumpid[baserotation - 1], framenum, rotation, 1);
} }
} }
} }

View file

@ -1258,6 +1258,8 @@ static void ST_drawInput(void)
V_DrawThinString(x, y, hudinfo[HUD_INPUT].f|((leveltime & 4) ? V_YELLOWMAP : V_REDMAP), "BAD DEMO!!"); V_DrawThinString(x, y, hudinfo[HUD_INPUT].f|((leveltime & 4) ? V_YELLOWMAP : V_REDMAP), "BAD DEMO!!");
} }
static boolean lt_active = false;
static patch_t *lt_patches[3]; static patch_t *lt_patches[3];
static INT32 lt_scroll = 0; static INT32 lt_scroll = 0;
static INT32 lt_mom = 0; static INT32 lt_mom = 0;
@ -1306,6 +1308,7 @@ void ST_startTitleCard(void)
ST_cacheLevelTitle(); ST_cacheLevelTitle();
// initialize HUD variables // initialize HUD variables
lt_active = true;
lt_ticker = lt_exitticker = lt_lasttic = 0; lt_ticker = lt_exitticker = lt_lasttic = 0;
lt_endtime = 2*TICRATE + (10*NEWTICRATERATIO); lt_endtime = 2*TICRATE + (10*NEWTICRATERATIO);
lt_scroll = BASEVIDWIDTH * FRACUNIT; lt_scroll = BASEVIDWIDTH * FRACUNIT;
@ -1314,21 +1317,11 @@ void ST_startTitleCard(void)
} }
// //
// What happens before drawing the title card. // Stops the title card.
// Which is just setting the HUD translucency.
// //
void ST_preDrawTitleCard(void) void ST_stopTitleCard(void)
{ {
if (!G_IsTitleCardAvailable()) lt_active = false;
return;
if (lt_ticker >= (lt_endtime + TICRATE))
return;
if (!lt_exitticker)
st_translucency = 0;
else
st_translucency = max(0, min((INT32)lt_exitticker-4, cv_translucenthud.value));
} }
// //
@ -1337,47 +1330,43 @@ void ST_preDrawTitleCard(void)
// //
void ST_runTitleCard(void) void ST_runTitleCard(void)
{ {
boolean run = !(paused || P_AutoPause()); if (!lt_active || ((paused || P_AutoPause()) && lt_ticker >= PRELEVELTIME))
if (!G_IsTitleCardAvailable())
return; return;
if (lt_ticker >= (lt_endtime + TICRATE)) if (!lt_exitticker)
return;
if (run || (lt_ticker < PRELEVELTIME))
{ {
// tick if (abs(lt_scroll) > FRACUNIT)
lt_ticker++; lt_scroll -= (lt_scroll>>2);
if (lt_ticker >= lt_endtime)
lt_exitticker++;
// scroll to screen (level title)
if (!lt_exitticker)
{
if (abs(lt_scroll) > FRACUNIT)
lt_scroll -= (lt_scroll>>2);
else
lt_scroll = 0;
}
// scroll away from screen (level title)
else else
lt_scroll = 0;
if (abs(lt_zigzag) > FRACUNIT)
lt_zigzag -= (lt_zigzag>>2);
else
lt_zigzag = 0;
}
else
{
lt_mom -= FRACUNIT*6;
if (lt_scroll > -BASEVIDWIDTH * FRACUNIT * 2)
{ {
lt_mom -= FRACUNIT*6;
lt_scroll += lt_mom; lt_scroll += lt_mom;
} }
// scroll to screen (zigzag) if (lt_zigzag > -(lt_patches[1]->width)*FRACUNIT)
if (!lt_exitticker)
{ {
if (abs(lt_zigzag) > FRACUNIT)
lt_zigzag -= (lt_zigzag>>2);
else
lt_zigzag = 0;
}
// scroll away from screen (zigzag)
else
lt_zigzag += lt_mom; lt_zigzag += lt_mom;
}
}
lt_ticker++;
lt_exitticker = max((signed)lt_ticker - (signed)lt_endtime, 0);
if (lt_ticker >= (lt_endtime + TICRATE))
{
lt_active = false;
return;
} }
} }
@ -1404,9 +1393,6 @@ void ST_drawTitleCard(void)
colormap = R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE); colormap = R_GetTranslationColormap(TC_DEFAULT, colornum, GTC_CACHE);
if (!G_IsTitleCardAvailable())
return;
if (!LUA_HudEnabled(hud_stagetitle)) if (!LUA_HudEnabled(hud_stagetitle))
goto luahook; goto luahook;
@ -1487,13 +1473,14 @@ void ST_preLevelTitleCardDrawer(void)
// //
void ST_drawWipeTitleCard(void) void ST_drawWipeTitleCard(void)
{ {
if (!lt_active)
return;
stplyr = &players[consoleplayer]; stplyr = &players[consoleplayer];
ST_preDrawTitleCard();
ST_drawTitleCard(); ST_drawTitleCard();
if (splitscreen) if (splitscreen)
{ {
stplyr = &players[secondarydisplayplayer]; stplyr = &players[secondarydisplayplayer];
ST_preDrawTitleCard();
ST_drawTitleCard(); ST_drawTitleCard();
} }
} }
@ -2705,24 +2692,14 @@ static boolean ST_doItemFinderIconsAndSound(void)
return true; return true;
} }
static boolean drawstagetitle = false;
// //
// Draw the status bar overlay, customisable: the user chooses which // Draw the status bar overlay, customisable: the user chooses which
// kind of information to overlay // kind of information to overlay
// //
static void ST_overlayDrawer(void) static void ST_overlayDrawer(void)
{ {
// Decide whether to draw the stage title or not
boolean stagetitle = false;
// Check for a valid level title
// If the HUD is enabled
// And, if Lua is running, if the HUD library has the stage title enabled
if (G_IsTitleCardAvailable() && *mapheaderinfo[gamemap-1]->lvlttl != '\0' && !(hu_showscores && (netgame || multiplayer)))
{
stagetitle = true;
ST_preDrawTitleCard();
}
// hu_showscores = auto hide score/time/rings when tab rankings are shown // hu_showscores = auto hide score/time/rings when tab rankings are shown
if (!(hu_showscores && (netgame || multiplayer))) if (!(hu_showscores && (netgame || multiplayer)))
{ {
@ -2862,7 +2839,7 @@ static void ST_overlayDrawer(void)
} }
// draw level title Tails // draw level title Tails
if (stagetitle && (!WipeInAction) && (!WipeStageTitle)) if (drawstagetitle && !WipeInAction && !WipeStageTitle)
ST_drawTitleCard(); ST_drawTitleCard();
if (!hu_showscores && (netgame || multiplayer) && LUA_HudEnabled(hud_textspectator)) if (!hu_showscores && (netgame || multiplayer) && LUA_HudEnabled(hud_textspectator))
@ -2933,7 +2910,22 @@ void ST_Drawer(void)
} }
} }
st_translucency = cv_translucenthud.value; // Decide whether to draw the stage title or not
if (lt_active)
{
drawstagetitle = !(hu_showscores && (netgame || multiplayer));
if (!lt_exitticker)
st_translucency = 0;
else
st_translucency = max(0, min((INT32)lt_exitticker-4, cv_translucenthud.value));
}
else
{
st_translucency = cv_translucenthud.value;
drawstagetitle = false;
}
if (st_overlay) if (st_overlay)
{ {

View file

@ -49,9 +49,9 @@ void ST_doPaletteStuff(void);
// title card // title card
void ST_startTitleCard(void); void ST_startTitleCard(void);
void ST_stopTitleCard(void);
void ST_runTitleCard(void); void ST_runTitleCard(void);
void ST_drawTitleCard(void); void ST_drawTitleCard(void);
void ST_preDrawTitleCard(void);
void ST_preLevelTitleCardDrawer(void); void ST_preLevelTitleCardDrawer(void);
void ST_drawWipeTitleCard(void); void ST_drawWipeTitleCard(void);