core/sm_srvcmds.cpp
author David Anderson <dvander@alliedmods.net>
Fri Feb 22 02:28:33 2008 +0000 (2008-02-22)
changeset 1877 ff0bbf1bc094
parent 1770 9c545310f947
child 1883 c9705da6f066
permissions -rw-r--r--
added sourcemod's VDF file. yay
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include "sm_srvcmds.h"
    33 #include "sm_version.h"
    34 #include "sm_stringutil.h"
    35 #include "HandleSys.h"
    36 #include "CoreConfig.h"
    37 #include "ConVarManager.h"
    38 
    39 RootConsoleMenu g_RootMenu;
    40 
    41 ConVar sourcemod_version("sourcemod_version", SVN_FULL_VERSION, FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY, "SourceMod Version");
    42 
    43 RootConsoleMenu::RootConsoleMenu()
    44 {
    45 	m_pCommands = sm_trie_create();
    46 	m_CfgExecDone = false;
    47 }
    48 
    49 RootConsoleMenu::~RootConsoleMenu()
    50 {
    51 	sm_trie_destroy(m_pCommands);
    52 
    53 	List<ConsoleEntry *>::iterator iter;
    54 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
    55 	{
    56 		delete (*iter);
    57 	}
    58 	m_Menu.clear();
    59 }
    60 
    61 extern void _IntExt_OnHostnameChanged(ConVar *var, const char *pOldValue, float flOldValue);
    62 
    63 class DetectHostNameChanges : public IConVarChangeListener
    64 {
    65 public:
    66 	void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue)
    67 	{
    68 		_IntExt_OnHostnameChanged(pConVar, oldValue, flOldValue);
    69 	}
    70 } s_HostnameChangeDetector;
    71 
    72 void RootConsoleMenu::OnSourceModStartup(bool late)
    73 {
    74 #if defined ORANGEBOX_BUILD
    75 	g_pCVar = icvar;
    76 #endif
    77 	CONVAR_REGISTER(this);
    78 	AddRootConsoleCommand("version", "Display version information", this);
    79 	AddRootConsoleCommand("credits", "Display credits listing", this);
    80 }
    81 
    82 void RootConsoleMenu::OnSourceModAllInitialized()
    83 {
    84 	g_ConVarManager.AddConVarChangeListener("hostname", &s_HostnameChangeDetector);
    85 }
    86 
    87 void RootConsoleMenu::OnSourceModShutdown()
    88 {
    89 	g_ConVarManager.RemoveConVarChangeListener("hostname", &s_HostnameChangeDetector);
    90 	RemoveRootConsoleCommand("credits", this);
    91 	RemoveRootConsoleCommand("version", this);
    92 }
    93 
    94 bool RootConsoleMenu::RegisterConCommandBase(ConCommandBase *pCommand)
    95 {
    96 	META_REGCVAR(pCommand);
    97 
    98 	/* Override values of convars created by SourceMod convar manager if specified on command line */
    99 	const char *cmdLineValue = icvar->GetCommandLineValue(pCommand->GetName());
   100 	if (cmdLineValue && !pCommand->IsCommand())
   101 	{
   102 		static_cast<ConVar *>(pCommand)->SetValue(cmdLineValue);
   103 	}
   104 
   105 	return true;
   106 }
   107 
   108 void RootConsoleMenu::ConsolePrint(const char *fmt, ...)
   109 {
   110 	char buffer[512];
   111 
   112 	va_list ap;
   113 	va_start(ap, fmt);
   114 	size_t len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
   115 	va_end(ap);
   116 
   117 	if (len >= sizeof(buffer) - 1)
   118 	{
   119 		buffer[510] = '\n';
   120 		buffer[511] = '\0';
   121 	} else {
   122 		buffer[len++] = '\n';
   123 		buffer[len] = '\0';
   124 	}
   125 	
   126 	META_CONPRINT(buffer);
   127 }
   128 
   129 bool RootConsoleMenu::AddRootConsoleCommand(const char *cmd, const char *text, IRootConsoleCommand *pHandler)
   130 {
   131 	if (sm_trie_retrieve(m_pCommands, cmd, NULL))
   132 	{
   133 		return false;
   134 	}
   135 
   136 	sm_trie_insert(m_pCommands, cmd, pHandler);
   137 
   138 	/* Sort this into the menu */
   139 	List<ConsoleEntry *>::iterator iter = m_Menu.begin();
   140 	ConsoleEntry *pEntry;
   141 	bool inserted = false;
   142 	while (iter != m_Menu.end())
   143 	{
   144 		pEntry = (*iter);
   145 		if (strcmp(cmd, pEntry->command.c_str()) < 0)
   146 		{
   147 			ConsoleEntry *pNew = new ConsoleEntry;
   148 			pNew->command.assign(cmd);
   149 			pNew->description.assign(text);
   150 			m_Menu.insert(iter, pNew);
   151 			inserted = true;
   152 			break;
   153 		}
   154 		iter++;
   155 	}
   156 
   157 	if (!inserted)
   158 	{
   159 		ConsoleEntry *pNew = new ConsoleEntry;
   160 		pNew->command.assign(cmd);
   161 		pNew->description.assign(text);
   162 		m_Menu.push_back(pNew);
   163 	}
   164 
   165 	return true;
   166 }
   167 
   168 bool RootConsoleMenu::RemoveRootConsoleCommand(const char *cmd, IRootConsoleCommand *pHandler)
   169 {
   170 	/* Sanity tests */
   171 	IRootConsoleCommand *object;
   172 	if (sm_trie_retrieve(m_pCommands, cmd, (void **)&object))
   173 	{
   174 		if (object != pHandler)
   175 		{
   176 			return false;
   177 		}
   178 	} else {
   179 		return false;
   180 	}
   181 
   182 	sm_trie_delete(m_pCommands, cmd);
   183 
   184 	List<ConsoleEntry *>::iterator iter;
   185 	ConsoleEntry *pEntry;
   186 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
   187 	{
   188 		pEntry = (*iter);
   189 		if (pEntry->command.compare(cmd) == 0)
   190 		{
   191 			delete pEntry;
   192 			m_Menu.erase(iter);
   193 			break;
   194 		}
   195 	}
   196 
   197 	return true;
   198 }
   199 
   200 void RootConsoleMenu::DrawGenericOption(const char *cmd, const char *text)
   201 {
   202 	char buffer[255];
   203 	size_t len, cmdlen = strlen(cmd);
   204 
   205 	len = UTIL_Format(buffer, sizeof(buffer), "    %s", cmd);
   206 	if (cmdlen < 16)
   207 	{
   208 		size_t num = 16 - cmdlen;
   209 		for (size_t i = 0; i < num; i++)
   210 		{
   211 			buffer[len++] = ' ';
   212 		}
   213 		len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", text);
   214 		ConsolePrint("%s", buffer);
   215 	}
   216 }
   217 
   218 extern void _IntExt_EnableYams();
   219 
   220 void RootConsoleMenu::GotRootCmd(const CCommand &cmd)
   221 {
   222 	unsigned int argnum = cmd.ArgC();
   223 
   224 	if (argnum >= 2)
   225 	{
   226 		const char *cmdname = cmd.Arg(1);
   227 		if (strcmp(cmdname, "text") == 0)
   228 		{
   229 			_IntExt_EnableYams();
   230 			return;
   231 		}
   232 		else if (strcmp(cmdname, "internal") == 0)
   233 		{
   234 			if (argnum >= 3)
   235 			{
   236 				const char *arg = cmd.Arg(2);
   237 				if (strcmp(arg, "1") == 0)
   238 				{
   239 					SM_ConfigsExecuted_Global();
   240 				}
   241 				else if (strcmp(arg, "2") == 0)
   242 				{
   243 					if (argnum >= 4)
   244 					{
   245 						SM_ConfigsExecuted_Plugin(atoi(cmd.Arg(3)));
   246 					}
   247 				}
   248 			}
   249 			return;
   250 		}
   251 
   252 		IRootConsoleCommand *pHandler;
   253 		if (sm_trie_retrieve(m_pCommands, cmdname, (void **)&pHandler))
   254 		{
   255 			pHandler->OnRootConsoleCommand(cmdname, cmd);
   256 			return;
   257 		}
   258 	}
   259 
   260 	ConsolePrint("SourceMod Menu:");
   261 	ConsolePrint("Usage: sm <command> [arguments]");
   262 
   263 	List<ConsoleEntry *>::iterator iter;
   264 	ConsoleEntry *pEntry;
   265 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
   266 	{
   267 		pEntry = (*iter);
   268 		DrawGenericOption(pEntry->command.c_str(), pEntry->description.c_str());
   269 	}
   270 }
   271 
   272 void RootConsoleMenu::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
   273 {
   274 	if (strcmp(cmdname, "credits") == 0)
   275 	{
   276 		ConsolePrint(" SourceMod was developed by AlliedModders, LLC.");
   277 		ConsolePrint(" Development would not have been possible without the following people:");
   278 		ConsolePrint("  David \"BAILOPAN\" Anderson, lead developer");
   279 		ConsolePrint("  Borja \"faluco\" Ferrer, Core developer");
   280 		ConsolePrint("  Scott \"Damaged Soul\" Ehlert, Core developer");
   281 		ConsolePrint("  Pavol \"PM OnoTo\" Marko, SourceHook developer");
   282 		ConsolePrint(" Special thanks to Viper of GameConnect");
   283 		ConsolePrint(" Special thanks to Mani of Mani-Admin-Plugin");
   284 		ConsolePrint(" http://www.sourcemod.net/");
   285 	} else if (strcmp(cmdname, "version") == 0) {
   286 		ConsolePrint(" SourceMod Version Information:");
   287 		ConsolePrint("    SourceMod Version: %s", SVN_FULL_VERSION);
   288 		ConsolePrint("    JIT Version: %s, %s", g_pVM->GetVMName(), g_pVM->GetVersionString());
   289 		ConsolePrint("    JIT Settings: %s", g_pVM->GetCPUOptimizations());
   290 		ConsolePrint("    http://www.sourcemod.net/");
   291 	}
   292 }
   293 
   294 CON_COMMAND(sm, "SourceMod Menu")
   295 {
   296 #if !defined ORANGEBOX_BUILD
   297 	CCommand args;
   298 #endif
   299 	g_RootMenu.GotRootCmd(args);
   300 }
   301 
   302 FILE *g_pHndlLog = NULL;
   303 
   304 void write_handles_to_log(const char *fmt, ...)
   305 {
   306 	va_list ap;
   307 	
   308 	va_start(ap, fmt);
   309 	vfprintf(g_pHndlLog, fmt, ap);
   310 	fprintf(g_pHndlLog, "\n");
   311 	va_end(ap);
   312 }
   313 
   314 void write_handles_to_game(const char *fmt, ...)
   315 {
   316 	size_t len;
   317 	va_list ap;
   318 	char buffer[1024];
   319 	
   320 	va_start(ap, fmt);
   321 	len = UTIL_FormatArgs(buffer, sizeof(buffer)-2, fmt, ap);
   322 	va_end(ap);
   323 
   324 	buffer[len] = '\n';
   325 	buffer[len+1] = '\0';
   326 
   327 	engine->LogPrint(buffer);
   328 }
   329 
   330 CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle leaks")
   331 {
   332 #if !defined ORANGEBOX_BUILD
   333 	CCommand args;
   334 #endif
   335 	if (args.ArgC() < 2)
   336 	{
   337 		g_RootMenu.ConsolePrint("Usage: sm_dump_handles <file> or <log> for game logs");
   338 		return;
   339 	}
   340 
   341 	if (strcmp(args.Arg(1), "log") != 0)
   342 	{
   343 		const char *arg = args.Arg(1);
   344 		FILE *fp = fopen(arg, "wt");
   345 		if (!fp)
   346 		{
   347 			g_RootMenu.ConsolePrint("Could not find file \"%s\"", arg);
   348 			return;
   349 		}
   350 
   351 		g_pHndlLog = fp;
   352 		g_HandleSys.Dump(write_handles_to_log);
   353 		g_pHndlLog = NULL;
   354 
   355 		fclose(fp);
   356 	}
   357 	else
   358 	{
   359 		g_HandleSys.Dump(write_handles_to_game);
   360 	}
   361 }