summaryrefslogtreecommitdiffhomepage
path: root/src/con_.h
diff options
context:
space:
mode:
authorMichael Smith <mikesmiffy128@gmail.com>2021-11-20 03:10:50 +0000
committerMichael Smith <mikesmiffy128@gmail.com>2021-11-20 03:18:08 +0000
commitda6f343032cb01597dc7866e66f091adf3243a62 (patch)
tree870f8cb8e82bb42202ab92bea03fc6ab35ada7ca /src/con_.h
Initial public snapshot
With code from Bill. Thanks Bill!
Diffstat (limited to 'src/con_.h')
-rw-r--r--src/con_.h278
1 files changed, 278 insertions, 0 deletions
diff --git a/src/con_.h b/src/con_.h
new file mode 100644
index 0000000..4c662fe
--- /dev/null
+++ b/src/con_.h
@@ -0,0 +1,278 @@
+/* XXX: THIS FILE SHOULD BE CALLED `con.h` BUT WINDOWS IS STUPID */
+/*
+ * Copyright © 2021 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_CON_H
+#define INC_CON_H
+
+#include <stdbool.h>
+
+#include "intdefs.h"
+
+#if defined(__GNUC__) || defined(__clang__)
+#define _CON_PRINTF(x, y) __attribute__((format(printf, (x), (y))))
+#else
+#define _CON_PRINTF(x, y)
+#endif
+
+#define CON_CMD_MAX_ARGC 64
+#define CON_CMD_MAX_LENGTH 512
+
+/* arguments to a console command, parsed by the engine (SDK name: CCommand) */
+struct con_cmdargs {
+ int argc;
+ int argv0size;
+ char argsbuf[CON_CMD_MAX_LENGTH];
+ char argvbuf[CON_CMD_MAX_LENGTH];
+ const char *argv[CON_CMD_MAX_ARGC];
+};
+
+/* an ARGB colour, passed to con_colourmsg */
+struct con_colour {
+ union {
+ struct { u8 r, g, b, a; };
+ u32 val;
+ uchar bytes[4];
+ };
+};
+
+#define CON_CMD_MAXCOMPLETE 64
+#define CON_CMD_MAXCOMPLLEN 64
+
+/* ConVar/ConCommand flag bits - undocumented ones are probably not useful... */
+enum {
+ CON_UNREG = 1,
+ CON_DEVONLY = 1 << 1, /* hide unless developer 1 is set */
+ CON_SERVERSIDE = 1 << 2, /* set con_cmdclient and run on server side */
+ CON_CLIENTDLL = 1 << 3,
+ CON_HIDDEN = 1 << 4, /* hide completely, often useful to remove! */
+ CON_PROTECTED = 1 << 5, /* don't send to clients (example: password) */
+ CON_SPONLY = 1 << 6,
+ CON_ARCHIVE = 1 << 7, /* save in config - plugin would need a VDF! */
+ CON_NOTIFY = 1 << 8, /* announce changes in game chat */
+ CON_USERINFO = 1 << 9,
+ CON_PRINTABLE = 1 << 10, /* do not allow non-printable values */
+ CON_UNLOGGED = 1 << 11,
+ CON_NOPRINT = 1 << 12, /* do not attempt to print, contains junk! */
+ CON_REPLICATE = 1 << 13, /* client will use server's value */
+ CON_CHEAT = 1 << 14, /* require sv_cheats 1 to change from default */
+ CON_DEMO = 1 << 16, /* record value at the start of a demo */
+ CON_NORECORD = 1 << 17, /* don't record the command to a demo, ever */
+ CON_NOTCONN = 1 << 22, /* cannot be changed while in-game */
+ CON_SRVEXEC = 1 << 28, /* server can make clients run the command */
+ CON_NOSRVQUERY = 1 << 29, /* server cannot query the clientside value */
+ CON_CCMDEXEC = 1 << 30 /* ClientCmd() function may run the command */
+};
+
+/* A callback function invoked to execute a command. */
+typedef void (*con_cmdcb)(const struct con_cmdargs *cmd);
+
+/* Obsolete callback; not used by SST, but might still exist in the engine. */
+typedef void (*con_cmdcbv1)(void);
+
+/*
+ * This is an autocompletion callback for suggesting arguments to a command.
+ * XXX: Autocompletion isn't really totally figured out or implemented yet.
+ */
+typedef int (*con_complcb)(const char *part,
+ char cmds[CON_CMD_MAXCOMPLETE][CON_CMD_MAXCOMPLLEN]);
+
+/*
+ * These are called by the plugin load/unload functions; they have no use
+ * elsewhere.
+ */
+bool con_init(void *(*f)(const char *, int *), int plugin_ver);
+void con_disconnect(void);
+
+/*
+ * These types *pretty much* match those in the engine. Their fields can be
+ * accessed and played with if you know what you're doing!
+ */
+
+struct con_cmdbase { // ConCommandBase in engine
+ void **vtable;
+ struct con_cmdbase *next;
+ bool registered;
+ const char *name;
+ const char *help;
+ uint flags;
+};
+
+struct con_cmd { // ConCommand in engine
+ struct con_cmdbase base;
+ union {
+ con_cmdcbv1 cb_v1;
+ con_cmdcb cb;
+ /*ICommandCallback*/ void *cb_iface; // does source even use this?
+ };
+ union {
+ con_complcb complcb;
+ /*ICommandCompletionCallback*/ void *complcb_iface; // ...or this?
+ };
+ bool has_complcb : 1, use_newcb : 1, use_newcmdiface : 1;
+};
+
+// con_var will be a bit different on linux; see offset_to_top etc.
+#ifdef __linux__
+#error FIXME: redo multi-vtable crap for itanium ABI!
+#endif
+
+struct con_var { // ConVar in engine
+ struct con_cmdbase base;
+ void **vtable_iconvar; // IConVar in engine (pure virtual)
+ struct con_var *parent;
+ const char *defaultval;
+ char *strval;
+ uint strlen;
+ float fval;
+ int ival;
+ bool hasmin;
+ // bool hasmax; // better packing here, might break engine ABI
+ int minval;
+ bool hasmax; // just sticking to sdk position for now
+ int maxval;
+ //void *cb; we don't currently bother with callback support. add if needed!
+};
+
+
+/*
+ * These functions get and set the values of console variables in a
+ * neatly-abstracted manner. Note: cvar values are always strings internally -
+ * numerical values are just interpretations of the underlying value.
+ */
+struct con_var *con_findvar(const char *name);
+struct con_cmd *con_findcmd(const char *name);
+const char *con_getvarstr(const struct con_var *v);
+float con_getvarf(const struct con_var *v);
+int con_getvari(const struct con_var *v);
+void con_setvarstr(struct con_var *v, const char *s);
+void con_setvarf(struct con_var *v, float f);
+void con_setvari(struct con_var *v, int i);
+
+/*
+ * These functions grab the callback function from an existing command, allowing
+ * it to be called directly or further dug into for convenient research.
+ *
+ * They perform sanity checks to ensure that the command implements the type of
+ * callback being requested. If this is already known, consider just grabbing
+ * the member directly to avoid the small amount of unnecessary work.
+ */
+con_cmdcb con_getcmdcb(const struct con_cmd *cmd);
+con_cmdcbv1 con_getcmdcbv1(const struct con_cmd *cmd);
+
+/*
+ * These functions provide basic console output, in white and red colours
+ * respectively. They are aliases to direct tier0 calls, so they work early on
+ * even before anything else is initialised.
+ */
+#if defined(__GNUC__) || defined(__clang__)
+#ifdef _WIN32
+#define __asm__(x) __asm__("_" x) // stupid mangling meme (not on linux, right?)
+#endif
+void con_msg(const char *fmt, ...) _CON_PRINTF(1, 2) __asm__("Msg");
+void con_warn(const char *fmt, ...) _CON_PRINTF(1, 2) __asm__("Warning");
+#undef __asm__
+#else
+#error Need an equivalent of asm names for your compiler!
+#endif
+
+extern void *_con_iface;
+extern void (*_con_colourmsgf)(void *this, const struct con_colour *c,
+ const char *fmt, ...) _CON_PRINTF(3, 4);
+/*
+ * This provides the same functionality as ConColorMsg which was removed from
+ * tier0 in the L4D engine branch - specifically, it allows printing a message
+ * with an arbitrary RGBA colour. It must only be used after a successful
+ * con_init() call.
+ */
+#define con_colourmsg(c, ...) _con_colourmsgf(_con_iface, c, __VA_ARGS__)
+
+/*
+ * The index of the client responsible for the currently executing command,
+ * or -1 if serverside. This is a global variable because of Source spaghetti,
+ * rather than unforced plugin spaghetti.
+ */
+extern int con_cmdclient;
+
+// internal detail, used by DEF_* macros below
+extern void *_con_vtab_cmd[];
+// msvc rtti tables are offset negatively from the vtable pointer. to make this
+// a constant expression we have to use a macro
+#define _con_vtab_var (_con_realvtab_var + 1)
+extern void *_con_realvtab_var[];
+extern void *_con_vtab_iconvar[];
+
+#define _DEF_CVAR(name_, desc, value, hasmin_, min, hasmax_, max, flags_) \
+ static struct con_var _cvar_##name_ = { \
+ .base = { \
+ .vtable = _con_vtab_var, \
+ .name = "" #name_, .help = "" desc, .flags = (flags_) \
+ }, \
+ .vtable_iconvar = _con_vtab_iconvar, \
+ .parent = &_cvar_##name_, /* bizarre, but how the engine does it */ \
+ .defaultval = value, .strlen = sizeof("" value), \
+ .hasmin = hasmin_, .minval = (min), .hasmax = hasmax_, .maxval = (max) \
+ }; \
+ struct con_var *name_ = (struct con_var *)&_cvar_##name_;
+
+/* Defines a console variable with no min/max values. */
+#define DEF_CVAR(name, desc, value, flags) \
+ _DEF_CVAR(name, desc, value, false, 0, false, 0, flags)
+
+/* Defines a console variable with a given mininum numeric value. */
+#define DEF_CVAR_MIN(name_, desc, value, min, flags_) \
+ _DEF_CVAR(name, desc, value, true, min, false, 0, flags)
+
+/* Defines a console variable in the given numeric value range. */
+#define DEF_CVAR_MINMAX(name_, desc, value, min, max, flags_) \
+ _DEF_CVAR(name, desc, value, true, min, true, max, flags)
+
+#define _DEF_CCMD(varname, name_, desc, func, flags_) \
+ static struct con_cmd _ccmd_##varname = { \
+ .base = { \
+ .vtable = _con_vtab_cmd, \
+ .name = "" #name_, .help = "" desc, .flags = (flags_) \
+ }, \
+ .cb = &func, \
+ .use_newcb = true \
+ }; \
+ struct con_cmd *varname = (struct con_cmd *)&_ccmd_##varname;
+
+/* Defines a command with a given function as its handler. */
+#define DEF_CCMD(name, desc, func, flags) \
+ _DEF_CCMD(name, name, desc, func, flags)
+
+/*
+ * Defines two complementary +- commands, with PLUS_ and MINUS_ prefixes on
+ * their C names.
+ */
+#define DEF_CCMD_PLUSMINUS(name, descplus, fplus, descminus, fminus, flags) \
+ _DEF_CCMD(PLUS_##name, "+" name, descplus, fplus, flags) \
+ _DEF_CCMD(MINUS_##name, "-" name, descminus, fminus, flags)
+
+/*
+ * Defines a console command with the handler function body immediately
+ * following the macro (like in Source itself).
+ */
+#define DEF_CCMD_HERE(name, desc, flags) \
+ static void _cmdf_##name(const struct con_cmdargs *cmd); \
+ _DEF_CCMD(name, name, desc, _cmdf_##name, flags) \
+ static void _cmdf_##name(const struct con_cmdargs *cmd) \
+ /* { body here } */
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80