Skip to content

Commit

Permalink
Add more complete ‘demomap’ command emulation.
Browse files Browse the repository at this point in the history
Detect ‘.dm2’ extension in SV_ParseMapCmd() and turn ‘demomap demo.dm2’
command into ‘demo demo.dm2 compat’, while setting ‘nextserver’
properly.

Allows mods that utilize demos as cinematics to work.
  • Loading branch information
skullernet committed Aug 3, 2024
1 parent 46ace81 commit 6547c41
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 15 deletions.
14 changes: 13 additions & 1 deletion doc/client.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,16 @@ NOTE: By default, during demo playback, Q2PRO overrides FOV value stored in
demo file with value of local ‘fov’ variable, unless stored FOV value is less
than 90. This behavior can be changed with ‘uf’ variable (see above).

NOTE: Recommened way to play demos in Q2PRO is the ‘demo’ command, but
‘demomap’ is still supported for compatibility. Playing demos using ‘demomap’
enables some compatibility options, such as hiding player gun in wide angle
view.

WARNING: Unlike ‘demo’ command, ‘demomap’ allows executing stufftext commands
from demos. Demos may change client settings, trick the client into connecting
to random servers, and have other security implications. Only play demos from
trusted sources using ‘demomap’!

seek [+-]<timespec|percent>[%]::
Seeks the given amount of time during demo playback. Prepend with ‘+’ to
seek forward relative to current position, prepend with ‘-’ to seek
Expand Down Expand Up @@ -1604,7 +1614,9 @@ it used to be you know where to look. The following list may be incomplete.
- ‘clientport’ variable has been renamed to ‘net_clientport’, and
‘ip_clientport’ alias is no longer supported.
- ‘demomap’ command has been removed in favor of ‘demo’ and ‘mvdplay’.
- ‘demomap’ command is emulated: if filename with ‘.dm2’ extension is specified,
client side demo playback is started. Otherwise ‘demomap’ command is equivalent
to ‘gamemap’ (attract loop mode is not supported).
- Q2PRO works only with virtual paths constrained to the quake file system.
All paths are normalized before use so that it is impossible to go past virtual
Expand Down
37 changes: 23 additions & 14 deletions src/server/commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,14 @@ static void SV_Map(bool restart)
if (!SV_ParseMapCmd(&cmd))
return;

#if USE_CLIENT
// hack for demomap
if (cmd.state == ss_demo) {
Cbuf_InsertText(&cmd_buffer, va("demo \"%s\" compat\n", cmd.server));
return;
}
#endif

// save pending CM to be freed later if ERR_DROP is thrown
Com_AbortFunc(abort_func, &cmd.cm);

Expand Down Expand Up @@ -290,21 +298,15 @@ SV_DemoMap_f
Puts the server in demo mode on a specific map/cinematic
==================
*/
#if USE_CLIENT
static void SV_DemoMap_f(void)
{
char *s = Cmd_Argv(1);
if (Cmd_Argc() != 2) {
Com_Printf("Usage: %s <mapname>\n", Cmd_Argv(0));
return;
}

if (!COM_CompareExtension(s, ".dm2"))
Cbuf_InsertText(&cmd_buffer, va("demo \"%s\"\n", s));
else if (!COM_CompareExtension(s, ".cin"))
Cbuf_InsertText(&cmd_buffer, va("map \"%s\" force\n", s));
else if (*s)
Com_Printf("\"%s\" only supports .dm2 and .cin files\n", Cmd_Argv(0));
else
Com_Printf("Usage: %s <demo>\n", Cmd_Argv(0));
SV_Map(false);
}
#endif

/*
==================
Expand Down Expand Up @@ -423,6 +425,15 @@ static void SV_Map_c(genctx_t *ctx, int argnum)
}
}

static void SV_DemoMap_c(genctx_t *ctx, int argnum)
{
#if USE_CLIENT
if (argnum == 1) {
FS_File_g("demos", ".dm2", FS_SEARCH_RECURSIVE, ctx);
}
#endif
}

static void SV_DumpEnts_f(void)
{
bsp_t *c = sv.cm.cache;
Expand Down Expand Up @@ -1741,9 +1752,7 @@ static const cmdreg_t c_server[] = {
{ "stuffcvar", SV_StuffCvar_f, SV_SetPlayer_c },
{ "printall", SV_PrintAll_f },
{ "map", SV_Map_f, SV_Map_c },
#if USE_CLIENT
{ "demomap", SV_DemoMap_f },
#endif
{ "demomap", SV_DemoMap_f, SV_DemoMap_c },
{ "gamemap", SV_GameMap_f, SV_Map_c },
{ "dumpents", SV_DumpEnts_f },
{ "setmaster", SV_SetMaster_f },
Expand Down
13 changes: 13 additions & 0 deletions src/server/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,19 @@ static bool check_server(mapcmd_t *cmd, const char *server, bool nextserver)
ret = SCR_CheckForCinematic(expanded);
}
cmd->state = ss_cinematic;
} else if (!COM_CompareExtension(s, ".dm2")) {
if (!sv_cinematics->integer && nextserver)
return false; // skip it
if (Q_concat(expanded, sizeof(expanded), "demos/", s) < sizeof(expanded)) {
#if USE_CLIENT
ret = cmd->loadgame ? Q_ERR(ENOSYS) : FS_LoadFile(expanded, NULL);
if (ret == Q_ERR(EFBIG))
ret = Q_ERR_SUCCESS;
#else
ret = Q_ERR(ENOSYS);
#endif
}
cmd->state = ss_demo;
} else {
CM_LoadOverrides(&cmd->cm, cmd->server, sizeof(cmd->server));
if (Q_concat(expanded, sizeof(expanded), "maps/", s, ".bsp") < sizeof(expanded)) {
Expand Down
4 changes: 4 additions & 0 deletions src/server/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,10 @@ void sv_min_timeout_changed(cvar_t *self);
//
// sv_init.c
//

// not a real server state! hack for demomap command.
#define ss_demo -1

void SV_ClientReset(client_t *client);
void SV_SetState(server_state_t state);
void SV_SpawnServer(const mapcmd_t *cmd);
Expand Down

0 comments on commit 6547c41

Please sign in to comment.