From 56c99c086fd14ee1b1131cb7df18c1b55ede5519 Mon Sep 17 00:00:00 2001 From: Kae <80987908+Novaenia@users.noreply.github.com> Date: Sun, 24 Nov 2024 12:51:55 +1100 Subject: [PATCH 1/3] scriptable chat --- source/client/StarClientApplication.cpp | 3 +- source/frontend/StarBaseScriptPane.cpp | 25 ++-- source/frontend/StarBaseScriptPane.hpp | 6 +- source/frontend/StarChat.cpp | 156 ++++++++++++++++-------- source/frontend/StarChat.hpp | 7 +- source/frontend/StarMainInterface.cpp | 14 ++- source/frontend/StarMainInterface.hpp | 1 + source/game/StarUniverseClient.cpp | 4 + source/game/StarUniverseClient.hpp | 1 + source/windowing/StarPane.cpp | 12 ++ 10 files changed, 158 insertions(+), 71 deletions(-) diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp index 250445c..b4e0955 100644 --- a/source/client/StarClientApplication.cpp +++ b/source/client/StarClientApplication.cpp @@ -684,8 +684,9 @@ void ClientApplication::changeState(MainAppState newState) { m_mainInterface = make_shared(m_universeClient, m_worldPainter, m_cinematicOverlay); m_universeClient->setLuaCallbacks("interface", LuaBindings::makeInterfaceCallbacks(m_mainInterface.get())); m_universeClient->setLuaCallbacks("chat", LuaBindings::makeChatCallbacks(m_mainInterface.get(), m_universeClient.get())); - m_universeClient->startLua(); + m_mainInterface->displayDefaultPanes(); + m_universeClient->startLua(); m_mainMixer->setWorldPainter(m_worldPainter); if (auto renderer = Application::renderer()) { diff --git a/source/frontend/StarBaseScriptPane.cpp b/source/frontend/StarBaseScriptPane.cpp index bfeebb7..63dbd08 100644 --- a/source/frontend/StarBaseScriptPane.cpp +++ b/source/frontend/StarBaseScriptPane.cpp @@ -14,7 +14,7 @@ namespace Star { -BaseScriptPane::BaseScriptPane(Json config) : Pane(), m_rawConfig(config) { +BaseScriptPane::BaseScriptPane(Json config, bool construct) : Pane(), m_rawConfig(config) { auto& root = Root::singleton(); auto assets = root.assets(); @@ -35,15 +35,8 @@ BaseScriptPane::BaseScriptPane(Json config) : Pane(), m_rawConfig(config) { }); } - m_reader->construct(assets->fetchJson(m_config.get("gui")), this); - - for (auto pair : m_config.getObject("canvasClickCallbacks", {})) - m_canvasClickCallbacks.set(findChild(pair.first), pair.second.toString()); - for (auto pair : m_config.getObject("canvasKeyCallbacks", {})) - m_canvasKeyCallbacks.set(findChild(pair.first), pair.second.toString()); - - m_script.setScripts(jsonToStringList(m_config.get("scripts", JsonArray()))); - m_script.setUpdateDelta(m_config.getUInt("scriptDelta", 1)); + if (construct) + this->construct(assets->fetchJson(m_config.get("gui"))); m_callbacksAdded = false; } @@ -140,4 +133,16 @@ GuiReaderPtr BaseScriptPane::reader() { return m_reader; } +void BaseScriptPane::construct(Json config) { + m_reader->construct(config, this); + + for (auto pair : m_config.getObject("canvasClickCallbacks", {})) + m_canvasClickCallbacks.set(findChild(pair.first), pair.second.toString()); + for (auto pair : m_config.getObject("canvasKeyCallbacks", {})) + m_canvasKeyCallbacks.set(findChild(pair.first), pair.second.toString()); + + m_script.setScripts(jsonToStringList(m_config.get("scripts", JsonArray()))); + m_script.setUpdateDelta(m_config.getUInt("scriptDelta", 1)); +} + } diff --git a/source/frontend/StarBaseScriptPane.hpp b/source/frontend/StarBaseScriptPane.hpp index 0c00547..08a4d69 100644 --- a/source/frontend/StarBaseScriptPane.hpp +++ b/source/frontend/StarBaseScriptPane.hpp @@ -15,7 +15,7 @@ STAR_CLASS(BaseScriptPane); class BaseScriptPane : public Pane { public: - BaseScriptPane(Json config); + BaseScriptPane(Json config, bool construct = true); virtual void show() override; void displayed() override; @@ -34,6 +34,8 @@ public: Maybe cursorOverride(Vec2I const& screenPosition) override; protected: virtual GuiReaderPtr reader() override; + void construct(Json config); + Json m_config; Json m_rawConfig; @@ -45,7 +47,7 @@ protected: bool m_interactive; bool m_callbacksAdded; - LuaUpdatableComponent m_script; + mutable LuaUpdatableComponent m_script; }; } diff --git a/source/frontend/StarChat.cpp b/source/frontend/StarChat.cpp index bbb28c1..da6c421 100644 --- a/source/frontend/StarChat.cpp +++ b/source/frontend/StarChat.cpp @@ -13,14 +13,25 @@ #include "StarPlayerStorage.hpp" #include "StarTeamClient.hpp" +#include "StarPlayer.hpp" +#include "StarConfigLuaBindings.hpp" +#include "StarPlayerLuaBindings.hpp" +#include "StarStatusControllerLuaBindings.hpp" +#include "StarCelestialLuaBindings.hpp" +#include "StarLuaGameConverters.hpp" + namespace Star { -Chat::Chat(UniverseClientPtr client) : m_client(client) { +Chat::Chat(UniverseClientPtr client, Json const& baseConfig) : BaseScriptPane(baseConfig, false) { + m_client = client; + m_scripted = baseConfig.get("scripts", Json()).isType(Json::Type::Array); + m_script.setLuaRoot(m_client->luaRoot()); + m_script.addCallbacks("world", LuaBindings::makeWorldCallbacks((World*)m_client->worldClient().get())); m_chatPrevIndex = 0; m_historyOffset = 0; - + auto assets = Root::singleton().assets(); - auto config = assets->json("/interface/chat/chat.config:config"); + auto config = baseConfig.get("config"); m_timeChatLastActive = Time::monotonicMilliseconds(); m_chatTextStyle = config.get("textStyle"); m_chatTextStyle.lineSpacing = config.get("lineHeight").toFloat(); @@ -45,15 +56,13 @@ Chat::Chat(UniverseClientPtr client) : m_client(client) { m_colorCodes[MessageContext::CommandResult] = config.query("colors.commandResult").toString(); m_colorCodes[MessageContext::RadioMessage] = config.query("colors.radioMessage").toString(); m_colorCodes[MessageContext::World] = config.query("colors.world").toString(); + if (!m_scripted) { + m_reader->registerCallback("textBox", [=](Widget*) { startChat(); }); + m_reader->registerCallback("upButton", [=](Widget*) { scrollUp(); }); + m_reader->registerCallback("downButton", [=](Widget*) { scrollDown(); }); + m_reader->registerCallback("bottomButton", [=](Widget*) { scrollBottom(); }); - GuiReader reader; - - reader.registerCallback("textBox", [=](Widget*) { startChat(); }); - reader.registerCallback("upButton", [=](Widget*) { scrollUp(); }); - reader.registerCallback("downButton", [=](Widget*) { scrollDown(); }); - reader.registerCallback("bottomButton", [=](Widget*) { scrollBottom(); }); - - reader.registerCallback("filterGroup", [=](Widget* widget) { + m_reader->registerCallback("filterGroup", [=](Widget* widget) { Json data = as(widget)->data(); auto filter = data.getArray("filter", {}); m_modeFilter.clear(); @@ -62,41 +71,49 @@ Chat::Chat(UniverseClientPtr client) : m_client(client) { m_sendMode = ChatSendModeNames.getLeft(data.getString("sendMode", "Broadcast")); m_historyOffset = 0; }); + } + + construct(baseConfig.get("gui")); m_sendMode = ChatSendMode::Broadcast; - - reader.construct(assets->json("/interface/chat/chat.config:gui"), this); - - m_textBox = fetchChild("textBox"); - m_say = fetchChild("say"); - m_chatLog = fetchChild("chatLog"); - if (auto logPadding = config.optQuery("padding")) { - m_chatLogPadding = jsonToVec2I(logPadding.get()); - m_chatLog->setSize(m_chatLog->size() + m_chatLogPadding * 2); - m_chatLog->setPosition(m_chatLog->position() - m_chatLogPadding); - } - else - m_chatLogPadding = Vec2I(); - m_bottomButton = fetchChild("bottomButton"); m_upButton = fetchChild("upButton"); + m_textBox = fetchChild("textBox"); + m_say = fetchChild("say"); + if (!m_scripted) { + if (auto logPadding = config.optQuery("padding")) { + m_chatLogPadding = jsonToVec2I(logPadding.get()); + m_chatLog->setSize(m_chatLog->size() + m_chatLogPadding * 2); + m_chatLog->setPosition(m_chatLog->position() - m_chatLogPadding); + } else + m_chatLogPadding = Vec2I(); - m_chatHistory.appendAll(m_client->playerStorage()->getMetadata("chatHistory").opt().apply(jsonToStringList).value()); + m_chatHistory.appendAll(m_client->playerStorage()->getMetadata("chatHistory").opt().apply(jsonToStringList).value()); + } else { + m_script.addCallbacks("player", LuaBindings::makePlayerCallbacks(m_client->mainPlayer().get())); + m_script.addCallbacks("status", LuaBindings::makeStatusControllerCallbacks(m_client->mainPlayer()->statusController())); + m_script.addCallbacks("celestial", LuaBindings::makeCelestialCallbacks(m_client.get())); + } show(); - updateBottomButton(); + //if (!m_scripted) { + //updateBottomButton(); - m_background = fetchChild("background"); - m_defaultHeight = m_background->size()[1]; - m_expanded = false; - updateSize(); + m_background = fetchChild("background"); + m_defaultHeight = m_background->size()[1]; + m_expanded = false; + updateSize(); + //} } void Chat::update(float dt) { Pane::update(dt); + if (m_scripted) + return; + auto team = m_client->teamClient()->currentTeam(); for (auto button : fetchChild("filterGroup")->buttons()) { auto mode = ChatSendModeNames.getLeft(button->data().getString("sendMode", "Broadcast")); @@ -108,40 +125,64 @@ void Chat::update(float dt) { } void Chat::startChat() { - show(); - m_textBox->focus(); + if (m_scripted) + m_script.invoke("startChat"); + else { + show(); + m_textBox->focus(); + } } void Chat::startCommand() { - show(); - m_textBox->setText("/"); - m_textBox->focus(); + if (m_scripted) + m_script.invoke("startCommand"); + else { + show(); + m_textBox->setText("/"); + m_textBox->focus(); + } } bool Chat::hasFocus() const { + if (m_scripted) + return m_script.invoke("hasFocus").value(); return m_textBox->hasFocus(); } void Chat::stopChat() { - m_textBox->setText(""); - m_textBox->blur(); - m_timeChatLastActive = Time::monotonicMilliseconds(); + if (m_scripted) + m_script.invoke("stopChat"); + else { + m_textBox->setText(""); + m_textBox->blur(); + m_timeChatLastActive = Time::monotonicMilliseconds(); + } } String Chat::currentChat() const { + if (m_scripted) + return m_script.invoke("currentChat").value(); return m_textBox->getText(); } bool Chat::setCurrentChat(String const& chat, bool moveCursor) { + if (m_scripted) + return m_script.invoke("setCurrentChat").value(); return m_textBox->setText(chat, true, moveCursor); } void Chat::clearCurrentChat() { - m_textBox->setText(""); - m_chatPrevIndex = 0; + if (m_scripted) + m_script.invoke("clearCurrentChat"); + else { + m_textBox->setText(""); + m_chatPrevIndex = 0; + } } ChatSendMode Chat::sendMode() const { + if (m_scripted) + return ChatSendModeNames.getLeft(m_script.invoke("sendMode").value()); return m_sendMode; } @@ -171,6 +212,13 @@ void Chat::addMessages(List const& messages, bool showPane) if (messages.empty()) return; + if (m_scripted) { + m_script.invoke("addMessages", messages.transformed([](ChatReceivedMessage const& message) { + return message.toJson(); + }), showPane); + return; + } + GuiContext& guiContext = GuiContext::singleton(); for (auto const& message : messages) { @@ -209,17 +257,22 @@ void Chat::addMessages(List const& messages, bool showPane) } void Chat::addHistory(String const& chat) { - if (m_chatHistory.size() > 0 && m_chatHistory.get(0).equals(chat)) + if (m_scripted) + m_script.invoke("addHistory", chat); + else if (m_chatHistory.size() > 0 && m_chatHistory.get(0).equals(chat)) return; - - m_chatHistory.prepend(chat); - m_chatHistory.resize(std::min((unsigned)m_chatHistory.size(), m_chatHistoryLimit)); - m_timeChatLastActive = Time::monotonicMilliseconds(); - m_client->playerStorage()->setMetadata("chatHistory", JsonArray::from(m_chatHistory)); + else { + m_chatHistory.prepend(chat); + m_chatHistory.resize(std::min((unsigned)m_chatHistory.size(), m_chatHistoryLimit)); + m_timeChatLastActive = Time::monotonicMilliseconds(); + m_client->playerStorage()->setMetadata("chatHistory", JsonArray::from(m_chatHistory)); + } } void Chat::clear(size_t count) { - if (count > m_receivedMessages.size()) + if (m_scripted) + m_script.invoke("clear", count); + else if (count > m_receivedMessages.size()) m_receivedMessages.clear(); else m_receivedMessages.erase(m_receivedMessages.begin(), m_receivedMessages.begin() + count); @@ -227,6 +280,8 @@ void Chat::clear(size_t count) { void Chat::renderImpl() { Pane::renderImpl(); + if (m_scripted) + return; if (m_textBox->hasFocus()) m_timeChatLastActive = Time::monotonicMilliseconds(); Vec4B fade = {255, 255, 255, 255}; @@ -303,6 +358,9 @@ void Chat::hide() { } float Chat::visible() const { + if (m_scripted) + return m_script.invoke("visible").value(1.0f); + double difference = (Time::monotonicMilliseconds() - m_timeChatLastActive) / 1000.0; if (difference < m_chatVisTime) return 1; @@ -310,7 +368,7 @@ float Chat::visible() const { } bool Chat::sendEvent(InputEvent const& event) { - if (active()) { + if (!m_scripted && active()) { if (hasFocus()) { if (event.is()) { auto actions = context()->actions(event); diff --git a/source/frontend/StarChat.hpp b/source/frontend/StarChat.hpp index df2d63c..53ed578 100644 --- a/source/frontend/StarChat.hpp +++ b/source/frontend/StarChat.hpp @@ -1,6 +1,6 @@ #pragma once -#include "StarPane.hpp" +#include "StarBaseScriptPane.hpp" #include "StarChatTypes.hpp" namespace Star { @@ -13,9 +13,9 @@ STAR_CLASS(ImageStretchWidget); STAR_CLASS(CanvasWidget); STAR_CLASS(Chat); -class Chat : public Pane { +class Chat : public BaseScriptPane { public: - Chat(UniverseClientPtr client); + Chat(UniverseClientPtr client, Json const&); void startChat(); void startCommand(); @@ -57,6 +57,7 @@ private: void updateBottomButton(); UniverseClientPtr m_client; + bool m_scripted; TextBoxWidgetPtr m_textBox; LabelWidgetPtr m_say; diff --git a/source/frontend/StarMainInterface.cpp b/source/frontend/StarMainInterface.cpp index 153ce07..41eceb7 100644 --- a/source/frontend/StarMainInterface.cpp +++ b/source/frontend/StarMainInterface.cpp @@ -141,7 +141,7 @@ MainInterface::MainInterface(UniverseClientPtr client, WorldPainterPtr painter, m_collections = make_shared(m_client, "/interface/scripted/collections/collectionsgui.config"); m_paneManager.registerPane(MainInterfacePanes::Collections, PaneLayer::Window, m_collections); - m_chat = make_shared(m_client); + m_chat = make_shared(m_client, Root::singleton().assets()->json("/interface/chat/chat.config")); m_paneManager.registerPane(MainInterfacePanes::Chat, PaneLayer::Hud, m_chat); m_clientCommandProcessor = make_shared(m_client, m_cinematicOverlay, &m_paneManager, m_config->macroCommands); @@ -171,11 +171,6 @@ MainInterface::MainInterface(UniverseClientPtr client, WorldPainterPtr painter, m_nameplatePainter = make_shared(); m_questIndicatorPainter = make_shared(m_client); m_chatBubbleManager = make_shared(); - - m_paneManager.displayRegisteredPane(MainInterfacePanes::ActionBar); - m_paneManager.displayRegisteredPane(MainInterfacePanes::Chat); - m_paneManager.displayRegisteredPane(MainInterfacePanes::TeamBar); - m_paneManager.displayRegisteredPane(MainInterfacePanes::StatusPane); } MainInterface::~MainInterface() { @@ -997,6 +992,13 @@ void MainInterface::reviveScriptPanes(List& panes) { } } +void MainInterface::displayDefaultPanes() { + m_paneManager.displayRegisteredPane(MainInterfacePanes::ActionBar); + m_paneManager.displayRegisteredPane(MainInterfacePanes::Chat); + m_paneManager.displayRegisteredPane(MainInterfacePanes::TeamBar); + m_paneManager.displayRegisteredPane(MainInterfacePanes::StatusPane); +} + PanePtr MainInterface::createEscapeDialog() { auto assets = Root::singleton().assets(); diff --git a/source/frontend/StarMainInterface.hpp b/source/frontend/StarMainInterface.hpp index 667a2fe..a4f617b 100644 --- a/source/frontend/StarMainInterface.hpp +++ b/source/frontend/StarMainInterface.hpp @@ -132,6 +132,7 @@ public: void takeScriptPanes(List& out); void reviveScriptPanes(List& panes); + void displayDefaultPanes(); private: PanePtr createEscapeDialog(); diff --git a/source/game/StarUniverseClient.cpp b/source/game/StarUniverseClient.cpp index d739f5a..427cecb 100644 --- a/source/game/StarUniverseClient.cpp +++ b/source/game/StarUniverseClient.cpp @@ -519,6 +519,10 @@ void UniverseClient::stopLua() { m_scriptContexts.clear(); } +LuaRootPtr UniverseClient::luaRoot() { + return m_luaRoot; +} + bool UniverseClient::reloadPlayer(Json const& data, Uuid const&, bool resetInterfaces, bool showIndicator) { auto player = mainPlayer(); bool playerInWorld = player->inWorld(); diff --git a/source/game/StarUniverseClient.hpp b/source/game/StarUniverseClient.hpp index 3a3860d..9452cf6 100644 --- a/source/game/StarUniverseClient.hpp +++ b/source/game/StarUniverseClient.hpp @@ -89,6 +89,7 @@ public: void setLuaCallbacks(String const& groupName, LuaCallbacks const& callbacks); void startLua(); void stopLua(); + LuaRootPtr luaRoot(); bool reloadPlayer(Json const& data, Uuid const& uuid, bool resetInterfaces = false, bool showIndicator = false); bool switchPlayer(Uuid const& uuid); diff --git a/source/windowing/StarPane.cpp b/source/windowing/StarPane.cpp index 1511fed..1e20402 100644 --- a/source/windowing/StarPane.cpp +++ b/source/windowing/StarPane.cpp @@ -411,6 +411,18 @@ LuaCallbacks Pane::makePaneCallbacks() { return isDisplayed(); }); + callbacks.registerCallback("hasFocus", [this]() { + hasFocus(); + }); + + callbacks.registerCallback("show", [this]() { + show(); + }); + + callbacks.registerCallback("hide", [this]() { + hide(); + }); + return callbacks; } From e437282d5cf33b01b967151a56c70d8d1603f375 Mon Sep 17 00:00:00 2001 From: Kae <80987908+Novaenia@users.noreply.github.com> Date: Wed, 27 Nov 2024 21:29:53 +1100 Subject: [PATCH 2/3] Update StarQuestManager.cpp --- source/game/StarQuestManager.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source/game/StarQuestManager.cpp b/source/game/StarQuestManager.cpp index 4dbc652..2aa22fb 100644 --- a/source/game/StarQuestManager.cpp +++ b/source/game/StarQuestManager.cpp @@ -412,9 +412,9 @@ void QuestManager::update(float dt) { for (auto& questId : expiredQuests) m_quests.remove(questId); - for (auto& q : m_quests) { - if (questValidOnServer(q.second)) - q.second->update(dt); + for (auto& q : m_quests.values()) { + if (questValidOnServer(q)) + q->update(dt); } } From cbde26aebeec3a3cb72cfd6b55c7867d27b8c789 Mon Sep 17 00:00:00 2001 From: Kae <80987908+Novaenia@users.noreply.github.com> Date: Sat, 30 Nov 2024 09:17:44 +1100 Subject: [PATCH 3/3] move loadstring out of LuaRoot --- source/core/StarLua.cpp | 10 +++++++++- source/game/scripting/StarLuaRoot.cpp | 7 ------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/source/core/StarLua.cpp b/source/core/StarLua.cpp index 5a2effa..91aebab 100644 --- a/source/core/StarLua.cpp +++ b/source/core/StarLua.cpp @@ -537,8 +537,16 @@ LuaContext LuaEngine::createContext() { LuaDetail::shallowCopy(m_state, -1, -2); lua_pop(m_state, 1); + auto context = LuaContext(LuaDetail::LuaHandle(RefPtr(this), popHandle(m_state))); + // Add loadstring + auto handleIndex = context.handleIndex(); + context.set("loadstring", createFunction([this, handleIndex](String const& source, Maybe const& name, Maybe const& env) -> LuaFunction { + String functionName = name ? strf("loadstring: {}", *name) : "loadstring"; + return createFunctionFromSource(env ? env->handleIndex() : handleIndex, source.utf8Ptr(), source.utf8Size(), functionName.utf8Ptr()); + })); + // Then set that environment as the new context environment in the registry. - return LuaContext(LuaDetail::LuaHandle(RefPtr(this), popHandle(m_state))); + return context; } void LuaEngine::collectGarbage(Maybe steps) { diff --git a/source/game/scripting/StarLuaRoot.cpp b/source/game/scripting/StarLuaRoot.cpp index a14d10a..592c24b 100644 --- a/source/game/scripting/StarLuaRoot.cpp +++ b/source/game/scripting/StarLuaRoot.cpp @@ -106,13 +106,6 @@ LuaContext LuaRoot::createContext(StringList const& scriptPaths) { } }); - auto handleIndex = newContext.handleIndex(); - auto engine = m_luaEngine.get(); - newContext.set("loadstring", m_luaEngine->createFunction([engine, handleIndex](String const& source, Maybe const& name, Maybe const& env) -> LuaFunction { - String functionName = name ? strf("loadstring: {}", *name) : "loadstring"; - return engine->createFunctionFromSource(env ? env->handleIndex() : handleIndex, source.utf8Ptr(), source.utf8Size(), functionName.utf8Ptr()); - })); - auto assets = Root::singleton().assets(); for (auto const& scriptPath : scriptPaths) {