aboutsummaryrefslogtreecommitdiff
path: root/api.c
diff options
context:
space:
mode:
Diffstat (limited to 'api.c')
-rw-r--r--api.c44
1 files changed, 39 insertions, 5 deletions
diff --git a/api.c b/api.c
index af7bb5e..8001f8f 100644
--- a/api.c
+++ b/api.c
@@ -6,16 +6,50 @@
#undef NO_EXTERNS
#include "os.h"
#include "log.h"
+#include "sst/x86.h"
-struct engserver *engserver;
+struct engserver *engserver = NULL;
+struct engclient *engclient = NULL;
+struct demoplayer *demoplayer = NULL;
+void (*cbuf_addtext)(char *) = NULL;
-void api_init() {
- void *engine_dll = os_dlopen("engine");
+bool api_init(void) {
+ void *engine_dll = os_dlhandle("engine");
createinterface_func engine_factory =
(createinterface_func)os_dlsym(engine_dll, "CreateInterface");
- if (!engine_factory) die("couldn't get engine factory");
+ if (!engine_factory) bail("couldn't get engine factory");
engserver = engine_factory(INTERFACEVERSION_VENGINESERVER, NULL);
- if (!engserver) die("couldn't get IVEngineServer from engine");
+ 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");
+
+ // 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;
+ debug("is_playing_demo = %p", (void *)instr);
+ // CEngineClient::IsPlayingDemo is a wrapper around a demoplayer call
+ // The first thing it does should be load 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);
+
+ return true;
}
// vi: sw=4 ts=4 noet tw=80 cc=80