core/CoreConfig.cpp
author David Anderson <dvander@alliedmods.net>
Thu Jun 21 23:06:37 2007 +0000 (2007-06-21)
changeset 997 2fc3152c3118
parent 978 54782a83a1ef
child 1019 394131f5bbf3
permissions -rw-r--r--
bumped menu api again - added feature to get menu end reason
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "CoreConfig.h"
    16 #include "sourcemod.h"
    17 #include "sourcemm_api.h"
    18 #include "sm_srvcmds.h"
    19 #include "sm_version.h"
    20 #include "sm_stringutil.h"
    21 #include "LibrarySys.h"
    22 #include "TextParsers.h"
    23 #include "Logger.h"
    24 #include "PluginSys.h"
    25 #include "ForwardSys.h"
    26 
    27 #ifdef PLATFORM_WINDOWS
    28 ConVar sm_corecfgfile("sm_corecfgfile", "addons\\sourcemod\\configs\\core.cfg", 0, "SourceMod core configuration file");
    29 #elif defined PLATFORM_LINUX
    30 ConVar sm_corecfgfile("sm_corecfgfile", "addons/sourcemod/configs/core.cfg", 0, "SourceMod core configuration file");
    31 #endif
    32 
    33 IForward *g_pOnServerCfg = NULL;
    34 IForward *g_pOnConfigsExecuted = NULL;
    35 CoreConfig g_CoreConfig;
    36 bool g_bConfigsExecd = false;
    37 
    38 void CoreConfig::OnSourceModAllInitialized()
    39 {
    40 	g_RootMenu.AddRootConsoleCommand("config", "Set core configuration options", this);
    41 	g_pOnServerCfg = g_Forwards.CreateForward("OnServerCfg", ET_Ignore, 0, NULL);
    42 	g_pOnConfigsExecuted = g_Forwards.CreateForward("OnConfigsExecuted", ET_Ignore, 0, NULL);
    43 }
    44 
    45 void CoreConfig::OnSourceModShutdown()
    46 {
    47 	g_RootMenu.RemoveRootConsoleCommand("config", this);
    48 	g_Forwards.ReleaseForward(g_pOnServerCfg);
    49 	g_Forwards.ReleaseForward(g_pOnConfigsExecuted);
    50 }
    51 
    52 void CoreConfig::OnSourceModLevelChange(const char *mapName)
    53 {
    54 	g_bConfigsExecd = false;
    55 }
    56 
    57 void CoreConfig::OnRootConsoleCommand(const char *command, unsigned int argcount)
    58 {
    59 	if (argcount >= 4)
    60 	{
    61 		const char *option = engine->Cmd_Argv(2);
    62 		const char *value = engine->Cmd_Argv(3);
    63 
    64 		char error[255];
    65 
    66 		ConfigResult res = SetConfigOption(option, value, ConfigSource_Console, error, sizeof(error));
    67 
    68 		if (res == ConfigResult_Reject)
    69 		{
    70 			g_RootMenu.ConsolePrint("[SM] Could not set config option \"%s\" to \"%s\" (%s)", option, value, error);
    71 		} else if (res == ConfigResult_Ignore) {
    72 			g_RootMenu.ConsolePrint("[SM] No such config option \"%s\" exists.", option);
    73 		} else {
    74 			g_RootMenu.ConsolePrint("Config option \"%s\" successfully set to \"%s.\"", option, value);
    75 		}
    76 
    77 		return;
    78 	}
    79 
    80 	g_RootMenu.ConsolePrint("[SM] Usage: sm config <option> <value>");
    81 }
    82 
    83 void CoreConfig::Initialize()
    84 {
    85 	SMCParseError err;
    86 	char filePath[PLATFORM_MAX_PATH];
    87 
    88 	/* Try to get command line value of core config convar */
    89 	const char *corecfg = icvar->GetCommandLineValue("sm_corecfgfile");
    90 
    91 	/* If sm_corecfgfile not specified on command line, use default value */
    92 	if (!corecfg)
    93 	{
    94 		corecfg = sm_corecfgfile.GetDefault();
    95 	}
    96 
    97 	/* Format path to config file */
    98 	g_LibSys.PathFormat(filePath, sizeof(filePath), "%s/%s", g_SourceMod.GetGamePath(), corecfg);
    99 
   100 	/* Parse config file */
   101 	if ((err=g_TextParser.ParseFile_SMC(filePath, this, NULL, NULL)) != SMCParse_Okay)
   102 	{
   103  		/* :TODO: This won't actually log or print anything :( - So fix that somehow */
   104 		const char *error = g_TextParser.GetSMCErrorString(err);
   105 		g_Logger.LogFatal("[SM] Error encountered parsing core config file: %s", error ? error : "");
   106 	}
   107 }
   108 
   109 SMCParseResult CoreConfig::ReadSMC_KeyValue(const char *key, const char *value, bool key_quotes, bool value_quotes)
   110 {
   111 	char error[255];
   112 	ConfigResult err = SetConfigOption(key, value, ConfigSource_File, error, sizeof(error));
   113 
   114 	if (err == ConfigResult_Reject)
   115 	{
   116 		/* This is a fatal error */
   117 		g_Logger.LogFatal("Config error (key: %s) (value: %s) %s", key, value, error);
   118 	}
   119 
   120 	return SMCParse_Continue;
   121 }
   122 
   123 ConfigResult CoreConfig::SetConfigOption(const char *option, const char *value, ConfigSource source, char *error, size_t maxlength)
   124 {
   125 	ConfigResult result;
   126 
   127 	/* Notify! */
   128 	SMGlobalClass *pBase = SMGlobalClass::head;
   129 	while (pBase)
   130 	{
   131 		if ((result = pBase->OnSourceModConfigChanged(option, value, source, error, maxlength)) != ConfigResult_Ignore)
   132 		{
   133 			return result;
   134 		}
   135 		pBase = pBase->m_pGlobalClassNext;
   136 	}
   137 
   138 	return ConfigResult_Ignore;
   139 }
   140 
   141 bool SM_AreConfigsExecuted()
   142 {
   143 	return g_bConfigsExecd;
   144 }
   145 
   146 inline bool IsPathSepChar(char c)
   147 {
   148 #if defined PLATFORM_WINDOWS
   149 	return (c == '\\' || c == '/');
   150 #elif defined PLATFORM_LINUX
   151 	return (c == '/');
   152 #endif
   153 }
   154 
   155 bool SM_ExecuteConfig(CPlugin *pl, AutoConfig *cfg, bool can_create)
   156 {
   157 	bool will_create = false;
   158 	
   159 	/* See if we should be creating */
   160 	if (can_create && cfg->create)
   161 	{
   162 		will_create = true;
   163 		
   164 		/* If the folder does not exist, attempt to create it.  
   165 		 * We're awfully nice.
   166 		 */
   167 		const char *folder = cfg->folder.c_str();
   168 		char path[PLATFORM_MAX_PATH];
   169 		char build[PLATFORM_MAX_PATH];
   170 
   171 		g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "cfg/%s", folder);
   172 
   173 		if (!g_LibSys.IsPathDirectory(path))
   174 		{
   175 			char *cur_ptr = path;
   176 			size_t len;
   177 			
   178 			g_LibSys.PathFormat(path, sizeof(path), "%s", folder);
   179 			len = g_SourceMod.BuildPath(Path_Game, build, sizeof(build), "cfg");
   180 
   181 			do
   182 			{
   183 				/* Find next suitable path */
   184 				char *next_ptr = cur_ptr;
   185 				while (*next_ptr != '\0')
   186 				{
   187 					if (IsPathSepChar(*next_ptr))
   188 					{
   189 						*next_ptr = '\0';
   190 						next_ptr++;
   191 						break;
   192 					}
   193 					next_ptr++;
   194 				}
   195 				if (*next_ptr == '\0')
   196 				{
   197 					next_ptr = NULL;
   198 				}
   199 				len += g_LibSys.PathFormat(&build[len], 
   200 					sizeof(build)-len,
   201 					"/%s",
   202 					cur_ptr);
   203 				if (!g_LibSys.CreateDirectory(build))
   204 				{
   205 					break;
   206 				}
   207 				cur_ptr = next_ptr;
   208 			} while (cur_ptr);
   209 		}
   210 	}
   211 
   212 	/* Check if the file exists. */
   213 	char file[PLATFORM_MAX_PATH];
   214 	char local[PLATFORM_MAX_PATH];
   215 
   216 	if (cfg->folder.size())
   217 	{
   218 		g_LibSys.PathFormat(local, 
   219 			sizeof(local), 
   220 			"%s/%s.cfg",
   221 			cfg->folder.c_str(),
   222 			cfg->autocfg.c_str());
   223 	} else {
   224 		g_LibSys.PathFormat(local,
   225 			sizeof(local),
   226 			"%s.cfg",
   227 			cfg->autocfg.c_str());
   228 	}
   229 	
   230 	g_SourceMod.BuildPath(Path_Game, file, sizeof(file), "cfg/%s", local);
   231 
   232 	bool file_exists = g_LibSys.IsPathFile(file);
   233 	if (!file_exists && will_create)
   234 	{
   235 		List<const ConVar *> *convars = NULL;
   236 		if (pl->GetProperty("ConVarList", (void **)&convars, false) && convars)
   237 		{
   238 			/* Attempt to create it */
   239 			FILE *fp = fopen(file, "wt");
   240 			if (fp)
   241 			{
   242 				fprintf(fp, "// This file was auto-generated by SourceMod (v%s)\n", SVN_FULL_VERSION);
   243 				fprintf(fp, "// ConVars for plugin \"%s\"\n", pl->GetFilename());
   244 				fprintf(fp, "\n\n");
   245 
   246 				List<const ConVar *>::iterator iter;
   247 				float x;
   248 				for (iter = convars->begin(); iter != convars->end(); iter++)
   249 				{
   250 					const ConVar *cvar = (*iter);
   251 					char descr[255];
   252 					char *dptr = descr;
   253 
   254 					/* Print comments until there is no more */
   255 					strncopy(descr, cvar->GetHelpText(), sizeof(descr));
   256 					while (*dptr != '\0')
   257 					{
   258 						/* Find the next line */
   259 						char *next_ptr = dptr;
   260 						while (*next_ptr != '\0')
   261 						{
   262 							if (*next_ptr == '\n')
   263 							{
   264 								*next_ptr = '\0';
   265 								next_ptr++;
   266 								break;
   267 							}
   268 							next_ptr++;
   269 						}
   270 						fprintf(fp, "// %s\n", dptr);
   271 						dptr = next_ptr;
   272 					}
   273 
   274 					fprintf(fp, "// -\n");
   275 					fprintf(fp, "// Default: \"%s\"\n", cvar->GetDefault());
   276 					if (cvar->GetMin(x))
   277 					{
   278 						fprintf(fp, "// Minimum: \"%02f\"\n", x);
   279 					}
   280 					if (cvar->GetMax(x))
   281 					{
   282 						fprintf(fp, "// Maximum: \"%02f\"\n", x);
   283 					}
   284 					fprintf(fp, "%s \"%s\"\n", cvar->GetName(), cvar->GetDefault());
   285 					fprintf(fp, "\n");
   286 				}
   287 				fprintf(fp, "\n");
   288 
   289 				file_exists = true;
   290 				can_create = false;
   291 				fclose(fp);
   292 			}
   293 		}
   294 	}
   295 
   296 	if (file_exists)
   297 	{
   298 		char cmd[255];
   299 		UTIL_Format(cmd, sizeof(cmd), "exec %s\n", local);
   300 		engine->ServerCommand(cmd);
   301 	}
   302 
   303 	return can_create;
   304 }
   305 
   306 void SM_DoSingleExecFwds(IPluginContext *ctx)
   307 {
   308 	IPluginFunction *pf;
   309 
   310 	if ((pf = ctx->GetFunctionByName("OnServerCfg")) != NULL)
   311 	{
   312 		pf->Execute(NULL);
   313 	}
   314 
   315 	if ((pf = ctx->GetFunctionByName("OnConfigsExecuted")) != NULL)
   316 	{
   317 		pf->Execute(NULL);
   318 	}
   319 }
   320 
   321 void SM_ConfigsExecuted_Plugin(unsigned int serial)
   322 {
   323 	IPluginIterator *iter = g_PluginSys.GetPluginIterator();
   324 	while (iter->MorePlugins())
   325 	{
   326 		CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
   327 		if (plugin->GetSerial() == serial)
   328 		{
   329 			SM_DoSingleExecFwds(plugin->GetBaseContext());
   330 			break;
   331 		}
   332 		iter->NextPlugin();
   333 	}
   334 	iter->Release();
   335 }
   336 
   337 void SM_ExecuteForPlugin(IPluginContext *ctx)
   338 {
   339 	CPlugin *plugin = (CPlugin *)g_PluginSys.GetPluginByCtx(ctx->GetContext());
   340 
   341 	unsigned int num = plugin->GetConfigCount();
   342 	if (!num)
   343 	{
   344 		SM_DoSingleExecFwds(ctx);
   345 	} else {
   346 		bool can_create = true;
   347 		for (unsigned int i=0; i<num; i++)
   348 		{
   349 			can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
   350 		}
   351 		char cmd[255];
   352 		UTIL_Format(cmd, sizeof(cmd), "sm internal 2 %d\n", plugin->GetSerial());
   353 		engine->ServerCommand(cmd);
   354 	}
   355 }
   356 
   357 void SM_ExecuteAllConfigs()
   358 {
   359 	if (g_bConfigsExecd)
   360 	{
   361 		return;
   362 	}
   363 
   364 	engine->ServerCommand("exec cfg/sourcemod/sourcemod.cfg\n");
   365 
   366 	IPluginIterator *iter = g_PluginSys.GetPluginIterator();
   367 	while (iter->MorePlugins())
   368 	{
   369 		CPlugin *plugin = (CPlugin *)(iter->GetPlugin());
   370 		unsigned int num = plugin->GetConfigCount();
   371 		bool can_create = true;
   372 		for (unsigned int i=0; i<num; i++)
   373 		{
   374 			can_create = SM_ExecuteConfig(plugin, plugin->GetConfig(i), can_create);
   375 		}
   376 		iter->NextPlugin();
   377 	}
   378 	iter->Release();
   379 
   380 	engine->ServerCommand("sm internal 1\n");
   381 }
   382 
   383 void SM_ConfigsExecuted_Global()
   384 {
   385 	if (g_bConfigsExecd)
   386 	{
   387 		return;
   388 	}
   389 
   390 	g_bConfigsExecd = true;
   391 
   392 	g_pOnServerCfg->Execute(NULL);
   393 	g_pOnConfigsExecuted->Execute(NULL);
   394 }