aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Matthew Wozniak <me@woz.blue> 2024-11-03 00:16:00 -0400
committerGravatar Matthew Wozniak <me@woz.blue> 2024-11-03 00:16:00 -0400
commitd00096fe2ea3dd64cff9878879c077f23a783e4a (patch)
tree38da364a01d63d8796dc5c38b20ff73539ac1c82
parenta2f7e37d8adf2047e1f3b0ea1227ac9d51514783 (diff)
downloadrt-d00096fe2ea3dd64cff9878879c077f23a783e4a.tar.gz
rt-d00096fe2ea3dd64cff9878879c077f23a783e4a.zip
find videomode
-rw-r--r--Makefile7
-rw-r--r--api.c34
-rw-r--r--api.h39
-rw-r--r--compile_flags.txt1
-rw-r--r--main.c5
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