From 461b6c7309a12eb26e9f7145f0a2c0f233316c24 Mon Sep 17 00:00:00 2001 From: ratawar Date: Mon, 15 Jun 2020 10:37:12 -0300 Subject: [PATCH] v2.3 --- plugins/profilestatus.smx | Bin 21498 -> 28290 bytes scripting/include/autoexecconfig.inc | 715 +++++++++++++++++++++++++ scripting/include/profilestatus.inc | 7 +- scripting/profilestatus.sp | 310 ++++++----- translations/profilestatus.phrases.txt | 51 +- 5 files changed, 930 insertions(+), 153 deletions(-) create mode 100644 scripting/include/autoexecconfig.inc diff --git a/plugins/profilestatus.smx b/plugins/profilestatus.smx index ae32bcedac07228c20bf896ee4ada91b7de80b7d..14bcc9b10b82571d8a586613e89db56a9c9861eb 100644 GIT binary patch literal 28290 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 diff --git a/scripting/include/autoexecconfig.inc b/scripting/include/autoexecconfig.inc new file mode 100644 index 0000000..73e07d9 --- /dev/null +++ b/scripting/include/autoexecconfig.inc @@ -0,0 +1,715 @@ +#if defined _autoexecconfig_included + #endinput +#endif +#define _autoexecconfig_included + + +#include + + +// Append +#define AUTOEXEC_APPEND_BAD_FILENAME 0 +#define AUTOEXEC_APPEND_FILE_NOT_FOUND 1 +#define AUTOEXEC_APPEND_BAD_HANDLE 2 +#define AUTOEXEC_APPEND_SUCCESS 3 + + + +// Find +#define AUTOEXEC_FIND_BAD_FILENAME 10 +#define AUTOEXEC_FIND_FILE_NOT_FOUND 11 +#define AUTOEXEC_FIND_BAD_HANDLE 12 +#define AUTOEXEC_FIND_NOT_FOUND 13 +#define AUTOEXEC_FIND_SUCCESS 14 + + + +// Clean +#define AUTOEXEC_CLEAN_FILE_NOT_FOUND 20 +#define AUTOEXEC_CLEAN_BAD_HANDLE 21 +#define AUTOEXEC_CLEAN_SUCCESS 22 + + + +// General +#define AUTOEXEC_NO_CONFIG 30 + + + +// Formatter +#define AUTOEXEC_FORMAT_BAD_FILENAME 40 +#define AUTOEXEC_FORMAT_SUCCESS 41 + + + +// Global variables +static char g_sConfigFile[PLATFORM_MAX_PATH]; +static char g_sRawFileName[PLATFORM_MAX_PATH]; +static char g_sFolderPath[PLATFORM_MAX_PATH]; + +static bool g_bCreateFile = false; +static Handle g_hPluginHandle = null; + + + +// Workaround for now +static int g_iLastFindResult; +static int g_iLastAppendResult; + + + + +/** + * Returns the last result from the parser. + * + * @return Returns one of the AUTOEXEC_FIND values or -1 if not set. +*/ +stock int AutoExecConfig_GetFindResult() +{ + return g_iLastFindResult; +} + + + + + +/** + * Returns the last result from the appender. + * + * @return Returns one of the AUTOEXEC_APPEND values or -1 if not set. +*/ +stock int AutoExecConfig_GetAppendResult() +{ + return g_iLastAppendResult; +} + + +/** + * Set if the config file should be created if it doesn't exist yet. + * + * @param create True if config file should be created, false otherwise. + * @noreturn + */ +stock void AutoExecConfig_SetCreateFile(bool create) +{ + g_bCreateFile = create; +} + + +/** + * Returns if the config file should be created if it doesn't exist. + * + * @return Returns true, if the config file should be created or false if it should not. + */ +stock bool AutoExecConfig_GetCreateFile() +{ + return g_bCreateFile; +} + + +/** + * Set the plugin for which the config file should be created. + * Set to null to use the calling plugin. + * Used to print the correct filename in the top comment when creating the file. + * + * @param plugin The plugin to create convars for or null to use the calling plugin. + * @noreturn + */ +stock void AutoExecConfig_SetPlugin(Handle plugin) +{ + g_hPluginHandle = plugin; +} + + +/** + * Returns the plugin for which the config file is created. + * + * @return The plugin handle + */ +stock Handle AutoExecConfig_GetPlugin() +{ + return g_hPluginHandle; +} + + +/** + * Set the global autoconfigfile used by functions of this file. + * + * @param file Name of the config file, path and .cfg extension is being added if not given. + * @param folder Folder under cfg/ to use. By default this is "sourcemod." + * @return True if formatter returned success, false otherwise. +*/ +stock bool AutoExecConfig_SetFile(char[] file, char[] folder="sourcemod") +{ + Format(g_sConfigFile, sizeof(g_sConfigFile), "%s", file); + + // Global buffers for cfg execution + strcopy(g_sRawFileName, sizeof(g_sRawFileName), file); + strcopy(g_sFolderPath, sizeof(g_sFolderPath), folder); + + + // Format the filename + return AutoExecConfig_FormatFileName(g_sConfigFile, sizeof(g_sConfigFile), folder) == AUTOEXEC_FORMAT_SUCCESS; +} + + + + + + +/** + * Get the formatted autoconfigfile used by functions of this file. + * + * @param buffer String to format. + * @param size Maximum size of buffer + * @return True if filename was set, false otherwise. +*/ +stock bool AutoExecConfig_GetFile(char[] buffer,int size) +{ + if(strlen(g_sConfigFile) > 0) + { + strcopy(buffer, size, g_sConfigFile); + + return true; + } + + // Security for decl users + buffer[0] = '\0'; + + return false; +} + + + + + + +/** + * Creates a convar and appends it to the autoconfigfile if not found. + * FCVAR_DONTRECORD will be skipped. + * + * @param name Name of new convar. + * @param defaultValue String containing the default value of new convar. + * @param description Optional description of the convar. + * @param flags Optional bitstring of flags determining how the convar should be handled. See FCVAR_* constants for more details. + * @param hasMin Optional boolean that determines if the convar has a minimum value. + * @param min Minimum floating point value that the convar can have if hasMin is true. + * @param hasMax Optional boolean that determines if the convar has a maximum value. + * @param max Maximum floating point value that the convar can have if hasMax is true. + * @return A handle to the newly created convar. If the convar already exists, a handle to it will still be returned. + * @error Convar name is blank or is the same as an existing console command. +*/ +stock ConVar AutoExecConfig_CreateConVar(const char[] name, const char[] defaultValue, const char[] description="", int flags=0, bool hasMin=false, float min=0.0, bool hasMax=false, float max=0.0) +{ + // If configfile was set and convar has no dontrecord flag + if(!(flags & FCVAR_DONTRECORD) && strlen(g_sConfigFile) > 0) + { + // Reset the results + g_iLastFindResult = -1; + g_iLastAppendResult = -1; + + + // Add it if not found + char buffer[64]; + + g_iLastFindResult = AutoExecConfig_FindValue(name, buffer, sizeof(buffer), true); + + // We only add this convar if it doesn't exist, or the file doesn't exist and it should be auto-generated + if(g_iLastFindResult == AUTOEXEC_FIND_NOT_FOUND || (g_iLastFindResult == AUTOEXEC_FIND_FILE_NOT_FOUND && g_bCreateFile)) + { + g_iLastAppendResult = AutoExecConfig_AppendValue(name, defaultValue, description, flags, hasMin, min, hasMax, max); + } + } + + + // Create the convar + return CreateConVar(name, defaultValue, description, flags, hasMin, min, hasMax, max); +} + + + + +/** + * Executes the autoconfigfile, and adds it to the OnConfigsExecuted forward. + * If we didn't created it already we let SourceMod create it. + * + * @noreturn +*/ +stock void AutoExecConfig_ExecuteFile() +{ + // Only let sourcemod create the file, if we didn't do that already. + AutoExecConfig(!g_bCreateFile, g_sRawFileName, g_sFolderPath); +} + + + + + +/** + * Formats a autoconfigfile, prefixes path and adds .cfg extension if missed. + * + * @param buffer String to format. + * @param size Maximum size of buffer. + * @return Returns one of the AUTOEXEC_FORMAT values.. +*/ +stock static int AutoExecConfig_FormatFileName(char[] buffer, int size, char[] folder="sourcemod") +{ + // No config set + if(strlen(g_sConfigFile) < 1) + { + return AUTOEXEC_NO_CONFIG; + } + + + // Can't be an cfgfile + if(StrContains(g_sConfigFile, ".cfg") == -1 && strlen(g_sConfigFile) < 4) + { + return AUTOEXEC_FORMAT_BAD_FILENAME; + } + + + // Pathprefix + char pathprefixbuffer[PLATFORM_MAX_PATH]; + if(strlen(folder) > 0) + { + Format(pathprefixbuffer, sizeof(pathprefixbuffer), "cfg/%s/", folder); + } + else + { + Format(pathprefixbuffer, sizeof(pathprefixbuffer), "cfg/"); + } + + + char filebuffer[PLATFORM_MAX_PATH]; + filebuffer[0] = '\0'; + + // Add path if file doesn't begin with it + if(StrContains(buffer, pathprefixbuffer) != 0) + { + StrCat(filebuffer, sizeof(filebuffer), pathprefixbuffer); + } + + StrCat(filebuffer, sizeof(filebuffer), g_sConfigFile); + + + // Add .cfg extension if file doesn't end with it + if(StrContains(filebuffer[strlen(filebuffer) - 4], ".cfg") != 0) + { + StrCat(filebuffer, sizeof(filebuffer), ".cfg"); + } + + strcopy(buffer, size, filebuffer); + + return AUTOEXEC_FORMAT_SUCCESS; +} + + + + + + +/** + * Appends a convar to the global autoconfigfile + * + * @param name Name of new convar. + * @param defaultValue String containing the default value of new convar. + * @param description Optional description of the convar. + * @param flags Optional bitstring of flags determining how the convar should be handled. See FCVAR_* constants for more details. + * @param hasMin Optional boolean that determines if the convar has a minimum value. + * @param min Minimum floating point value that the convar can have if hasMin is true. + * @param hasMax Optional boolean that determines if the convar has a maximum value. + * @param max Maximum floating point value that the convar can have if hasMax is true. + * @return Returns one of the AUTOEXEC_APPEND values +*/ +stock int AutoExecConfig_AppendValue(const char[] name, const char[] defaultValue, const char[] description, int flags, bool hasMin, float min, bool hasMax, float max) +{ + // No config set + if(strlen(g_sConfigFile) < 1) + { + return AUTOEXEC_NO_CONFIG; + } + + + char filebuffer[PLATFORM_MAX_PATH]; + strcopy(filebuffer, sizeof(filebuffer), g_sConfigFile); + + + //PrintToServer("pathbuffer: %s", filebuffer); + + bool bFileExists = FileExists(filebuffer); + + if(g_bCreateFile || bFileExists) + { + // If the file already exists we open it in append mode, otherwise we use a write mode which creates the file + File fFile = OpenFile(filebuffer, (bFileExists ? "a" : "w")); + char writebuffer[2048]; + + + if(fFile == null) + { + return AUTOEXEC_APPEND_BAD_HANDLE; + } + + // We just created the file, so add some header about version and stuff + if(g_bCreateFile && !bFileExists) + { + fFile.WriteLine( "// This file was auto-generated by AutoExecConfig read and append beta"); + + GetPluginFilename(g_hPluginHandle, writebuffer, sizeof(writebuffer)); + Format(writebuffer, sizeof(writebuffer), "// ConVars for plugin \"%s\"", writebuffer); + fFile.WriteLine(writebuffer); + } + + // Spacer + fFile.WriteLine("\n"); + + + // This is used for multiline comments + int newlines = GetCharCountInStr('\n', description); + if(newlines == 0) + { + // We have no newlines, we can write the description to the file as is + Format(writebuffer, sizeof(writebuffer), "// %s", description); + fFile.WriteLine(writebuffer); + } + else + { + char[][] newlineBuf = new char[newlines +1][2048]; + ExplodeString(description, "\n", newlineBuf, newlines +1, 2048, false); + + // Each newline gets a commented newline + for(int i; i <= newlines; i++) + { + if(strlen(newlineBuf[i]) > 0) + { + fFile.WriteLine("// %s", newlineBuf[i]); + } + } + } + + + // Descspacer + fFile.WriteLine("// -"); + + + // Default + Format(writebuffer, sizeof(writebuffer), "// Default: \"%s\"", defaultValue); + fFile.WriteLine(writebuffer); + + + // Minimum + if(hasMin) + { + Format(writebuffer, sizeof(writebuffer), "// Minimum: \"%f\"", min); + fFile.WriteLine(writebuffer); + } + + + // Maximum + if(hasMax) + { + Format(writebuffer, sizeof(writebuffer), "// Maximum: \"%f\"", max); + fFile.WriteLine(writebuffer); + } + + + // Write end and defaultvalue + Format(writebuffer, sizeof(writebuffer), "%s \"%s\"", name, defaultValue); + fFile.WriteLine(writebuffer); + + + fFile.Close(); + + + // Clean up the file + //AutoExecConfig_CleanFile(filebuffer, false); + + + return AUTOEXEC_APPEND_SUCCESS; + } + + return AUTOEXEC_APPEND_FILE_NOT_FOUND; +} + + + + + + +/** + * Returns a convars value from the global autoconfigfile + * + * @param cvar Cvar to search for. + * @param value Buffer to store result into. + * @param size Maximum size of buffer. + * @param caseSensitive Whether or not the search should be case sensitive. + * @return Returns one of the AUTOEXEC_FIND values +*/ +stock int AutoExecConfig_FindValue(const char[] cvar, char[] value, int size, bool caseSensitive=false) +{ + // Security for decl users + value[0] = '\0'; + + + // No config set + if(strlen(g_sConfigFile) < 1) + { + return AUTOEXEC_NO_CONFIG; + } + + + char filebuffer[PLATFORM_MAX_PATH]; + strcopy(filebuffer, sizeof(filebuffer), g_sConfigFile); + + + + //PrintToServer("pathbuffer: %s", filebuffer); + + bool bFileExists = FileExists(filebuffer); + + // We want to create the config file and it doesn't exist yet. + if(g_bCreateFile && !bFileExists) + { + return AUTOEXEC_FIND_FILE_NOT_FOUND; + } + + + if(bFileExists) + { + File fFile = OpenFile(filebuffer, "r"); + int valuestart; + int valueend; + int cvarend; + + // Just an reminder to self, leave the values that high + char sConvar[64]; + char sValue[64]; + char readbuffer[2048]; + char copybuffer[2048]; + + if(fFile == null) + { + return AUTOEXEC_FIND_BAD_HANDLE; + } + + + while(!fFile.EndOfFile() && fFile.ReadLine(readbuffer, sizeof(readbuffer))) + { + // Is a comment or not valid + if(IsCharSpace(readbuffer[0]) || readbuffer[0] == '/' || !IsCharAlpha(readbuffer[0])) + { + continue; + } + + + // Has not enough spaces, must have at least 1 + if(GetCharCountInStr(' ', readbuffer) < 1) + { + continue; + } + + + // Ignore cvars which aren't quoted + if(GetCharCountInStr('"', readbuffer) != 2) + { + continue; + } + + + + // Get the start of the value + if( (valuestart = StrContains(readbuffer, "\"")) == -1 ) + { + continue; + } + + + // Get the end of the value + if( (valueend = StrContains(readbuffer[valuestart+1], "\"")) == -1 ) + { + continue; + } + + + // Get the start of the cvar, + if( (cvarend = StrContains(readbuffer, " ")) == -1 || cvarend >= valuestart) + { + continue; + } + + + // Skip if cvarendindex is before valuestartindex + if(cvarend >= valuestart) + { + continue; + } + + + // Convar + // Tempcopy for security + strcopy(copybuffer, sizeof(copybuffer), readbuffer); + copybuffer[cvarend] = '\0'; + + strcopy(sConvar, sizeof(sConvar), copybuffer); + + + // Value + // Tempcopy for security + strcopy(copybuffer, sizeof(copybuffer), readbuffer[valuestart+1]); + copybuffer[valueend] = '\0'; + + strcopy(sValue, sizeof(sValue), copybuffer); + + + //PrintToServer("Cvar %s has a value of %s", sConvar, sValue); + + if(StrEqual(sConvar, cvar, caseSensitive)) + { + Format(value, size, "%s", sConvar); + + fFile.Close(); + return AUTOEXEC_FIND_SUCCESS; + } + } + + fFile.Close(); + return AUTOEXEC_FIND_NOT_FOUND; + } + + + return AUTOEXEC_FIND_FILE_NOT_FOUND; +} + + + + + + +/** + * Cleans the global autoconfigfile from too much spaces + * + * @return One of the AUTOEXEC_CLEAN values. +*/ +stock int AutoExecConfig_CleanFile() +{ + // No config set + if(strlen(g_sConfigFile) < 1) + { + return AUTOEXEC_NO_CONFIG; + } + + + char sfile[PLATFORM_MAX_PATH]; + strcopy(sfile, sizeof(sfile), g_sConfigFile); + + + // Security + if(!FileExists(sfile)) + { + return AUTOEXEC_CLEAN_FILE_NOT_FOUND; + } + + + + char sfile2[PLATFORM_MAX_PATH]; + Format(sfile2, sizeof(sfile2), "%s_tempcopy", sfile); + + + char readbuffer[2048]; + int count; + bool firstreached; + + + // Open files + File fFile1 = OpenFile(sfile, "r"); + File fFile2 = OpenFile(sfile2, "w"); + + + + // Check filehandles + if(fFile1 == null || fFile2 == null) + { + if(fFile1 != null) + { + //PrintToServer("Handle1 invalid"); + fFile1.Close(); + } + + if(fFile2 != null) + { + //PrintToServer("Handle2 invalid"); + fFile2.Close(); + } + + return AUTOEXEC_CLEAN_BAD_HANDLE; + } + + + + while(!fFile1.EndOfFile() && fFile1.ReadLine(readbuffer, sizeof(readbuffer))) + { + // Is space + if(IsCharSpace(readbuffer[0])) + { + count++; + } + // No space, count from start + else + { + count = 0; + } + + + // Don't write more than 1 space if seperation after informations have been reached + if(count < 2 || !firstreached) + { + ReplaceString(readbuffer, sizeof(readbuffer), "\n", ""); + fFile2.WriteLine(readbuffer); + } + + + // First bigger seperation after informations has been reached + if(count == 2) + { + firstreached = true; + } + } + + + fFile1.Close(); + fFile2.Close(); + + + // This might be a risk, for now it works + DeleteFile(sfile); + RenameFile(sfile, sfile2); + + return AUTOEXEC_CLEAN_SUCCESS; +} + + + + + + +/** + * Returns how many times the given char occures in the given string. + * + * @param str String to search for in. + * @return Occurences of the given char found in string. +*/ +stock static int GetCharCountInStr(int character, const char[] str) +{ + int len = strlen(str); + int count; + + for(int i; i < len; i++) + { + if(str[i] == character) + { + count++; + } + } + + return count; +} diff --git a/scripting/include/profilestatus.inc b/scripting/include/profilestatus.inc index e5f47b8..198a0e3 100644 --- a/scripting/include/profilestatus.inc +++ b/scripting/include/profilestatus.inc @@ -1,10 +1,10 @@ /* ** */ -#if defined _INCLUDE_included +#if defined _profilestatus_included #endinput #endif -#define _INCLUDE_included +#define _profilestatus_included /** * Gets player's hours from the API response body. @@ -111,8 +111,6 @@ stock int GetGameBans(char[] responseBodyBans) { return -1; } -<<<<<<< Updated upstream -======= /** * Gets players' Steam level from the API response body. * @@ -161,7 +159,6 @@ stock int GetCommVisibState(const char[] responseBodyPrivate) { return -1; } ->>>>>>> Stashed changes /** * Returns true if player is VAC Banned, false otherwise. * diff --git a/scripting/profilestatus.sp b/scripting/profilestatus.sp index 815c70b..11d8f2d 100644 --- a/scripting/profilestatus.sp +++ b/scripting/profilestatus.sp @@ -3,24 +3,22 @@ #include #include #include +#include #pragma semicolon 1 #pragma newdecls required -<<<<<<< Updated upstream -#define PLUGIN_VERSION "2.2" -======= #define PLUGIN_VERSION "2.3" ->>>>>>> Stashed changes #define CHOICE1 "hoursTable" #define CHOICE2 "bansTable" +#define CHOICE3 "levelTable" public Plugin myinfo = { name = "[ANY] Profile Status", author = "ratawar", - description = "Limits server entrance to players based on game playtime or VAC/Steam Bans status.", + description = "Limits server entrance to players.", version = PLUGIN_VERSION, url = "https://forums.alliedmods.net/showthread.php?p=2697650" }; @@ -47,12 +45,6 @@ ConVar g_cvCommunityBan, g_cvGameBans, g_cvEconomyBan; -<<<<<<< Updated upstream - -static Regex - r_ApiKey, - r_SteamID; -======= ConVar g_cvEnableLevelCheck, @@ -63,7 +55,6 @@ ConVar ConVar g_cvEnablePrivateProfileCheck; ->>>>>>> Stashed changes Database g_Database; @@ -72,8 +63,11 @@ Database static char cAPIKey[64], - cvDatabase[16], + cvDatabase[64], EcBan[10]; + +char DBDRIVER[16]; +bool g_bIsLite; int minHours, vacDays, @@ -82,7 +76,7 @@ int minHours, economyBan; static int - c = 2; + c = 3; //} @@ -90,43 +84,28 @@ static int public void OnPluginStart() { + /* Setting file */ + + AutoExecConfig_SetCreateFile(true); + AutoExecConfig_SetFile("ProfileStatus"); + /* Plugin Version */ - CreateConVar("sm_profilestatus_version", PLUGIN_VERSION, "Plugin version.", FCVAR_REPLICATED | FCVAR_NOTIFY | FCVAR_DONTRECORD); + AutoExecConfig_CreateConVar("sm_profilestatus_version", PLUGIN_VERSION, "Plugin version.", FCVAR_REPLICATED | FCVAR_NOTIFY | FCVAR_DONTRECORD); /* Basic Data */ -<<<<<<< Updated upstream - g_cvEnable = CreateConVar("sm_profilestatus_enable", "1", "Enable the plugin?", FCVAR_NOTIFY, true, 0.0, true, 1.0); - g_cvApiKey = CreateConVar("sm_profilestatus_apikey", "", "Your Steam API key (https://steamcommunity.com/dev/apikey).", FCVAR_PROTECTED); - - /* Database Name */ - g_cvDatabase = CreateConVar("sm_profilestatus_database", "storage-local", - "Hour Check module's database name. Change this value only if you're using another database. (Only SQLite supported.)"); -======= g_cvEnable = AutoExecConfig_CreateConVar("sm_profilestatus_enable", "1", "Enable the plugin?", FCVAR_NOTIFY, true, 0.0, true, 1.0); g_cvApiKey = AutoExecConfig_CreateConVar("sm_profilestatus_apikey", "", "Your Steam API key (https://steamcommunity.com/dev/apikey)", FCVAR_PROTECTED); /* Database Name */ g_cvDatabase = AutoExecConfig_CreateConVar("sm_profilestatus_database", "storage-local", "Database name. Change this value only if you're using another database set in databases.cfg"); ->>>>>>> Stashed changes /* Hour Check Module */ - g_cvEnableHourCheck = CreateConVar("sm_profilestatus_hours_enable", "1", "Enable Hour Checking functions?", FCVAR_NOTIFY, true, 0.0, true, 1.0); - g_cvMinHours = CreateConVar("sm_profilestatus_hours_minhours", "", "Minimum of hours requiered to enter the server."); - g_cvHoursWhitelistEnable = CreateConVar("sm_profilestatus_hours_whitelist_enable", "1", "Enable Hours Check Whitelist?"); - g_cvHoursWhitelistAuto = CreateConVar("sm_profilestatus_hours_whitelist_auto", "1", "Whitelist members that have been checked automatically?", FCVAR_NOTIFY, true, 0.0, true, 1.0); + g_cvEnableHourCheck = AutoExecConfig_CreateConVar("sm_profilestatus_hours_enable", "1", "Enable Hour Checking functions?", FCVAR_NOTIFY, true, 0.0, true, 1.0); + g_cvMinHours = AutoExecConfig_CreateConVar("sm_profilestatus_hours_minhours", "", "Minimum of hours requiered to enter the server."); + g_cvHoursWhitelistEnable = AutoExecConfig_CreateConVar("sm_profilestatus_hours_whitelist_enable", "1", "Enable Hours Check Whitelist?"); + g_cvHoursWhitelistAuto = AutoExecConfig_CreateConVar("sm_profilestatus_hours_whitelist_auto", "1", "Whitelist members that have been checked automatically?", FCVAR_NOTIFY, true, 0.0, true, 1.0); /* Ban Check Module */ -<<<<<<< Updated upstream - g_cvEnableBanDetection = CreateConVar("sm_profilestatus_bans_enable", "1", "Enable Ban Checking functions?", FCVAR_NOTIFY, true, 0.0, true, 1.0); - g_cvBansWhitelist = CreateConVar("sm_profilestatus_bans_whitelist", "1", "Enable Bans Whitelist?", FCVAR_NOTIFY, true, 0.0, true, 1.0); - g_cvVACDays = CreateConVar("sm_profilestatus_vac_days", "0", "Minimum days since the last VAC ban to be allowed into the server (0 for zero tolerance)."); - g_cvVACAmount = CreateConVar("sm_profilestatus_vac_amount", "0", "Amount of VAC bans tolerated until prohibition (0 for zero tolerance)."); - g_cvCommunityBan = CreateConVar("sm_profilestatus_community_ban", "0", "0- Don't kick if there's a community ban | 1- Kick if there's a community ban"); - g_cvGameBans = CreateConVar("sm_profilestatus_game_bans", "5", "Amount of game bans tolerated until prohibition (0 for zero tolerance)."); - g_cvEconomyBan = CreateConVar("sm_profilestatus_economy_bans", "0", - "0- Don't check for economy bans | 1- Kick if user is economy \"banned\" only. | 2- Kick if user is in either \"banned\" or \"probation\" state.", - _, true, 1.0, true, 2.0); -======= g_cvEnableBanDetection = AutoExecConfig_CreateConVar("sm_profilestatus_bans_enable", "1", "Enable Ban Checking functions?", FCVAR_NOTIFY, true, 0.0, true, 1.0); g_cvBansWhitelist = AutoExecConfig_CreateConVar("sm_profilestatus_bans_whitelist", "1", "Enable Bans Whitelist?", FCVAR_NOTIFY, true, 0.0, true, 1.0); g_cvVACDays = AutoExecConfig_CreateConVar("sm_profilestatus_vac_days", "0", "Minimum days since the last VAC ban to be allowed into the server (0 for zero tolerance)."); @@ -141,7 +120,6 @@ public void OnPluginStart() { g_cvLevelWhitelistAuto = AutoExecConfig_CreateConVar("sm_profilestatus_level_whitelist_auto", "1", "Whitelist members that have been checked automatically?", FCVAR_NOTIFY, true, 0.0, true, 1.0); g_cvMinLevel = AutoExecConfig_CreateConVar("sm_profilestatus_minlevel", "", "Minimum level required to enter the server."); g_cvMaxLevel = AutoExecConfig_CreateConVar("sm_profilestatus_maxlevel", "", "Maximum level tolerated to enter the server (can be left blank for no maximum)."); ->>>>>>> Stashed changes /* Private Profile Check Module */ @@ -151,7 +129,8 @@ public void OnPluginStart() { LoadTranslations("profilestatus.phrases"); - AutoExecConfig(true, "ProfileStatus"); + AutoExecConfig_ExecuteFile(); + AutoExecConfig_CleanFile(); } @@ -180,7 +159,7 @@ public void OnConfigsExecuted() { PrintToServer("[PS] No usage of database detected! Aborting database connection."); } -/* Database connection and tables creation */ +/* Database connection, driver check and tables creation */ public void SQL_ConnectDatabase(Database db, const char[] error, any data) { @@ -193,23 +172,62 @@ public void SQL_ConnectDatabase(Database db, const char[] error, any data) { PrintToServer("[PS] Database connection to \"%s\" successful!", cvDatabase); g_Database = db; + GetDriver(); CreateTable(); } +public void GetDriver() { + + SQL_ReadDriver(g_Database, DBDRIVER, sizeof(DBDRIVER)); + g_bIsLite = strcmp(DBDRIVER, "sqlite") == 0 ? true : false; + +} + public void CreateTable() { char sQuery1[256]; char sQuery2[256]; + char sQuery3[256]; + + if (g_bIsLite) { + StrCat(sQuery1, sizeof(sQuery1), "CREATE TABLE IF NOT EXISTS ps_whitelist("); + StrCat(sQuery1, sizeof(sQuery1), "entry INTEGER PRIMARY KEY, "); + StrCat(sQuery1, sizeof(sQuery1), "steamid VARCHAR(17), "); + StrCat(sQuery1, sizeof(sQuery1), "unique (steamid));"); + + StrCat(sQuery2, sizeof(sQuery2), "CREATE TABLE IF NOT EXISTS ps_whitelist_bans("); + StrCat(sQuery2, sizeof(sQuery2), "entry INTEGER PRIMARY KEY, "); + StrCat(sQuery2, sizeof(sQuery2), "steamid VARCHAR(17), "); + StrCat(sQuery2, sizeof(sQuery2), "unique (steamid));"); + + StrCat(sQuery3, sizeof(sQuery3), "CREATE TABLE IF NOT EXISTS ps_whitelist_level("); + StrCat(sQuery3, sizeof(sQuery3), "entry INTEGER PRIMARY KEY, "); + StrCat(sQuery3, sizeof(sQuery3), "steamid VARCHAR(17), "); + StrCat(sQuery3, sizeof(sQuery3), "unique (steamid));"); + + g_Database.Query(SQL_CreateTable, sQuery1); + g_Database.Query(SQL_CreateTable, sQuery2); + g_Database.Query(SQL_CreateTable, sQuery3); + return; + } StrCat(sQuery1, sizeof(sQuery1), "CREATE TABLE IF NOT EXISTS ps_whitelist("); - StrCat(sQuery1, sizeof(sQuery1), "entry INTEGER PRIMARY KEY, "); - StrCat(sQuery1, sizeof(sQuery1), "steamid VARCHAR(17), "); - StrCat(sQuery1, sizeof(sQuery1), "unique (steamid));"); + StrCat(sQuery1, sizeof(sQuery1), "entry INT NOT NULL AUTO_INCREMENT, "); + StrCat(sQuery1, sizeof(sQuery1), "steamid VARCHAR(17) UNIQUE, "); + StrCat(sQuery1, sizeof(sQuery1), "PRIMARY KEY (entry));"); + StrCat(sQuery2, sizeof(sQuery2), "CREATE TABLE IF NOT EXISTS ps_whitelist_bans("); - StrCat(sQuery2, sizeof(sQuery2), "entry INTEGER PRIMARY KEY, "); - StrCat(sQuery2, sizeof(sQuery2), "steamid VARCHAR(17), "); - StrCat(sQuery2, sizeof(sQuery2), "unique (steamid));"); + StrCat(sQuery2, sizeof(sQuery2), "entry INT NOT NULL AUTO_INCREMENT, "); + StrCat(sQuery2, sizeof(sQuery2), "steamid VARCHAR(17) UNIQUE, "); + StrCat(sQuery2, sizeof(sQuery2), "PRIMARY KEY (entry));"); + + StrCat(sQuery3, sizeof(sQuery3), "CREATE TABLE IF NOT EXISTS ps_whitelist_level("); + StrCat(sQuery3, sizeof(sQuery3), "entry INT NOT NULL AUTO_INCREMENT, "); + StrCat(sQuery3, sizeof(sQuery3), "steamid VARCHAR(17) UNIQUE, "); + StrCat(sQuery3, sizeof(sQuery3), "PRIMARY KEY (entry));"); + g_Database.Query(SQL_CreateTable, sQuery1); g_Database.Query(SQL_CreateTable, sQuery2); + g_Database.Query(SQL_CreateTable, sQuery3); } public void SQL_CreateTable(Database db, DBResultSet results, const char[] error, any data) { @@ -221,7 +239,7 @@ public void SQL_CreateTable(Database db, DBResultSet results, const char[] error return; } - c -= 1; + c--; if (!c) PrintToServer("[PS] Tables successfully created or were already created!"); } @@ -252,7 +270,7 @@ public void SQL_QueryHoursWhitelist(Database db, DBResultSet results, const char PrintToServer("[PS] Error while checking if user %s is hour whitelisted! %s", auth, error); return; } - + if (!results.RowCount) { RequestHours(client, auth); @@ -303,19 +321,6 @@ public int RequestHours_OnHTTPResponse(Handle request, bool bFailure, bool bRequ return; } -<<<<<<< Updated upstream - if (totalPlayedTime < iMinHours) { - KickClient(client, "%t", "Not Enough Hours", totalPlayedTime, iMinHours); - return; - } - - char auth[40]; - GetClientAuthId(client, AuthId_SteamID64, auth, sizeof(auth)); - - if (!g_cvHoursWhitelistAuto.BoolValue) { - PrintToServer("[PS] Player passed hour check, but will not be whitelisted!"); - return; -======= if (minHours != 0) { if (totalPlayedTime < minHours) { KickClient(client, "%t", "Not Enough Hours", totalPlayedTime, minHours); @@ -327,10 +332,7 @@ public int RequestHours_OnHTTPResponse(Handle request, bool bFailure, bool bRequ char auth[40]; GetClientAuthId(client, AuthId_SteamID64, auth, sizeof(auth)); AddPlayerToHoursWhitelist(auth); ->>>>>>> Stashed changes } - - AddPlayerToWhitelist(auth); } public void AddPlayerToHoursWhitelist(char[] auth) { @@ -363,7 +365,7 @@ public void SQL_AddPlayerToHoursWhitelist(Database db, DBResultSet results, cons /* Ban Check Module */ -void QueryBansWhitelist(int client, char[] auth) { +public void QueryBansWhitelist(int client, char[] auth) { char BansWhitelistQuery[256]; Format(BansWhitelistQuery, sizeof(BansWhitelistQuery), "SELECT * FROM ps_whitelist_bans WHERE steamid='%s'", auth); @@ -409,7 +411,7 @@ void RequestBans(int client, char[] auth) { Handle CreateRequest_RequestBans(int client, char[] auth) { char apikey[40]; - GetConVarString(g_cvApiKey, apikey, sizeof(apikey)); + g_cvApiKey.GetString(apikey, sizeof(apikey)); char request_url[512]; @@ -467,8 +469,6 @@ public int RequestBans_OnHTTPResponse(Handle request, bool bFailure, bool bReque } -<<<<<<< Updated upstream -======= /* Steam Level Check Module */ public void QueryLevelWhitelist(int client, char[] auth) { @@ -640,7 +640,6 @@ public int RequestPrivate_OnHTTPResponse(Handle request, bool bFailure, bool bRe KickClient(client, "%t", "No Private Profile"); } ->>>>>>> Stashed changes /* Whitelist Menu */ public void OpenWhitelistMenu(int client) { @@ -648,18 +647,19 @@ public void OpenWhitelistMenu(int client) { Menu menu = new Menu(mPickWhitelist, MENU_ACTIONS_ALL); menu.AddItem(CHOICE1, "Hours Whitelist"); menu.AddItem(CHOICE2, "Bans Whitelist"); + menu.AddItem(CHOICE3, "Level Whitelist"); menu.ExitButton = true; menu.Display(client, 20); } public int mPickWhitelist(Menu menu, MenuAction action, int param1, int param2) { - switch(action) { + switch (action) { case MenuAction_Display: { char buffer[255]; - Format(buffer, sizeof(buffer), "Select a table"); + Format(buffer, sizeof(buffer), "%t", "Select a Table"); Panel panel = view_as(param2); panel.SetTitle(buffer); @@ -688,7 +688,13 @@ public void MenuQuery(int param1, char[] info) { int client = param1; char table[32]; - StrEqual(info, "hoursTable", false) ? Format(table, sizeof(table), "ps_whitelist") : Format(table, sizeof(table), "ps_whitelist_bans"); + + if (StrEqual(info, "hoursTable", false)) + Format(table, sizeof(table), "ps_whitelist"); + if (StrEqual(info, "bansTable", false)) + Format(table, sizeof(table), "ps_whitelist_bans"); + if (StrEqual(info, "levelTable", false)) + Format(table, sizeof(table), "ps_whitelist_level"); char query[256]; g_Database.Format(query, sizeof(query), "SELECT * FROM %s", table); @@ -710,16 +716,22 @@ public void SQL_MenuQuery(Database db, DBResultSet results, const char[] error, if (db == null || results == null) { - - LogError("[PS] Error while querying %s for menu display! %s", table, error); - PrintToServer("[PS] Error while querying %s for menu display! %s", table, error); - CPrintToChat(client, "[PS] Error while querying %s for menu display! %s", table, error); - return; - } - + + LogError("[PS] Error while querying %s for menu display! %s", table, error); + PrintToServer("[PS] Error while querying %s for menu display! %s", table, error); + CPrintToChat(client, "[PS] Error while querying %s for menu display! %s", table, error); + return; + } + char type[16]; - StrEqual(table, "ps_whitelist", false) ? Format(type, sizeof(type), "Hours") : Format(type, sizeof(type), "Bans"); + if (StrEqual(table, "hoursTable", false)) + Format(type, sizeof(type), "Hours"); + if (StrEqual(table, "bansTable", false)) + Format(type, sizeof(type), "Bans"); + if (StrEqual(table, "levelTable", false)) + Format(type, sizeof(type), "Level"); + int entryCol, steamidCol; results.FieldNameToNum("entry", entryCol); @@ -727,22 +739,10 @@ public void SQL_MenuQuery(Database db, DBResultSet results, const char[] error, Menu menu = new Menu(TablesMenu, MENU_ACTIONS_ALL); menu.SetTitle("Showing %s Whitelist", type); - - char steamid[32], id[16]; - int count; - -<<<<<<< Updated upstream - while (results.FetchRow()) { - count++; - results.FetchString(steamidCol, steamid, sizeof(steamid)); - IntToString(count, id, sizeof(id)); - menu.AddItem(id, steamid, ITEMDRAW_DISABLED); - } + char steamid[32], id[16]; + int count; - menu.ExitBackButton = true; - menu.Display(client, MENU_TIME_FOREVER); -======= if (!results.FetchRow()) { CPrintToChat(client, "%t", "No Results"); OpenWhitelistMenu(client); @@ -759,12 +759,11 @@ public void SQL_MenuQuery(Database db, DBResultSet results, const char[] error, menu.Display(client, MENU_TIME_FOREVER); } ->>>>>>> Stashed changes } public int TablesMenu(Menu menu, MenuAction action, int param1, int param2) { - switch(action) { + switch (action) { case MenuAction_Cancel: { @@ -790,7 +789,7 @@ public Action Command_Generic(int client, int args) { if (StrEqual(arg1, "whitelist", false)) OpenWhitelistMenu(client); - if (!StrEqual(arg1, "hours", false) && !StrEqual(arg1, "bans", false)) { + if (!StrEqual(arg1, "hours", false) && !StrEqual(arg1, "bans", false) && !StrEqual(arg1, "level", false)) { CReplyToCommand(client, "%t", "Command Generic Usage"); return Plugin_Handled; } @@ -813,7 +812,12 @@ public void Command(char[] arg1, char[] arg2, char[] arg3, int client) { char query[256], table[32]; - StrEqual(arg1, "hours", false) ? Format(table, sizeof(table), "ps_whitelist") : Format(table, sizeof(table), "ps_whitelist_bans"); + if (StrEqual(arg1, "hours", false)) + Format(table, sizeof(table), "ps_whitelist"); + if (StrEqual(arg1, "bans", false)) + Format(table, sizeof(table), "ps_whitelist_bans"); + if (StrEqual(arg1, "level", false)) + Format(table, sizeof(table), "ps_whitelist_level"); if (StrEqual(arg2, "add")) Format(query, sizeof(query), "INSERT INTO %s (steamid) VALUES (%s);", table, arg3); @@ -843,34 +847,42 @@ public void SQL_Command(Database db, DBResultSet results, const char[] error, Da pack.ReadString(arg3, sizeof(arg3)); delete pack; - char module[16]; - StrEqual(arg1, "hours", false) ? Format(module, sizeof(module), "Hours") : Format(module, sizeof(module), "Bans"); - if (StrEqual(arg2, "add")) { if (db == null) { - LogError("[PS] Error while adding %s to the %s whitelist! %s", arg3, module, error); - PrintToServer("[PS] Error while adding %s to the %s whitelist! %s", arg3, module, error); - CPrintToChat(client, "[PS] Error while adding %s to the %s whitelist! %s", arg3, module, error); + LogError("[PS] Error while adding %s to the %s whitelist! %s", arg3, arg1, error); + PrintToServer("[PS] Error while adding %s to the %s whitelist! %s", arg3, arg1, error); + CPrintToChat(client, "[PS] Error while adding %s to the %s whitelist! %s", arg3, arg1, error); return; } if (results == null) { - if (StrEqual(module, "Hours", false)) { + if (StrEqual(arg1, "hours", false)) { CPrintToChat(client, "%t", "Nothing Hour Added", arg3); return; } - CPrintToChat(client, "%t", "Nothing Ban Added", arg3); - return; + if (StrEqual(arg1, "bans", false)) { + CPrintToChat(client, "%t", "Nothing Ban Added", arg3); + return; + } + if (StrEqual(arg1, "level", false)) { + CPrintToChat(client, "%t", "Nothing Level Added", arg3); + + } } - if (StrEqual(module, "Hours", false)) { + if (StrEqual(arg1, "hours", false)) { CPrintToChat(client, "%t", "Successfully Hour Added", arg3); return; } - - CPrintToChat(client, "%t", "Successfully Ban Added", arg3); - + if (StrEqual(arg1, "bans", false)) { + CPrintToChat(client, "%t", "Successfully Ban Added", arg3); + return; + } + if (StrEqual(arg1, "level", false)) { + CPrintToChat(client, "%t", "Successfully Level Added", arg3); + return; + } } if (StrEqual(arg2, "remove")) { @@ -884,19 +896,32 @@ public void SQL_Command(Database db, DBResultSet results, const char[] error, Da } if (!results.AffectedRows) { - if (StrEqual(module, "Hours", false)) { - + if (StrEqual(arg1, "hours", false)) { CPrintToChat(client, "%t", "Nothing Hour Removed", arg3); return; } - CPrintToChat(client, "%t", "Nothing Ban Removed", arg3); + if (StrEqual(arg1, "bans", false)) { + CPrintToChat(client, "%t", "Nothing Ban Removed", arg3); + return; + } + if (StrEqual(arg1, "level", false)) { + CPrintToChat(client, "%t", "Nothing Level Removed", arg3); + return; + } } - if (StrEqual(module, "Hours", false)) { + + if (StrEqual(arg1, "hours", false)) { CPrintToChat(client, "%t", "Successfully Hour Removed", arg3); return; } - CPrintToChat(client, "%t", "Successfully Ban Removed", arg3); - + if (StrEqual(arg1, "bans", false)) { + CPrintToChat(client, "%t", "Successfully Ban Removed", arg3); + return; + } + if (StrEqual(arg1, "level", false)) { + CPrintToChat(client, "%t", "Successfully Level Removed", arg3); + + } } if (StrEqual(arg2, "check")) { @@ -910,22 +935,33 @@ public void SQL_Command(Database db, DBResultSet results, const char[] error, Da } if (!results.RowCount) { - if (StrEqual(module, "Hours", false)) { - + if (StrEqual(arg1, "hours", false)) { CPrintToChat(client, "%t", "Hour Check Not Whitelisted", arg3); return; } - CPrintToChat(client, "%t", "Ban Check Not Whitelisted", arg3); - + if (StrEqual(arg1, "bans", false)) { + CPrintToChat(client, "%t", "Ban Check Not Whitelisted", arg3); + return; + } + if (StrEqual(arg1, "level", false)) { + CPrintToChat(client, "%t", "Level Check Not Whitelisted", arg3); + return; + } } - if (StrEqual(module, "Hours", false)) { - + if (StrEqual(arg1, "hours", false)) { CPrintToChat(client, "%t", "Hour Check Whitelisted", arg3); return; } - CPrintToChat(client, "%t", "Ban Check Whitelisted", arg3); + if (StrEqual(arg1, "bans", false)) { + CPrintToChat(client, "%t", "Ban Check Whitelisted", arg3); + return; + } + if (StrEqual(arg1, "level", false)) { + CPrintToChat(client, "%t", "Level Check Whitelisted", arg3); + return; + } } -} +} /* On Client Authorized */ @@ -937,35 +973,20 @@ public void OnClientAuthorized(int client) { char auth[40]; GetClientAuthId(client, AuthId_SteamID64, auth, sizeof(auth)); -<<<<<<< Updated upstream - if (g_cvEnableHourCheck.BoolValue) - if (g_cvHoursWhitelistEnable) { - PrintToServer("[PS] Checking hours database for %s existance.", auth); - QueryDBForClient(client, auth); - return; -======= if (g_cvEnableHourCheck) { if (g_cvHoursWhitelistEnable) { QueryHoursWhitelist(client, auth); ->>>>>>> Stashed changes } else RequestHours(client, auth); + } -<<<<<<< Updated upstream - if (g_cvEnableBanDetection.BoolValue) - if (g_cvBansWhitelist.BoolValue) { - PrintToServer("[PS] Checking bans database for %s existance.", auth); -======= if (g_cvEnableBanDetection) { if (g_cvBansWhitelist) { ->>>>>>> Stashed changes QueryBansWhitelist(client, auth); - return; } else RequestBans(client, auth); + } -<<<<<<< Updated upstream -======= if (g_cvEnableLevelCheck) { if (g_cvLevelWhitelistEnable) { QueryLevelWhitelist(client, auth); @@ -976,5 +997,4 @@ public void OnClientAuthorized(int client) { if (g_cvEnablePrivateProfileCheck) { CheckPrivateProfile(client, auth); } ->>>>>>> Stashed changes } \ No newline at end of file diff --git a/translations/profilestatus.phrases.txt b/translations/profilestatus.phrases.txt index 90a650d..671391d 100644 --- a/translations/profilestatus.phrases.txt +++ b/translations/profilestatus.phrases.txt @@ -35,6 +35,14 @@ "en" "{green}[PS]{default} Steam ID {gray}{1} {default}is {red}not {default}ban whitelisted!" "es" "{green}[PS]{default} El Steam ID {gray}{1} {red}no está {default}en la whitelist de bans." "pt" "{green}[PS]{default} A Steam ID {gray}{1} {red}não está {default}na whitelist dos bans!" + } + "Level Check Not Whitelisted" + { + "#format" "{1:s}" + + "en" "{green}[PS]{default} Steam ID {gray}{1} {default}is {red}not {default}level whitelisted!" + "es" "{green}[PS]{default} El Steam ID {gray}{1} {red}no está {default}en la whitelist de niveles." + "pt" "{green}[PS]{default} A Steam ID {gray}{1} {red}não está {default}na whitelist dos níveis!" } "Hour Check Whitelisted" { @@ -52,6 +60,14 @@ "es" "{green}[PS]{default} El Steam ID {gray}{1} {green}está {default}en la whitelist de bans." "pt" "{green}[PS]{default} A Steam ID {gray}{1} {green}está {default}na whitelist dos bans!" } + "Level Check Whitelisted" + { + "#format" "{1:s}" + + "en" "{green}[PS]{default} Steam ID {gray}{1} {green}is {default}level whitelisted!" + "es" "{green}[PS]{default} El Steam ID {gray}{1} {green}está {default}en la whitelist de niveles." + "pt" "{green}[PS]{default} A Steam ID {gray}{1} {green}está {default}na whitelist dos níveis!" + } "Successfully Hour Removed" { "#format" "{1:s}" @@ -68,6 +84,14 @@ "es" "{green}[PS]{default} ¡Removida ID {gray}{1} {default}de la whitelist de horas con éxito!" "pt" "{green}[PS]{default} Removida ID {gray}{1} {default}da whitelist das horas com sucesso!" } + "Successfully Level Removed" + { + "#format" "{1:s}" + + "en" "{green}[PS]{default} Successfully removed {gray}{1} {default}from the level whitelist!" + "es" "{green}[PS]{default} ¡Removida ID {gray}{1} {default}de la whitelist de niveles con éxito!" + "pt" "{green}[PS]{default} Removida ID {gray}{1} {default}da whitelist dos níveis com sucesso!" + } "Nothing Hour Removed" { "#format" "{1:s}" @@ -84,6 +108,14 @@ "es" "{green}[PS]{default} ¡La ID {gray}{1} {default}no estaba en la whitelist de bans!" "pt" "{green}[PS]{default} ID {gray}{1} {default}não estava na whitelist dos bans!" } + "Nothing Ban Removed" + { + "#format" "{1:s}" + + "en" "{green}[PS]{default} ID {gray}{1} {default}was not in level whitelist!" + "es" "{green}[PS]{default} ¡La ID {gray}{1} {default}no estaba en la whitelist de niveles!" + "pt" "{green}[PS]{default} ID {gray}{1} {default}não estava na whitelist dos níveis!" + } "Successfully Hour Added" { "#format" "{1:s}" @@ -99,6 +131,14 @@ "en" "{green}[PS]{default} Successfully added {gray}{1} {default}to the bans whitelist!" "es" "{green}[PS]{default} ¡Agregada la ID {gray}{1} {default}a la whitelist de bans!" "pt" "{green}[PS]{default} Adicionada a ID {gray}{1} {default}à whitelist dos bans com sucesso!" + } + "Successfully Level Added" + { + "#format" "{1:s}" + + "en" "{green}[PS]{default} Successfully added {gray}{1} {default}to the level whitelist!" + "es" "{green}[PS]{default} ¡Agregada la ID {gray}{1} {default}a la whitelist de niveles!" + "pt" "{green}[PS]{default} Adicionada a ID {gray}{1} {default}à whitelist dos níveis com sucesso!" } "Nothing Hour Added" { @@ -117,6 +157,14 @@ "es" "{green}[PS]{default} ¡La ID {gray}{1} {default}ya estaba en la whitelist de bans!" "pt" "{green}[PS]{default} ID {gray}{1} {default}já estava na whitelist dos bans!" } + "Nothing Level Added" + { + "#format" "{1:s}" + + "en" "{green}[PS]{default} ID {gray}{1} {default}was already in level whitelist!" + "es" "{green}[PS]{default} ¡La ID {gray}{1} {default}ya estaba en la whitelist de niveles!" + "pt" "{green}[PS]{default} ID {gray}{1} {default}já estava na whitelist dos níveis!" + } "Command Generic Usage" { "en" "{green}[PS]{default} Usage: sm_ps " @@ -171,8 +219,6 @@ "es" "Este servidor prohíbe jugadores en situación de Trade Ban o Probation." "pt" "Esse servidor proíbe jogadores em situação de Trade Ban ou Probation." } -<<<<<<< Updated upstream -======= "Invisible Level" { "en" "Error while retrieving your Steam level! Make sure your profile is public." @@ -213,5 +259,4 @@ "es" "{green}[PS]{default} ¡Esta tabla está vacía!" "pt" "{green}[PS]{default} Esta tabela está vazia!" } ->>>>>>> Stashed changes } \ No newline at end of file