Skip to content

Commit

Permalink
server: fix the save command's checks for multiplayer/dedicated
Browse files Browse the repository at this point in the history
Also makes the save and load messages nicer.

Signed-off-by: bones_was_here <[email protected]>
  • Loading branch information
bones-was-here committed Aug 28, 2024
1 parent 61e9482 commit f4b7eca
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 52 deletions.
5 changes: 0 additions & 5 deletions cl_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -620,10 +620,6 @@ static void CL_EstablishConnection_Local(void)
CL_EstablishConnection("local:1", -2);
}

static qbool CL_Intermission(void)
{
return cl.intermission;
}

/*
==============
Expand Down Expand Up @@ -3149,7 +3145,6 @@ void CL_Init (void)

host.hook.ConnectLocal = CL_EstablishConnection_Local;
host.hook.Disconnect = CL_DisconnectEx;
host.hook.CL_Intermission = CL_Intermission;
host.hook.ToggleMenu = CL_ToggleMenu_Hook;
}
}
1 change: 0 additions & 1 deletion host.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,6 @@ void Host_Init (void)
host.hook.ConnectLocal = NULL;
host.hook.Disconnect = NULL;
host.hook.ToggleMenu = NULL;
host.hook.CL_Intermission = NULL;
host.hook.SV_Shutdown = NULL;

host.state = host_init;
Expand Down
1 change: 0 additions & 1 deletion host.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ typedef struct host_static_s
void (*ConnectLocal)(void);
void (*Disconnect)(qbool, const char *, ... );
void (*ToggleMenu)(void);
qbool (*CL_Intermission)(void); // Quake compatibility
void (*CL_SendCvar)(struct cmd_state_s *);
void (*SV_SendCvar)(struct cmd_state_s *);
void (*SV_Shutdown)(void);
Expand Down
4 changes: 2 additions & 2 deletions sv_ccmds.c
Original file line number Diff line number Diff line change
Expand Up @@ -1655,8 +1655,8 @@ void SV_InitOperatorCommands(void)
Cmd_AddCommand(CF_SERVER | CF_SERVER_FROM_CLIENT, "pause", SV_Pause_f, "pause the game (if the server allows pausing)");
Cmd_AddCommand(CF_SHARED, "kick", SV_Kick_f, "kick a player off the server by number or name");
Cmd_AddCommand(CF_SHARED | CF_SERVER_FROM_CLIENT, "ping", SV_Ping_f, "print ping times of all players on the server");
Cmd_AddCommand(CF_SHARED, "load", SV_Loadgame_f, "load a saved game file");
Cmd_AddCommand(CF_SHARED, "save", SV_Savegame_f, "save the game to a file");
Cmd_AddCommand(CF_SERVER, "load", SV_Loadgame_f, "load a saved game file");
Cmd_AddCommand(CF_SERVER, "save", SV_Savegame_f, "save the game to a file");
Cmd_AddCommand(CF_SHARED, "viewmodel", SV_Viewmodel_f, "change model of viewthing entity in current level");
Cmd_AddCommand(CF_SHARED, "viewframe", SV_Viewframe_f, "change animation frame of viewthing entity in current level");
Cmd_AddCommand(CF_SHARED, "viewnext", SV_Viewnext_f, "change to next animation frame of viewthing entity in current level");
Expand Down
77 changes: 34 additions & 43 deletions sv_save.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ void SV_Savegame_to(prvm_prog_t *prog, const char *name)
f = FS_OpenRealFile(name, "wb", false);
if (!f)
{
Con_Print("ERROR: couldn't open.\n");
Con_Print(CON_ERROR "ERROR: couldn't open.\n");
return;
}

Expand Down Expand Up @@ -180,30 +180,6 @@ void SV_Savegame_to(prvm_prog_t *prog, const char *name)
Con_Print("done.\n");
}

static qbool SV_CanSave(void)
{
prvm_prog_t *prog = SVVM_prog;
if(SV_IsLocalServer() == 1)
{
// singleplayer checks
// FIXME: This only checks if the first player is dead?
if ((svs.clients[0].active && PRVM_serveredictfloat(svs.clients[0].edict, deadflag)))
{
Con_Print("Can't savegame with a dead player\n");
return false;
}

if(host.hook.CL_Intermission && host.hook.CL_Intermission())
{
Con_Print("Can't save in intermission.\n");
return false;
}
}
else
Con_Print(CON_WARN "Warning: saving a multiplayer game may have strange results when restored (to properly resume, all players must join in the same player slots and then the game can be reloaded).\n");
return true;
}

/*
===============
SV_Savegame_f
Expand All @@ -216,13 +192,10 @@ void SV_Savegame_f(cmd_state_t *cmd)

if (!sv.active)
{
Con_Print("Can't save - no server running.\n");
Con_Print(CON_ERROR "Can't save - no server running.\n");
return;
}

if(!SV_CanSave())
return;

if (Cmd_Argc(cmd) != 2)
{
Con_Print("save <savename> : save a game\n");
Expand All @@ -231,10 +204,28 @@ void SV_Savegame_f(cmd_state_t *cmd)

if (strstr(Cmd_Argv(cmd, 1), ".."))
{
Con_Print("Relative pathnames are not allowed.\n");
Con_Print(CON_ERROR "Relative pathnames are not allowed.\n");
return;
}

for (int i = 0; i < svs.maxclients; ++i)
if (svs.clients[i].active && PRVM_serveredictfloat(svs.clients[i].edict, deadflag))
{
Con_Print(CON_ERROR "Can't savegame with a dead player\n");
return;
}

// bones_was_here: intermission_running isn't declared in dpdefs, but it's used by
// id1 Quake, all Quake mods (afaict), Nexuiz and Xonotic.
if (PRVM_serverglobalfloat(intermission_running))
{
Con_Print(CON_ERROR "Can't save in intermission.\n");
return;
}

if (SV_IsLocalServer() != 1)
Con_Print(CON_WARN "Warning: saving a multiplayer game may have strange results when restored (to properly resume, all players must join in the same player slots and then the game can be reloaded).\n");

dp_strlcpy (name, Cmd_Argv(cmd, 1), sizeof (name));
FS_DefaultExtension (name, ".sav", sizeof (name));

Expand Down Expand Up @@ -285,7 +276,7 @@ void SV_Loadgame_f(cmd_state_t *cmd)
t = text = (char *)FS_LoadFile (filename, tempmempool, false, NULL);
if (!text)
{
Con_Print("ERROR: couldn't open.\n");
Con_Print(CON_ERROR "ERROR: couldn't open.\n");
return;
}

Expand All @@ -298,7 +289,7 @@ void SV_Loadgame_f(cmd_state_t *cmd)
if (version != SAVEGAME_VERSION)
{
Mem_Free(text);
Con_Printf("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
Con_Printf(CON_ERROR "Savegame is version %i, not %i\n", version, SAVEGAME_VERSION);
return;
}

Expand Down Expand Up @@ -340,7 +331,7 @@ void SV_Loadgame_f(cmd_state_t *cmd)
if (!sv.active)
{
Mem_Free(text);
Con_Print("Couldn't load map\n");
Con_Printf(CON_ERROR "Couldn't load map \"%s\"\n", mapname);
return;
}
sv.paused = true; // pause until all clients connect
Expand Down Expand Up @@ -407,7 +398,7 @@ void SV_Loadgame_f(cmd_state_t *cmd)
if (strcmp(com_token,"{"))
{
Mem_Free(text);
Host_Error ("First token isn't a brace");
Host_Error ("%s: first token isn't a brace", __func__);
}

if (entnum == -1)
Expand All @@ -427,7 +418,7 @@ void SV_Loadgame_f(cmd_state_t *cmd)
if (entnum >= MAX_EDICTS)
{
Mem_Free(text);
Host_Error("Host_PerformLoadGame: too many edicts in save file (reached MAX_EDICTS %i)", MAX_EDICTS);
Host_Error("%s: too many edicts in save file (reached MAX_EDICTS %i)", __func__, MAX_EDICTS);
}
while (entnum >= prog->max_edicts)
PRVM_MEM_IncreaseEdicts(prog);
Expand Down Expand Up @@ -487,7 +478,7 @@ void SV_Loadgame_f(cmd_state_t *cmd)
if (i >= 0 && i < MAX_LIGHTSTYLES)
dp_strlcpy(sv.lightstyles[i], com_token, sizeof(sv.lightstyles[i]));
else
Con_Printf("unsupported lightstyle %i \"%s\"\n", i, com_token);
Con_Printf(CON_WARN "unsupported lightstyle %i \"%s\"\n", i, com_token);
}
else if (!strcmp(com_token, "sv.model_precache"))
{
Expand All @@ -500,7 +491,7 @@ void SV_Loadgame_f(cmd_state_t *cmd)
sv.models[i] = Mod_ForName (sv.model_precache[i], true, false, sv.model_precache[i][0] == '*' ? sv.worldname : NULL);
}
else
Con_Printf("unsupported model %i \"%s\"\n", i, com_token);
Con_Printf(CON_WARN "unsupported model %i \"%s\"\n", i, com_token);
}
else if (!strcmp(com_token, "sv.sound_precache"))
{
Expand All @@ -510,7 +501,7 @@ void SV_Loadgame_f(cmd_state_t *cmd)
if (i >= 0 && i < MAX_SOUNDS)
dp_strlcpy(sv.sound_precache[i], com_token, sizeof(sv.sound_precache[i]));
else
Con_Printf("unsupported sound %i \"%s\"\n", i, com_token);
Con_Printf(CON_WARN "unsupported sound %i \"%s\"\n", i, com_token);
}
else if (!strcmp(com_token, "sv.buffer"))
{
Expand All @@ -526,15 +517,15 @@ void SV_Loadgame_f(cmd_state_t *cmd)
Con_Printf(CON_ERROR "failed to create stringbuffer %i\n", i);
}
else
Con_Printf("unsupported stringbuffer index %i \"%s\"\n", i, com_token);
Con_Printf(CON_WARN "unsupported stringbuffer index %i \"%s\"\n", i, com_token);
}
else
Con_Printf("unexpected end of line when parsing sv.buffer (expected buffer index)\n");
Con_Printf(CON_WARN "unexpected end of line when parsing sv.buffer (expected buffer index)\n");
}
else if (!strcmp(com_token, "sv.bufstr"))
{
if (!COM_ParseToken_Simple(&t, false, false, true))
Con_Printf("unexpected end of line when parsing sv.bufstr\n");
Con_Printf(CON_WARN "unexpected end of line when parsing sv.bufstr\n");
else
{
i = atoi(com_token);
Expand All @@ -547,10 +538,10 @@ void SV_Loadgame_f(cmd_state_t *cmd)
if (COM_ParseToken_Simple(&t, false, false, true))
BufStr_Set(prog, stringbuffer, k, com_token);
else
Con_Printf("unexpected end of line when parsing sv.bufstr (expected string)\n");
Con_Printf(CON_WARN "unexpected end of line when parsing sv.bufstr (expected string)\n");
}
else
Con_Printf("unexpected end of line when parsing sv.bufstr (expected strindex)\n");
Con_Printf(CON_WARN "unexpected end of line when parsing sv.bufstr (expected strindex)\n");
}
else
Con_Printf(CON_ERROR "failed to create stringbuffer %i \"%s\"\n", i, com_token);
Expand Down

0 comments on commit f4b7eca

Please sign in to comment.