From f4b7ecaf3dfdb91eb7af5003fd253a824afdec93 Mon Sep 17 00:00:00 2001 From: bones_was_here Date: Sun, 25 Aug 2024 20:17:29 +1000 Subject: [PATCH] server: fix the save command's checks for multiplayer/dedicated Also makes the save and load messages nicer. Signed-off-by: bones_was_here --- cl_main.c | 5 ---- host.c | 1 - host.h | 1 - sv_ccmds.c | 4 +-- sv_save.c | 77 ++++++++++++++++++++++++------------------------------ 5 files changed, 36 insertions(+), 52 deletions(-) diff --git a/cl_main.c b/cl_main.c index 17921410..5ca74b64 100644 --- a/cl_main.c +++ b/cl_main.c @@ -620,10 +620,6 @@ static void CL_EstablishConnection_Local(void) CL_EstablishConnection("local:1", -2); } -static qbool CL_Intermission(void) -{ - return cl.intermission; -} /* ============== @@ -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; } } diff --git a/host.c b/host.c index ab0b0779..b92f11b3 100644 --- a/host.c +++ b/host.c @@ -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; diff --git a/host.h b/host.h index e72d75a2..def3d0a2 100644 --- a/host.h +++ b/host.h @@ -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); diff --git a/sv_ccmds.c b/sv_ccmds.c index 64b3d197..836181f2 100644 --- a/sv_ccmds.c +++ b/sv_ccmds.c @@ -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"); diff --git a/sv_save.c b/sv_save.c index 5901b6dc..653292a0 100644 --- a/sv_save.c +++ b/sv_save.c @@ -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; } @@ -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 @@ -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 : save a game\n"); @@ -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)); @@ -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; } @@ -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; } @@ -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 @@ -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) @@ -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); @@ -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")) { @@ -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")) { @@ -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")) { @@ -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); @@ -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); -- 2.39.2