|
@@ -0,0 +1,159 @@
|
|
|
+/**
|
|
|
+ * [CSRD] Name Filter
|
|
|
+ *
|
|
|
+ * An in-house plugin that tidies up names.
|
|
|
+ * Made in response to a few script kiddies that are (ab)using newlines and other non-printing
|
|
|
+ * characters in their name.
|
|
|
+ *
|
|
|
+ */
|
|
|
+#pragma semicolon 1
|
|
|
+#include <sourcemod>
|
|
|
+
|
|
|
+#include <sdktools_functions>
|
|
|
+
|
|
|
+#pragma newdecls required
|
|
|
+
|
|
|
+#define PLUGIN_VERSION "1.0.0"
|
|
|
+public Plugin myinfo = {
|
|
|
+ name = "[CSRD] Name Filter",
|
|
|
+ author = "nosoop",
|
|
|
+ description = "Filters out rather unscrupulous characters from names and locks the name if "
|
|
|
+ ... "they are using a completely non-printable name.",
|
|
|
+ version = PLUGIN_VERSION,
|
|
|
+ url = "https://pika.nom-nom-nom.us/git/"
|
|
|
+}
|
|
|
+
|
|
|
+#define UNPRINTABLE_NAME_USER_FORMAT "unprintable (%d)"
|
|
|
+
|
|
|
+bool g_bNameLockSupported;
|
|
|
+
|
|
|
+int g_FilteredWhitespace[] = {
|
|
|
+ 0xe2a080, // braille pattern blank U+2800
|
|
|
+ 0x0a, // linefeed
|
|
|
+ 0x0d, // carriage return
|
|
|
+ 0
|
|
|
+};
|
|
|
+
|
|
|
+public void OnPluginStart() {
|
|
|
+ for (int i = 1; i <= MaxClients; i++) {
|
|
|
+ if (IsClientConnected(i)) {
|
|
|
+ OnNameUpdated(i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ g_bNameLockSupported = CommandExists("namelockid");
|
|
|
+}
|
|
|
+
|
|
|
+public void OnClientConnected(int client) {
|
|
|
+ OnNameUpdated(client);
|
|
|
+}
|
|
|
+
|
|
|
+public void OnClientSettingsChanged(int client) {
|
|
|
+ OnNameUpdated(client);
|
|
|
+}
|
|
|
+
|
|
|
+void OnNameUpdated(int client) {
|
|
|
+ char currentName[MAX_NAME_LENGTH], newNameBuffer[MAX_NAME_LENGTH];
|
|
|
+
|
|
|
+ GetClientName(client, currentName, sizeof(currentName));
|
|
|
+
|
|
|
+ bool bNameChanged;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Copies valid characters into another buffer (while also dealing with Unicode).
|
|
|
+ * The buffer is used if any characters are filtered.
|
|
|
+ */
|
|
|
+ for (int i = 0; i < strlen(currentName); /* ... */) {
|
|
|
+ int fullChar, nCharBytes;
|
|
|
+ fullChar = GetMultiByteCharacterAt(currentName, i, nCharBytes);
|
|
|
+
|
|
|
+ bool bCharFiltered;
|
|
|
+
|
|
|
+ // Filter out whitespace
|
|
|
+ int c;
|
|
|
+ do {
|
|
|
+ bCharFiltered |= (fullChar == g_FilteredWhitespace[c]);
|
|
|
+ } while (g_FilteredWhitespace[++c] != 0 && !bCharFiltered);
|
|
|
+
|
|
|
+ if (!bCharFiltered) {
|
|
|
+ // it's a character that we don't really care about
|
|
|
+ StrCatMultiByteChar(newNameBuffer, sizeof(newNameBuffer), fullChar, nCharBytes);
|
|
|
+ } else {
|
|
|
+ StrCat(newNameBuffer, sizeof(newNameBuffer), " ");
|
|
|
+ }
|
|
|
+
|
|
|
+ bNameChanged |= bCharFiltered;
|
|
|
+
|
|
|
+ i += nCharBytes;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (bNameChanged) {
|
|
|
+ // Remove surrounding whitespace
|
|
|
+ TrimString(newNameBuffer);
|
|
|
+
|
|
|
+ // If there's no printable characters in the buffer, the player is a total dongbus.
|
|
|
+ if (strlen(newNameBuffer) == 0) {
|
|
|
+ Format(newNameBuffer, sizeof(newNameBuffer), UNPRINTABLE_NAME_USER_FORMAT,
|
|
|
+ GetClientUserId(client));
|
|
|
+
|
|
|
+ SetClientNameLock(client);
|
|
|
+ }
|
|
|
+ SetClientName(client, newNameBuffer);
|
|
|
+ }
|
|
|
+ // TODO else not name changed, but check if we can do other non-filter stuff? (trim)
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Attempts to lock the specified client's name.
|
|
|
+ */
|
|
|
+stock void SetClientNameLock(int client, bool locked = true) {
|
|
|
+ if (g_bNameLockSupported) {
|
|
|
+ ServerCommand("namelockid %d %d", GetClientUserId(client), locked ? 0 : 1);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Gets a possibly multi-byte character at the specified position in a string as an integer.
|
|
|
+ *
|
|
|
+ * If the character is an ASCII character, the integer representation of the character will be
|
|
|
+ * returned, and the number of characters read will be 1.
|
|
|
+ *
|
|
|
+ * This stock is made specifically for the purpose of handling strings with multi-byte
|
|
|
+ * characters.
|
|
|
+ */
|
|
|
+stock int GetMultiByteCharacterAt(const char[] text, int pos, int &read = 0) {
|
|
|
+ int nCharBytes, charOutput;
|
|
|
+
|
|
|
+ nCharBytes = GetCharBytes(text[pos]);
|
|
|
+
|
|
|
+ for (int b = 0; b < nCharBytes; b++) {
|
|
|
+ charOutput = charOutput << 8;
|
|
|
+
|
|
|
+ // read in the current byte
|
|
|
+ charOutput |= text[pos + b] & 0xFF;
|
|
|
+
|
|
|
+ read++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return charOutput;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Appends a multi-byte character to a string.
|
|
|
+ */
|
|
|
+stock void StrCatMultiByteChar(char[] buffer, int maxlen, int character, int size) {
|
|
|
+ char[] appended = new char[size];
|
|
|
+
|
|
|
+ MultiByteCharacterToCharArray(appended, size, character);
|
|
|
+
|
|
|
+ StrCat(buffer, maxlen, appended);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Converts a multi-byte character to a char array.
|
|
|
+ */
|
|
|
+stock void MultiByteCharacterToCharArray(char[] buffer, int charsize, int character) {
|
|
|
+ for (int i = 0; i < charsize; i++) {
|
|
|
+ buffer[i] = (character >> ((charsize - i - 1) * 8 )) & 0xFF;
|
|
|
+ }
|
|
|
+}
|