/* * 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