diff --git a/plugins/profilestatus.smx b/plugins/profilestatus.smx index ae32bce..14bcc9b 100644 Binary files a/plugins/profilestatus.smx and b/plugins/profilestatus.smx differ 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