/* * ============================================================================ * * Zombie:Reloaded * * File: config.inc * Description: Config API and executing. * * ============================================================================ */ /** * @section List of config files under this modules control. */ #define CONFIG_FILE_MODELS 0 #define CONFIG_FILE_DOWNLOADS 1 #define CONFIG_FILE_PLAYERCLASSES 2 #define CONFIG_FILE_WEAPONS 3 #define CONFIG_FILE_WEAPONGROUPS 4 #define CONFIG_FILE_HITGROUPS 5 /** * @endsection */ /** * @section Config file flags. */ #define CONFIG_FILE_FLAG_MODELS 1 #define CONFIG_FILE_FLAG_DOWNLOADS 2 #define CONFIG_FILE_FLAG_PLAYERCLASSES 4 #define CONFIG_FILE_FLAG_WEAPONS 8 #define CONFIG_FILE_FLAG_WEAPONGROUPS 16 #define CONFIG_FILE_FLAG_HITGROUPS 32 /** * @endsection */ /** * The max length of a config/value string. */ #define CONFIG_OPTION_MAX_LENGTH 32 enum ConfigKeyvalueAction { Create, /** Create a key. */ Delete, /** Delete a key. */ Set, /** Modify setting of a key. */ Get, /** Get setting of a key. */ } /** * @section Global data handle initializations. */ new Handle:arrayModelsList = INVALID_HANDLE; new Handle:kvClassData = INVALID_HANDLE; new Handle:kvWeapons = INVALID_HANDLE; new Handle:kvWeaponGroups = INVALID_HANDLE; new Handle:kvHitgroups = INVALID_HANDLE; /** * Load plugin configs. */ ConfigLoad() { decl String:mapconfig[PLATFORM_MAX_PATH]; // Get map name and format into config path. GetCurrentMap(mapconfig, sizeof(mapconfig)); Format(mapconfig, sizeof(mapconfig), "sourcemod/zombiereloaded/%s.cfg", mapconfig); // Prepend cfg to path. decl String:path[PLATFORM_MAX_PATH]; Format(path, sizeof(path), "cfg/%s", mapconfig); // File doesn't exist, then stop. if (!FileExists(path)) { return; } // Execute config file. ServerCommand("exec %s", mapconfig); // Log action. if (LogCheckFlag(LOG_CORE_EVENTS)) { LogMessageFormatted(-1, "", "", "Executed map config file: %s.", LOG_FORMAT_TYPE_SIMPLE, mapconfig); } } /** * Load config file. * * @param file The cvar define of the path to the file. * @return True if the file exists, false if not. */ bool:ConfigGetFilePath(CvarsList:cvar, String:path[]) { // Get cvar's path. decl String:filepath[PLATFORM_MAX_PATH]; GetConVarString(Handle:g_hCvarsList[cvar], filepath, sizeof(filepath)); // Build full path in return string. BuildPath(Path_SM, path, PLATFORM_MAX_PATH, filepath); return FileExists(path); } /** * Creates, deletes, sets, or gets any key/setting of any ZR config keyvalue file in memory. * Only use when interacting with a command or manipulating single keys/values, * using this function everywhere would be EXTREMELY inefficient. * * @param config Config index of config to modify. (see CONFIG_FILE_* defines) * @param action Action to perform on keyvalue tree. (see enum ConfigKeyvalueAction) * @param keys Array containing keys to traverse into. * @param keysMax The size of the 'keys' array. * @param setting (Optional) The name of the setting to modify. * @param value (Optional) The new value to set. * @param maxlen (Optional) The maxlength of the gotten value. * @return True if the change was made successfully, false otherwise. */ bool:ConfigKeyvalueTreeSetting(config, ConfigKeyvalueAction:action = Create, const String:keys[][], keysMax, const String:setting[] = "", String:value[] = "", maxlen = 0) { // Retrieve handle of the keyvalue tree. new Handle:hConfig = ConfigGetFileHandle(config); // If handle is invalid, then stop. if (hConfig == INVALID_HANDLE) { return false; } // Rewind keyvalue tree. KvRewind(hConfig); // x = keys index. // Traverse into the keygroup, stop if it fails. for (new x = 0; x < keysMax; x++) { // If key is empty, then break the loop. if (!keys[x][0]) { break; } // Try to jump to next level in the transversal stack, create key if specified. new bool:exists = KvJumpToKey(hConfig, keys[x], (action == Create)); // If exists is false, then stop. if (!exists) { // Key doesn't exist. return false; } } switch(action) { case Create: { if (!setting[0] || !value[0]) { // We created the key already, so return true. return true; } // Set new value. KvSetString(hConfig, setting, value); } case Delete: { // Return deletion result. return KvDeleteKey(hConfig, setting); } case Set: { // Set new value. KvSetString(hConfig, setting, value); } case Get: { // Get current value. KvGetString(hConfig, setting, value, maxlen); } } // We successfully set or got the value. return true; } /** * Return handle to array or keygroup for globally stored data. * * @param configindex Index of the config. (see CONFIG_FILE_* defines) */ Handle:ConfigGetFileHandle(config) { switch(config) { case CONFIG_FILE_MODELS: { // Return model list array handle. return arrayModelsList; } case CONFIG_FILE_DOWNLOADS: { // We don't store download data. return INVALID_HANDLE; } case CONFIG_FILE_PLAYERCLASSES: { // Return class config keyvalue file handle. return kvClassData; } case CONFIG_FILE_WEAPONS: { // Return weapon config keyvalue file handle. return kvWeapons; } case CONFIG_FILE_WEAPONGROUPS: { // Return weapon groups config keyvalue file handle. return kvWeaponGroups; } case CONFIG_FILE_HITGROUPS: { // Return hitgroups config keyvalue file handle. return kvHitgroups; } } // Invalid config index. return INVALID_HANDLE; } /** * Iterate through a file and store each line in an array. * * @param path Path to the file to iterate through. * @return The handle of the array, don't forget to call CloseHandle * on it when finished! */ Handle:ConfigLinesToArray(const String:path[]) { new Handle:arrayLines = CreateArray(PLATFORM_MAX_PATH); decl String:line[PLATFORM_MAX_PATH]; // Open file. new Handle:hFile = OpenFile(path, "r"); // If file couldn't be opened, then stop. if (hFile == INVALID_HANDLE) { return INVALID_HANDLE; } while(!IsEndOfFile(hFile)) { // Get current line text. ReadFileLine(hFile, line, sizeof(line)); // If line contains a ";", then stop. if (StrContains(line, ";") > -1) { continue; } // Cut out comments at the end of a line. if (StrContains(line, "//") > -1) { SplitString(line, "//", line, sizeof(line)); } // Trim off whitespace. TrimString(line); // If line is empty, then stop. if (!line[0]) { continue; } // Push line into array. PushArrayString(arrayLines, line); } // Close file handle. CloseHandle(hFile); // Return array handle. return arrayLines; } /** * Converts string of "yes" or "no" to a boolean value. * * @param option "yes" or "no" string to be converted. * @return True if string is "yes", false otherwise. */ bool:ConfigSettingToBool(const String:option[]) { // If option is equal to "yes," then return true. if (StrEqual(option, "yes", false)) { return true; } // Option isn't "yes." return false; } /** * Converts boolean value to "yes" or "no". * * @param bOption True/false value to be converted to "yes"/"no", respectively. * @param option Destination string buffer to store "yes" or "no" in. * @param maxlen Length of destination string buffer (can't be more than 4). */ ConfigBoolToSetting(bool:bOption, String:option[], maxlen) { // If option is true, then copy "yes" to return string. if (bOption) { strcopy(option, maxlen, "yes"); } // If option is false, then copy "no" to return string. else { strcopy(option, maxlen, "no"); } }