aboutsummaryrefslogtreecommitdiff
path: root/api.c
diff options
context:
space:
mode:
Diffstat (limited to 'api.c')
-rw-r--r--api.c166
1 files changed, 83 insertions, 83 deletions
diff --git a/api.c b/api.c
index b24514e..563b1cc 100644
--- a/api.c
+++ b/api.c
@@ -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