void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output) { AStringVector split = StringSplit(a_Cmd, " "); if (split.empty()) { return; } // Special handling: "stop" and "restart" are built in if ((split[0].compare("stop") == 0) || (split[0].compare("restart") == 0)) { return; } // "help" and "reload" are to be handled by MCS, so that they work no matter what if (split[0] == "help") { PrintHelp(split, a_Output); return; } if (split[0] == "reload") { cPluginManager::Get()->ReloadPlugins(); return; } // There is currently no way a plugin can do these (and probably won't ever be): if (split[0].compare("chunkstats") == 0) { cRoot::Get()->LogChunkStats(a_Output); a_Output.Finished(); return; } #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) if (split[0].compare("dumpmem") == 0) { LeakFinderXmlOutput Output("memdump.xml"); DumpUsedMemory(&Output); return; } if (split[0].compare("killmem") == 0) { while (true) { new char[100 * 1024 * 1024]; // Allocate and leak 100 MiB in a loop -> fill memory and kill MCS } } #endif if (cPluginManager::Get()->ExecuteConsoleCommand(split, a_Output)) { a_Output.Finished(); return; } a_Output.Out("Unknown command, type 'help' for all commands."); a_Output.Finished(); }
void cServer::PrintHelp(const AStringVector & a_Split, cCommandOutputCallback & a_Output) { UNUSED(a_Split); typedef std::pair<AString, AString> AStringPair; typedef std::vector<AStringPair> AStringPairs; class cCallback : public cPluginManager::cCommandEnumCallback { public: cCallback(void) : m_MaxLen(0) {} virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) override { UNUSED(a_Plugin); UNUSED(a_Permission); if (!a_HelpString.empty()) { m_Commands.push_back(AStringPair(a_Command, a_HelpString)); if (m_MaxLen < a_Command.length()) { m_MaxLen = a_Command.length(); } } return false; } AStringPairs m_Commands; size_t m_MaxLen; } Callback; cPluginManager::Get()->ForEachConsoleCommand(Callback); std::sort(Callback.m_Commands.begin(), Callback.m_Commands.end()); for (AStringPairs::const_iterator itr = Callback.m_Commands.begin(), end = Callback.m_Commands.end(); itr != end; ++itr) { const AStringPair & cmd = *itr; a_Output.Out(Printf("%-*s%s\n", static_cast<int>(Callback.m_MaxLen), cmd.first.c_str(), cmd.second.c_str())); } // for itr - Callback.m_Commands[] a_Output.Finished(); }
void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallback & a_Output) { AStringVector split = StringSplit(a_Cmd, " "); if (split.empty()) { return; } // "stop" and "restart" are handled in cRoot::ExecuteConsoleCommand, our caller, due to its access to controlling variables // "help" and "reload" are to be handled by MCS, so that they work no matter what if (split[0] == "help") { PrintHelp(split, a_Output); a_Output.Finished(); return; } else if (split[0] == "reload") { cPluginManager::Get()->ReloadPlugins(); a_Output.Finished(); return; } else if (split[0] == "reloadplugins") { cPluginManager::Get()->ReloadPlugins(); a_Output.Out("Plugins reloaded"); a_Output.Finished(); return; } else if (split[0] == "load") { if (split.size() > 1) { cPluginManager::Get()->RefreshPluginList(); // Refresh the plugin list, so that if the plugin was added just now, it is loadable a_Output.Out(cPluginManager::Get()->LoadPlugin(split[1]) ? "Plugin loaded" : "Error occurred loading plugin"); } else { a_Output.Out("Usage: load <PluginFolder>"); } a_Output.Finished(); return; } else if (split[0] == "unload") { if (split.size() > 1) { cPluginManager::Get()->UnloadPlugin(split[1]); a_Output.Out("Plugin unload scheduled"); } else { a_Output.Out("Usage: unload <PluginFolder>"); } a_Output.Finished(); return; } if (split[0] == "destroyentities") { class WorldCallback : public cWorldListCallback { virtual bool Item(cWorld * a_World) override { class EntityCallback : public cEntityCallback { virtual bool Item(cEntity * a_Entity) override { if (!a_Entity->IsPlayer()) { a_Entity->Destroy(); } return false; } } EC; a_World->ForEachEntity(EC); return false; } } WC; cRoot::Get()->ForEachWorld(WC); a_Output.Out("Destroyed all entities"); a_Output.Finished(); return; } // There is currently no way a plugin can do these (and probably won't ever be): else if (split[0].compare("chunkstats") == 0) { cRoot::Get()->LogChunkStats(a_Output); a_Output.Finished(); return; } #if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER) else if (split[0].compare("dumpmem") == 0) { LeakFinderXmlOutput Output("memdump.xml"); DumpUsedMemory(&Output); return; } else if (split[0].compare("killmem") == 0) { for (;;) { new char[100 * 1024 * 1024]; // Allocate and leak 100 MiB in a loop -> fill memory and kill MCS } } #endif else if (cPluginManager::Get()->ExecuteConsoleCommand(split, a_Output, a_Cmd)) { a_Output.Finished(); return; } a_Output.Out("Unknown command, type 'help' for all commands."); a_Output.Finished(); }