| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 | 
							- /**
 
-  * [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.
 
-  * 
 
-  * If their existing name has no printable characters, their name will be changed to
 
-  * "unprintable" plus their userid and their name will be locked.
 
-  */
 
- #pragma semicolon 1
 
- #include <sourcemod>
 
- #include <sdktools_functions>
 
- #pragma newdecls required
 
- #define PLUGIN_VERSION "1.0.4"
 
- 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)"
 
- int g_FilteredMultiByteWhitespace[] = {
 
- 	0xe2a080, // braille pattern blank U+2800
 
- 	0
 
- };
 
- public void OnPluginStart() {
 
- 	for (int i = 1; i <= MaxClients; i++) {
 
- 		if (IsClientConnected(i)) {
 
- 			OnNameUpdated(i);
 
- 		}
 
- 	}
 
- }
 
- 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 non-printing characters that can't be handled elsewhere.
 
- 		switch (nCharBytes) {
 
- 			case 3: {
 
- 				// filter unicode invisible characters
 
- 				bCharFiltered |= IsUnicodeCharInvisible(fullChar);
 
- 			}
 
- 			case 1: {
 
- 				// filter out newlines
 
- 				bCharFiltered |= (fullChar == 0x0d || fullChar == 0x0a);
 
- 			}
 
- 			default: {
 
- 				// unhandled
 
- 			}
 
- 		}
 
- 		
 
- 		if (!bCharFiltered) {
 
- 			// it's a character we're not filtering
 
- 			StrCatMultiByteChar(newNameBuffer, sizeof(newNameBuffer), fullChar, nCharBytes);
 
- 		}
 
- 		
 
- 		bNameChanged |= bCharFiltered;
 
- 		
 
- 		i += nCharBytes;
 
- 	}
 
- 	
 
- 	if (bNameChanged) {
 
- 		// Remove surrounding whitespace
 
- 		TrimString(newNameBuffer);
 
- 		
 
- 		// TODO remove duplicate whitespace
 
- 		
 
- 		// 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)
 
- }
 
- bool IsUnicodeCharInvisible(int uchar) {
 
- 	// handle invisible math operators, &c. (U+205F ... U+206F)
 
- 	// could do (char & 0xe281a0) plus check for U+205F, I think?
 
- 	if (uchar >= 0xe2819f && uchar <= 0xe281af) {
 
- 		return true;
 
- 	}
 
- 	
 
- 	// handle other blacklisted characters
 
- 	int c;
 
- 	do {
 
- 		if (uchar == g_FilteredMultiByteWhitespace[c]) {
 
- 			return true;
 
- 		}
 
- 	} while (g_FilteredMultiByteWhitespace[++c] != 0);
 
- 	
 
- 	return false;
 
- }
 
- /**
 
-  * Attempts to lock the specified client's name with the existing `namelockid` command.
 
-  */
 
- stock bool SetClientNameLock(int client, bool locked = true) {
 
- 	if (CommandExists("namelockid")) {
 
- 		ServerCommand("namelockid %d %d", GetClientUserId(client), locked ? 0 : 1);
 
- 		return true;
 
- 	}
 
- 	return false;
 
- }
 
- /**
 
-  * 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;
 
- 	}
 
- }
 
 
  |