From d00096fe2ea3dd64cff9878879c077f23a783e4a Mon Sep 17 00:00:00 2001 From: Matthew Wozniak Date: Sun, 3 Nov 2024 00:16:00 -0400 Subject: find videomode --- Makefile | 7 ++++--- api.c | 34 +++++++++++++++++++++++++++++++--- api.h | 39 +++++++++++++++++++++++++++++++++++++-- compile_flags.txt | 1 + main.c | 5 +---- 5 files changed, 74 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 61e4b7d..db5c765 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,15 @@ CC = clang OBJS = main.o api.o 3p/sst/x86.o hook.o -WARNINGS=-Wpedantic -Wextra -Wno-gnu-zero-variadic-macro-arguments \ +WARNINGS=-Wall -Wpedantic -Wextra -Wno-gnu-zero-variadic-macro-arguments \ -D_CRT_SECURE_NO_WARNINGS +CFLAGS:=$(CFLAGS) -m32 -flto -I3p -std=c23 all: rt.exe rt.exe: $(OBJS) - $(CC) -m32 -fuse-ld=lld $(CFLAGS) $(LDFLAGS) $(OBJS) -o rt.exe + $(CC) -fuse-ld=lld $(CFLAGS) $(LDFLAGS) $(OBJS) -o rt.exe %.o: %.c - $(CC) -c -m32 -include stdbool.h -I3p -std=c23 $(WARNINGS) $(CFLAGS) $< -o $@ + $(CC) -c $(WARNINGS) $(CFLAGS) $< -o $@ clean: rm -f *.o 3p/sst/*.o *.exe *.pdb diff --git a/api.c b/api.c index 8001f8f..b24514e 100644 --- a/api.c +++ b/api.c @@ -10,18 +10,28 @@ 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(INTERFACEVERSION_VENGINESERVER, NULL); + 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; @@ -41,13 +51,31 @@ bool api_init(void) { // 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 + // 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; } diff --git a/api.h b/api.h index 086ef46..d1afbc2 100644 --- a/api.h +++ b/api.h @@ -4,8 +4,10 @@ #ifndef ENGINEAPI_H #define ENGINEAPI_H -#define INTERFACEVERSION_VENGINESERVER "VEngineServer021" +#define VENGINE_SERVER_INTERFACE_VERSION "VEngineServer021" #define VENGINE_CLIENT_INTERFACE_VERSION "VEngineClient013" +#define VENGINE_LAUNCHER_INTERFACE_VERSION "VENGINE_LAUNCHER_API_VERSION004" +#define VENGINE_TOOL_INTERFACE_VERSION "VENGINETOOL003" #include "intdef.h" @@ -25,13 +27,42 @@ struct engclient { } *vt; }; +struct engineapi { + struct { + usize _pad[7]; + void *set_engine_window; + } *vt; +}; + +struct enginetools { + struct { + usize _pad[64]; + void *is_recording_movie; + } *vt; +}; + +struct movieinfo { + char name[256]; + int curframe; + int type; + int jpeg_quality; +}; + +struct videomode { + struct { + usize _pad[22]; + void (*__thiscall write_movie_frame)(struct videomode *this, + struct movieinfo *info); + } *vt; +}; + struct demoplayer { struct { void *_destructor; void * (*__thiscall get_demo_file)(struct demoplayer *this); int (*__thiscall get_playback_tick)(struct demoplayer *this); int (*__thiscall get_total_ticks)(struct demoplayer *this); - void *_whatisthisihavenoidea; + void *_whatisthisihavenoidea; // TODO bool (*__thiscall start_playback)(struct demoplayer *this, const char *filename, bool as_time_demo); bool (*__thiscall is_playing_back)(struct demoplayer *this); @@ -55,7 +86,11 @@ struct demoplayer { #ifndef NO_EXTERNS extern struct engserver *engserver; extern struct engclient *engclient; +extern struct engineapi *engineapi; +extern struct enginetools *enginetools; extern struct demoplayer *demoplayer; +extern struct videomode **videomode; +extern struct movieinfo *movieinfo; extern void (*cbuf_addtext)(char *); #endif diff --git a/compile_flags.txt b/compile_flags.txt index 7745765..4cb8bb9 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -5,4 +5,5 @@ stdbool.h -I3p -Wpedantic -Wextra +-std=c23 -Wno-gnu-zero-variadic-macro-arguments diff --git a/main.c b/main.c index 376c615..47f6dec 100644 --- a/main.c +++ b/main.c @@ -13,10 +13,8 @@ void (*orig_cbuf_addtext)(char *); void hook_cbuf_addtext(char *str) { orig_cbuf_addtext(str); - info("%s", str); // this is the last thing that happens when the game is opened if (!strcmp(str, "exec modsettings.cfg mod\n")) { - demoplayer->vt->start_playback(demoplayer, "demo.dem", false); } } @@ -36,7 +34,6 @@ void WINAPI *hook_LoadLibraryExA(const char *filename, void *hfile, int flags) { const char *basename = filename; for (const char *p = filename; *p; p++) if (*p == '\\') basename = p + 1; - info("loaded %s", basename); if (!strcmp(basename, "engine.dll")) { if (!api_init()) die("couldn't get apis"); @@ -49,7 +46,7 @@ void WINAPI *hook_LoadLibraryExA(const char *filename, void *hfile, int flags) { typedef int (*LauncherMain_t)(void *instance, void *prev_inst, char *cmdline, int cmd_show); -int main(/* int argc, char **argv */) { +int main(void/* int argc, char **argv */) { SetDllDirectoryA("bin/"); // TODO: make this changeable by the user -- cgit v1.2.3-54-g00ecf