diff options
| -rwxr-xr-x | compile | 1 | ||||
| -rw-r--r-- | compile.bat | 1 | ||||
| -rw-r--r-- | src/chatmsg.c | 127 | ||||
| -rw-r--r-- | src/chatmsg.h | 38 |
4 files changed, 167 insertions, 0 deletions
@@ -61,6 +61,7 @@ src="\ chunklets/fastspin.c chunklets/msg.c chunklets/x86.c + chatmsg.c clientcon.c con_.c con_.S diff --git a/compile.bat b/compile.bat index 3eae3a8..4920914 100644 --- a/compile.bat +++ b/compile.bat @@ -99,6 +99,7 @@ setlocal DisableDelayedExpansion :+ alias.c
:+ autojump.c
:+ bind.c
+:+ chatmsg.c
:+ clientcon.c
:+ con_.c
:+ con_.S
diff --git a/src/chatmsg.c b/src/chatmsg.c new file mode 100644 index 0000000..d0f2a64 --- /dev/null +++ b/src/chatmsg.c @@ -0,0 +1,127 @@ +/* + * Copyright © Michael Smith <mikesmiffy128@gmail.com> + * Copyright © Hayden K <imaciidz@gmail.com> + * Copyright © Willian Henrique <wsimanbrazil@yahoo.com.br> + * + * 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 "chunklets/x86.h" +#include "engineapi.h" +#include "ent.h" +#include "feature.h" +#include "langext.h" +#include "x86util.h" + +FEATURE() +REQUIRE(ent) +REQUIRE_GLOBAL(globalvars) + +struct IRecipientFilter { + const struct IRecipientFilter_vtable { + void *dtor; +#ifndef _WIN32 + void *dtor2; +#endif + bool (*VCALLCONV IsReliable)(struct IRecipientFilter *this); + bool (*VCALLCONV IsInitMessage)(struct IRecipientFilter *this); + int (*VCALLCONV GetRecipientCount)(struct IRecipientFilter *this); + int (*VCALLCONV GetRecipientIndex)(struct IRecipientFilter *this, + int slot); + } *vtable; +}; + +// this function serves as two identical functions! +static bool VCALLCONV IsReliable_IsInitMessage(struct IRecipientFilter *this) { + return false; +} + +static int VCALLCONV GetRecipientCount(struct IRecipientFilter *this) { + int count = 0; + for (int i = 1; i <= globalvars->maxclients; ++i) { + // if there's an entity in a player slot, just assume there's a player. + // this is simpler than what the engine's own CBroadcastRecipientFilter + // seems to do, but holds up in practice + struct edict *e = ent_getedict(i); + if (e && e->ent_unknown) ++count; + } + return count; +} + +static int VCALLCONV GetRecipientIndex(struct IRecipientFilter *this, int slot) { + if_cold (slot < 0 || slot > globalvars->maxclients) return -1; + // this isn't _particularly_ efficient (is it technically quadratic?) + // but maxplayers is never a particularly big number, so it's not really a + // big deal to do this just to send the occasional chat broadcast + for (int i = 1; i <= globalvars->maxclients; ++i) { + struct edict *e = ent_getedict(i); + if (e && e->ent_unknown && !slot--) return i; + } + return -1; +} + +static const struct IRecipientFilter_vtable recipientfilter_vtable = { + 0, // should never get called +#ifndef _WIN32 + 0, // ditto +#endif + &IsReliable_IsInitMessage, + &IsReliable_IsInitMessage, + &GetRecipientCount, + &GetRecipientIndex +}; + +typedef void (*UTIL_ClientPrintFilter_func)(struct IRecipientFilter *, int, + const char *, const char *, const char *, const char *, const char *); +static UTIL_ClientPrintFilter_func UTIL_ClientPrintFilter; + +static bool find_UTIL_ClientPrintFilter(const uchar *insns) { +#ifdef _WIN32 + for (const uchar *p = insns; p - insns < 128;) { + if (p[0] == X86_PUSHI8 && p[1] == 0x02 && p[3] == X86_CALL) { + p = p + 8 + mem_loads32(p + 4); + insns = p; + for (p = insns; p - insns < 96;) { + if (p[0] == X86_PUSHEAX && p[1] == X86_CALL) { + UTIL_ClientPrintFilter = (UTIL_ClientPrintFilter_func)( + p + 6 + mem_loads32(p + 2)); + return true; + } + NEXT_INSN(p, "UTIL_ClientPrintFilter"); + } + return false; + } + NEXT_INSN(p, "UTIL_ClientPrintFilter"); + } +#endif + // TODO(linux): the usual code search stuff + return false; +} + +void chatmsg_broadcast(const char *msg) { + struct IRecipientFilter filter = {.vtable = &recipientfilter_vtable}; + UTIL_ClientPrintFilter(&filter, /*HUD_PRINTTALK*/ 3, msg, 0, 0, 0, 0); + return; +} + +INIT { + struct con_cmd *cmd_ent_dump = con_findcmd("ent_dump"); + if_cold (!cmd_ent_dump) return FEAT_INCOMPAT; + if_cold (!find_UTIL_ClientPrintFilter(cmd_ent_dump->cb_insns)) { + errmsg_errorx("couldn't find UTIL_ClientPrintFilter"); + return FEAT_INCOMPAT; + } + return FEAT_OK; +} + +// vi: sw=4 ts=4 noet tw=80 cc=80 diff --git a/src/chatmsg.h b/src/chatmsg.h new file mode 100644 index 0000000..b5f63bb --- /dev/null +++ b/src/chatmsg.h @@ -0,0 +1,38 @@ +/* + * Copyright © Michael Smith <mikesmiffy128@gmail.com> + * Copyright © Hayden K <imaciidz@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_CHATMSG_H +#define INC_CHATMSG_H + +/* + * Sends a message to the in-game chat for all players. Strings can have control + * characters embedded to set colors. A control character must be at the start + * of the string to use any subsequent ones. \x02 (STX) only works at the start + * of the string, and precludes using the other control characters. + * + * The list of possible control characters is as follows: + * - \x02 (STX) - Use team color up to the end of the player name + * - \x03 (ETX) - Use team color from this point forward + * - \x04 (EOT) - Use location color from this point forward + * - \x05 (ENQ) - Use achievement color from this point forward + * - \x01 (SOH) - Use normal color from this point forward + */ +void chatmsg_broadcast(const char *msg); + +#endif + +// vi: sw=4 ts=4 noet tw=80 cc=80 |
