core/sm_srvcmds.cpp
author Scott Ehlert <ds@alliedmods.net>
Sat Jul 12 09:05:19 2008 +0000 (2008-07-12)
changeset 2201 d2b8bc01ccd8
parent 2193 db7c6362f3f2
child 2281 fcb07f41ad91
permissions -rw-r--r--
Builds against latest OB SDK now
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 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 #include "ShareSys.h"
    39 
    40 RootConsoleMenu g_RootMenu;
    41 
    42 ConVar sourcemod_version("sourcemod_version", SVN_FULL_VERSION, FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY, "SourceMod Version");
    43 
    44 RootConsoleMenu::RootConsoleMenu()
    45 {
    46 	m_pCommands = sm_trie_create();
    47 	m_CfgExecDone = false;
    48 }
    49 
    50 RootConsoleMenu::~RootConsoleMenu()
    51 {
    52 	sm_trie_destroy(m_pCommands);
    53 
    54 	List<ConsoleEntry *>::iterator iter;
    55 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
    56 	{
    57 		delete (*iter);
    58 	}
    59 	m_Menu.clear();
    60 }
    61 
    62 void RootConsoleMenu::OnSourceModStartup(bool late)
    63 {
    64 #if defined ORANGEBOX_BUILD
    65 	g_pCVar = icvar;
    66 #endif
    67 	CONVAR_REGISTER(this);
    68 	AddRootConsoleCommand("version", "Display version information", this);
    69 	AddRootConsoleCommand("credits", "Display credits listing", this);
    70 }
    71 
    72 void RootConsoleMenu::OnSourceModAllInitialized()
    73 {
    74 	g_ShareSys.AddInterface(NULL, this);
    75 }
    76 
    77 void RootConsoleMenu::OnSourceModShutdown()
    78 {
    79 	RemoveRootConsoleCommand("credits", this);
    80 	RemoveRootConsoleCommand("version", this);
    81 }
    82 
    83 bool RootConsoleMenu::RegisterConCommandBase(ConCommandBase *pCommand)
    84 {
    85 	META_REGCVAR(pCommand);
    86 
    87 	/* Override values of convars created by SourceMod convar manager if specified on command line */
    88 	const char *cmdLineValue = icvar->GetCommandLineValue(pCommand->GetName());
    89 	if (cmdLineValue && !pCommand->IsCommand())
    90 	{
    91 		static_cast<ConVar *>(pCommand)->SetValue(cmdLineValue);
    92 	}
    93 
    94 	return true;
    95 }
    96 
    97 void RootConsoleMenu::ConsolePrint(const char *fmt, ...)
    98 {
    99 	char buffer[512];
   100 
   101 	va_list ap;
   102 	va_start(ap, fmt);
   103 	size_t len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
   104 	va_end(ap);
   105 
   106 	if (len >= sizeof(buffer) - 1)
   107 	{
   108 		buffer[510] = '\n';
   109 		buffer[511] = '\0';
   110 	} else {
   111 		buffer[len++] = '\n';
   112 		buffer[len] = '\0';
   113 	}
   114 	
   115 	META_CONPRINT(buffer);
   116 }
   117 
   118 bool RootConsoleMenu::AddRootConsoleCommand(const char *cmd, const char *text, IRootConsoleCommand *pHandler)
   119 {
   120 	if (sm_trie_retrieve(m_pCommands, cmd, NULL))
   121 	{
   122 		return false;
   123 	}
   124 
   125 	sm_trie_insert(m_pCommands, cmd, pHandler);
   126 
   127 	/* Sort this into the menu */
   128 	List<ConsoleEntry *>::iterator iter = m_Menu.begin();
   129 	ConsoleEntry *pEntry;
   130 	bool inserted = false;
   131 	while (iter != m_Menu.end())
   132 	{
   133 		pEntry = (*iter);
   134 		if (strcmp(cmd, pEntry->command.c_str()) < 0)
   135 		{
   136 			ConsoleEntry *pNew = new ConsoleEntry;
   137 			pNew->command.assign(cmd);
   138 			pNew->description.assign(text);
   139 			m_Menu.insert(iter, pNew);
   140 			inserted = true;
   141 			break;
   142 		}
   143 		iter++;
   144 	}
   145 
   146 	if (!inserted)
   147 	{
   148 		ConsoleEntry *pNew = new ConsoleEntry;
   149 		pNew->command.assign(cmd);
   150 		pNew->description.assign(text);
   151 		m_Menu.push_back(pNew);
   152 	}
   153 
   154 	return true;
   155 }
   156 
   157 bool RootConsoleMenu::RemoveRootConsoleCommand(const char *cmd, IRootConsoleCommand *pHandler)
   158 {
   159 	/* Sanity tests */
   160 	IRootConsoleCommand *object;
   161 	if (sm_trie_retrieve(m_pCommands, cmd, (void **)&object))
   162 	{
   163 		if (object != pHandler)
   164 		{
   165 			return false;
   166 		}
   167 	} else {
   168 		return false;
   169 	}
   170 
   171 	sm_trie_delete(m_pCommands, cmd);
   172 
   173 	List<ConsoleEntry *>::iterator iter;
   174 	ConsoleEntry *pEntry;
   175 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
   176 	{
   177 		pEntry = (*iter);
   178 		if (pEntry->command.compare(cmd) == 0)
   179 		{
   180 			delete pEntry;
   181 			m_Menu.erase(iter);
   182 			break;
   183 		}
   184 	}
   185 
   186 	return true;
   187 }
   188 
   189 void RootConsoleMenu::DrawGenericOption(const char *cmd, const char *text)
   190 {
   191 	char buffer[255];
   192 	size_t len, cmdlen = strlen(cmd);
   193 
   194 	len = UTIL_Format(buffer, sizeof(buffer), "    %s", cmd);
   195 	if (cmdlen < 16)
   196 	{
   197 		size_t num = 16 - cmdlen;
   198 		for (size_t i = 0; i < num; i++)
   199 		{
   200 			buffer[len++] = ' ';
   201 		}
   202 		len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", text);
   203 		ConsolePrint("%s", buffer);
   204 	}
   205 }
   206 
   207 const char *RootConsoleMenu::GetInterfaceName()
   208 {
   209 	return SMINTERFACE_ROOTCONSOLE_NAME;
   210 }
   211 
   212 unsigned int RootConsoleMenu::GetInterfaceVersion()
   213 {
   214 	return SMINTERFACE_ROOTCONSOLE_VERSION;
   215 }
   216 
   217 void RootConsoleMenu::GotRootCmd(const CCommand &cmd)
   218 {
   219 	unsigned int argnum = cmd.ArgC();
   220 
   221 	if (argnum >= 2)
   222 	{
   223 		const char *cmdname = cmd.Arg(1);
   224 		if (strcmp(cmdname, "internal") == 0)
   225 		{
   226 			if (argnum >= 3)
   227 			{
   228 				const char *arg = cmd.Arg(2);
   229 				if (strcmp(arg, "1") == 0)
   230 				{
   231 					SM_ConfigsExecuted_Global();
   232 				}
   233 				else if (strcmp(arg, "2") == 0)
   234 				{
   235 					if (argnum >= 4)
   236 					{
   237 						SM_ConfigsExecuted_Plugin(atoi(cmd.Arg(3)));
   238 					}
   239 				}
   240 			}
   241 			return;
   242 		}
   243 
   244 		IRootConsoleCommand *pHandler;
   245 		if (sm_trie_retrieve(m_pCommands, cmdname, (void **)&pHandler))
   246 		{
   247 			pHandler->OnRootConsoleCommand(cmdname, cmd);
   248 			return;
   249 		}
   250 	}
   251 
   252 	ConsolePrint("SourceMod Menu:");
   253 	ConsolePrint("Usage: sm <command> [arguments]");
   254 
   255 	List<ConsoleEntry *>::iterator iter;
   256 	ConsoleEntry *pEntry;
   257 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
   258 	{
   259 		pEntry = (*iter);
   260 		DrawGenericOption(pEntry->command.c_str(), pEntry->description.c_str());
   261 	}
   262 }
   263 
   264 void RootConsoleMenu::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
   265 {
   266 	if (strcmp(cmdname, "credits") == 0)
   267 	{
   268 		ConsolePrint(" SourceMod was developed by AlliedModders, LLC.");
   269 		ConsolePrint(" Development would not have been possible without the following people:");
   270 		ConsolePrint("  David \"BAILOPAN\" Anderson, lead developer");
   271 		ConsolePrint("  Borja \"faluco\" Ferrer, core developer");
   272 		ConsolePrint("  Scott \"Damaged Soul\" Ehlert, core developer");
   273 		ConsolePrint("  Matt \"pRED\" Woodrow, core developer");
   274 		ConsolePrint("  Michael \"ferret\" McKoy, plugin developer");
   275 		ConsolePrint("  Pavol \"PM OnoTo\" Marko, SourceHook developer");
   276 		ConsolePrint(" Special thanks to Viper of GameConnect");
   277 		ConsolePrint(" Special thanks to Mani of Mani-Admin-Plugin");
   278 		ConsolePrint(" http://www.sourcemod.net/");
   279 	}
   280 	else if (strcmp(cmdname, "version") == 0)
   281 	{
   282 		ConsolePrint(" SourceMod Version Information:");
   283 		ConsolePrint("    SourceMod Version: %s", SVN_FULL_VERSION);
   284 		ConsolePrint("    SourcePawn Engine: %s (build %s)", g_pSourcePawn2->GetEngineName(), g_pSourcePawn2->GetVersionString());
   285 		ConsolePrint("    SourcePawn API: v1 = %d, v2 = %d", g_pSourcePawn->GetEngineAPIVersion(), g_pSourcePawn2->GetAPIVersion());
   286 		ConsolePrint("    Compiled on: %s %s", __DATE__, __TIME__);
   287 		ConsolePrint("    http://www.sourcemod.net/");
   288 	}
   289 }
   290 
   291 CON_COMMAND(sm, "SourceMod Menu")
   292 {
   293 #if !defined ORANGEBOX_BUILD
   294 	CCommand args;
   295 #endif
   296 	g_RootMenu.GotRootCmd(args);
   297 }
   298 
   299 FILE *g_pHndlLog = NULL;
   300 
   301 void write_handles_to_log(const char *fmt, ...)
   302 {
   303 	va_list ap;
   304 	
   305 	va_start(ap, fmt);
   306 	vfprintf(g_pHndlLog, fmt, ap);
   307 	fprintf(g_pHndlLog, "\n");
   308 	va_end(ap);
   309 }
   310 
   311 void write_handles_to_game(const char *fmt, ...)
   312 {
   313 	size_t len;
   314 	va_list ap;
   315 	char buffer[1024];
   316 	
   317 	va_start(ap, fmt);
   318 	len = UTIL_FormatArgs(buffer, sizeof(buffer)-2, fmt, ap);
   319 	va_end(ap);
   320 
   321 	buffer[len] = '\n';
   322 	buffer[len+1] = '\0';
   323 
   324 	engine->LogPrint(buffer);
   325 }
   326 
   327 CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle leaks")
   328 {
   329 #if !defined ORANGEBOX_BUILD
   330 	CCommand args;
   331 #endif
   332 	if (args.ArgC() < 2)
   333 	{
   334 		g_RootMenu.ConsolePrint("Usage: sm_dump_handles <file> or <log> for game logs");
   335 		return;
   336 	}
   337 
   338 	if (strcmp(args.Arg(1), "log") != 0)
   339 	{
   340 		const char *arg = args.Arg(1);
   341 		FILE *fp = fopen(arg, "wt");
   342 		if (!fp)
   343 		{
   344 			g_RootMenu.ConsolePrint("Could not find file \"%s\"", arg);
   345 			return;
   346 		}
   347 
   348 		g_pHndlLog = fp;
   349 		g_HandleSys.Dump(write_handles_to_log);
   350 		g_pHndlLog = NULL;
   351 
   352 		fclose(fp);
   353 	}
   354 	else
   355 	{
   356 		g_HandleSys.Dump(write_handles_to_game);
   357 	}
   358 }