Added my own minimal implementation of a chat processor.

* Removed Chat-Processor dependency.
* Added cvar `shavit_chat_colon`.
* Fixed inconsistencies with default chat messages.
This commit is contained in:
shavit 2018-05-08 19:01:29 +03:00
parent b5a41ae4d0
commit 9461c29f71
5 changed files with 324 additions and 161 deletions

View File

@ -18,13 +18,12 @@ Including a records system, map zones (start/end marks etc), bonuses, HUD with u
# Requirements:
* Steam version of Counter-Strike: Source or Counter-Strike: Global Offensive.
* [SourceMod 1.9 or above](http://www.sourcemod.net/downloads.php)
* A MySQL database (preferably locally hosted) if your database is likely to grow big, or if you want to use the rankings plugin. MySQL server version of 5.5.5 or above (MariaDB equivalent works too) is highly recommended.
# Optional requirements:
* [DHooks](http://users.alliedmods.net/~drifter/builds/dhooks/2.1/) - required for 250/260 runspeed for all weapons.
* [Bunnyhop Statistics](https://forums.alliedmods.net/showthread.php?t=286135) - to show amount of scrolls for non-auto styles in the key display. Required for TF2 servers.
* [SteamWorks](https://forums.alliedmods.net/showthread.php?t=229556) - for the `{serverip}` advertisement variable.
* [Chat-Processor](https://github.com/Drixevel/Chat-Processor) - if you're enabling the `shavit-chat` module.
* A MySQL database (preferably locally hosted) if your database is likely to grow or want to use the rankings plugin. MySQL server version of 5.5.5 or above (MariaDB equivalent works too) is recommended.
# Optional requirements, for the best experience:
* [DHooks](http://users.alliedmods.net/~drifter/builds/dhooks/2.1/)
* [Bunnyhop Statistics](https://forums.alliedmods.net/showthread.php?t=286135)
* [SteamWorks](https://forums.alliedmods.net/showthread.php?t=229556)
# Installation:
Refer to the [wiki page](https://github.com/shavitush/bhoptimer/wiki/1.-Installation).

View File

@ -0,0 +1,46 @@
// These are the chat messages for the bhoptimer implementation of a chat processor.
// Notes:
// In CS:S and TF2, the colon uses the default chat color.
// In CS:GO, the colon uses the same color the player name uses.
"Chat Messages"
{
"CS:S"
{
"Cstrike_Chat_CT_Loc" "(Counter-Terrorist) {name} {def}{colon} {msg}"
"Cstrike_Chat_CT" "(Counter-Terrorist) {name} {def}{colon} {msg}"
"Cstrike_Chat_T_Loc" "(Terrorist) {name} {def}{colon} {msg}"
"Cstrike_Chat_T" "(Terrorist) {name} {def}{colon} {msg}"
"Cstrike_Chat_CT_Dead" "*DEAD*(Counter-Terrorist) {name} {def}{colon} {msg}"
"Cstrike_Chat_T_Dead" "*DEAD*(Terrorist) {name} {def}{colon} {msg}"
"Cstrike_Chat_Spec" "(Spectator) {name} {def}{colon} {msg}"
"Cstrike_Chat_All" "{name} {def}{colon} {msg}"
"Cstrike_Chat_AllDead" "*DEAD* {name} {def}{colon} {msg}"
"Cstrike_Chat_AllSpec" "*SPEC* {name} {def}{colon} {msg}"
}
"CS:GO"
{
"Cstrike_Chat_CT_Loc" "(Counter-Terrorist) {name} {colon} {msg}"
"Cstrike_Chat_CT" "(Counter-Terrorist) {name} {colon} {msg}"
"Cstrike_Chat_T_Loc" "(Terrorist) {name} {colon} {msg}"
"Cstrike_Chat_T" "(Terrorist) {name} {colon} {msg}"
"Cstrike_Chat_CT_Dead" "*DEAD*(Counter-Terrorist) {name} {colon} {msg}"
"Cstrike_Chat_T_Dead" "*DEAD*(Terrorist) {name} {colon} {msg}"
"Cstrike_Chat_Spec" "(Spectator) {name} {colon} {msg}"
"Cstrike_Chat_All" "{name} {colon} {msg}"
"Cstrike_Chat_AllDead" "*DEAD* {name} {colon} {msg}"
"Cstrike_Chat_AllSpec" "*SPEC* {name} {colon} {msg}"
}
"TF2"
{
"TF_Chat_Team_Loc" "(TEAM) {name} {def}{colon} {msg}"
"TF_Chat_Team" "(TEAM) {name} {def}{colon} {msg}"
"TF_Chat_Team_Dead" "*DEAD*(TEAM) {name} {def}{colon} {msg}"
"TF_Chat_Spec" "(Spectator) {name} {def}{colon} {msg}"
"TF_Chat_All" "{name} {def}{colon} {msg}"
"TF_Chat_AllDead" "*DEAD* {name} {def}{colon} {msg}"
"TF_Chat_AllSpec" "*SPEC* {name} {def}{colon} {msg}"
"TF_Chat_Coach" "(Coach) {name} {def}{colon} {msg}"
}
}

View File

@ -1,79 +0,0 @@
#if defined _chat_processor_included
#endinput
#endif
#define _chat_processor_included
//Globals
#define MAXLENGTH_FLAG 32
#define MAXLENGTH_NAME 128
#define MAXLENGTH_MESSAGE 128
#define MAXLENGTH_BUFFER 255
//Natives
/**
* Retrieves the current format string assigned from a flag string.
* Example: "Cstrike_Chat_All" = "{1} : {2}"
* You can find the config formats in either the translations or the configs.
*
* param sFlag Flag string to retrieve the format string from.
* param sBuffer Format string from the flag string.
* param iSize Size of the format string buffer.
*
* noreturn
**/
native void ChatProcessor_GetFlagFormatString(const char[] sFlag, char[] sBuffer, int iSize);
//Forwards
/**
* Called while sending a chat message before It's sent.
* Limits on the name and message strings can be found above.
*
* param author Author that created the message.
* param recipients Array of clients who will receive the message.
* param flagstring Flag string to determine the type of message.
* param name Name string of the author to be pushed.
* param message Message string from the author to be pushed.
* param processcolors Toggle to process colors in the buffer strings.
* param removecolors Toggle to remove colors in the buffer strings. (Requires bProcessColors = true)
*
* return types
* - Plugin_Continue Stops the message.
* - Plugin_Stop Stops the message.
* - Plugin_Changed Fires the post-forward below and prints out a message.
* - Plugin_Handled Fires the post-forward below but doesn't print a message.
**/
forward Action CP_OnChatMessage(int& author, ArrayList recipients, char[] flagstring, char[] name, char[] message, bool& processcolors, bool& removecolors);
/**
* Called after the chat message is sent to the designated clients by the author.
*
* param author Author that sent the message.
* param recipients Array of clients who received the message.
* param flagstring Flag string to determine the type of message.
* param formatstring Format string used in the message based on the flag string.
* param name Name string of the author.
* param message Message string from the author.
* param processcolors Check if colors were processed in the buffer strings.
* param removecolors Check if colors were removed from the buffer strings.
*
* noreturn
**/
forward void CP_OnChatMessagePost(int author, ArrayList recipients, const char[] flagstring, const char[] formatstring, const char[] name, const char[] message, bool processcolors, bool removecolors);
#if !defined REQUIRE_PLUGIN
public void __pl_chat_processor_SetNTVOptional()
{
MarkNativeAsOptional("ChatProcessor_GetFlagFormatString");
}
#endif
public SharedPlugin __pl_chat_processor =
{
name = "chat-processor",
file = "chat-processor.smx",
#if defined REQUIRE_PLUGIN
required = 1
#else
required = 0
#endif
};

View File

@ -21,7 +21,6 @@
// Note: For donator perks, give donators a custom flag and then override it to have "shavit_chat".
#include <sourcemod>
#include <chat-processor>
#include <clientprefs>
#undef REQUIRE_PLUGIN
@ -32,6 +31,12 @@
#undef REQUIRE_EXTENSIONS
#include <cstrike>
#define MAXLENGTH_NAME 128
#define MAXLENGTH_TEXT 192
#define MAXLENGTH_MESSAGE 255
#define MAXLENGTH_CMESSAGE 16
#define MAXLENGTH_BUFFER 255
enum ChatRanksCache
{
iCRRangeType, // 0 - flat, 1 - percent, 2 - point range
@ -66,10 +71,12 @@ bool gB_RTLer = false;
// cvars
ConVar gCV_RankingsIntegration = null;
ConVar gCV_CustomChat = null;
ConVar gCV_Colon = null;
// cached cvars
bool gB_RankingsIntegration = true;
int gI_CustomChat = 1;
char gS_Colon[MAXLENGTH_CMESSAGE];
// cache
EngineVersion gEV_Type = Engine_Unknown;
@ -87,11 +94,18 @@ char gS_CustomName[MAXPLAYERS+1][128];
bool gB_MessageEnabled[MAXPLAYERS+1];
char gS_CustomMessage[MAXPLAYERS+1][16];
// chat procesor
bool gB_Protobuf = false;
StringMap gSM_Messages = null;
char gS_ControlCharacters[][] = { "\n", "\t", "\r",
"\x01", "\x02", "\x03", "\x04", "\x05", "\x06", "\x07", "\x08", "\x09",
"\x0A", "\x0B", "\x0C", "\x0D", "\x0E", "\x0F", "\x10" };
public Plugin myinfo =
{
name = "[shavit] Chat",
name = "[shavit] Chat Processor",
author = "shavit",
description = "Custom chat privileges (custom name/message colors), and rankings integration.",
description = "Custom chat privileges (custom name/message colors), chat processor, and rankings integration.",
version = SHAVIT_VERSION,
url = "https://github.com/shavitush/bhoptimer"
}
@ -125,12 +139,18 @@ public void OnPluginStart()
gCV_RankingsIntegration = CreateConVar("shavit_chat_rankings", "1", "Integrate with rankings?\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0);
gCV_CustomChat = CreateConVar("shavit_chat_customchat", "1", "Allow custom chat names or message colors?\n0 - Disabled\n1 - Enabled (requires chat flag/'shavit_chat' override)\n2 - Allow use by everyone", 0, true, 0.0, true, 2.0);
gCV_Colon = CreateConVar("shavit_chat_colon", ":", "String to use as the colon when messaging.");
gCV_RankingsIntegration.AddChangeHook(OnConVarChanged);
gCV_CustomChat.AddChangeHook(OnConVarChanged);
gCV_Colon.AddChangeHook(OnConVarChanged);
AutoExecConfig();
gSM_Messages = new StringMap();
gB_Protobuf = (GetUserMessageType() == UM_Protobuf);
HookUserMessage(GetUserMessageId("SayText2"), Hook_SayText2, true);
gH_ChatCookie = RegClientCookie("shavit_chat_selection", "Chat settings", CookieAccess_Protected);
gA_ChatRanks = new ArrayList(view_as<int>(CRCACHE_SIZE));
@ -154,6 +174,11 @@ public void OnMapStart()
{
SetFailState("Could not load the chat configuration file. Make sure it exists (addons/sourcemod/configs/shavit-chat.cfg) and follows the proper syntax!");
}
if(!LoadChatSettings())
{
SetFailState("Could not load the chat settings file. Make sure it exists (addons/sourcemod/configs/shavit-chatsettings.cfg) and follows the proper syntax!");
}
}
bool LoadChatConfig()
@ -226,10 +251,252 @@ bool LoadChatConfig()
return true;
}
bool LoadChatSettings()
{
char[] sPath = new char[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sPath, PLATFORM_MAX_PATH, "configs/shavit-chatsettings.cfg");
KeyValues kv = new KeyValues("shavit-chat");
if(!kv.ImportFromFile(sPath) || !kv.GotoFirstSubKey())
{
delete kv;
return false;
}
gSM_Messages.Clear();
if(gEV_Type == Engine_CSS)
{
kv.JumpToKey("CS:S");
}
else if(gEV_Type == Engine_CSGO)
{
kv.JumpToKey("CS:GO");
}
if(gEV_Type == Engine_TF2)
{
kv.JumpToKey("TF2");
}
kv.GotoFirstSubKey(false);
do
{
char[] sSection = new char[32];
kv.GetSectionName(sSection, 32);
char[] sText = new char[MAXLENGTH_BUFFER];
kv.GetString(NULL_STRING, sText, MAXLENGTH_BUFFER);
gSM_Messages.SetString(sSection, sText);
}
while(kv.GotoNextKey(false));
delete kv;
return true;
}
public Action Hook_SayText2(UserMsg msg_id, any msg, const int[] players, int playersNum, bool reliable, bool init)
{
int client = 0;
char[] sMessage = new char[32];
char[] sOriginalName = new char[MAXLENGTH_NAME];
char[] sOriginalText = new char[MAXLENGTH_TEXT];
if(gB_Protobuf)
{
Protobuf pbmsg = msg;
client = pbmsg.ReadInt("ent_idx");
pbmsg.ReadString("msg_name", sMessage, 32);
pbmsg.ReadString("params", sOriginalName, MAXLENGTH_NAME, 0);
pbmsg.ReadString("params", sOriginalText, MAXLENGTH_TEXT, 1);
delete pbmsg;
}
else
{
BfRead bfmsg = msg;
client = bfmsg.ReadByte();
bfmsg.ReadByte(); // chat parameter
bfmsg.ReadString(sMessage, 32);
bfmsg.ReadString(sOriginalName, MAXLENGTH_NAME);
bfmsg.ReadString(sOriginalText, MAXLENGTH_TEXT);
delete bfmsg;
}
char[] sTextFormatting = new char[MAXLENGTH_BUFFER];
// not a hooked message
if(!gSM_Messages.GetString(sMessage, sTextFormatting, MAXLENGTH_BUFFER))
{
return Plugin_Continue;
}
Format(sTextFormatting, MAXLENGTH_BUFFER, "\x01%s", sTextFormatting);
// remove control characters
for(int i = 0; i < sizeof(gS_ControlCharacters); i++)
{
ReplaceString(sOriginalName, MAXLENGTH_NAME, gS_ControlCharacters[i], "");
ReplaceString(sOriginalText, MAXLENGTH_TEXT, gS_ControlCharacters[i], "");
}
char[] sName = new char[MAXLENGTH_NAME];
char[] sCMessage = new char[MAXLENGTH_CMESSAGE];
if((gI_CustomChat > 0 && (CheckCommandAccess(client, "shavit_chat", ADMFLAG_CHAT) || gI_CustomChat == 2)) && gI_ChatSelection[client] == -1)
{
if(gB_NameEnabled[client])
{
strcopy(sName, MAXLENGTH_NAME, gS_CustomName[client]);
}
if(gB_MessageEnabled[client])
{
strcopy(sCMessage, MAXLENGTH_CMESSAGE, gS_CustomMessage[client]);
}
}
else
{
GetPlayerChatSettings(client, sName, sCMessage);
}
if(strlen(sName) > 0)
{
FormatChat(client, sName, MAXLENGTH_NAME);
if(gEV_Type == Engine_CSGO)
{
FormatEx(sOriginalName, MAXLENGTH_NAME, " %s", sName);
}
else
{
strcopy(sOriginalName, MAXLENGTH_NAME, sName);
}
}
if(strlen(sMessage) > 0)
{
FormatChat(client, sCMessage, MAXLENGTH_CMESSAGE);
char[] sTemp = new char[MAXLENGTH_CMESSAGE];
// support RTL messages
if(gB_RTLer && RTLify(sTemp, MAXLENGTH_CMESSAGE, sOriginalText) > 0)
{
TrimString(sOriginalText);
Format(sOriginalText, MAXLENGTH_MESSAGE, "%s%s", sOriginalText, sCMessage);
}
else
{
Format(sOriginalText, MAXLENGTH_MESSAGE, "%s%s", sCMessage, sOriginalText);
}
}
ReplaceString(sTextFormatting, MAXLENGTH_BUFFER, "{name}", sOriginalName);
ReplaceString(sTextFormatting, MAXLENGTH_BUFFER, "{def}", "\x01");
ReplaceString(sTextFormatting, MAXLENGTH_BUFFER, "{colon}", gS_Colon);
ReplaceString(sTextFormatting, MAXLENGTH_BUFFER, "{msg}", sOriginalText);
DataPack pack = new DataPack();
pack.WriteCell(GetClientSerial(client)); // client serial
pack.WriteCell(StrContains(sMessage, "_All") != -1); // all chat
pack.WriteString(sTextFormatting); // text
RequestFrame(Frame_SendText, pack);
return Plugin_Stop;
}
void Frame_SendText(DataPack pack)
{
pack.Reset();
int serial = pack.ReadCell();
bool allchat = pack.ReadCell();
char[] sText = new char[MAXLENGTH_BUFFER];
pack.ReadString(sText, MAXLENGTH_BUFFER);
delete pack;
int client = GetClientFromSerial(serial);
if(client == 0)
{
return;
}
int team = GetClientTeam(client);
int[] clients = new int[MaxClients];
int count = 0;
for(int i = 1; i <= MaxClients; i++)
{
if(!IsClientConnected(i))
{
continue;
}
if(IsClientSourceTV(i) || IsClientReplay(i) || // sourcetv?
(IsClientInGame(i) && (allchat || GetClientTeam(i) == team)))
{
clients[count++] = i;
}
}
// should never happen
if(count == 0)
{
return;
}
Handle hSayText2 = StartMessage("SayText2", clients, count, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS);
if(hSayText2 == null)
{
return;
}
if(gB_Protobuf)
{
Protobuf pbmsg = view_as<any>(hSayText2);
pbmsg.SetInt("ent_idx", client);
pbmsg.SetBool("chat", true);
pbmsg.SetString("msg_name", sText);
for(int i = 1; i <= 4; i++)
{
pbmsg.AddString("params", "");
}
delete pbmsg;
}
else
{
BfWrite bfmsg = view_as<any>(hSayText2);
bfmsg.WriteByte(client);
bfmsg.WriteByte(true);
bfmsg.WriteString(sText);
delete bfmsg;
}
EndMessage();
return;
}
public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
{
gB_RankingsIntegration = gCV_RankingsIntegration.BoolValue;
gI_CustomChat = gCV_CustomChat.IntValue;
gCV_Colon.GetString(gS_Colon, MAXLENGTH_CMESSAGE);
}
public void Shavit_OnDatabaseLoaded()
@ -396,6 +663,7 @@ public Action Command_CCName(int client, int args)
char[] sArgs = new char[128];
GetCmdArgString(sArgs, 128);
TrimString(sArgs);
if(args == 0 || strlen(sArgs) == 0)
{
@ -444,6 +712,7 @@ public Action Command_CCMessage(int client, int args)
char[] sArgs = new char[32];
GetCmdArgString(sArgs, 32);
TrimString(sArgs);
if(args == 0 || strlen(sArgs) == 0)
{
@ -675,78 +944,6 @@ public Action Command_ReloadChatRanks(int client, int args)
return Plugin_Handled;
}
public Action CP_OnChatMessage(int &author, ArrayList recipients, char[] flagstring, char[] name, char[] message, bool &processcolors, bool &removecolors)
{
if(author == 0)
{
return Plugin_Continue;
}
char[] sName = new char[MAXLENGTH_NAME];
char[] sMessage = new char[MAXLENGTH_MESSAGE];
if((gI_CustomChat > 0 && (CheckCommandAccess(author, "shavit_chat", ADMFLAG_CHAT) || gI_CustomChat == 2)) && gI_ChatSelection[author] == -1)
{
if(gB_NameEnabled[author])
{
strcopy(sName, MAXLENGTH_NAME, gS_CustomName[author]);
}
if(gB_MessageEnabled[author])
{
strcopy(sMessage, MAXLENGTH_MESSAGE, gS_CustomMessage[author]);
}
}
else
{
GetPlayerChatSettings(author, sName, sMessage);
}
if(strlen(sName) > 0)
{
FormatChat(author, sName, MAXLENGTH_NAME);
if(gEV_Type == Engine_CSGO)
{
FormatEx(name, MAXLENGTH_NAME, " %s", sName);
}
else
{
strcopy(name, MAXLENGTH_NAME, sName);
}
}
if(strlen(sMessage) > 0)
{
FormatChat(author, sMessage, MAXLENGTH_MESSAGE);
char[] sTemp = new char[MAXLENGTH_MESSAGE];
// proper colors with rtler
if(gB_RTLer && RTLify(sTemp, MAXLENGTH_MESSAGE, message) > 0)
{
TrimString(message);
Format(message, MAXLENGTH_MESSAGE, "%s%s", message, sMessage);
}
else
{
Format(message, MAXLENGTH_MESSAGE, "%s%s", sMessage, message);
}
}
#if defined DEBUG
PrintToServer("%N %s", author, flagstring);
#endif
removecolors = true;
processcolors = false;
return Plugin_Changed;
}
void FormatColors(char[] buffer, int size, bool colors, bool escape)
{
if(colors)

View File

@ -1766,7 +1766,7 @@ public Action Hook_SayText2(UserMsg msg_id, any msg, const int[] players, int pl
BfRead bfmsg = msg;
bfmsg.ReadByte();
bfmsg.ReadByte();
bfmsg.ReadString(sMessage, 24, false);
bfmsg.ReadString(sMessage, 24);
delete bfmsg;
}