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. --- 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 ++++++++++++++++++++---------- 8 files changed, 149 insertions(+), 24 deletions(-) create mode 100644 src/nosleep.c create mode 100644 src/nosleep.h (limited to 'src') 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