core/sm_srvcmds.cpp
author David Anderson <dvander@alliedmods.net>
Wed Feb 27 13:49:57 2008 +0000 (2008-02-27)
changeset 1900 457329ae65bd
parent 1883 c9705da6f066
child 1902 ce912ad912a5
permissions -rw-r--r--
fixed amb1483 - GetEntPropString() rejected FIELD_MODELNAME/FIELD_SOUNDNAME
     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 #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 extern void _IntExt_OnHostnameChanged(ConVar *var, const char *pOldValue, float flOldValue);
    63 
    64 class DetectHostNameChanges : public IConVarChangeListener
    65 {
    66 public:
    67 	void OnConVarChanged(ConVar *pConVar, const char *oldValue, float flOldValue)
    68 	{
    69 		_IntExt_OnHostnameChanged(pConVar, oldValue, flOldValue);
    70 	}
    71 } s_HostnameChangeDetector;
    72 
    73 void RootConsoleMenu::OnSourceModStartup(bool late)
    74 {
    75 #if defined ORANGEBOX_BUILD
    76 	g_pCVar = icvar;
    77 #endif
    78 	CONVAR_REGISTER(this);
    79 	AddRootConsoleCommand("version", "Display version information", this);
    80 	AddRootConsoleCommand("credits", "Display credits listing", this);
    81 }
    82 
    83 void RootConsoleMenu::OnSourceModAllInitialized()
    84 {
    85 	g_ConVarManager.AddConVarChangeListener("hostname", &s_HostnameChangeDetector);
    86 	g_ShareSys.AddInterface(NULL, this);
    87 }
    88 
    89 void RootConsoleMenu::OnSourceModShutdown()
    90 {
    91 	g_ConVarManager.RemoveConVarChangeListener("hostname", &s_HostnameChangeDetector);
    92 	RemoveRootConsoleCommand("credits", this);
    93 	RemoveRootConsoleCommand("version", this);
    94 }
    95 
    96 bool RootConsoleMenu::RegisterConCommandBase(ConCommandBase *pCommand)
    97 {
    98 	META_REGCVAR(pCommand);
    99 
   100 	/* Override values of convars created by SourceMod convar manager if specified on command line */
   101 	const char *cmdLineValue = icvar->GetCommandLineValue(pCommand->GetName());
   102 	if (cmdLineValue && !pCommand->IsCommand())
   103 	{
   104 		static_cast<ConVar *>(pCommand)->SetValue(cmdLineValue);
   105 	}
   106 
   107 	return true;
   108 }
   109 
   110 void RootConsoleMenu::ConsolePrint(const char *fmt, ...)
   111 {
   112 	char buffer[512];
   113 
   114 	va_list ap;
   115 	va_start(ap, fmt);
   116 	size_t len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
   117 	va_end(ap);
   118 
   119 	if (len >= sizeof(buffer) - 1)
   120 	{
   121 		buffer[510] = '\n';
   122 		buffer[511] = '\0';
   123 	} else {
   124 		buffer[len++] = '\n';
   125 		buffer[len] = '\0';
   126 	}
   127 	
   128 	META_CONPRINT(buffer);
   129 }
   130 
   131 bool RootConsoleMenu::AddRootConsoleCommand(const char *cmd, const char *text, IRootConsoleCommand *pHandler)
   132 {
   133 	if (sm_trie_retrieve(m_pCommands, cmd, NULL))
   134 	{
   135 		return false;
   136 	}
   137 
   138 	sm_trie_insert(m_pCommands, cmd, pHandler);
   139 
   140 	/* Sort this into the menu */
   141 	List<ConsoleEntry *>::iterator iter = m_Menu.begin();
   142 	ConsoleEntry *pEntry;
   143 	bool inserted = false;
   144 	while (iter != m_Menu.end())
   145 	{
   146 		pEntry = (*iter);
   147 		if (strcmp(cmd, pEntry->command.c_str()) < 0)
   148 		{
   149 			ConsoleEntry *pNew = new ConsoleEntry;
   150 			pNew->command.assign(cmd);
   151 			pNew->description.assign(text);
   152 			m_Menu.insert(iter, pNew);
   153 			inserted = true;
   154 			break;
   155 		}
   156 		iter++;
   157 	}
   158 
   159 	if (!inserted)
   160 	{
   161 		ConsoleEntry *pNew = new ConsoleEntry;
   162 		pNew->command.assign(cmd);
   163 		pNew->description.assign(text);
   164 		m_Menu.push_back(pNew);
   165 	}
   166 
   167 	return true;
   168 }
   169 
   170 bool RootConsoleMenu::RemoveRootConsoleCommand(const char *cmd, IRootConsoleCommand *pHandler)
   171 {
   172 	/* Sanity tests */
   173 	IRootConsoleCommand *object;
   174 	if (sm_trie_retrieve(m_pCommands, cmd, (void **)&object))
   175 	{
   176 		if (object != pHandler)
   177 		{
   178 			return false;
   179 		}
   180 	} else {
   181 		return false;
   182 	}
   183 
   184 	sm_trie_delete(m_pCommands, cmd);
   185 
   186 	List<ConsoleEntry *>::iterator iter;
   187 	ConsoleEntry *pEntry;
   188 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
   189 	{
   190 		pEntry = (*iter);
   191 		if (pEntry->command.compare(cmd) == 0)
   192 		{
   193 			delete pEntry;
   194 			m_Menu.erase(iter);
   195 			break;
   196 		}
   197 	}
   198 
   199 	return true;
   200 }
   201 
   202 void RootConsoleMenu::DrawGenericOption(const char *cmd, const char *text)
   203 {
   204 	char buffer[255];
   205 	size_t len, cmdlen = strlen(cmd);
   206 
   207 	len = UTIL_Format(buffer, sizeof(buffer), "    %s", cmd);
   208 	if (cmdlen < 16)
   209 	{
   210 		size_t num = 16 - cmdlen;
   211 		for (size_t i = 0; i < num; i++)
   212 		{
   213 			buffer[len++] = ' ';
   214 		}
   215 		len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", text);
   216 		ConsolePrint("%s", buffer);
   217 	}
   218 }
   219 
   220 const char *RootConsoleMenu::GetInterfaceName()
   221 {
   222 	return SMINTERFACE_ROOTCONSOLE_NAME;
   223 }
   224 
   225 unsigned int RootConsoleMenu::GetInterfaceVersion()
   226 {
   227 	return SMINTERFACE_ROOTCONSOLE_VERSION;
   228 }
   229 
   230 extern void _IntExt_EnableYams();
   231 
   232 void RootConsoleMenu::GotRootCmd(const CCommand &cmd)
   233 {
   234 	unsigned int argnum = cmd.ArgC();
   235 
   236 	if (argnum >= 2)
   237 	{
   238 		const char *cmdname = cmd.Arg(1);
   239 		if (strcmp(cmdname, "text") == 0)
   240 		{
   241 			_IntExt_EnableYams();
   242 			return;
   243 		}
   244 		else if (strcmp(cmdname, "internal") == 0)
   245 		{
   246 			if (argnum >= 3)
   247 			{
   248 				const char *arg = cmd.Arg(2);
   249 				if (strcmp(arg, "1") == 0)
   250 				{
   251 					SM_ConfigsExecuted_Global();
   252 				}
   253 				else if (strcmp(arg, "2") == 0)
   254 				{
   255 					if (argnum >= 4)
   256 					{
   257 						SM_ConfigsExecuted_Plugin(atoi(cmd.Arg(3)));
   258 					}
   259 				}
   260 			}
   261 			return;
   262 		}
   263 
   264 		IRootConsoleCommand *pHandler;
   265 		if (sm_trie_retrieve(m_pCommands, cmdname, (void **)&pHandler))
   266 		{
   267 			pHandler->OnRootConsoleCommand(cmdname, cmd);
   268 			return;
   269 		}
   270 	}
   271 
   272 	ConsolePrint("SourceMod Menu:");
   273 	ConsolePrint("Usage: sm <command> [arguments]");
   274 
   275 	List<ConsoleEntry *>::iterator iter;
   276 	ConsoleEntry *pEntry;
   277 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
   278 	{
   279 		pEntry = (*iter);
   280 		DrawGenericOption(pEntry->command.c_str(), pEntry->description.c_str());
   281 	}
   282 }
   283 
   284 void RootConsoleMenu::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
   285 {
   286 	if (strcmp(cmdname, "credits") == 0)
   287 	{
   288 		ConsolePrint(" SourceMod was developed by AlliedModders, LLC.");
   289 		ConsolePrint(" Development would not have been possible without the following people:");
   290 		ConsolePrint("  David \"BAILOPAN\" Anderson, lead developer");
   291 		ConsolePrint("  Borja \"faluco\" Ferrer, Core developer");
   292 		ConsolePrint("  Scott \"Damaged Soul\" Ehlert, Core developer");
   293 		ConsolePrint("  Pavol \"PM OnoTo\" Marko, SourceHook developer");
   294 		ConsolePrint(" Special thanks to Viper of GameConnect");
   295 		ConsolePrint(" Special thanks to Mani of Mani-Admin-Plugin");
   296 		ConsolePrint(" http://www.sourcemod.net/");
   297 	} else if (strcmp(cmdname, "version") == 0) {
   298 		ConsolePrint(" SourceMod Version Information:");
   299 		ConsolePrint("    SourceMod Version: %s", SVN_FULL_VERSION);
   300 		ConsolePrint("    JIT Version: %s, %s", g_pVM->GetVMName(), g_pVM->GetVersionString());
   301 		ConsolePrint("    JIT Settings: %s", g_pVM->GetCPUOptimizations());
   302 		ConsolePrint("    http://www.sourcemod.net/");
   303 	}
   304 }
   305 
   306 CON_COMMAND(sm, "SourceMod Menu")
   307 {
   308 #if !defined ORANGEBOX_BUILD
   309 	CCommand args;
   310 #endif
   311 	g_RootMenu.GotRootCmd(args);
   312 }
   313 
   314 FILE *g_pHndlLog = NULL;
   315 
   316 void write_handles_to_log(const char *fmt, ...)
   317 {
   318 	va_list ap;
   319 	
   320 	va_start(ap, fmt);
   321 	vfprintf(g_pHndlLog, fmt, ap);
   322 	fprintf(g_pHndlLog, "\n");
   323 	va_end(ap);
   324 }
   325 
   326 void write_handles_to_game(const char *fmt, ...)
   327 {
   328 	size_t len;
   329 	va_list ap;
   330 	char buffer[1024];
   331 	
   332 	va_start(ap, fmt);
   333 	len = UTIL_FormatArgs(buffer, sizeof(buffer)-2, fmt, ap);
   334 	va_end(ap);
   335 
   336 	buffer[len] = '\n';
   337 	buffer[len+1] = '\0';
   338 
   339 	engine->LogPrint(buffer);
   340 }
   341 
   342 CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle leaks")
   343 {
   344 #if !defined ORANGEBOX_BUILD
   345 	CCommand args;
   346 #endif
   347 	if (args.ArgC() < 2)
   348 	{
   349 		g_RootMenu.ConsolePrint("Usage: sm_dump_handles <file> or <log> for game logs");
   350 		return;
   351 	}
   352 
   353 	if (strcmp(args.Arg(1), "log") != 0)
   354 	{
   355 		const char *arg = args.Arg(1);
   356 		FILE *fp = fopen(arg, "wt");
   357 		if (!fp)
   358 		{
   359 			g_RootMenu.ConsolePrint("Could not find file \"%s\"", arg);
   360 			return;
   361 		}
   362 
   363 		g_pHndlLog = fp;
   364 		g_HandleSys.Dump(write_handles_to_log);
   365 		g_pHndlLog = NULL;
   366 
   367 		fclose(fp);
   368 	}
   369 	else
   370 	{
   371 		g_HandleSys.Dump(write_handles_to_game);
   372 	}
   373 }