1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/CoreConfig.cpp Sun Mar 30 07:00:22 2008 +0000
1.3 @@ -0,0 +1,420 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#include <ITextParsers.h>
1.36 +#include "CoreConfig.h"
1.37 +#include "sourcemod.h"
1.38 +#include "sourcemm_api.h"
1.39 +#include "sm_srvcmds.h"
1.40 +#include "sm_version.h"
1.41 +#include "sm_stringutil.h"
1.42 +#include "LibrarySys.h"
1.43 +#include "Logger.h"
1.44 +#include "PluginSys.h"
1.45 +#include "ForwardSys.h"
1.46 +
1.47 +#ifdef PLATFORM_WINDOWS
1.48 +ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
1.49 +#elif defined PLATFORM_LINUX
1.50 +ConVar sm_corecfgfile("sm_corecfgfile", "addons/sourcemod/configs/core.cfg", 0, "SourceMod core configuration file");
1.51 +#endif
1.52 +
1.53 +IForward *g_pOnServerCfg = NULL;
1.54 +IForward *g_pOnConfigsExecuted = NULL;
1.55 +CoreConfig g_CoreConfig;
1.56 +bool g_bConfigsExecd = false;
1.57 +
1.58 +void CoreConfig::OnSourceModAllInitialized()
1.59 +{
1.60 + g_RootMenu.AddRootConsoleCommand("config", "Set core configuration options", this);
1.61 + g_pOnServerCfg = g_Forwards.CreateForward("OnServerCfg", ET_Ignore, 0, NULL);
1.62 + g_pOnConfigsExecuted = g_Forwards.CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL);
1.63 +}
1.64 +
1.65 +void CoreConfig::OnSourceModShutdown()
1.66 +{
1.67 + g_RootMenu.RemoveRootConsoleCommand("config", this);
1.68 + g_Forwards.ReleaseForward(g_pOnServerCfg);
1.69 + g_Forwards.ReleaseForward(g_pOnConfigsExecuted);
1.70 +}
1.71 +
1.72 +void CoreConfig::OnSourceModLevelChange(const char *mapName)
1.73 +{
1.74 + g_bConfigsExecd = false;
1.75 +}
1.76 +
1.77 +void CoreConfig::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
1.78 +{
1.79 + int argcount = command.ArgC();
1.80 + if (argcount >= 4)
1.81 + {
1.82 + const char *option = command.Arg(2);
1.83 + const char *value = command.Arg(3);
1.84 +
1.85 + char error[255];
1.86 +
1.87 + ConfigResult res = SetConfigOption(option, value, ConfigSource_Console, error, sizeof(error));
1.88 +
1.89 + if (res == ConfigResult_Reject)
1.90 + {
1.91 + g_RootMenu.ConsolePrint("[SM] Could not set config option \"%s\" to \"%s\" (%s)", option, value, error);
1.92 + } else if (res == ConfigResult_Ignore) {
1.93 + g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option);
1.94 + } else {
1.95 + g_RootMenu.ConsolePrint("Config option \"%s\" successfully set to \"%s.\"", option, value);
1.96 + }
1.97 +
1.98 + return;
1.99 + }
1.100 +
1.101 + g_RootMenu.ConsolePrint("[SM] Usage: sm config <option> <value>");
1.102 +}
1.103 +
1.104 +void CoreConfig::Initialize()
1.105 +{
1.106 + SMCError err;
1.107 + char filePath[PLATFORM_MAX_PATH];
1.108 +
1.109 + /* Try to get command line value of core config convar */
1.110 + const char *corecfg = icvar->GetCommandLineValue("sm_corecfgfile");
1.111 +
1.112 + /* If sm_corecfgfile not specified on command line, use default value */
1.113 + if (!corecfg)
1.114 + {
1.115 + corecfg = sm_corecfgfile.GetDefault();
1.116 + }
1.117 +
1.118 + /* Format path to config file */
1.119 + g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
1.120 +
1.121 + /* Parse config file */
1.122 + if ((err=textparsers->ParseFile_SMC(filePath, this, NULL)) != SMCError_Okay)
1.123 + {
1.124 + /* :TODO: This won't actually log or print anything :( - So fix that somehow */
1.125 + const char *error = textparsers->GetSMCErrorString(err);
1.126 + g_Logger.LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : "");
1.127 + }
1.128 +}
1.129 +
1.130 +SMCResult CoreConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
1.131 +{
1.132 + char error[255];
1.133 + ConfigResult err = SetConfigOption(key, value, ConfigSource_File, error, sizeof(error));
1.134 +
1.135 + if (err == ConfigResult_Reject)
1.136 + {
1.137 + /* This is a fatal error */
1.138 + g_Logger.LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
1.139 + }
1.140 +
1.141 + return SMCResult_Continue;
1.142 +}
1.143 +
1.144 +ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, ConfigSource source, char *error, size_t maxlength)
1.145 +{
1.146 + ConfigResult result;
1.147 +
1.148 + /* Notify! */
1.149 + SMGlobalClass *pBase = SMGlobalClass::head;
1.150 + while (pBase)
1.151 + {
1.152 + if ((result = pBase->OnSourceModConfigChanged(option, value, source, error, maxlength)) != ConfigResult_Ignore)
1.153 + {
1.154 + return result;
1.155 + }
1.156 + pBase = pBase->m_pGlobalClassNext;
1.157 + }
1.158 +
1.159 + return ConfigResult_Ignore;
1.160 +}
1.161 +
1.162 +bool SM_AreConfigsExecuted()
1.163 +{
1.164 + return g_bConfigsExecd;
1.165 +}
1.166 +
1.167 +inline bool IsPathSepChar(char c)
1.168 +{
1.169 +#if defined PLATFORM_WINDOWS
1.170 + return (c == '\\' || c == '/');
1.171 +#elif defined PLATFORM_LINUX
1.172 + return (c == '/');
1.173 +#endif
1.174 +}
1.175 +
1.176 +bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create)
1.177 +{
1.178 + bool will_create = false;
1.179 +
1.180 + /* See if we should be creating */
1.181 + if (can_create && cfg->create)
1.182 + {
1.183 + will_create = true;
1.184 +
1.185 + /* If the folder does not exist, attempt to create it.
1.186 + * We're awfully nice.
1.187 + */
1.188 + const char *folder = cfg->folder.c_str();
1.189 + char path[PLATFORM_MAX_PATH];
1.190 + char build[PLATFORM_MAX_PATH];
1.191 +
1.192 + g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "cfg/%s", folder);
1.193 +
1.194 + if (!g_LibSys.IsPathDirectory(path))
1.195 + {
1.196 + char *cur_ptr = path;
1.197 + size_t len;
1.198 +
1.199 + g_LibSys.PathFormat(path, sizeof(path), "%s", folder);
1.200 + len = g_SourceMod.BuildPath(Path_Game, build, sizeof(build), "cfg");
1.201 +
1.202 + do
1.203 + {
1.204 + /* Find next suitable path */
1.205 + char *next_ptr = cur_ptr;
1.206 + while (*next_ptr != '\0')
1.207 + {
1.208 + if (IsPathSepChar(*next_ptr))
1.209 + {
1.210 + *next_ptr = '\0';
1.211 + next_ptr++;
1.212 + break;
1.213 + }
1.214 + next_ptr++;
1.215 + }
1.216 + if (*next_ptr == '\0')
1.217 + {
1.218 + next_ptr = NULL;
1.219 + }
1.220 + len += g_LibSys.PathFormat(&build[len],
1.221 + sizeof(build)-len,
1.222 + "/%s",
1.223 + cur_ptr);
1.224 + if (!g_LibSys.CreateFolder(build))
1.225 + {
1.226 + break;
1.227 + }
1.228 + cur_ptr = next_ptr;
1.229 + } while (cur_ptr);
1.230 + }
1.231 + }
1.232 +
1.233 + /* Check if the file exists. */
1.234 + char file[PLATFORM_MAX_PATH];
1.235 + char local[PLATFORM_MAX_PATH];
1.236 +
1.237 + if (cfg->folder.size())
1.238 + {
1.239 + g_LibSys.PathFormat(local,
1.240 + sizeof(local),
1.241 + "%s/%s.cfg",
1.242 + cfg->folder.c_str(),
1.243 + cfg->autocfg.c_str());
1.244 + } else {
1.245 + g_LibSys.PathFormat(local,
1.246 + sizeof(local),
1.247 + "%s.cfg",
1.248 + cfg->autocfg.c_str());
1.249 + }
1.250 +
1.251 + g_SourceMod.BuildPath(Path_Game, file, sizeof(file), "cfg/%s", local);
1.252 +
1.253 + bool file_exists = g_LibSys.IsPathFile(file);
1.254 + if (!file_exists && will_create)
1.255 + {
1.256 + List<const ConVar *> *convars = NULL;
1.257 + if (pl->GetProperty("ConVarList", (void **)&convars, false) && convars)
1.258 + {
1.259 + /* Attempt to create it */
1.260 + FILE *fp = fopen(file, "wt");
1.261 + if (fp)
1.262 + {
1.263 + fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SVN_FULL_VERSION);
1.264 + fprintf(fp, "// ConVars for plugin \"%s\"\n", pl->GetFilename());
1.265 + fprintf(fp, "\n\n");
1.266 +
1.267 + List<const ConVar *>::iterator iter;
1.268 + float x;
1.269 + for (iter = convars->begin(); iter != convars->end(); iter++)
1.270 + {
1.271 + const ConVar *cvar = (*iter);
1.272 +
1.273 + if ((cvar->GetFlags() & FCVAR_DONTRECORD) == FCVAR_DONTRECORD)
1.274 + {
1.275 + continue;
1.276 + }
1.277 +
1.278 + char descr[255];
1.279 + char *dptr = descr;
1.280 +
1.281 + /* Print comments until there is no more */
1.282 + strncopy(descr, cvar->GetHelpText(), sizeof(descr));
1.283 + while (*dptr != '\0')
1.284 + {
1.285 + /* Find the next line */
1.286 + char *next_ptr = dptr;
1.287 + while (*next_ptr != '\0')
1.288 + {
1.289 + if (*next_ptr == '\n')
1.290 + {
1.291 + *next_ptr = '\0';
1.292 + next_ptr++;
1.293 + break;
1.294 + }
1.295 + next_ptr++;
1.296 + }
1.297 + fprintf(fp, "// %s\n", dptr);
1.298 + dptr = next_ptr;
1.299 + }
1.300 +
1.301 + fprintf(fp, "// -\n");
1.302 + fprintf(fp, "// Default: \"%s\"\n", cvar->GetDefault());
1.303 + if (cvar->GetMin(x))
1.304 + {
1.305 + fprintf(fp, "// Minimum: \"%02f\"\n", x);
1.306 + }
1.307 + if (cvar->GetMax(x))
1.308 + {
1.309 + fprintf(fp, "// Maximum: \"%02f\"\n", x);
1.310 + }
1.311 + fprintf(fp, "%s \"%s\"\n", cvar->GetName(), cvar->GetDefault());
1.312 + fprintf(fp, "\n");
1.313 + }
1.314 + fprintf(fp, "\n");
1.315 +
1.316 + file_exists = true;
1.317 + can_create = false;
1.318 + fclose(fp);
1.319 + }
1.320 + }
1.321 + }
1.322 +
1.323 + if (file_exists)
1.324 + {
1.325 + char cmd[255];
1.326 + UTIL_Format(cmd, sizeof(cmd), "exec %s\n", local);
1.327 + engine->ServerCommand(cmd);
1.328 + }
1.329 +
1.330 + return can_create;
1.331 +}
1.332 +
1.333 +void SM_DoSingleExecFwds(IPluginContext *ctx)
1.334 +{
1.335 + IPluginFunction *pf;
1.336 +
1.337 + if ((pf = ctx->GetFunctionByName("OnServerCfg")) != NULL)
1.338 + {
1.339 + pf->Execute(NULL);
1.340 + }
1.341 +
1.342 + if ((pf = ctx->GetFunctionByName("OnConfigsExecuted")) != NULL)
1.343 + {
1.344 + pf->Execute(NULL);
1.345 + }
1.346 +}
1.347 +
1.348 +void SM_ConfigsExecuted_Plugin(unsigned int serial)
1.349 +{
1.350 + IPluginIterator *iter = g_PluginSys.GetPluginIterator();
1.351 + while (iter->MorePlugins())
1.352 + {
1.353 + CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
1.354 + if (plugin->GetSerial() == serial)
1.355 + {
1.356 + SM_DoSingleExecFwds(plugin->GetBaseContext());
1.357 + break;
1.358 + }
1.359 + iter->NextPlugin();
1.360 + }
1.361 + iter->Release();
1.362 +}
1.363 +
1.364 +void SM_ExecuteForPlugin(IPluginContext *ctx)
1.365 +{
1.366 + CPlugin *plugin = (CPlugin *)g_PluginSys.GetPluginByCtx(ctx->GetContext());
1.367 +
1.368 + unsigned int num = plugin->GetConfigCount();
1.369 + if (!num)
1.370 + {
1.371 + SM_DoSingleExecFwds(ctx);
1.372 + }
1.373 + else
1.374 + {
1.375 + bool can_create = true;
1.376 + for (unsigned int i=0; i<num; i++)
1.377 + {
1.378 + can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
1.379 + }
1.380 + char cmd[255];
1.381 + UTIL_Format(cmd, sizeof(cmd), "sm internal 2 %d\n", plugin->GetSerial());
1.382 + engine->ServerCommand(cmd);
1.383 + }
1.384 +}
1.385 +
1.386 +void SM_ExecuteAllConfigs()
1.387 +{
1.388 + if (g_bConfigsExecd)
1.389 + {
1.390 + return;
1.391 + }
1.392 +
1.393 + engine->ServerCommand("exec sourcemod/sourcemod.cfg\n");
1.394 +
1.395 + IPluginIterator *iter = g_PluginSys.GetPluginIterator();
1.396 + while (iter->MorePlugins())
1.397 + {
1.398 + CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
1.399 + unsigned int num = plugin->GetConfigCount();
1.400 + bool can_create = true;
1.401 + for (unsigned int i=0; i<num; i++)
1.402 + {
1.403 + can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
1.404 + }
1.405 + iter->NextPlugin();
1.406 + }
1.407 + iter->Release();
1.408 +
1.409 + engine->ServerCommand("sm internal 1\n");
1.410 +}
1.411 +
1.412 +void SM_ConfigsExecuted_Global()
1.413 +{
1.414 + if (g_bConfigsExecd)
1.415 + {
1.416 + return;
1.417 + }
1.418 +
1.419 + g_bConfigsExecd = true;
1.420 +
1.421 + g_pOnServerCfg->Execute(NULL);
1.422 + g_pOnConfigsExecuted->Execute(NULL);
1.423 +}