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

summaryrefslogtreecommitdiff
path: root/source/game/scripting/StarScriptableThread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/game/scripting/StarScriptableThread.cpp')
-rw-r--r--source/game/scripting/StarScriptableThread.cpp152
1 files changed, 152 insertions, 0 deletions
diff --git a/source/game/scripting/StarScriptableThread.cpp b/source/game/scripting/StarScriptableThread.cpp
new file mode 100644
index 0000000..cbd32ad
--- /dev/null
+++ b/source/game/scripting/StarScriptableThread.cpp
@@ -0,0 +1,152 @@
+#include "StarScriptableThread.hpp"
+#include "StarLuaRoot.hpp"
+#include "StarLuaComponents.hpp"
+#include "StarConfigLuaBindings.hpp"
+#include "StarTickRateMonitor.hpp"
+#include "StarNpc.hpp"
+#include "StarRoot.hpp"
+#include "StarJsonExtra.hpp"
+#include "StarLogging.hpp"
+#include "StarAssets.hpp"
+
+namespace Star {
+
+ScriptableThread::ScriptableThread(Json parameters)
+ : Thread("ScriptableThread: " + parameters.getString("name")), // TODO
+ m_stop(false),
+ m_errorOccurred(false),
+ m_shouldExpire(true),
+ m_parameters(std::move(parameters)) {
+ m_luaRoot = make_shared<LuaRoot>();
+ m_name = m_parameters.getString("name");
+
+ m_timestep = 1.0f / m_parameters.getFloat("tickRate",60.0f);
+
+ // since thread's not blocking anything important, allow modifying the instruction limit
+ if (auto instructionLimit = m_parameters.optUInt("instructionLimit"))
+ m_luaRoot->luaEngine().setInstructionLimit(instructionLimit.value());
+
+ m_luaRoot->addCallbacks("thread", makeThreadCallbacks());
+ m_luaRoot->addCallbacks(
+ "config", LuaBindings::makeConfigCallbacks(bind(&ScriptableThread::configValue, this, _1, _2)));
+
+ for (auto& p : m_parameters.getObject("scripts")) {
+ auto scriptComponent = make_shared<ScriptComponent>();
+ scriptComponent->setLuaRoot(m_luaRoot);
+ scriptComponent->setScripts(jsonToStringList(p.second.toArray()));
+
+ m_scriptContexts.set(p.first, scriptComponent);
+ scriptComponent->init();
+ }
+}
+
+ScriptableThread::~ScriptableThread() {
+ m_stop = true;
+
+ m_scriptContexts.clear();
+
+ join();
+}
+
+void ScriptableThread::start() {
+ m_stop = false;
+ m_errorOccurred = false;
+ Thread::start();
+}
+
+void ScriptableThread::stop() {
+ m_stop = true;
+ Thread::join();
+}
+
+void ScriptableThread::setPause(bool pause) {
+ m_pause = pause;
+}
+
+bool ScriptableThread::errorOccurred() {
+ return m_errorOccurred;
+}
+
+bool ScriptableThread::shouldExpire() {
+ return m_shouldExpire;
+}
+
+void ScriptableThread::passMessage(Message&& message) {
+ RecursiveMutexLocker locker(m_messageMutex);
+ m_messages.append(std::move(message));
+}
+
+void ScriptableThread::run() {
+ try {
+ auto& root = Root::singleton();
+
+ double updateMeasureWindow = m_parameters.getDouble("updateMeasureWindow",0.5);
+ TickRateApproacher tickApproacher(1.0f / m_timestep, updateMeasureWindow);
+
+ while (!m_stop && !m_errorOccurred) {
+ LogMap::set(strf("lua_{}_update", m_name), strf("{:4.2f}Hz", tickApproacher.rate()));
+
+ update();
+ tickApproacher.setTargetTickRate(1.0f / m_timestep);
+ tickApproacher.tick();
+
+ double spareTime = tickApproacher.spareTime();
+
+ int64_t spareMilliseconds = floor(spareTime * 1000);
+ if (spareMilliseconds > 0)
+ Thread::sleepPrecise(spareMilliseconds);
+ }
+ } catch (std::exception const& e) {
+ Logger::error("ScriptableThread exception caught: {}", outputException(e, true));
+ m_errorOccurred = true;
+ }
+ for (auto& p : m_scriptContexts)
+ p.second->uninit();
+}
+
+Maybe<Json> ScriptableThread::receiveMessage(String const& message, JsonArray const& args) {
+ Maybe<Json> result;
+ for (auto& p : m_scriptContexts) {
+ result = p.second->handleMessage(message, true, args);
+ if (result)
+ break;
+ }
+ return result;
+}
+
+void ScriptableThread::update() {
+ float dt = m_timestep;
+
+ if (dt > 0.0f && !m_pause) {
+ for (auto& p : m_scriptContexts) {
+ p.second->update(p.second->updateDt(dt));
+ }
+ }
+
+ List<Message> messages;
+ {
+ RecursiveMutexLocker locker(m_messageMutex);
+ messages = std::move(m_messages);
+ }
+ for (auto& message : messages) {
+ if (auto resp = receiveMessage(message.message, message.args))
+ message.promise.fulfill(*resp);
+ else
+ message.promise.fail("Message not handled by thread");
+ }
+}
+
+LuaCallbacks ScriptableThread::makeThreadCallbacks() {
+ LuaCallbacks callbacks;
+
+ callbacks.registerCallback("stop", [this]() {
+ m_stop = true;
+ });
+
+ return callbacks;
+}
+
+Json ScriptableThread::configValue(String const& name, Json def) const {
+ return m_parameters.get(name, std::move(def));
+}
+}