aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api.c39
-rw-r--r--api.h23
-rw-r--r--main.c7
-rw-r--r--render.c21
4 files changed, 59 insertions, 31 deletions
diff --git a/api.c b/api.c
index f2be734..5ac08ee 100644
--- a/api.c
+++ b/api.c
@@ -33,6 +33,7 @@ struct audio_device **audio_device = 0;
struct soundstate *snd = 0;
void (*snd_recordbuffer)(void) = 0;
void (*cbuf_addtext)(char *) = 0;
+bool steampipe = false;
// This macro is Copyright 2024 Michael Smith under the same license as above.
#define NEXT_INSN(p, tgt) do { \
@@ -46,7 +47,8 @@ void (*cbuf_addtext)(char *) = 0;
// TODO: should this be split up?
-bool api_init(void) {
+bool api_init(bool _steampipe) {
+ steampipe = _steampipe;
void *engine_dll = os_dlhandle("engine");
createinterface_func engine_factory =
(createinterface_func)os_dlsym(engine_dll, "CreateInterface");
@@ -81,13 +83,13 @@ bool api_init(void) {
if (!cbuf_addtext) bail("couldn't find cbuf_addtext");
// find demoplayer
- instr = (const u8 *)engclient->vt->is_playing_demo;
+ instr = steampipe ? (const u8 *)engclient->vt->steampipe_is_playing_demo :
+ (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
@@ -105,7 +107,6 @@ bool api_init(void) {
}
NEXT_INSN(p, "videomode");
}
- debug("videomode = %p", (void *)videomode);
// find cl_movieinfo
{
@@ -129,7 +130,6 @@ bool api_init(void) {
if (instr[0] != X86_ALUMI8 || instr[1] != X86_MODRM(0, 7, 5))
bail("couldn't get movieinfo");
movieinfo = *(struct movieinfo **)(instr + 2);
- debug("movieinfo = %p", (void *)movieinfo);
}
// find SND_RecordBuffer... this is something!
@@ -138,15 +138,22 @@ bool api_init(void) {
struct concommand *snd_restart = cvar->vt->find_command(cvar, "snd_restart");
instr = (const u8 *)snd_restart->callback;
void *s_init = 0;
- // S_Init is the 3rd call in Snd_Restart_f
+ // S_Init is called after setting snd_firsttime to true. Look for the
+ // second call after the mov
+ bool snd_firsttime_set = false;
int call_count = 0;
- for (const u8 *p = instr; p - instr < 64;) {
- if (*p == X86_CALL && ++call_count == 3)
+ for (const u8 *p = instr; p - instr < 80;) {
+ // mov byte ptr [snd_firsttime], 1
+ if (p[0] == X86_MOVMI8 && p[1] == 0x05 && p[6] == 1)
+ snd_firsttime_set = true;
+ if (p[0] == X86_CALL && snd_firsttime_set && ++call_count == 2) {
s_init = (void *)(p + 5 + *(i32 *)(p + 1));
+ break;
+ }
NEXT_INSN(p, "S_Init");
}
- debug("S_Init = %p", (void *)s_init);
- if (!s_init) bail("couldn't find S_Init");
+ if (!s_init)
+ bail("couldn't find S_Init");
// step 2: find g_AudioDevice in S_Init
// g_AudioDevice is the first variable assignment after the check for
// the -nosound command line arg. look for that.
@@ -162,8 +169,8 @@ bool api_init(void) {
}
NEXT_INSN(p, "g_AudioDevice");
}
- debug("g_AudioDevice = %p", (void *)audio_device);
- if (!audio_device) bail("couldn't get ptr to g_AudioDevice");
+ if (!audio_device)
+ bail("couldn't get ptr to g_AudioDevice");
}
return true;
}
@@ -172,8 +179,9 @@ bool api_find_snd_recordbuffer(void) {
// continuation, we must do this part later
// step 3: Find S_TransferStereo16 in CAudioDirectSound::TransferSamples
void *transferstereo16 = 0;
- const u8 *instr = (*audio_device)->vt->transfer_samples;
- debug("CAudioDirectSound::TransferSamples = %p", (void *)instr);
+ const u8 *instr = steampipe ?
+ (*audio_device)->vt->steampipe_transfer_samples :
+ (*audio_device)->vt->transfer_samples;
// S_TransferStereo16 is the 8th call in TransferSamples
int call_count = 0;
for (const u8 *p = instr; p - instr < 384 /* big func! */;) {
@@ -183,7 +191,6 @@ bool api_find_snd_recordbuffer(void) {
}
if (!transferstereo16)
bail("couldn't find transferstereo16");
- debug("S_TransferStereo16 = %p", transferstereo16);
// step 4: find SND_RecordBuffer in S_TransferStereo16
// it should be the next call after an 'add ecx, ecx'
// We are also going to get Snd_WriteLinearBlastStereo16 to get some other
@@ -208,8 +215,6 @@ bool api_find_snd_recordbuffer(void) {
}
if (!snd_recordbuffer)
bail("couldn't find snd_recordbuffer");
- debug("SND_RecordBuffer = %p", (void *)snd_recordbuffer);
- debug("Snd_WriteLinearBlastStereo16 + 3 = %p", (void *)snd);
return true;
}
diff --git a/api.h b/api.h
index df8c191..878b3d0 100644
--- a/api.h
+++ b/api.h
@@ -39,6 +39,7 @@ struct engclient {
struct {
usize _pad[75];
void (*VIRTUAL is_playing_demo)(struct engclient *this);
+ void (*VIRTUAL steampipe_is_playing_demo)(struct engclient *this);
} *vt;
};
@@ -81,6 +82,7 @@ struct audio_device {
struct {
usize _pad[22];
void *transfer_samples;
+ void *steampipe_transfer_samples;
} *vt;
};
@@ -142,9 +144,14 @@ struct videomode {
usize _pad[22];
void (*VIRTUAL write_movie_frame)(struct videomode *this,
struct movieinfo *info);
- usize _pad2[4];
+ usize _pad2[3];
+ void (*VIRTUAL steampipe_write_movie_frame)(struct videomode *this,
+ struct movieinfo *info);
void (*VIRTUAL read_screen_pixels)(struct videomode *this,
int x, int y, int w, int h, void *buf, enum image_format fmt);
+ usize _pad3;
+ void (*VIRTUAL steampipe_read_screen_pixels)(struct videomode *this,
+ int x, int y, int w, int h, void *buf, enum image_format fmt);
} *vt;
};
@@ -164,14 +171,13 @@ struct demoplayer {
/* EPIC HACK:
* Snd_WriteLinearBlastStereo16 is an inline asm function that starts with
*
- * mov ebx,snd_p
- * mov edi,snd_out
- * mov ecx,snd_linear_count
- * mov esi,snd_vol
+ * mov ebx, snd_p
+ * mov edi, snd_out
+ * mov ecx, snd_linear_count
+ * mov esi, snd_vol
*
* Luckily for us, these are all the things that we need!!!!
- * So, we just use the instructions as a struct so we don't have to copy
- * anything. It just works.
+ * So, we just use the instructions as a struct.
*/
struct soundstate {
u16 _mov_ebx;
@@ -195,10 +201,11 @@ extern struct movieinfo *movieinfo;
extern void (*cbuf_addtext)(char *);
extern void (*snd_recordbuffer)(void);
extern struct soundstate *snd;
+extern bool steampipe;
#endif
// initializes required engine apis. returns false on error.
-bool api_init(void);
+bool api_init(bool steampipe);
bool api_find_snd_recordbuffer(void);
#endif
diff --git a/main.c b/main.c
index 440e9c3..0761665 100644
--- a/main.c
+++ b/main.c
@@ -70,9 +70,10 @@ 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;
-
- if (!strcmp(basename, "gameui.dll")) {
- if (!api_init()) die("couldn't get apis");
+ if (!strcmp(basename, "gameui.dll") || !strcmp(basename, "GameUI.dll")) {
+ if (!api_init(basename[0] == 'G'))
+ die("couldn't get apis");
+ cbuf_addtext("echo THIS WORKS!!!!!!!!!!!!;");
orig_cbuf_addtext = (void (*)(char *))
hook_inline((void *)cbuf_addtext, (void *)hook_cbuf_addtext);
}
diff --git a/render.c b/render.c
index 7b03e79..ecea85a 100644
--- a/render.c
+++ b/render.c
@@ -75,7 +75,13 @@ bool do_frame(struct videomode *this, struct movieinfo *info) {
struct { u8 bgr[3]; } *data = 0;
HR(imf_buffer->lpVtbl->Lock(imf_buffer, (u8 **)&data, NULL, NULL));
// THIS IS SLOW!!
- this->vt->read_screen_pixels(this, 0, 0, args.width, args.height, raw, IMAGE_FORMAT_BGR888);
+ if (steampipe)
+ this->vt->steampipe_read_screen_pixels(this, 0, 0, args.width,
+ args.height, raw, IMAGE_FORMAT_BGR888);
+ else
+ this->vt->read_screen_pixels(this, 0, 0, args.width, args.height, raw,
+ IMAGE_FORMAT_BGR888);
+
for (int y = args.height - 1; y > 0; y--) {
memcpy(data + ((args.height - y) * args.width), raw + y * args.width,
szpx * args.width);
@@ -140,6 +146,8 @@ void VIRTUAL hook_stop_playback(struct demoplayer *this) {
return;
}
+ info("finished!");
+
if (!do_stop())
die("oopsie!");
@@ -150,8 +158,12 @@ bool render_init(void) {
bool r =
os_mprot((*videomode)->vt, 28 * sizeof(void *), PAGE_EXECUTE_READWRITE);
if (!r) bail("couldn't mprotect videomode vtable");
- orig_write_movie_frame = (*videomode)->vt->write_movie_frame;
- (*videomode)->vt->write_movie_frame = hook_write_movie_frame;
+
+ typeof(orig_write_movie_frame) *wmf = steampipe ?
+ &(*videomode)->vt->steampipe_write_movie_frame :
+ &(*videomode)->vt->write_movie_frame;
+ orig_write_movie_frame = *wmf;
+ *wmf = hook_write_movie_frame;
r = os_mprot(demoplayer->vt, 18 * sizeof(void *), PAGE_EXECUTE_READWRITE);
if (!r) bail("couldn't mprotect demoplayer vtable");
@@ -170,6 +182,9 @@ bool render_init(void) {
sprintf(framerate_cmd, "host_framerate %d;", args.fps);
cbuf_addtext(framerate_cmd);
+ if (CoInitializeEx(NULL, COINIT_MULTITHREADED) == RPC_E_CHANGED_MODE)
+ warn("changed COM concurrency mode!");
+
HR(MFStartup(MF_VERSION, 0));
// init sinkwriter