core/sm_srvcmds.cpp
author David Anderson <dvander@alliedmods.net>
Sun Aug 26 17:41:02 2007 +0000 (2007-08-26)
changeset 1369 bd9ccced1b1a
parent 1330 ab94316bb52b
child 1541 e46ad208b9b4
permissions -rw-r--r--
fixed amb834 - command callbacks could potentially occur on invalid clients in very rare cases
     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 
    38 RootConsoleMenu g_RootMenu;
    39 
    40 ConVar sourcemod_version("sourcemod_version", SVN_FULL_VERSION, FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY, "SourceMod Version");
    41 
    42 RootConsoleMenu::RootConsoleMenu()
    43 {
    44 	m_pCommands = sm_trie_create();
    45 	m_CfgExecDone = false;
    46 }
    47 
    48 RootConsoleMenu::~RootConsoleMenu()
    49 {
    50 	sm_trie_destroy(m_pCommands);
    51 
    52 	List<ConsoleEntry *>::iterator iter;
    53 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
    54 	{
    55 		delete (*iter);
    56 	}
    57 	m_Menu.clear();
    58 }
    59 
    60 extern void _IntExt_OnHostnameChanged(ConVar *pConVar, char const *oldValue);
    61 
    62 void RootConsoleMenu::OnSourceModStartup(bool late)
    63 {
    64 	ConCommandBaseMgr::OneTimeInit(this);
    65 	AddRootConsoleCommand("version", "Display version information", this);
    66 	AddRootConsoleCommand("credits", "Display credits listing", this);
    67 
    68 	ConVar *pHost = icvar->FindVar("hostname");
    69 	pHost->InstallChangeCallback(_IntExt_OnHostnameChanged);
    70 }
    71 
    72 void RootConsoleMenu::OnSourceModShutdown()
    73 {
    74 	RemoveRootConsoleCommand("credits", this);
    75 	RemoveRootConsoleCommand("version", this);
    76 }
    77 
    78 bool RootConsoleMenu::RegisterConCommandBase(ConCommandBase *pCommand)
    79 {
    80 	META_REGCVAR(pCommand);
    81 
    82 	/* Override values of convars created by SourceMod convar manager if specified on command line */
    83 	const char *cmdLineValue = icvar->GetCommandLineValue(pCommand->GetName());
    84 	if (cmdLineValue && !pCommand->IsCommand())
    85 	{
    86 		static_cast<ConVar *>(pCommand)->SetValue(cmdLineValue);
    87 	}
    88 
    89 	return true;
    90 }
    91 
    92 void RootConsoleMenu::ConsolePrint(const char *fmt, ...)
    93 {
    94 	char buffer[512];
    95 
    96 	va_list ap;
    97 	va_start(ap, fmt);
    98 	size_t len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
    99 	va_end(ap);
   100 
   101 	if (len >= sizeof(buffer) - 1)
   102 	{
   103 		buffer[510] = '\n';
   104 		buffer[511] = '\0';
   105 	} else {
   106 		buffer[len++] = '\n';
   107 		buffer[len] = '\0';
   108 	}
   109 	
   110 	META_CONPRINT(buffer);
   111 }
   112 
   113 bool RootConsoleMenu::AddRootConsoleCommand(const char *cmd, const char *text, IRootConsoleCommand *pHandler)
   114 {
   115 	if (sm_trie_retrieve(m_pCommands, cmd, NULL))
   116 	{
   117 		return false;
   118 	}
   119 
   120 	sm_trie_insert(m_pCommands, cmd, pHandler);
   121 
   122 	/* Sort this into the menu */
   123 	List<ConsoleEntry *>::iterator iter = m_Menu.begin();
   124 	ConsoleEntry *pEntry;
   125 	bool inserted = false;
   126 	while (iter != m_Menu.end())
   127 	{
   128 		pEntry = (*iter);
   129 		if (strcmp(cmd, pEntry->command.c_str()) < 0)
   130 		{
   131 			ConsoleEntry *pNew = new ConsoleEntry;
   132 			pNew->command.assign(cmd);
   133 			pNew->description.assign(text);
   134 			m_Menu.insert(iter, pNew);
   135 			inserted = true;
   136 			break;
   137 		}
   138 		iter++;
   139 	}
   140 
   141 	if (!inserted)
   142 	{
   143 		ConsoleEntry *pNew = new ConsoleEntry;
   144 		pNew->command.assign(cmd);
   145 		pNew->description.assign(text);
   146 		m_Menu.push_back(pNew);
   147 	}
   148 
   149 	return true;
   150 }
   151 
   152 bool RootConsoleMenu::RemoveRootConsoleCommand(const char *cmd, IRootConsoleCommand *pHandler)
   153 {
   154 	/* Sanity tests */
   155 	IRootConsoleCommand *object;
   156 	if (sm_trie_retrieve(m_pCommands, cmd, (void **)&object))
   157 	{
   158 		if (object != pHandler)
   159 		{
   160 			return false;
   161 		}
   162 	} else {
   163 		return false;
   164 	}
   165 
   166 	sm_trie_delete(m_pCommands, cmd);
   167 
   168 	List<ConsoleEntry *>::iterator iter;
   169 	ConsoleEntry *pEntry;
   170 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
   171 	{
   172 		pEntry = (*iter);
   173 		if (pEntry->command.compare(cmd) == 0)
   174 		{
   175 			delete pEntry;
   176 			m_Menu.erase(iter);
   177 			break;
   178 		}
   179 	}
   180 
   181 	return true;
   182 }
   183 
   184 void RootConsoleMenu::DrawGenericOption(const char *cmd, const char *text)
   185 {
   186 	char buffer[255];
   187 	size_t len, cmdlen = strlen(cmd);
   188 
   189 	len = UTIL_Format(buffer, sizeof(buffer), "    %s", cmd);
   190 	if (cmdlen < 16)
   191 	{
   192 		size_t num = 16 - cmdlen;
   193 		for (size_t i = 0; i < num; i++)
   194 		{
   195 			buffer[len++] = ' ';
   196 		}
   197 		len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", text);
   198 		ConsolePrint("%s", buffer);
   199 	}
   200 }
   201 
   202 extern void _IntExt_EnableYams();
   203 
   204 void RootConsoleMenu::GotRootCmd()
   205 {
   206 	unsigned int argnum = GetArgumentCount();
   207 
   208 	if (argnum >= 2)
   209 	{
   210 		const char *cmd = GetArgument(1);
   211 		if (strcmp(cmd, "text") == 0)
   212 		{
   213 			_IntExt_EnableYams();
   214 			return;
   215 		} else if (strcmp(cmd, "internal") == 0) {
   216 			if (argnum >= 3)
   217 			{
   218 				const char *arg = GetArgument(2);
   219 				if (strcmp(arg, "1") == 0)
   220 				{
   221 					SM_ConfigsExecuted_Global();
   222 				} else if (strcmp(arg, "2") == 0) {
   223 					if (argnum >= 4)
   224 					{
   225 						SM_ConfigsExecuted_Plugin(atoi(GetArgument(3)));
   226 					}
   227 				}
   228 			}
   229 			return;
   230 		}
   231 
   232 		IRootConsoleCommand *pHandler;
   233 		if (sm_trie_retrieve(m_pCommands, cmd, (void **)&pHandler))
   234 		{
   235 			pHandler->OnRootConsoleCommand(cmd, argnum);
   236 			return;
   237 		}
   238 	}
   239 
   240 	ConsolePrint("SourceMod Menu:");
   241 	ConsolePrint("Usage: sm <command> [arguments]");
   242 
   243 	List<ConsoleEntry *>::iterator iter;
   244 	ConsoleEntry *pEntry;
   245 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
   246 	{
   247 		pEntry = (*iter);
   248 		DrawGenericOption(pEntry->command.c_str(), pEntry->description.c_str());
   249 	}
   250 }
   251 
   252 const char *RootConsoleMenu::GetArgument(unsigned int argno)
   253 {
   254 	return engine->Cmd_Argv(argno);
   255 }
   256 
   257 const char *RootConsoleMenu::GetArguments()
   258 {
   259 	return engine->Cmd_Args();
   260 }
   261 
   262 unsigned int RootConsoleMenu::GetArgumentCount()
   263 {
   264 	return engine->Cmd_Argc();
   265 }
   266 
   267 void RootConsoleMenu::OnRootConsoleCommand(const char *cmd, unsigned int argcount)
   268 {
   269 	if (strcmp(cmd, "credits") == 0)
   270 	{
   271 		ConsolePrint(" SourceMod was developed by AlliedModders, LLC.");
   272 		ConsolePrint(" Development would not have been possible without the following people:");
   273 		ConsolePrint("  David \"BAILOPAN\" Anderson, lead developer");
   274 		ConsolePrint("  Borja \"faluco\" Ferrer, Core developer");
   275 		ConsolePrint("  Scott \"Damaged Soul\" Ehlert, Core developer");
   276 		ConsolePrint("  Pavol \"PM OnoTo\" Marko, SourceHook developer");
   277 		ConsolePrint(" Special thanks to Viper of GameConnect");
   278 		ConsolePrint(" Special thanks to Mani of Mani-Admin-Plugin");
   279 		ConsolePrint(" http://www.sourcemod.net/");
   280 	} else if (strcmp(cmd, "version") == 0) {
   281 		ConsolePrint(" SourceMod Version Information:");
   282 		ConsolePrint("    SourceMod Version: %s", SVN_FULL_VERSION);
   283 		ConsolePrint("    JIT Version: %s, %s", g_pVM->GetVMName(), g_pVM->GetVersionString());
   284 		ConsolePrint("    JIT Settings: %s", g_pVM->GetCPUOptimizations());
   285 		ConsolePrint("    http://www.sourcemod.net/");
   286 	}
   287 }
   288 
   289 CON_COMMAND(sm, "SourceMod Menu")
   290 {
   291 	g_RootMenu.GotRootCmd();
   292 }
   293 
   294 CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle leaks")
   295 {
   296 	if (engine->Cmd_Argc() < 2)
   297 	{
   298 		g_RootMenu.ConsolePrint("Usage: sm_dump_handles <file>");
   299 		return;
   300 	}
   301 
   302 	const char *arg = engine->Cmd_Argv(1);
   303 	FILE *fp = fopen(arg, "wt");
   304 	if (!fp)
   305 	{
   306 		g_RootMenu.ConsolePrint("Could not find file \"%s\"", arg);
   307 		return;
   308 	}
   309 
   310 	g_HandleSys.Dump(fp);
   311 
   312 	fclose(fp);
   313 }