/**
* vim: set ts=4 sw=4 tw=99 noet :
* =============================================================================
* SourceMod
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see .
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or .
*
* Version: $Id$
*/
#include "sm_srvcmds.h"
#include "sm_stringutil.h"
#include "CoreConfig.h"
#include "ConVarManager.h"
#include "logic_bridge.h"
#include
RootConsoleMenu g_RootMenu;
ConVar sourcemod_version("sourcemod_version", SOURCEMOD_VERSION, FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY, "SourceMod Version");
RootConsoleMenu::RootConsoleMenu()
{
m_CfgExecDone = false;
}
RootConsoleMenu::~RootConsoleMenu()
{
List::iterator iter;
for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
{
delete (*iter);
}
m_Menu.clear();
}
void RootConsoleMenu::OnSourceModStartup(bool late)
{
#if SOURCE_ENGINE >= SE_ORANGEBOX
g_pCVar = icvar;
#endif
CONVAR_REGISTER(this);
AddRootConsoleCommand("version", "Display version information", this);
AddRootConsoleCommand("credits", "Display credits listing", this);
}
void RootConsoleMenu::OnSourceModAllInitialized()
{
sharesys->AddInterface(NULL, this);
}
void RootConsoleMenu::OnSourceModShutdown()
{
RemoveRootConsoleCommand("credits", this);
RemoveRootConsoleCommand("version", this);
}
bool RootConsoleMenu::RegisterConCommandBase(ConCommandBase *pCommand)
{
META_REGCVAR(pCommand);
/* Override values of convars created by SourceMod convar manager if specified on command line */
const char *cmdLineValue = icvar->GetCommandLineValue(pCommand->GetName());
if (cmdLineValue && !pCommand->IsCommand())
{
static_cast(pCommand)->SetValue(cmdLineValue);
}
return true;
}
void RootConsoleMenu::ConsolePrint(const char *fmt, ...)
{
char buffer[512];
va_list ap;
va_start(ap, fmt);
size_t len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
if (len >= sizeof(buffer) - 1)
{
buffer[510] = '\n';
buffer[511] = '\0';
} else {
buffer[len++] = '\n';
buffer[len] = '\0';
}
META_CONPRINT(buffer);
}
bool RootConsoleMenu::AddRootConsoleCommand(const char *cmd, const char *text, IRootConsoleCommand *pHandler)
{
return _AddRootConsoleCommand(cmd, text, pHandler, false);
}
bool RootConsoleMenu::AddRootConsoleCommand2(const char *cmd, const char *text, IRootConsoleCommand *pHandler)
{
return _AddRootConsoleCommand(cmd, text, pHandler, true);
}
bool RootConsoleMenu::_AddRootConsoleCommand(const char *cmd,
const char *text,
IRootConsoleCommand *pHandler,
bool version2)
{
if (m_Commands.contains(cmd))
return false;
/* Sort this into the menu */
List::iterator iter = m_Menu.begin();
ConsoleEntry *pEntry;
bool inserted = false;
while (iter != m_Menu.end())
{
pEntry = (*iter);
if (strcmp(cmd, pEntry->command.c_str()) < 0)
{
ConsoleEntry *pNew = new ConsoleEntry;
pNew->command.assign(cmd);
pNew->description.assign(text);
pNew->version2 = version2;
pNew->cmd = pHandler;
m_Commands.insert(cmd, pNew);
m_Menu.insert(iter, pNew);
inserted = true;
break;
}
iter++;
}
if (!inserted)
{
ConsoleEntry *pNew = new ConsoleEntry;
pNew->command.assign(cmd);
pNew->description.assign(text);
pNew->version2 = version2;
pNew->cmd = pHandler;
m_Commands.insert(cmd, pNew);
m_Menu.push_back(pNew);
}
return true;
}
bool RootConsoleMenu::RemoveRootConsoleCommand(const char *cmd, IRootConsoleCommand *pHandler)
{
m_Commands.remove(cmd);
List::iterator iter;
ConsoleEntry *pEntry;
for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
{
pEntry = (*iter);
if (pEntry->command.compare(cmd) == 0)
{
delete pEntry;
m_Menu.erase(iter);
break;
}
}
return true;
}
void RootConsoleMenu::DrawGenericOption(const char *cmd, const char *text)
{
char buffer[255];
size_t len, cmdlen = strlen(cmd);
len = UTIL_Format(buffer, sizeof(buffer), " %s", cmd);
if (cmdlen < 16)
{
size_t num = 16 - cmdlen;
for (size_t i = 0; i < num; i++)
{
buffer[len++] = ' ';
}
len += snprintf(&buffer[len], sizeof(buffer) - len, " - %s", text);
ConsolePrint("%s", buffer);
}
}
const char *RootConsoleMenu::GetInterfaceName()
{
return SMINTERFACE_ROOTCONSOLE_NAME;
}
unsigned int RootConsoleMenu::GetInterfaceVersion()
{
return SMINTERFACE_ROOTCONSOLE_VERSION;
}
#if SOURCE_ENGINE==SE_EPISODEONE || SOURCE_ENGINE==SE_DARKMESSIAH
class CCommandArgs : public ICommandArgs
{
public:
CCommandArgs(const CCommand& _cmd)
{
}
const char *Arg(int n) const
{
return engine->Cmd_Argv(n);
}
int ArgC() const
{
return engine->Cmd_Argc();
}
const char *ArgS() const
{
return engine->Cmd_Args();
}
};
#else
class CCommandArgs : public ICommandArgs
{
const CCommand *cmd;
public:
CCommandArgs(const CCommand& _cmd) : cmd(&_cmd)
{
}
const char *Arg(int n) const
{
return cmd->Arg(n);
}
int ArgC() const
{
return cmd->ArgC();
}
const char *ArgS() const
{
return cmd->ArgS();
}
};
#endif
void RootConsoleMenu::GotRootCmd(const CCommand &cmd)
{
unsigned int argnum = cmd.ArgC();
if (argnum >= 2)
{
const char *cmdname = cmd.Arg(1);
if (strcmp(cmdname, "internal") == 0)
{
if (argnum >= 3)
{
const char *arg = cmd.Arg(2);
if (strcmp(arg, "1") == 0)
{
SM_ConfigsExecuted_Global();
}
else if (strcmp(arg, "2") == 0)
{
if (argnum >= 4)
{
SM_ConfigsExecuted_Plugin(atoi(cmd.Arg(3)));
}
}
}
return;
}
CCommandArgs ocmd(cmd);
ConsoleEntry *entry;
if (m_Commands.retrieve(cmdname, &entry))
{
if (entry->version2)
{
entry->cmd->OnRootConsoleCommand2(cmdname, &ocmd);
}
else
{
entry->cmd->OnRootConsoleCommand(cmdname, cmd);
}
return;
}
}
ConsolePrint("SourceMod Menu:");
ConsolePrint("Usage: sm [arguments]");
List::iterator iter;
ConsoleEntry *pEntry;
for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
{
pEntry = (*iter);
DrawGenericOption(pEntry->command.c_str(), pEntry->description.c_str());
}
}
void RootConsoleMenu::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
{
if (strcmp(cmdname, "credits") == 0)
{
ConsolePrint(" SourceMod was developed by AlliedModders, LLC.");
ConsolePrint(" Development would not have been possible without the following people:");
ConsolePrint(" David \"BAILOPAN\" Anderson");
ConsolePrint(" Matt \"pRED\" Woodrow");
ConsolePrint(" Scott \"DS\" Ehlert");
ConsolePrint(" Fyren");
ConsolePrint(" Nicholas \"psychonic\" Hastings");
ConsolePrint(" Asher \"asherkin\" Baker");
ConsolePrint(" Borja \"faluco\" Ferrer");
ConsolePrint(" Pavol \"PM OnoTo\" Marko");
ConsolePrint(" Special thanks to Liam, ferret, and Mani");
ConsolePrint(" Special thanks to Viper and SteamFriends");
ConsolePrint(" http://www.sourcemod.net/");
}
else if (strcmp(cmdname, "version") == 0)
{
ConsolePrint(" SourceMod Version Information:");
ConsolePrint(" SourceMod Version: %s", SOURCEMOD_VERSION);
if (g_pSourcePawn2->IsJitEnabled())
ConsolePrint(" SourcePawn Engine: %s (build %s)", g_pSourcePawn2->GetEngineName(), g_pSourcePawn2->GetVersionString());
else
ConsolePrint(" SourcePawn Engine: %s (build %s NO JIT)", g_pSourcePawn2->GetEngineName(), g_pSourcePawn2->GetVersionString());
ConsolePrint(" SourcePawn API: v1 = %d, v2 = %d", g_pSourcePawn->GetEngineAPIVersion(), g_pSourcePawn2->GetAPIVersion());
ConsolePrint(" Compiled on: %s %s", __DATE__, __TIME__);
ConsolePrint(" Build ID: %s", SOURCEMOD_BUILD_ID);
ConsolePrint(" http://www.sourcemod.net/");
}
}
CON_COMMAND(sm, "SourceMod Menu")
{
#if SOURCE_ENGINE <= SE_DARKMESSIAH
CCommand args;
#endif
g_RootMenu.GotRootCmd(args);
}
FILE *g_pHndlLog = NULL;
void write_handles_to_log(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(g_pHndlLog, fmt, ap);
fprintf(g_pHndlLog, "\n");
va_end(ap);
}
void write_handles_to_game(const char *fmt, ...)
{
size_t len;
va_list ap;
char buffer[1024];
va_start(ap, fmt);
len = UTIL_FormatArgs(buffer, sizeof(buffer)-2, fmt, ap);
va_end(ap);
buffer[len] = '\n';
buffer[len+1] = '\0';
engine->LogPrint(buffer);
}
CON_COMMAND(sm_dump_handles, "Dumps Handle usage to a file for finding Handle leaks")
{
#if SOURCE_ENGINE <= SE_DARKMESSIAH
CCommand args;
#endif
if (args.ArgC() < 2)
{
g_RootMenu.ConsolePrint("Usage: sm_dump_handles or for game logs");
return;
}
if (strcmp(args.Arg(1), "log") != 0)
{
const char *arg = args.Arg(1);
FILE *fp = fopen(arg, "wt");
if (!fp)
{
g_RootMenu.ConsolePrint("Could not find file \"%s\"", arg);
return;
}
g_pHndlLog = fp;
logicore.DumpHandles(write_handles_to_log);
g_pHndlLog = NULL;
fclose(fp);
}
else
{
logicore.DumpHandles(write_handles_to_game);
}
}
CON_COMMAND(sm_reload_translations, "Reparses all loaded translation files")
{
translator->RebuildLanguageDatabase();
}