From 117f3ad6ae3fb6df54bc553bd1efbab080d39606 Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Mon, 25 Apr 2022 04:24:52 +0100 Subject: Add engine_no_focus_sleep backport, fix codegen Default gamedata values actually work the way they're supposed to now. --- compile | 3 +- compile.bat | 7 +++-- gamedata/inputsystem.kv | 8 ++++++ src/autojump.c | 2 +- src/build/mkgamedata.c | 20 +++++++++----- src/factory.h | 3 +- src/gamedata.h | 2 ++ src/nosleep.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ src/nosleep.h | 27 ++++++++++++++++++ src/rinput.c | 2 +- src/sst.c | 44 +++++++++++++++++++---------- 11 files changed, 163 insertions(+), 28 deletions(-) create mode 100644 gamedata/inputsystem.kv create mode 100644 src/nosleep.c create mode 100644 src/nosleep.h diff --git a/compile b/compile index fdeb843..76dc638 100755 --- a/compile +++ b/compile @@ -47,6 +47,7 @@ src="\ gameinfo.c hook.c kv.c + nosleep.c sst.c x86.c" if [ "$dbg" = 1 ]; then src="$src \ @@ -59,7 +60,7 @@ $HOSTCC -O2 -fuse-ld=lld $warnings -D_FILE_OFFSET_BITS=64 -o .build/codegen \ $HOSTCC -O2 -fuse-ld=lld $warnings -D_FILE_OFFSET_BITS=64 -o .build/mkgamedata \ src/build/mkgamedata.c src/kv.c .build/codegen `for s in $src; do echo "src/$s"; done` -.build/mkgamedata gamedata/gamelib.kv gamedata/engine.kv +.build/mkgamedata gamedata/engine.kv gamedata/gamelib.kv gamedata/inputsystem.kv for s in $src; do cc "$s"; done $CC -shared -fpic -fuse-ld=lld -O0 -w -o .build/libtier0.so src/stubs/tier0.c $CC -shared -fpic -fuse-ld=lld -O0 -w -o .build/libvstdlib.so src/stubs/vstdlib.c diff --git a/compile.bat b/compile.bat index c8e2d40..1364b01 100644 --- a/compile.bat +++ b/compile.bat @@ -39,9 +39,9 @@ goto :eof -o .build/codegen.exe src/build/codegen.c src/build/cmeta.c || exit /b %HOSTCC% -municode -O2 %warnings% -D_CRT_SECURE_NO_WARNINGS -ladvapi32 ^ -o .build/mkgamedata.exe src/build/mkgamedata.c src/kv.c || exit /b -.build\codegen.exe src/autojump.c src/con_.c src/demorec.c src/extmalloc.c src/fixes.c ^ -src/gamedata.c src/gameinfo.c src/hook.c src/kv.c src/rinput.c src/sst.c src/x86.c || exit /b -.build\mkgamedata.exe gamedata/engine.kv gamedata/gamelib.kv || exit /b +.build\codegen.exe src/autojump.c src/con_.c src/demorec.c src/extmalloc.c src/fixes.c src/gamedata.c ^ +src/gameinfo.c src/hook.c src/kv.c src/nosleep.c src/rinput.c src/sst.c src/x86.c || exit /b +.build\mkgamedata.exe gamedata/engine.kv gamedata/gamelib.kv gamedata/inputsystem.kv || exit /b llvm-rc /FO .build\dll.res src\dll.rc || exit /b %CC% -shared -O0 -w -o .build/tier0.dll src/stubs/tier0.c %CC% -shared -O0 -w -o .build/vstdlib.dll src/stubs/vstdlib.c @@ -54,6 +54,7 @@ call :cc src/gamedata.c || exit /b call :cc src/gameinfo.c || exit /b call :cc src/hook.c || exit /b call :cc src/kv.c || exit /b +call :cc src/nosleep.c || exit /b call :cc src/rinput.c || exit /b call :cc src/sst.c || exit /b call :cc src/x86.c || exit /b diff --git a/gamedata/inputsystem.kv b/gamedata/inputsystem.kv new file mode 100644 index 0000000..5e242c2 --- /dev/null +++ b/gamedata/inputsystem.kv @@ -0,0 +1,8 @@ +// = inputsystem library = + +vtidx_SleepUntilInput { + default 31 // TODO(compat): don't really know yet if this causes any issues + Portal2 34 // IAppSystem changes +} + +// vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/autojump.c b/src/autojump.c index 6c30df9..a8d7ee2 100644 --- a/src/autojump.c +++ b/src/autojump.c @@ -74,7 +74,7 @@ static bool unprot(void *gm) { bool autojump_init(void) { // TODO(featgen): auto-check these factories if (!factory_client || !factory_server) { - con_warn("autojump: missing required interfaces\n"); + con_warn("autojump: missing required factories\n"); return false; } if (!gamedata_has_vtidx_CheckJumpButton || !gamedata_has_off_mv) { diff --git a/src/build/mkgamedata.c b/src/build/mkgamedata.c index e2e59ff..c5f6820 100644 --- a/src/build/mkgamedata.c +++ b/src/build/mkgamedata.c @@ -68,6 +68,7 @@ struct ent { }; struct ent *next; } *ents_head, **ents_tail = &ents_head; +const char **curdefval; // dumb hacky afterthought, woopsy struct parsestate { const os_char *filename; @@ -106,15 +107,20 @@ static void kv_cb(enum kv_token type, const char *p, uint len, void *ctxt) { e->next = 0; *ents_tail = e; ents_tail = &e->next; + curdefval = &e->defval; // dumb hacky afterthought part 2 break; case KV_NEST_END: state->incond = false; break; case KV_VAL: case KV_VAL_QUOTED: if (state->incond) { - // dumb special case mentioned above + // continuation of dumb hackiness if (!strcmp(state->lastkey, "default")) { - (*ents_tail)->defval = state->lastkey; + char *s = malloc(len + 1); + if (!s) die("couldn't allocate default value string"); + memcpy(s, p, len); + s[len] = '\0'; + *curdefval = s; break; } struct ent_cond *c = malloc(sizeof(*c)); @@ -203,7 +209,7 @@ F( "#define gamedata_has_%s true", e->name) for (struct ent *e = ents_head; e; e = e->next) { if (e->iscond) { if (e->defval) { -F( "int gamedata_%s = %s", e->name, e->defval); +F( "int gamedata_%s = %s;", e->name, e->defval); } else { F( "int gamedata_%s;", e->name); @@ -216,7 +222,10 @@ _( "void gamedata_init(void) {") for (struct ent *e = ents_head; e; e = e->next) { if (e->iscond) { for (struct ent_cond *c = e->cond; c; c = c->next) { - if (!e->defval) { + if (e->defval) { +F( " if (GAMETYPE_MATCHES(%s)) gamedata_%s = %s;", c->name, e->name, c->expr) + } + else { // XXX: not bothering to generate `else`s. technically this // has different semantics; we hope that the compiler can // just do the right thing either way. @@ -225,9 +234,6 @@ F( " gamedata_%s = %s;", e->name, c->expr) F( " gamedata_has_%s = true;", e->name) _( " }") } - else { -F( " if (GAMETYPE_MATCHES(%s)) %s = %s;", c->name, e->name, c->expr) - } } } } diff --git a/src/factory.h b/src/factory.h index a72afef..18bf069 100644 --- a/src/factory.h +++ b/src/factory.h @@ -6,7 +6,8 @@ /* Access to game and engine factories obtained on plugin load */ typedef void *(*ifacefactory)(const char *name, int *ret); -extern ifacefactory factory_client, factory_server, factory_engine; +extern ifacefactory factory_client, factory_server, factory_engine, + factory_inputsystem; #endif diff --git a/src/gamedata.h b/src/gamedata.h index e127f7c..b5e4ed7 100644 --- a/src/gamedata.h +++ b/src/gamedata.h @@ -17,6 +17,8 @@ #ifndef INC_GAMEDATA_H #define INC_GAMEDATA_H +#include + #ifdef _WIN32 #define NVDTOR 1 #else diff --git a/src/nosleep.c b/src/nosleep.c new file mode 100644 index 0000000..db206e0 --- /dev/null +++ b/src/nosleep.c @@ -0,0 +1,73 @@ +/* + * Copyright © 2022 Michael Smith + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "con_.h" +#include "hook.h" +#include "factory.h" +#include "gamedata.h" +#include "os.h" +#include "vcall.h" + +DEF_CVAR_UNREG(engine_no_focus_sleep, + "Delay while tabbed out (SST reimplementation)", 50, + CON_ARCHIVE | CON_HIDDEN) + +static void **vtable; + +typedef void (*VCALLCONV SleepUntilInput_func)(void *this, int timeout); +static SleepUntilInput_func orig_SleepUntilInput; +static void VCALLCONV hook_SleepUntilInput(void *this, int timeout) { + orig_SleepUntilInput(this, con_getvari(engine_no_focus_sleep)); +} + +bool nosleep_init(void) { + struct con_var *v = con_findvar("engine_no_focus_sleep"); + if (v) return false; // no need! + con_reg(engine_no_focus_sleep); + // TODO(featgen): auto-check these factories + if (!factory_inputsystem) { + con_warn("nosleep: missing required factories\n"); + return false; + } + if (!gamedata_has_vtidx_SleepUntilInput) { + con_warn("nosleep: missing gamedata entries for this engine\n"); + return false; + } + void *insys = factory_inputsystem("InputSystemVersion001", 0); + if (!insys) { + con_warn("nosleep: couldn't get intput system interface\n"); + return false; + } + vtable = *(void ***)insys; + if (!os_mprot(vtable + gamedata_vtidx_SleepUntilInput, + sizeof(void *), PAGE_EXECUTE_READWRITE)) { + con_warn("nosleep: couldn't make memory writeable\n"); + return false; + } + orig_SleepUntilInput = (SleepUntilInput_func)hook_vtable(vtable, + gamedata_vtidx_SleepUntilInput, (void *)&hook_SleepUntilInput); + engine_no_focus_sleep->base.flags &= ~CON_HIDDEN; + return true; +} + +void nosleep_end(void) { + unhook_vtable(vtable, gamedata_vtidx_SleepUntilInput, + (void *)orig_SleepUntilInput); +} + +// vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/nosleep.h b/src/nosleep.h new file mode 100644 index 0000000..4d5237f --- /dev/null +++ b/src/nosleep.h @@ -0,0 +1,27 @@ +/* + * Copyright © 2022 Michael Smith + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INC_NOSLEEP_H +#define INC_NOSLEEP_H + +#include + +bool nosleep_init(void); +void nosleep_end(void); + +#endif + +// vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/rinput.c b/src/rinput.c index 867b5be..8d94b36 100644 --- a/src/rinput.c +++ b/src/rinput.c @@ -31,7 +31,7 @@ // loaded. If m_rawinput already exists, we do nothing; people should use the // game's native raw input instead in that case. -#define ERR "sst: rinput: error: " +#define ERR "rinput: error: " #define USAGEPAGE_MOUSE 1 #define USAGE_MOUSE 2 diff --git a/src/sst.c b/src/sst.c index 0a31796..733e127 100644 --- a/src/sst.c +++ b/src/sst.c @@ -30,6 +30,7 @@ #include "gameinfo.h" #include "gametype.h" #include "hook.h" +#include "nosleep.h" #include "os.h" #include "rinput.h" #include "vcall.h" @@ -72,7 +73,8 @@ static void *clientlib = 0; // more source spaghetti wow! static void VCALLCONV SetCommandClient(void *this, int i) { con_cmdclient = i; } -ifacefactory factory_client = 0, factory_server = 0, factory_engine = 0; +ifacefactory factory_client = 0, factory_server = 0, factory_engine = 0, + factory_inputsystem = 0; // TODO(featgen): I wanted some nice fancy automatic feature system that // figures out the dependencies at build time and generates all the init glue @@ -81,6 +83,7 @@ ifacefactory factory_client = 0, factory_server = 0, factory_engine = 0; static bool has_autojump = false; static bool has_demorec = false; static bool has_demorec_custom = false; +static bool has_nosleep = false; #ifdef _WIN32 static bool has_rinput = false; #endif @@ -205,9 +208,9 @@ DEF_CCMD_HERE(sst_autoload_enable, "Register SST to load on game startup", 0) { // XXX: oh, crap, we're clobbering unicode again. welp, let's hope the // theory that the engine is just as bad if not worse is true so that it // doesn't matter. - if (fprintf(f, "Plugin { file \"%" fS "\" }\n", relpath) < 0) { + if (fprintf(f, "Plugin { file \"%" fS "\" }\n", relpath) < 0 || + fflush(f) == -1) { con_warn("error: couldn't write to %" fS ": %s", path, strerror(errno)); - // XXX: ?????? now what } fclose(f); } @@ -230,9 +233,6 @@ DEF_CCMD_HERE(sst_autoload_disable, "Stop loading SST on game startup", 0) { static bool do_load(ifacefactory enginef, ifacefactory serverf) { factory_engine = enginef; factory_server = serverf; -#ifndef __linux__ - void *clientlib = 0; -#endif if (!con_init(enginef, ifacever)) return false; if (!gameinfo_init(enginef)) { con_disconnect(); return false; } const void **p = vtable_firstdiff; @@ -250,28 +250,43 @@ static bool do_load(ifacefactory enginef, ifacefactory serverf) { *p = (void *)&nop_p_v; // OnEdictFreed #ifdef _WIN32 - //if (gameinfo_serverlib) serverlib = GetModuleHandleW(gameinfo_serverlib); - if (gameinfo_clientlib) clientlib = GetModuleHandleW(gameinfo_clientlib); + //serverlib = GetModuleHandleW(gameinfo_serverlib); + void *clientlib = GetModuleHandleW(gameinfo_clientlib); #else // Linux Source load order seems to be different to the point where if we // +plugin_load or use a vdf then RTLD_NOLOAD won't actually find these, so // we have to just dlopen them normally - and then remember to decrement the // refcount again later in do_unload() so nothing gets leaked - //if (gameinfo_serverlib) serverlib = dlopen(gameinfo_serverlib, 0); - if (gameinfo_clientlib) clientlib = dlopen(gameinfo_clientlib, 0); + //serverlib = dlopen(gameinfo_serverlib, RTLD_NOW); + clientlib = dlopen(gameinfo_clientlib, RTLD_NOW); #endif if (!clientlib) { con_warn("sst: warning: couldn't get the game's client library\n"); - goto nc; } - factory_client = (ifacefactory)os_dlsym(clientlib, "CreateInterface"); - if (!factory_client) { + else if (!(factory_client = (ifacefactory)os_dlsym(clientlib, + "CreateInterface"))) { con_warn("sst: warning: couldn't get client's CreateInterface\n"); } +#ifdef _WIN32 + void *inputsystemlib = GetModuleHandleW(L"inputsystem.dll"); +#else + // TODO(linux): assuming the above doesn't apply to this; check if it does! + void *inputsystemlib = dlopen("bin/libinputsystem.so", + RTLD_NOW | RLTD_NOLOAD); + if (inputsystemlib) dlclose(inputsystemlib); // blegh +#endif + if (!inputsystemlib) { + con_warn("sst: warning: couldn't get the input system library\n"); + } + else if (!(factory_inputsystem = (ifacefactory)os_dlsym(inputsystemlib, + "CreateInterface"))) { + con_warn("sst: warning: couldn't get input system's CreateInterface\n"); + } -nc: gamedata_init(); + gamedata_init(); has_autojump = autojump_init(); has_demorec = demorec_init(); + has_nosleep = nosleep_init(); #ifdef _WIN32 has_rinput = rinput_init(); #endif @@ -320,6 +335,7 @@ static void do_unload(void) { if (has_autojump) autojump_end(); if (has_demorec) demorec_end(); + if (has_nosleep) nosleep_end(); #ifdef _WIN32 if (has_rinput) rinput_end(); #endif -- cgit v1.2.3