diff options
| author | 2022-07-23 23:47:26 +0100 | |
|---|---|---|
| committer | 2022-07-23 23:47:26 +0100 | |
| commit | c8d7588251fd4fe63ac6afe2a90ca7066c786609 (patch) | |
| tree | f547831424d20c6f1b3f2b6bdea97c2f53502deb | |
| parent | 8f5673d5f4e63b158b1cd2a2aef874ac83b3662d (diff) | |
| download | sst-c8d7588251fd4fe63ac6afe2a90ca7066c786609.tar.gz sst-c8d7588251fd4fe63ac6afe2a90ca7066c786609.zip | |
Add event system
| -rw-r--r-- | compile.bat | 2 | ||||
| -rw-r--r-- | src/build/cmeta.c | 32 | ||||
| -rw-r--r-- | src/build/cmeta.h | 12 | ||||
| -rw-r--r-- | src/build/codegen.c | 120 | ||||
| -rw-r--r-- | src/event.h | 35 | ||||
| -rw-r--r-- | src/fov.c | 4 | ||||
| -rw-r--r-- | src/fov.h | 6 | ||||
| -rw-r--r-- | src/sst.c | 8 | ||||
| -rw-r--r-- | src/sst.h | 26 | 
9 files changed, 235 insertions, 10 deletions
| diff --git a/compile.bat b/compile.bat index 3981af5..d5a24b5 100644 --- a/compile.bat +++ b/compile.bat @@ -76,7 +76,7 @@ setlocal DisableDelayedExpansion  if "%dbg%"=="1" set src=%src% src/dbg.c
  if "%dbg%"=="1" set src=%src% src/udis86.c
 -%HOSTCC% -municode -O2 %warnings% -D_CRT_SECURE_NO_WARNINGS ^
 +%HOSTCC% -municode -O2 %warnings% -D_CRT_SECURE_NO_WARNINGS -ladvapi32 ^
  -o .build/codegen.exe src/build/codegen.c src/build/cmeta.c || exit /b
  %HOSTCC% -municode -O2 %warnings% -D_CRT_SECURE_NO_WARNINGS ^
  -o .build/mkgamedata.exe src/build/mkgamedata.c src/kv.c || exit /b
 diff --git a/src/build/cmeta.c b/src/build/cmeta.c index bf18903..3d49927 100644 --- a/src/build/cmeta.c +++ b/src/build/cmeta.c @@ -266,4 +266,36 @@ void cmeta_conmacros(const struct cmeta *cm,  	}  } +void cmeta_evdefmacros(const struct cmeta *cm, void (*cb_def)(const char *name)) { +	Token *tp = (Token *)cm; +	if (!tp || !tp->next || !tp->next->next) return; // DEF_EVENT, (, name +	while (tp) { +		if (equal(tp, "DEF_EVENT") && equal(tp->next, "(")) { +			tp = tp->next->next; +			char *name = malloc(tp->len + 1); +			if (!name) die1("couldn't allocate memory"); +			memcpy(name, tp->loc, tp->len); +			name[tp->len] = '\0'; +			cb_def(name); +		} +		tp = tp->next; +	} +} + +void cmeta_evhandlermacros(const struct cmeta *cm, const char *modname, +		void (*cb_handler)(const char *evname, const char *modname)) { +	Token *tp = (Token *)cm; +	while (tp) { +		if (equal(tp, "HANDLE_EVENT") && equal(tp->next, "(")) { +			tp = tp->next->next; +			char *name = malloc(tp->len + 1); +			if (!name) die1("couldn't allocate memory"); +			memcpy(name, tp->loc, tp->len); +			name[tp->len] = '\0'; +			cb_handler(name, modname); +		} +		tp = tp->next; +	} +} +  // vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/build/cmeta.h b/src/build/cmeta.h index 4757654..125ce2c 100644 --- a/src/build/cmeta.h +++ b/src/build/cmeta.h @@ -39,6 +39,18 @@ void cmeta_includes(const struct cmeta *cm,  void cmeta_conmacros(const struct cmeta *cm,  		void (*cb)(const char *name, bool isvar, bool unreg)); +/* + * Iterates through all event-related macros and takes note of which events are + * defined, giving a callback for each. + */ +void cmeta_evdefmacros(const struct cmeta *cm, void (*cb)(const char *name)); + +/* + * Iterates through all event-related macros and gives a callback for each event + * that is handled by the given module. + */ +void cmeta_evhandlermacros(const struct cmeta *cm, const char *modname, +		void (*cb)(const char *evname, const char *modname));  #endif  // vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/build/codegen.c b/src/build/codegen.c index d96059d..1dee6a1 100644 --- a/src/build/codegen.c +++ b/src/build/codegen.c @@ -20,6 +20,8 @@  #include "../os.h"  #include "cmeta.h" +#include "skiplist.h" +#include "vec.h"  #define MAXENT 65536 // arbitrary limit!  static struct ent { @@ -47,6 +49,51 @@ static void oncondef(const char *name, bool isvar, bool unreg) {  	PUT(name, isvar, unreg);  } +struct vec_str VEC(const char *); +DECL_SKIPLIST(static, event, struct event, const char *, 4) +struct event { +	const char *name; +	struct vec_str handlers; +	struct skiplist_hdr_event hdr; +}; +static inline int cmp_event(struct event *e, const char *s) { +	return strcmp(e->name, s); +} +static inline struct skiplist_hdr_event *hdr_event(struct event *e) { +	return &e->hdr; +} +DEF_SKIPLIST(static, event, cmp_event, hdr_event) +struct skiplist_hdr_event events = {0}; + +static void onevdef(const char *name) { +	struct event *e = skiplist_get_event(&events, name); +	if (!e) { +		struct event *e = malloc(sizeof(*e)); +		if (!e) die("couldn't allocate memory"); +		e->name = name; +		e->handlers = (struct vec_str){0}; +		e->hdr = (struct skiplist_hdr_event){0}; +		skiplist_insert_event(&events, name, e); +	} +	else { +		fprintf(stderr, "codegen: error: duplicate event definition `%s`\n", +				name); +		exit(2); +	} +} + +static void onevhandler(const char *evname, const char *modname) { +	struct event *e = skiplist_get_event(&events, evname); +	if (!e) { +		fprintf(stderr, "codegen: error: module `%s` trying to handle " +				"non-existent event `%s`\n", modname, evname); +		exit(2); +	} +	// NOTE: not bothering to check for more than one handler in a file. +	// compiler will get that anyway. +	if (!vec_push(&e->handlers, modname)) die("couldn't allocate memory"); +} +  #define _(x) \  	if (fprintf(out, "%s\n", x) < 0) die("couldn't write to file");  #define F(f, ...) \ @@ -55,10 +102,67 @@ static void oncondef(const char *name, bool isvar, bool unreg) {  _( "/* This file is autogenerated by src/build/codegen.c. DO NOT EDIT! */") \  _( "") +struct passinfo { +	const struct cmeta *cm; +	const os_char *path; +}; +struct vec_passinfo VEC(struct passinfo) pass2 = {0}; +  int OS_MAIN(int argc, os_char *argv[]) {  	for (++argv; *argv; ++argv) {  		const struct cmeta *cm = cmeta_loadfile(*argv);  		cmeta_conmacros(cm, &oncondef); +		cmeta_evdefmacros(cm, &onevdef); +		if (!vec_push(&pass2, ((struct passinfo){cm, *argv}))) { +			die("couldn't allocate memory"); +		} +	} + +	// we have to a second pass for event handlers. also, there's a bunch of +	// terrible garbage here. don't stare for too long... +	for (struct passinfo *pi = pass2.data; pi - pass2.data < pass2.sz; ++pi) { +		// XXX: I guess we should cache these by name or something! +		const struct cmeta *cm = pi->cm; +#ifdef _WIN32 +		int arglen = wcslen(pi->path); +		char *p = malloc(arglen + 1); +		if (!p) die("couldn't allocate string"); +		// XXX: Unicode isn't real, it can't hurt you. +		for (const ushort *q = pi->path; q - pi->path < arglen; ++q) { +			p[q - pi->path] = *q; // ugh this is stupid +		} +		p[arglen] = '\0'; +#else +		const char *p = p->path; +#endif +		const char *lastslash = p - 1; +		for (; *p; ++p) { +#ifdef _WIN32 +			if (*p == '/' || *p == '\\') { +#else +			if (*p == '/') { +#endif +				lastslash = p; +			} +		} +		int len = strlen(lastslash + 1); +		if (len <= 3 || lastslash[len - 1] != '.' || lastslash[len] != 'c') { +			fprintf(stderr, "filenames should end in .c probably\n"); +			exit(2); +		} +		char *modname = malloc(len - 1); +		if (!modname) die("couldn't allocate string"); +		memcpy(modname, lastslash + 1, len - 2); +		modname[len - 2] = '\0'; +		// ugh. same dumb hacks from compile scripts +		if (!strcmp(modname, "con_")) { +			free(modname); // might as well +			modname = "con"; +		} +		else if (!strcmp(modname, "sst")) { +			continue; // I guess??? +		} +		cmeta_evhandlermacros(cm, modname, &onevhandler);  	}  	FILE *out = fopen(".build/include/cmdinit.gen.h", "wb"); @@ -86,7 +190,21 @@ F( "	extfree(%s->strval);", p->name);  		}  	}  _( "}") -	if (fflush(out) == EOF) die("couldn't fully write cmdinit.gen.h"); +	if (fclose(out) == EOF) die("couldn't fully write cmdinit.gen.h"); + +	out = fopen(".build/include/evglue.gen.h", "wb"); +	if (!out) die("couldn't open evglue.gen.h"); +	H() +	for (const struct event *e = events.x[0]; e; e = e->hdr.x[0]) { +F( "void _evemit_%s(void) {", e->name) +		for (const char **pp = e->handlers.data; +				pp - e->handlers.data < e->handlers.sz; ++pp) { +F( "	void _evhandler_%s_%s(void);", *pp, e->name); // blegh. +F( "	_evhandler_%s_%s();", *pp, e->name); +		} +_( "}") +	} +	if (fclose(out) == EOF) die("couldn't fully write evglue.gen.h");  	return 0;  } diff --git a/src/event.h b/src/event.h new file mode 100644 index 0000000..41965e9 --- /dev/null +++ b/src/event.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2022 Michael Smith <mikesmiffy128@gmail.com> + * + * 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_EVENT_H +#define INC_EVENT_H + +#define _EVENT_CAT4_(a, b, c, d) a##b##c##d +#define _EVENT_CAT4(a, b, c, d) _EVENT_CAT4_(a, b, c, d) + +#define DECL_EVENT(evname) void _evemit_##evname(void); +#define DEF_EVENT(evname) \ +	DECL_EVENT(evname) \ +	static inline void _evown_##evname(void) { _evemit_##evname(); } +#define EMIT_EVENT(evname) _evown_##evname(); + +#define HANDLE_EVENT(evname) \ +	void _EVENT_CAT4(_evhandler_, MODULE_NAME, _, evname)(void) \ +	/* function body here */ + +#endif + +// vi: sw=4 ts=4 noet tw=80 cc=80 @@ -23,10 +23,12 @@  #include "engineapi.h"  #include "errmsg.h"  #include "ent.h" +#include "event.h"  #include "gametype.h"  #include "hook.h"  #include "intdefs.h"  #include "mem.h" +#include "sst.h"  #include "vcall.h"  #include "x86.h" @@ -74,7 +76,7 @@ static void fovcb(struct con_var *v) {  }  // called by sst.c in ClientActive to ensure fov is applied on load -void fov_onload(void) { +HANDLE_EVENT(ClientActive) {  	if (real_fov_desired == fov_desired) {  		void *player = ent_get(1); // "  		if (player) orig_SetDefaultFOV(player, con_getvari(fov_desired)); @@ -19,15 +19,9 @@  #include <stdbool.h> -#include "engineapi.h" -  bool fov_init(bool has_ent);  void fov_end(void); -// annoying spaghetti, from sst.c. maybe one day there could be some proper -// event system... -void fov_onload(void); -  #endif  // vi: sw=4 ts=4 noet tw=80 cc=80 @@ -31,6 +31,7 @@  #include "engineapi.h"  #include "errmsg.h"  #include "ent.h" +#include "event.h"  #include "fov.h"  #include "fixes.h"  #include "gameinfo.h" @@ -473,11 +474,13 @@ DECL_VFUNC_DYN(void, ServerCommand, const char *)  DEF_CVAR(_sst_onload_echo, "EXPERIMENTAL! Don't rely on this existing!", "",  		CON_HIDDEN) +DEF_EVENT(ClientActive) +  static void VCALLCONV ClientActive(void *this, struct edict *player) {  	// XXX: it's kind of dumb that we get handed the edict here then go look it  	// up again in fov.c but I can't be bothered refactoring any further now  	// that this finally works, do something later lol -	if (has_fov) fov_onload(); +	EMIT_EVENT(ClientActive)  	// continuing dumb portal hack. didn't even seem worth adding a feature for  	if (has_vtidx_ServerCommand && con_getvarstr(_sst_onload_echo)[0]) { @@ -530,4 +533,7 @@ EXPORT const void *CreateInterface(const char *name, int *ret) {  	return 0;  } +// no better place to put this lol +#include <evglue.gen.h> +  // vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/sst.h b/src/sst.h new file mode 100644 index 0000000..247346b --- /dev/null +++ b/src/sst.h @@ -0,0 +1,26 @@ +/* + * Copyright © 2022 Michael Smith <mikesmiffy128@gmail.com> + * + * 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_SST_H +#define INC_SST_H + +#include "event.h" + +DECL_EVENT(ClientActive) + +#endif + +// vi: sw=4 ts=4 noet tw=80 cc=80 | 
