sourcemod/core/logic/RootConsoleMenu.cpp
2018-03-19 20:12:51 +00:00

290 lines
8.1 KiB
C++

// 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 <http://www.gnu.org/licenses/>.
//
// 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 <http://www.sourcemod.net/license.php>.
#include "RootConsoleMenu.h"
#include <amtl/am-string.h>
#include <sourcemod_version.h>
#include <ISourceMod.h>
#include <bridge/include/CoreProvider.h>
#include "HandleSys.h"
RootConsoleMenu g_RootMenu;
// Some top-level commands that are just thrown in here.
static bool sm_dump_handles(int client, const ICommandArgs *args);
RootConsoleMenu::RootConsoleMenu()
{
}
RootConsoleMenu::~RootConsoleMenu()
{
List<ConsoleEntry *>::iterator iter;
for (iter=m_Menu.begin(); iter!=m_Menu.end(); iter++)
{
delete (*iter);
}
m_Menu.clear();
}
void RootConsoleMenu::OnSourceModStartup(bool late)
{
AddRootConsoleCommand3("version", "Display version information", this);
AddRootConsoleCommand3("credits", "Display credits listing", this);
bridge->DefineCommand("sm_dump_handles", "Dumps Handle usage to a file for finding Handle leaks",
sm_dump_handles);
bridge->DefineCommand("sm", "SourceMod Menu", [this] (int client, const ICommandArgs *args) -> bool {
GotRootCmd(args);
return true;
});
}
void RootConsoleMenu::OnSourceModAllInitialized()
{
sharesys->AddInterface(NULL, this);
}
void RootConsoleMenu::OnSourceModShutdown()
{
RemoveRootConsoleCommand("credits", this);
RemoveRootConsoleCommand("version", this);
}
void RootConsoleMenu::ConsolePrint(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
bridge->ConsolePrintVa(fmt, ap);
va_end(ap);
}
bool RootConsoleMenu::AddRootConsoleCommand(const char *cmd, const char *text, IRootConsoleCommand *pHandler)
{
return false;
}
bool RootConsoleMenu::AddRootConsoleCommand2(const char *cmd, const char *text, IRootConsoleCommand *pHandler)
{
return false;
}
bool RootConsoleMenu::AddRootConsoleCommand3(const char *cmd,
const char *text,
IRootConsoleCommand *pHandler)
{
if (m_Commands.contains(cmd))
return false;
/* Sort this into the menu */
List<ConsoleEntry *>::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->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->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<ConsoleEntry *>::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 = ke::SafeSprintf(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;
}
void RootConsoleMenu::GotRootCmd(const ICommandArgs *cmd)
{
unsigned int argnum = cmd->ArgC();
if (argnum >= 2)
{
const char *cmdname = cmd->Arg(1);
ConsoleEntry *entry;
if (m_Commands.retrieve(cmdname, &entry))
{
entry->cmd->OnRootConsoleCommand(cmdname, cmd);
return;
}
}
ConsolePrint("SourceMod Menu:");
ConsolePrint("Usage: sm <command> [arguments]");
List<ConsoleEntry *>::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 ICommandArgs *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", SOURCEMOD_BUILD_TIME);
#if defined(SM_GENERATED_BUILD)
ConsolePrint(" Built from: https://github.com/alliedmodders/sourcemod/commit/%s", SOURCEMOD_SHA);
ConsolePrint(" Build ID: %s:%s", SOURCEMOD_LOCAL_REV, SOURCEMOD_SHA);
#endif
ConsolePrint(" http://www.sourcemod.net/");
}
}
static bool sm_dump_handles(int client, const ICommandArgs *args)
{
if (args->ArgC() < 2) {
bridge->ConsolePrint("Usage: sm_dump_handles <file> or <log> for game logs");
return true;
}
if (strcmp(args->Arg(1), "log") == 0) {
auto write_handles_to_game = [] (const char *str) -> void
{
char buffer[1024];
size_t len = ke::SafeStrcpy(buffer, sizeof(buffer)-2, str);
buffer[len] = '\n';
buffer[len+1] = '\0';
bridge->LogToGame(buffer);
};
g_HandleSys.Dump(write_handles_to_game);
return true;
}
FILE *fp = nullptr;
auto write_handles_to_log = [&fp] (const char *str) -> void
{
fprintf(fp, "%s\n", str);
};
char filename[PLATFORM_MAX_PATH];
const char *arg = args->Arg(1);
g_pSM->BuildPath(Path_Game, filename, sizeof(filename), "%s", arg);
fp = fopen(filename, "wt");
if (!fp) {
bridge->ConsolePrint("Failed to open \"%s\" for writing", filename);
return true;
}
g_HandleSys.Dump(write_handles_to_log);
fclose(fp);
return true;
}