From 64f127a22f7661dc7a9953dc458585c3eb5adc0c Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Sun, 17 Dec 2023 01:50:21 +0000 Subject: Cancel fast-forward after the player disconnects Avoids spurious and confusing fast-forward behaviour in the event of resetting a run, then disconnecting early and deciding to load some other map. Also fixes a stupid typo (s/propand/propane/). --- src/gameserver.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 src/gameserver.c (limited to 'src/gameserver.c') diff --git a/src/gameserver.c b/src/gameserver.c new file mode 100644 index 0000000..5a76027 --- /dev/null +++ b/src/gameserver.c @@ -0,0 +1,76 @@ +/* + * Copyright © 2023 Michael Smith + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "con_.h" +#include "errmsg.h" +#include "feature.h" +#include "gamedata.h" +#include "intdefs.h" +#include "mem.h" +#include "x86.h" +#include "vcall.h" +#include "x86util.h" + +FEATURE() +REQUIRE_GAMEDATA(vtidx_GetSpawnCount) + +DECL_VFUNC_DYN(int, GetSpawnCount) + +static void *sv; + +int gameserver_spawncount(void) { return GetSpawnCount(sv); } + +static bool find_sv(con_cmdcb pause_cb) { +#ifdef _WIN32 + // The last thing pause does is call BroadcastPrintf with 4 args including + // `this`, all on the stack since it's varargs. 2 of the args are pushed + // immediately before `this`, so we can just look for 3 back-to-back pushes + // and a call. + const uchar *insns = (const uchar *)pause_cb; + int pushes = 0; + for (const uchar *p = insns; p - insns < 256;) { + if (*p == X86_PUSHIW || *p >= X86_PUSHEAX && *p <= X86_PUSHEDI) { + if (++pushes == 3) { + if (*p != X86_PUSHIW || p[5] != X86_CALL) { + // it'd be super weird to have this many pushes anywhere + // else in the function, so give up here + return false; + } + sv = mem_loadptr(p + 1); + return true; + } + } + else { + pushes = 0; + } + NEXT_INSN(p, "load of sv pointer"); + } +#else +#warning TODO(linux): the usual x86 stuff +#endif + return false; +} + +INIT { + struct con_cmd *pause = con_findcmd("pause"); + if (!find_sv(pause->cb)) { + errmsg_errorx("couldn't find game server object\n"); + return false; + } + return true; +} + +// vi: sw=4 ts=4 noet tw=80 cc=80 -- cgit v1.2.3