core/sm_srvcmds.cpp
author David Anderson <dvander@alliedmods.net>
Fri Aug 30 10:16:28 2013 -0700 (2013-08-30)
changeset 4109 10eb68d668af
parent 4074 84b49d686a77
child 4116 3e58428d988f
permissions -rw-r--r--
Use Refcounted to manage to NativeEntry (bug 5852 part 4, r=ds).
     1 /**
     2  * vim: set ts=4 sw=4 tw=99 noet :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2009 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 <sourcemod_version.h>
    34 #include "sm_stringutil.h"
    35 #include "CoreConfig.h"
    36 #include "ConVarManager.h"
    37 #include "logic_bridge.h"
    38 
    39 RootConsoleMenu g_RootMenu;
    40 
    41 ConVar sourcemod_version("sourcemod_version", SM_VERSION_STRING, FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY, "SourceMod Version");
    42 
    43 RootConsoleMenu::RootConsoleMenu()
    44 {
    45 	m_CfgExecDone = false;
    46 }
    47 
    48 RootConsoleMenu::~RootConsoleMenu()
    49 {
    50 	List<ConsoleEntry *>::iterator iter;
    51 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
    52 	{
    53 		delete (*iter);
    54 	}
    55 	m_Menu.clear();
    56 }
    57 
    58 void RootConsoleMenu::OnSourceModStartup(bool late)
    59 {
    60 #if SOURCE_ENGINE >= SE_ORANGEBOX
    61 	g_pCVar = icvar;
    62 #endif
    63 	CONVAR_REGISTER(this);
    64 	AddRootConsoleCommand("version", "Display version information", this);
    65 	AddRootConsoleCommand("credits", "Display credits listing", this);
    66 }
    67 
    68 void RootConsoleMenu::OnSourceModAllInitialized()
    69 {
    70 	sharesys->AddInterface(NULL, this);
    71 }
    72 
    73 void RootConsoleMenu::OnSourceModShutdown()
    74 {
    75 	RemoveRootConsoleCommand("credits", this);
    76 	RemoveRootConsoleCommand("version", this);
    77 }
    78 
    79 bool RootConsoleMenu::RegisterConCommandBase(ConCommandBase *pCommand)
    80 {
    81 	META_REGCVAR(pCommand);
    82 
    83 	/* Override values of convars created by SourceMod convar manager if specified on command line */
    84 	const char *cmdLineValue = icvar->GetCommandLineValue(pCommand->GetName());
    85 	if (cmdLineValue && !pCommand->IsCommand())
    86 	{
    87 		static_cast<ConVar *>(pCommand)->SetValue(cmdLineValue);
    88 	}
    89 
    90 	return true;
    91 }
    92 
    93 void RootConsoleMenu::ConsolePrint(const char *fmt, ...)
    94 {
    95 	char buffer[512];
    96 
    97 	va_list ap;
    98 	va_start(ap, fmt);
    99 	size_t len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
   100 	va_end(ap);
   101 
   102 	if (len >= sizeof(buffer) - 1)
   103 	{
   104 		buffer[510] = '\n';
   105 		buffer[511] = '\0';
   106 	} else {
   107 		buffer[len++] = '\n';
   108 		buffer[len] = '\0';
   109 	}
   110 	
   111 	META_CONPRINT(buffer);
   112 }
   113 
   114 bool RootConsoleMenu::AddRootConsoleCommand(const char *cmd, const char *text, IRootConsoleCommand *pHandler)
   115 {
   116 	return _AddRootConsoleCommand(cmd, text, pHandler, false);
   117 }
   118 
   119 bool RootConsoleMenu::AddRootConsoleCommand2(const char *cmd, const char *text, IRootConsoleCommand *pHandler)
   120 {
   121 	return _AddRootConsoleCommand(cmd, text, pHandler, true);
   122 }
   123 
   124 bool RootConsoleMenu::_AddRootConsoleCommand(const char *cmd,
   125 											 const char *text,
   126 											 IRootConsoleCommand *pHandler,
   127 											 bool version2)
   128 {
   129 	if (m_Commands.contains(cmd))
   130 		return false;
   131 
   132 	/* Sort this into the menu */
   133 	List<ConsoleEntry *>::iterator iter = m_Menu.begin();
   134 	ConsoleEntry *pEntry;
   135 	bool inserted = false;
   136 	while (iter != m_Menu.end())
   137 	{
   138 		pEntry = (*iter);
   139 		if (strcmp(cmd, pEntry->command.c_str()) < 0)
   140 		{
   141 			ConsoleEntry *pNew = new ConsoleEntry;
   142 			pNew->command.assign(cmd);
   143 			pNew->description.assign(text);
   144 			pNew->version2 = version2;
   145 			pNew->cmd = pHandler;
   146 			m_Commands.insert(cmd, pNew);
   147 			m_Menu.insert(iter, pNew);
   148 			inserted = true;
   149 			break;
   150 		}
   151 		iter++;
   152 	}
   153 
   154 	if (!inserted)
   155 	{
   156 		ConsoleEntry *pNew = new ConsoleEntry;
   157 		pNew->command.assign(cmd);
   158 		pNew->description.assign(text);
   159 		pNew->version2 = version2;
   160 		pNew->cmd = pHandler;
   161 		m_Commands.insert(cmd, pNew);
   162 		m_Menu.push_back(pNew);
   163 	}
   164 
   165 	return true;
   166 }
   167 
   168 bool RootConsoleMenu::RemoveRootConsoleCommand(const char *cmd, IRootConsoleCommand *pHandler)
   169 {
   170 	m_Commands.remove(cmd);
   171 
   172 	List<ConsoleEntry *>::iterator iter;
   173 	ConsoleEntry *pEntry;
   174 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
   175 	{
   176 		pEntry = (*iter);
   177 		if (pEntry->command.compare(cmd) == 0)
   178 		{
   179 			delete pEntry;
   180 			m_Menu.erase(iter);
   181 			break;
   182 		}
   183 	}
   184 
   185 	return true;
   186 }
   187 
   188 void RootConsoleMenu::DrawGenericOption(const char *cmd, const char *text)
   189 {
   190 	char buffer[255];
   191 	size_t len, cmdlen = strlen(cmd);
   192 
   193 	len = UTIL_Format(buffer, sizeof(buffer), "    %s", cmd);
   194 	if (cmdlen < 16)
   195 	{
   196 		size_t num = 16 - cmdlen;
   197 		for (size_t i = 0; i < num; i++)
   198 		{
   199 			buffer[len++] = ' ';
   200 		}
   201 		len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", text);
   202 		ConsolePrint("%s", buffer);
   203 	}
   204 }
   205 
   206 const char *RootConsoleMenu::GetInterfaceName()
   207 {
   208 	return SMINTERFACE_ROOTCONSOLE_NAME;
   209 }
   210 
   211 unsigned int RootConsoleMenu::GetInterfaceVersion()
   212 {
   213 	return SMINTERFACE_ROOTCONSOLE_VERSION;
   214 }
   215 
   216 #if SOURCE_ENGINE==SE_EPISODEONE || SOURCE_ENGINE==SE_DARKMESSIAH
   217 class CCommandArgs : public ICommandArgs
   218 {
   219 public:
   220 	CCommandArgs(const CCommand& _cmd)
   221 	{
   222 	}
   223 	const char *Arg(int n) const
   224 	{
   225 		return engine->Cmd_Argv(n);
   226 	}
   227 	int ArgC() const
   228 	{
   229 		return engine->Cmd_Argc();
   230 	}
   231 	const char *ArgS() const
   232 	{
   233 		return engine->Cmd_Args();
   234 	}
   235 };
   236 #else
   237 class CCommandArgs : public ICommandArgs
   238 {
   239 	const CCommand *cmd;
   240 public:
   241 	CCommandArgs(const CCommand& _cmd) : cmd(&_cmd)
   242 	{
   243 	}
   244 	const char *Arg(int n) const
   245 	{
   246 		return cmd->Arg(n);
   247 	}
   248 	int ArgC() const
   249 	{
   250 		return cmd->ArgC();
   251 	}
   252 	const char *ArgS() const
   253 	{
   254 		return cmd->ArgS();
   255 	}
   256 };
   257 #endif
   258 
   259 void RootConsoleMenu::GotRootCmd(const CCommand &cmd)
   260 {
   261 	unsigned int argnum = cmd.ArgC();
   262 
   263 	if (argnum >= 2)
   264 	{
   265 		const char *cmdname = cmd.Arg(1);
   266 		if (strcmp(cmdname, "internal") == 0)
   267 		{
   268 			if (argnum >= 3)
   269 			{
   270 				const char *arg = cmd.Arg(2);
   271 				if (strcmp(arg, "1") == 0)
   272 				{
   273 					SM_ConfigsExecuted_Global();
   274 				}
   275 				else if (strcmp(arg, "2") == 0)
   276 				{
   277 					if (argnum >= 4)
   278 					{
   279 						SM_ConfigsExecuted_Plugin(atoi(cmd.Arg(3)));
   280 					}
   281 				}
   282 			}
   283 			return;
   284 		}
   285 
   286 		CCommandArgs ocmd(cmd);
   287 
   288 		ConsoleEntry *entry;
   289 		if (m_Commands.retrieve(cmdname, &entry))
   290 		{
   291 			if (entry->version2)
   292 			{
   293 				entry->cmd->OnRootConsoleCommand2(cmdname, &ocmd);
   294 			}
   295 			else
   296 			{
   297 				entry->cmd->OnRootConsoleCommand(cmdname, cmd);
   298 			}
   299 			return;
   300 		}
   301 	}
   302 
   303 	ConsolePrint("SourceMod Menu:");
   304 	ConsolePrint("Usage: sm <command> [arguments]");
   305 
   306 	List<ConsoleEntry *>::iterator iter;
   307 	ConsoleEntry *pEntry;
   308 	for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
   309 	{
   310 		pEntry = (*iter);
   311 		DrawGenericOption(pEntry->command.c_str(), pEntry->description.c_str());
   312 	}
   313 }
   314 
   315 void RootConsoleMenu::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
   316 {
   317 	if (strcmp(cmdname, "credits") == 0)
   318 	{
   319 		ConsolePrint(" SourceMod was developed by AlliedModders, LLC.");
   320 		ConsolePrint(" Development would not have been possible without the following people:");
   321 		ConsolePrint("  David \"BAILOPAN\" Anderson");
   322 		ConsolePrint("  Matt \"pRED\" Woodrow");
   323 		ConsolePrint("  Scott \"DS\" Ehlert");
   324 		ConsolePrint("  Fyren");
   325 		ConsolePrint("  Nicholas \"psychonic\" Hastings");
   326 		ConsolePrint("  Asher \"asherkin\" Baker");
   327 		ConsolePrint("  Borja \"faluco\" Ferrer");
   328 		ConsolePrint("  Pavol \"PM OnoTo\" Marko");
   329 		ConsolePrint(" Special thanks to Liam, ferret, and Mani");
   330 		ConsolePrint(" Special thanks to Viper and SteamFriends");
   331 		ConsolePrint(" http://www.sourcemod.net/");
   332 	}
   333 	else if (strcmp(cmdname, "version") == 0)
   334 	{
   335 		ConsolePrint(" SourceMod Version Information:");
   336 		ConsolePrint("    SourceMod Version: %s", SM_VERSION_STRING);
   337 		ConsolePrint("    SourcePawn Engine: %s (build %s)", g_pSourcePawn2->GetEngineName(), g_pSourcePawn2->GetVersionString());
   338 		ConsolePrint("    SourcePawn API: v1 = %d, v2 = %d", g_pSourcePawn->GetEngineAPIVersion(), g_pSourcePawn2->GetAPIVersion());
   339 		ConsolePrint("    Compiled on: %s %s", __DATE__, __TIME__);
   340 		ConsolePrint("    Build ID: %s", SM_BUILD_UNIQUEID);
   341 		ConsolePrint("    http://www.sourcemod.net/");
   342 	}
   343 }
   344 
   345 CON_COMMAND(sm, "SourceMod Menu")
   346 {
   347 #if SOURCE_ENGINE <= SE_DARKMESSIAH
   348 	CCommand args;
   349 #endif
   350 	g_RootMenu.GotRootCmd(args);
   351 }
   352 
   353 FILE *g_pHndlLog = NULL;
   354 
   355 void write_handles_to_log(const char *fmt, ...)
   356 {
   357 	va_list ap;
   358 	
   359 	va_start(ap, fmt);
   360 	vfprintf(g_pHndlLog, fmt, ap);
   361 	fprintf(g_pHndlLog, "\n");
   362 	va_end(ap);
   363 }
   364 
   365 void write_handles_to_game(const char *fmt, ...)
   366 {
   367 	size_t len;
   368 	va_list ap;
   369 	char buffer[1024];
   370 	
   371 	va_start(ap, fmt);
   372 	len = UTIL_FormatArgs(buffer, sizeof(buffer)-2, fmt, ap);
   373 	va_end(ap);
   374 
   375 	buffer[len] = '\n';
   376 	buffer[len+1] = '\0';
   377 
   378 	engine->LogPrint(buffer);
   379 }
   380 
   381 CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle leaks")
   382 {
   383 #if SOURCE_ENGINE <= SE_DARKMESSIAH
   384 	CCommand args;
   385 #endif
   386 	if (args.ArgC() < 2)
   387 	{
   388 		g_RootMenu.ConsolePrint("Usage: sm_dump_handles <file> or <log> for game logs");
   389 		return;
   390 	}
   391 
   392 	if (strcmp(args.Arg(1), "log") != 0)
   393 	{
   394 		const char *arg = args.Arg(1);
   395 		FILE *fp = fopen(arg, "wt");
   396 		if (!fp)
   397 		{
   398 			g_RootMenu.ConsolePrint("Could not find file \"%s\"", arg);
   399 			return;
   400 		}
   401 
   402 		g_pHndlLog = fp;
   403 		logicore.DumpHandles(write_handles_to_log);
   404 		g_pHndlLog = NULL;
   405 
   406 		fclose(fp);
   407 	}
   408 	else
   409 	{
   410 		logicore.DumpHandles(write_handles_to_game);
   411 	}
   412 }
   413