Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/frontend/StarClientCommandProcessor.cpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
commit6352e8e3196f78388b6c771073f9e03eaa612673 (patch)
treee23772f79a7fbc41bc9108951e9e136857484bf4 /source/frontend/StarClientCommandProcessor.cpp
parent6741a057e5639280d85d0f88ba26f000baa58f61 (diff)
everything everywhere
all at once
Diffstat (limited to 'source/frontend/StarClientCommandProcessor.cpp')
-rw-r--r--source/frontend/StarClientCommandProcessor.cpp375
1 files changed, 375 insertions, 0 deletions
diff --git a/source/frontend/StarClientCommandProcessor.cpp b/source/frontend/StarClientCommandProcessor.cpp
new file mode 100644
index 0000000..535403d
--- /dev/null
+++ b/source/frontend/StarClientCommandProcessor.cpp
@@ -0,0 +1,375 @@
+#include "StarClientCommandProcessor.hpp"
+#include "StarItem.hpp"
+#include "StarAssets.hpp"
+#include "StarItemDatabase.hpp"
+#include "StarPlayer.hpp"
+#include "StarPlayerTech.hpp"
+#include "StarPlayerInventory.hpp"
+#include "StarPlayerLog.hpp"
+#include "StarWorldClient.hpp"
+#include "StarAiInterface.hpp"
+#include "StarQuestInterface.hpp"
+#include "StarStatistics.hpp"
+
+namespace Star {
+
+ClientCommandProcessor::ClientCommandProcessor(UniverseClientPtr universeClient, CinematicPtr cinematicOverlay,
+ MainInterfacePaneManager* paneManager, StringMap<StringList> macroCommands)
+ : m_universeClient(move(universeClient)), m_cinematicOverlay(move(cinematicOverlay)),
+ m_paneManager(paneManager), m_macroCommands(move(macroCommands)) {
+ m_builtinCommands = {
+ {"reload", bind(&ClientCommandProcessor::reload, this)},
+ {"whoami", bind(&ClientCommandProcessor::whoami, this)},
+ {"gravity", bind(&ClientCommandProcessor::gravity, this)},
+ {"debug", bind(&ClientCommandProcessor::debug, this)},
+ {"boxes", bind(&ClientCommandProcessor::boxes, this)},
+ {"fullbright", bind(&ClientCommandProcessor::fullbright, this)},
+ {"setGravity", bind(&ClientCommandProcessor::setGravity, this, _1)},
+ {"resetGravity", bind(&ClientCommandProcessor::resetGravity, this)},
+ {"fixedCamera", bind(&ClientCommandProcessor::fixedCamera, this)},
+ {"monochromeLighting", bind(&ClientCommandProcessor::monochromeLighting, this)},
+ {"radioMessage", bind(&ClientCommandProcessor::radioMessage, this, _1)},
+ {"clearRadioMessages", bind(&ClientCommandProcessor::clearRadioMessages, this)},
+ {"clearCinematics", bind(&ClientCommandProcessor::clearCinematics, this)},
+ {"startQuest", bind(&ClientCommandProcessor::startQuest, this, _1)},
+ {"completeQuest", bind(&ClientCommandProcessor::completeQuest, this, _1)},
+ {"failQuest", bind(&ClientCommandProcessor::failQuest, this, _1)},
+ {"previewNewQuest", bind(&ClientCommandProcessor::previewNewQuest, this, _1)},
+ {"previewQuestComplete", bind(&ClientCommandProcessor::previewQuestComplete, this, _1)},
+ {"previewQuestFailed", bind(&ClientCommandProcessor::previewQuestFailed, this, _1)},
+ {"clearScannedObjects", bind(&ClientCommandProcessor::clearScannedObjects, this)},
+ {"played", bind(&ClientCommandProcessor::playTime, this)},
+ {"deaths", bind(&ClientCommandProcessor::deathCount, this)},
+ {"cinema", bind(&ClientCommandProcessor::cinema, this, _1)},
+ {"suicide", bind(&ClientCommandProcessor::suicide, this)},
+ {"naked", bind(&ClientCommandProcessor::naked, this)},
+ {"resetAchievements", bind(&ClientCommandProcessor::resetAchievements, this)},
+ {"statistic", bind(&ClientCommandProcessor::statistic, this, _1)},
+ {"giveessentialitem", bind(&ClientCommandProcessor::giveEssentialItem, this, _1)},
+ {"maketechavailable", bind(&ClientCommandProcessor::makeTechAvailable, this, _1)},
+ {"enabletech", bind(&ClientCommandProcessor::enableTech, this, _1)},
+ {"upgradeship", bind(&ClientCommandProcessor::upgradeShip, this, _1)}
+ };
+}
+
+bool ClientCommandProcessor::adminCommandAllowed() const {
+ return Root::singleton().configuration()->get("allowAdminCommandsFromAnyone").toBool() ||
+ m_universeClient->mainPlayer()->isAdmin();
+}
+
+String ClientCommandProcessor::previewQuestPane(StringList const& arguments, function<PanePtr(QuestPtr)> createPane) {
+ Maybe<String> templateId = {};
+ templateId = arguments[0];
+ if (auto quest = createPreviewQuest(*templateId, arguments.at(1), arguments.at(2), m_universeClient->mainPlayer().get())) {
+ auto pane = createPane(quest);
+ m_paneManager->displayPane(PaneLayer::ModalWindow, pane);
+ return "Previewed quest";
+ }
+ return "No such quest";
+}
+
+StringList ClientCommandProcessor::handleCommand(String const& commandLine) {
+ try {
+ if (!commandLine.beginsWith("/"))
+ throw StarException("ClientCommandProcessor expected command, does not start with '/'");
+
+ String allArguments = commandLine.substr(1);
+ String command = allArguments.extract();
+ auto arguments = m_parser.tokenizeToStringList(allArguments);
+
+ StringList result;
+ if (auto builtinCommand = m_builtinCommands.maybe(command)) {
+ result.append((*builtinCommand)(arguments));
+ } else if (auto macroCommand = m_macroCommands.maybe(command)) {
+ for (auto const& c : *macroCommand) {
+ if (c.beginsWith("/"))
+ result.appendAll(handleCommand(c));
+ else
+ result.append(c);
+ }
+ } else {
+ m_universeClient->sendChat(commandLine, ChatSendMode::Broadcast);
+ }
+ return result;
+ } catch (ShellParsingException const& e) {
+ Logger::error("Shell parsing exception: %s", outputException(e, false));
+ return {"Shell parsing exception"};
+ } catch (std::exception const& e) {
+ Logger::error("Exception caught handling client command %s: %s", commandLine, outputException(e, true));
+ return {strf("Exception caught handling client command %s", commandLine)};
+ }
+}
+
+bool ClientCommandProcessor::debugDisplayEnabled() const {
+ return m_debugDisplayEnabled;
+}
+
+bool ClientCommandProcessor::fixedCameraEnabled() const {
+ return m_fixedCameraEnabled;
+}
+
+String ClientCommandProcessor::reload() {
+ Root::singleton().reload();
+ return "Client Star::Root reloaded";
+}
+
+String ClientCommandProcessor::whoami() {
+ return strf("Client: You are %s. You are %san Admin.",
+ m_universeClient->mainPlayer()->name(), m_universeClient->mainPlayer()->isAdmin() ? "" : "not ");
+}
+
+String ClientCommandProcessor::gravity() {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ return strf("%s", m_universeClient->worldClient()->gravity(m_universeClient->mainPlayer()->position()));
+}
+
+String ClientCommandProcessor::debug() {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ m_debugDisplayEnabled = !m_debugDisplayEnabled;
+ return strf("Debug display %s", m_debugDisplayEnabled ? "enabled" : "disabled");
+}
+
+String ClientCommandProcessor::boxes() {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ return strf("Geometry debug display %s",
+ m_universeClient->worldClient()->toggleCollisionDebug()
+ ? "enabled" : "disabled");
+}
+
+String ClientCommandProcessor::fullbright() {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ return strf("Fullbright render lighting %s",
+ m_universeClient->worldClient()->toggleFullbright()
+ ? "enabled" : "disabled");
+}
+
+String ClientCommandProcessor::setGravity(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ m_universeClient->worldClient()->overrideGravity(lexicalCast<float>(arguments.at(0)));
+ return strf("Gravity set to %s, the change is LOCAL ONLY", arguments.at(0));
+}
+
+String ClientCommandProcessor::resetGravity() {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ m_universeClient->worldClient()->resetGravity();
+ return "Gravity reset";
+}
+
+String ClientCommandProcessor::fixedCamera() {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ m_fixedCameraEnabled = !m_fixedCameraEnabled;
+ return strf("Fixed camera %s", m_fixedCameraEnabled ? "enabled" : "disabled");
+}
+
+String ClientCommandProcessor::monochromeLighting() {
+ bool monochrome = !Root::singleton().configuration()->get("monochromeLighting").toBool();
+ Root::singleton().configuration()->set("monochromeLighting", monochrome);
+ return strf("Monochrome lighting %s", monochrome ? "enabled" : "disabled");
+}
+
+String ClientCommandProcessor::radioMessage(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ if (arguments.size() != 1)
+ return "Must provide one argument";
+
+ m_universeClient->mainPlayer()->queueRadioMessage(arguments.at(0));
+ return "Queued radio message";
+}
+
+String ClientCommandProcessor::clearRadioMessages() {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ m_universeClient->mainPlayer()->log()->clearRadioMessages();
+ return "Player radio message records cleared!";
+}
+
+String ClientCommandProcessor::clearCinematics() {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ m_universeClient->mainPlayer()->log()->clearCinematics();
+ return "Player cinematic records cleared!";
+}
+
+String ClientCommandProcessor::startQuest(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ auto questArc = QuestArcDescriptor::fromJson(Json::parse(arguments.at(0)));
+ m_universeClient->questManager()->offer(make_shared<Quest>(questArc, 0, m_universeClient->mainPlayer().get()));
+ return "Quest started";
+}
+
+String ClientCommandProcessor::completeQuest(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ m_universeClient->questManager()->getQuest(arguments.at(0))->complete();
+ return strf("Quest %s complete", arguments.at(0));
+}
+
+String ClientCommandProcessor::failQuest(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ m_universeClient->questManager()->getQuest(arguments.at(0))->fail();
+ return strf("Quest %s failed", arguments.at(0));
+}
+
+String ClientCommandProcessor::previewNewQuest(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ return previewQuestPane(arguments, [this](QuestPtr const& quest) {
+ return make_shared<NewQuestInterface>(m_universeClient->questManager(), quest, m_universeClient->mainPlayer());
+ });
+}
+
+String ClientCommandProcessor::previewQuestComplete(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ return previewQuestPane(arguments, [this](QuestPtr const& quest) {
+ return make_shared<QuestCompleteInterface>(quest, m_universeClient->mainPlayer(), CinematicPtr{});
+ });
+}
+
+String ClientCommandProcessor::previewQuestFailed(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ return previewQuestPane(arguments, [this](QuestPtr const& quest) {
+ return make_shared<QuestFailedInterface>(quest, m_universeClient->mainPlayer());
+ });
+}
+
+String ClientCommandProcessor::clearScannedObjects() {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ m_universeClient->mainPlayer()->log()->clearScannedObjects();
+ return "Player scanned objects cleared!";
+}
+
+String ClientCommandProcessor::playTime() {
+ return strf("Total play time: %s", Time::printDuration(m_universeClient->mainPlayer()->log()->playTime()));
+}
+
+String ClientCommandProcessor::deathCount() {
+ auto deaths = m_universeClient->mainPlayer()->log()->deathCount();
+ return strf("Total deaths: %s%s", deaths, deaths == 0 ? ". Well done!" : "");
+}
+
+String ClientCommandProcessor::cinema(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ m_cinematicOverlay->load(Root::singleton().assets()->json(arguments.at(0)));
+ if (arguments.size() > 1)
+ m_cinematicOverlay->setTime(lexicalCast<float>(arguments.at(1)));
+ return strf("Started cinematic %s at %s", arguments.at(0), arguments.size() > 1 ? arguments.at(1) : "beginning");
+}
+
+String ClientCommandProcessor::suicide() {
+ m_universeClient->mainPlayer()->kill();
+ return "You are now dead";
+}
+
+String ClientCommandProcessor::naked() {
+ auto playerInventory = m_universeClient->mainPlayer()->inventory();
+ for (auto slot : EquipmentSlotNames.leftValues())
+ playerInventory->addItems(playerInventory->addToBags(playerInventory->takeSlot(slot)));
+ return "You are now naked";
+}
+
+String ClientCommandProcessor::resetAchievements() {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ if (m_universeClient->statistics()->reset()) {
+ return "Achievements reset";
+ }
+ return "Unable to reset achievements";
+}
+
+String ClientCommandProcessor::statistic(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ StringList values;
+ for (String const& statName : arguments) {
+ values.append(strf("%s = %s", statName, m_universeClient->statistics()->stat(statName)));
+ }
+ return values.join("\n");
+}
+
+String ClientCommandProcessor::giveEssentialItem(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ if (arguments.size() < 2)
+ return "Not enough arguments to /giveessentialitem";
+
+ try {
+ auto item = Root::singleton().itemDatabase()->item(ItemDescriptor(arguments.at(0)));
+ auto slot = EssentialItemNames.getLeft(arguments.at(1));
+ m_universeClient->mainPlayer()->inventory()->setEssentialItem(slot, item);
+ return strf("Put %s in player slot %s", item->name(), arguments.at(1));
+ } catch (MapException e) {
+ return strf("Invalid essential item slot %s.", arguments.at(1));
+ }
+}
+
+String ClientCommandProcessor::makeTechAvailable(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ if (arguments.size() == 0)
+ return "Not enouch arguments to /maketechavailable";
+
+ m_universeClient->mainPlayer()->techs()->makeAvailable(arguments.at(0));
+ return strf("Added %s to player's visible techs", arguments.at(0));
+}
+
+String ClientCommandProcessor::enableTech(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ if (arguments.size() == 0)
+ return "Not enouch arguments to /enabletech";
+
+ m_universeClient->mainPlayer()->techs()->makeAvailable(arguments.at(0));
+ m_universeClient->mainPlayer()->techs()->enable(arguments.at(0));
+ return strf("Player tech %s enabled", arguments.at(0));
+}
+
+String ClientCommandProcessor::upgradeShip(StringList const& arguments) {
+ if (!adminCommandAllowed())
+ return "You must be an admin to use this command.";
+
+ if (arguments.size() == 0)
+ return "Not enouch arguments to /upgradeship";
+
+ auto shipUpgrades = Json::parseJson(arguments.at(0));
+ m_universeClient->rpcInterface()->invokeRemote("ship.applyShipUpgrades", shipUpgrades);
+ return strf("Upgraded ship");
+}
+
+}