summaryrefslogtreecommitdiffhomepage
path: root/src/gameserver.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gameserver.c')
-rw-r--r--src/gameserver.c76
1 files changed, 76 insertions, 0 deletions
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 <mikesmiffy128@gmail.com>
+ *
+ * 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