diff options
author | Matthew Wozniak <me@woz.blue> | 2024-11-01 13:47:31 -0400 |
---|---|---|
committer | Matthew Wozniak <me@woz.blue> | 2024-11-01 13:48:09 -0400 |
commit | a2f7e37d8adf2047e1f3b0ea1227ac9d51514783 (patch) | |
tree | 2942ee2a12abe02e27f119552221c6a06ac87273 /api.c | |
parent | fb95177298bb92098b61f09b9f66c1fce32f2f02 (diff) | |
download | rt-a2f7e37d8adf2047e1f3b0ea1227ac9d51514783.tar.gz rt-a2f7e37d8adf2047e1f3b0ea1227ac9d51514783.zip |
play demo using the demoplayer object
Diffstat (limited to 'api.c')
-rw-r--r-- | api.c | 44 |
1 files changed, 39 insertions, 5 deletions
@@ -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
|