diff options
Diffstat (limited to 'api.c')
-rw-r--r-- | api.c | 166 |
1 files changed, 83 insertions, 83 deletions
@@ -1,83 +1,83 @@ -// SPDX-License-Identifier: ISC
-// SPDX-FileCopyrightText: 2024 Matthew Wozniak <me@woz.blue>
-
-#define NO_EXTERNS
-#include "api.h"
-#undef NO_EXTERNS
-#include "os.h"
-#include "log.h"
-#include "sst/x86.h"
-
-struct engserver *engserver = NULL;
-struct engclient *engclient = NULL;
-struct engineapi *engineapi = NULL;
-struct enginetools *enginetools = NULL;
-struct demoplayer *demoplayer = NULL;
-struct videomode **videomode = NULL;
-struct movieinfo *movieinfo = NULL;
-void (*cbuf_addtext)(char *) = NULL;
-
-// TODO: should this be split up?
-
-bool api_init(void) {
- void *engine_dll = os_dlhandle("engine");
- createinterface_func engine_factory =
- (createinterface_func)os_dlsym(engine_dll, "CreateInterface");
- if (!engine_factory) bail("couldn't get engine factory");
- engserver = engine_factory(VENGINE_SERVER_INTERFACE_VERSION, NULL);
- if (!engserver) bail("couldn't get IVEngineServer from engine");
- engclient = engine_factory(VENGINE_CLIENT_INTERFACE_VERSION, NULL);
- if (!engclient) bail("couldn't get IVEngineClient from engine");
- engineapi = engine_factory(VENGINE_LAUNCHER_INTERFACE_VERSION, NULL);
- if (!engineapi) bail("couldn't get IEngineAPI from engine");
- enginetools = engine_factory(VENGINE_TOOL_INTERFACE_VERSION, NULL);
- if (!engineapi) bail("couldn't get IEngineTools from engine");
-
- // find cbuf_addtext
- const u8 *instr = (const u8 *)engserver->vt->server_command;
- // ServerCommand() calls a few small functions before Cbuf_AddText but they
- // get inlined. look for 'push esi' and then a call.
- for (const u8 *p = instr; p - instr < 64;) {
- if (*p == X86_PUSHESI && *++p == X86_CALL) {
- // jump is relative to after the instruction
- cbuf_addtext = (void (*)(char *))(p + 5 + *(i32 *)(p + 1));
- }
- int l = x86_len(p);
- if (l == -1)
- bail("invalid instruction looking for cbuf_addtext");
- p += l;
- }
- if (!cbuf_addtext) bail("couldn't find cbuf_addtext");
-
- // find demoplayer
- instr = (const u8 *)engclient->vt->is_playing_demo;
- // CEngineClient::IsPlayingDemo is a wrapper around a demoplayer call
- // The first thing it does should be load a ptr to demoplayer into ECX
- if (instr[0] != X86_MOVRMW || instr[1] != X86_MODRM(0, 1, 5))
- bail("couldn't get demoplayer");
- demoplayer = **(struct demoplayer ***)(instr + 2);
- debug("demoplayer = %p", (void *)demoplayer);
-
- // find videomode
- // CEngineAPI::SetEngineWindow calls videomode->SetGameWindow after
- // detaching the current window with another vcall. Look for the second one.
- // This, like the demoplayer, is a pointer. Mind the double dereference.
- instr = (const u8 *)engineapi->vt->set_engine_window;
- int mov_ecx_counter = 0;
- for (const u8 *p = instr; p - instr < 64;) {
- if (p[0] == X86_MOVRMW && p[1] == X86_MODRM(0, 1, 5)
- && ++mov_ecx_counter == 2) {
- videomode = *(struct videomode ***)(p + 2);
- break;
- }
- int l = x86_len(p);
- if (l == -1)
- bail("invalid instruction looking for videomode");
- p += l;
- }
- debug("videomode = %p", (void *)videomode);
-
- return true;
-}
-
-// vi: sw=4 ts=4 noet tw=80 cc=80
+// SPDX-License-Identifier: ISC +// SPDX-FileCopyrightText: 2024 Matthew Wozniak <me@woz.blue> + +#define NO_EXTERNS +#include "api.h" +#undef NO_EXTERNS +#include "os.h" +#include "log.h" +#include "sst/x86.h" + +struct engserver *engserver = NULL; +struct engclient *engclient = NULL; +struct engineapi *engineapi = NULL; +struct enginetools *enginetools = NULL; +struct demoplayer *demoplayer = NULL; +struct videomode **videomode = NULL; +struct movieinfo *movieinfo = NULL; +void (*cbuf_addtext)(char *) = NULL; + +// TODO: should this be split up? + +bool api_init(void) { + void *engine_dll = os_dlhandle("engine"); + createinterface_func engine_factory = + (createinterface_func)os_dlsym(engine_dll, "CreateInterface"); + if (!engine_factory) bail("couldn't get engine factory"); + engserver = engine_factory(VENGINE_SERVER_INTERFACE_VERSION, NULL); + if (!engserver) bail("couldn't get IVEngineServer from engine"); + engclient = engine_factory(VENGINE_CLIENT_INTERFACE_VERSION, NULL); + if (!engclient) bail("couldn't get IVEngineClient from engine"); + engineapi = engine_factory(VENGINE_LAUNCHER_INTERFACE_VERSION, NULL); + if (!engineapi) bail("couldn't get IEngineAPI from engine"); + enginetools = engine_factory(VENGINE_TOOL_INTERFACE_VERSION, NULL); + if (!engineapi) bail("couldn't get IEngineTools from engine"); + + // find cbuf_addtext + const u8 *instr = (const u8 *)engserver->vt->server_command; + // ServerCommand() calls a few small functions before Cbuf_AddText but they + // get inlined. look for 'push esi' and then a call. + for (const u8 *p = instr; p - instr < 64;) { + if (*p == X86_PUSHESI && *++p == X86_CALL) { + // jump is relative to after the instruction + cbuf_addtext = (void (*)(char *))(p + 5 + *(i32 *)(p + 1)); + } + int l = x86_len(p); + if (l == -1) + bail("invalid instruction looking for cbuf_addtext"); + p += l; + } + if (!cbuf_addtext) bail("couldn't find cbuf_addtext"); + + // find demoplayer + instr = (const u8 *)engclient->vt->is_playing_demo; + // CEngineClient::IsPlayingDemo is a wrapper around a demoplayer call + // The first thing it does should be load a ptr to demoplayer into ECX + if (instr[0] != X86_MOVRMW || instr[1] != X86_MODRM(0, 1, 5)) + bail("couldn't get demoplayer"); + demoplayer = **(struct demoplayer ***)(instr + 2); + debug("demoplayer = %p", (void *)demoplayer); + + // find videomode + // CEngineAPI::SetEngineWindow calls videomode->SetGameWindow after + // detaching the current window with another vcall. Look for the second one. + // This, like the demoplayer, is a pointer. Mind the double dereference. + instr = (const u8 *)engineapi->vt->set_engine_window; + int mov_ecx_counter = 0; + for (const u8 *p = instr; p - instr < 64;) { + if (p[0] == X86_MOVRMW && p[1] == X86_MODRM(0, 1, 5) + && ++mov_ecx_counter == 2) { + videomode = *(struct videomode ***)(p + 2); + break; + } + int l = x86_len(p); + if (l == -1) + bail("invalid instruction looking for videomode"); + p += l; + } + debug("videomode = %p", (void *)videomode); + + return true; +} + +// vi: sw=4 ts=4 noet tw=80 cc=80 |