Add ability to schedule Lua scripts (#3416)

This commit is contained in:
Alexander Bock
2024-09-23 11:34:51 +02:00
committed by GitHub
parent 24a2247aa4
commit db23148af0
3 changed files with 121 additions and 2 deletions

View File

@@ -102,7 +102,6 @@ public:
void addLibrary(LuaLibrary library);
bool hasLibrary(const std::string& name);
virtual void preSync(bool isMaster) override;
virtual void encode(SyncBuffer* syncBuffer) override;
virtual void decode(SyncBuffer* syncBuffer) override;
@@ -111,6 +110,11 @@ public:
void queueScript(Script script);
void queueScript(std::string script);
// Runs the `script` every `timeout` seconds wallclock time
void registerRepeatedScript(std::string identifier, std::string script,
double timeout, std::string preScript = "", std::string postScript = "");
void removeRepeatedScript(std::string_view identifier);
std::vector<std::string> allLuaFunctions() const;
const std::vector<LuaLibrary>& allLuaLibraries() const;
@@ -141,6 +145,19 @@ private:
std::vector<std::string> _scriptsToSync;
struct RepeatedScriptInfo {
/// This script is run everytime `timeout` seconds have passed
std::string script;
/// This script is run when the repeated script is unregistered
std::string postScript;
std::string identifier;
double timeout = 0.0;
double lastRun = 0.0;
};
std::vector<RepeatedScriptInfo> _repeatedScripts;
// Logging variables
bool _logFileExists = false;
bool _logScripts = true;

View File

@@ -27,6 +27,7 @@
#include <openspace/documentation/documentation.h>
#include <openspace/engine/configuration.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/network/parallelpeer.h>
#include <openspace/util/syncbuffer.h>
@@ -103,6 +104,12 @@ void ScriptEngine::deinitialize() {
ZoneScoped;
_registeredLibraries.clear();
for (const RepeatedScriptInfo& info : _repeatedScripts) {
if (info.postScript.empty()) {
queueScript(info.postScript);
}
}
_repeatedScripts.clear();
}
void ScriptEngine::initializeLuaState(lua_State* state) {
@@ -553,6 +560,17 @@ void ScriptEngine::postSync(bool isMaster) {
}
}
}
double now =
global::sessionRecording->isSavingFramesDuringPlayback() ?
global::sessionRecording->currentApplicationInterpolationTime() :
global::windowDelegate->applicationTime();
for (RepeatedScriptInfo& info : _repeatedScripts) {
if (now - info.lastRun >= info.timeout) {
runScript({ info.script });
info.lastRun = now;
}
}
}
void ScriptEngine::queueScript(Script script) {
@@ -568,6 +586,55 @@ void ScriptEngine::queueScript(std::string script) {
queueScript({ .code = std::move(script) });
}
void ScriptEngine::registerRepeatedScript(std::string identifier, std::string script,
double timeout, std::string preScript,
std::string postScript)
{
auto it = std::find_if(
_repeatedScripts.begin(),
_repeatedScripts.end(),
[&identifier](const RepeatedScriptInfo& info) {
return info.identifier == identifier;
}
);
if (it != _repeatedScripts.end()) {
throw ghoul::RuntimeError(
std::format("Script with identifier '{}' already registered", identifier),
"ScriptEngine"
);
}
if (!preScript.empty()) {
runScript({ std::move(preScript) });
}
_repeatedScripts.emplace_back(
std::move(script),
std::move(postScript),
std::move(identifier),
timeout
);
}
void ScriptEngine::removeRepeatedScript(std::string_view identifier) {
auto it = std::find_if(
_repeatedScripts.begin(),
_repeatedScripts.end(),
[&identifier](const RepeatedScriptInfo& info) {
return info.identifier == identifier;
}
);
if (it != _repeatedScripts.end()) {
if (!it->postScript.empty()) {
queueScript(it->postScript);
}
_repeatedScripts.erase(it);
}
else {
LERROR(std::format("Could not find script with identifier '{}'", identifier));
}
}
void ScriptEngine::addBaseLibrary() {
ZoneScoped;
@@ -645,7 +712,9 @@ void ScriptEngine::addBaseLibrary() {
codegen::lua::WalkDirectoryFiles,
codegen::lua::WalkDirectoryFolders,
codegen::lua::DirectoryForPath,
codegen::lua::UnzipFile
codegen::lua::UnzipFile,
codegen::lua::RegisterRepeatedScript,
codegen::lua::RemoveRepeatedScript
}
};
addLibrary(lib);

View File

@@ -279,6 +279,39 @@ std::vector<std::filesystem::path> walkCommon(const std::filesystem::path& path,
}
}
/**
* This function registers another Lua script that will be periodically executed as long
* as the application is running. The `identifier` is used to later remove the script. The
* `script` is being executed every `timeout` seconds. This timeout is only as accurate as
* the framerate at which the application is running. Optionally the `preScript` Lua
* script is run when registering the repeated script and the `postScript` is run when
* unregistering it or when the application closes.
* If the `timeout` is 0, the script will be executed every frame.
* The `identifier` has to be a unique name that cannot have been used to register a
* repeated script before. A registered script is removed with the #removeRepeatedScript
* function.
*/
[[codegen::luawrap]] void registerRepeatedScript(std::string identifier,
std::string script, double timeout = 0.0,
std::string preScript = "",
std::string postScript = "")
{
openspace::global::scriptEngine->registerRepeatedScript(
std::move(identifier),
std::move(script),
timeout,
std::move(preScript),
std::move(postScript)
);
}
/**
* Removes a previously registered repeated script (see #registerRepeatedScript)
*/
[[codegen::luawrap]] void removeRepeatedScript(std::string identifier) {
openspace::global::scriptEngine->removeRepeatedScript(identifier);
}
#include "scriptengine_lua_codegen.cpp"
} // namespace