runtime udates
Some checks failed
CI / React UI Build (push) Successful in 11s
CI / Native Windows Build And Tests (push) Successful in 2m39s
CI / Windows Release Package (push) Has been cancelled

This commit is contained in:
Aiden
2026-05-11 00:22:55 +10:00
parent 861593123d
commit f6b26bf28b
4 changed files with 237 additions and 280 deletions

View File

@@ -1,5 +1,21 @@
#include "RuntimeStore.h"
namespace
{
std::string TrimCopy(const std::string& text)
{
std::size_t start = 0;
while (start < text.size() && std::isspace(static_cast<unsigned char>(text[start])))
++start;
std::size_t end = text.size();
while (end > start && std::isspace(static_cast<unsigned char>(text[end - 1])))
--end;
return text.substr(start, end - start);
}
}
RuntimeStore::RuntimeStore(RuntimeHost& runtimeHost) :
mRuntimeHost(runtimeHost)
{
@@ -64,37 +80,178 @@ std::string RuntimeStore::BuildPersistentStateJson() const
bool RuntimeStore::CreateStoredLayer(const std::string& shaderId, std::string& error)
{
return mRuntimeHost.AddLayer(shaderId, error);
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
auto shaderIt = mRuntimeHost.mPackagesById.find(shaderId);
if (shaderIt == mRuntimeHost.mPackagesById.end())
{
error = "Unknown shader id: " + shaderId;
return false;
}
RuntimeHost::LayerPersistentState layer;
layer.id = mRuntimeHost.GenerateLayerId();
layer.shaderId = shaderId;
layer.bypass = false;
mRuntimeHost.EnsureLayerDefaultsLocked(layer, shaderIt->second);
mRuntimeHost.mPersistentState.layers.push_back(layer);
mRuntimeHost.mReloadRequested = true;
mRuntimeHost.MarkRenderStateDirtyLocked();
return mRuntimeHost.SavePersistentState(error);
}
bool RuntimeStore::DeleteStoredLayer(const std::string& layerId, std::string& error)
{
return mRuntimeHost.RemoveLayer(layerId, error);
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
auto it = std::find_if(mRuntimeHost.mPersistentState.layers.begin(), mRuntimeHost.mPersistentState.layers.end(),
[&layerId](const RuntimeHost::LayerPersistentState& layer) { return layer.id == layerId; });
if (it == mRuntimeHost.mPersistentState.layers.end())
{
error = "Unknown layer id: " + layerId;
return false;
}
mRuntimeHost.mPersistentState.layers.erase(it);
mRuntimeHost.mReloadRequested = true;
mRuntimeHost.MarkRenderStateDirtyLocked();
return mRuntimeHost.SavePersistentState(error);
}
bool RuntimeStore::MoveStoredLayer(const std::string& layerId, int direction, std::string& error)
{
return mRuntimeHost.MoveLayer(layerId, direction, error);
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
auto it = std::find_if(mRuntimeHost.mPersistentState.layers.begin(), mRuntimeHost.mPersistentState.layers.end(),
[&layerId](const RuntimeHost::LayerPersistentState& layer) { return layer.id == layerId; });
if (it == mRuntimeHost.mPersistentState.layers.end())
{
error = "Unknown layer id: " + layerId;
return false;
}
const std::ptrdiff_t index = std::distance(mRuntimeHost.mPersistentState.layers.begin(), it);
const std::ptrdiff_t newIndex = index + direction;
if (newIndex < 0 || newIndex >= static_cast<std::ptrdiff_t>(mRuntimeHost.mPersistentState.layers.size()))
return true;
std::swap(mRuntimeHost.mPersistentState.layers[index], mRuntimeHost.mPersistentState.layers[newIndex]);
mRuntimeHost.mReloadRequested = true;
mRuntimeHost.MarkRenderStateDirtyLocked();
return mRuntimeHost.SavePersistentState(error);
}
bool RuntimeStore::MoveStoredLayerToIndex(const std::string& layerId, std::size_t targetIndex, std::string& error)
{
return mRuntimeHost.MoveLayerToIndex(layerId, targetIndex, error);
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
auto it = std::find_if(mRuntimeHost.mPersistentState.layers.begin(), mRuntimeHost.mPersistentState.layers.end(),
[&layerId](const RuntimeHost::LayerPersistentState& layer) { return layer.id == layerId; });
if (it == mRuntimeHost.mPersistentState.layers.end())
{
error = "Unknown layer id: " + layerId;
return false;
}
if (mRuntimeHost.mPersistentState.layers.empty())
return true;
if (targetIndex >= mRuntimeHost.mPersistentState.layers.size())
targetIndex = mRuntimeHost.mPersistentState.layers.size() - 1;
const std::size_t sourceIndex = static_cast<std::size_t>(std::distance(mRuntimeHost.mPersistentState.layers.begin(), it));
if (sourceIndex == targetIndex)
return true;
RuntimeHost::LayerPersistentState movedLayer = *it;
mRuntimeHost.mPersistentState.layers.erase(mRuntimeHost.mPersistentState.layers.begin() + static_cast<std::ptrdiff_t>(sourceIndex));
mRuntimeHost.mPersistentState.layers.insert(mRuntimeHost.mPersistentState.layers.begin() + static_cast<std::ptrdiff_t>(targetIndex), movedLayer);
mRuntimeHost.mReloadRequested = true;
mRuntimeHost.MarkRenderStateDirtyLocked();
return mRuntimeHost.SavePersistentState(error);
}
bool RuntimeStore::SetStoredLayerBypassState(const std::string& layerId, bool bypassed, std::string& error)
{
return mRuntimeHost.SetLayerBypass(layerId, bypassed, error);
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
RuntimeHost::LayerPersistentState* layer = mRuntimeHost.FindLayerById(layerId);
if (!layer)
{
error = "Unknown layer id: " + layerId;
return false;
}
layer->bypass = bypassed;
mRuntimeHost.mReloadRequested = true;
mRuntimeHost.MarkParameterStateDirtyLocked();
return mRuntimeHost.SavePersistentState(error);
}
bool RuntimeStore::SetStoredLayerShaderSelection(const std::string& layerId, const std::string& shaderId, std::string& error)
{
return mRuntimeHost.SetLayerShader(layerId, shaderId, error);
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
RuntimeHost::LayerPersistentState* layer = mRuntimeHost.FindLayerById(layerId);
if (!layer)
{
error = "Unknown layer id: " + layerId;
return false;
}
auto shaderIt = mRuntimeHost.mPackagesById.find(shaderId);
if (shaderIt == mRuntimeHost.mPackagesById.end())
{
error = "Unknown shader id: " + shaderId;
return false;
}
layer->shaderId = shaderId;
layer->parameterValues.clear();
mRuntimeHost.EnsureLayerDefaultsLocked(*layer, shaderIt->second);
mRuntimeHost.mReloadRequested = true;
mRuntimeHost.MarkRenderStateDirtyLocked();
return mRuntimeHost.SavePersistentState(error);
}
bool RuntimeStore::SetStoredParameterValue(const std::string& layerId, const std::string& parameterId, const JsonValue& newValue, std::string& error)
{
return mRuntimeHost.UpdateLayerParameter(layerId, parameterId, newValue, error);
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
RuntimeHost::LayerPersistentState* layer = mRuntimeHost.FindLayerById(layerId);
if (!layer)
{
error = "Unknown layer id: " + layerId;
return false;
}
auto shaderIt = mRuntimeHost.mPackagesById.find(layer->shaderId);
if (shaderIt == mRuntimeHost.mPackagesById.end())
{
error = "Unknown shader id: " + layer->shaderId;
return false;
}
const ShaderPackage& shaderPackage = shaderIt->second;
auto parameterIt = std::find_if(shaderPackage.parameters.begin(), shaderPackage.parameters.end(),
[&parameterId](const ShaderParameterDefinition& definition) { return definition.id == parameterId; });
if (parameterIt == shaderPackage.parameters.end())
{
error = "Unknown parameter id: " + parameterId;
return false;
}
if (parameterIt->type == ShaderParameterType::Trigger)
{
ShaderParameterValue& value = layer->parameterValues[parameterId];
const double previousCount = value.numberValues.empty() ? 0.0 : value.numberValues[0];
const double triggerTime = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - mRuntimeHost.mStartTime).count();
value.numberValues = { previousCount + 1.0, triggerTime };
mRuntimeHost.MarkParameterStateDirtyLocked();
return true;
}
ShaderParameterValue normalized;
if (!mRuntimeHost.NormalizeAndValidateValue(*parameterIt, newValue, normalized, error))
return false;
layer->parameterValues[parameterId] = normalized;
mRuntimeHost.MarkParameterStateDirtyLocked();
return mRuntimeHost.SavePersistentState(error);
}
bool RuntimeStore::SetStoredParameterValueByControlKey(const std::string& layerKey, const std::string& parameterKey, const JsonValue& newValue, std::string& error)
@@ -109,17 +266,86 @@ bool RuntimeStore::SetStoredParameterValueByControlKey(const std::string& layerK
bool RuntimeStore::ResetStoredLayerParameterValues(const std::string& layerId, std::string& error)
{
return mRuntimeHost.ResetLayerParameters(layerId, error);
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
RuntimeHost::LayerPersistentState* layer = mRuntimeHost.FindLayerById(layerId);
if (!layer)
{
error = "Unknown layer id: " + layerId;
return false;
}
auto shaderIt = mRuntimeHost.mPackagesById.find(layer->shaderId);
if (shaderIt == mRuntimeHost.mPackagesById.end())
{
error = "Unknown shader id: " + layer->shaderId;
return false;
}
layer->parameterValues.clear();
mRuntimeHost.EnsureLayerDefaultsLocked(*layer, shaderIt->second);
mRuntimeHost.MarkParameterStateDirtyLocked();
return mRuntimeHost.SavePersistentState(error);
}
bool RuntimeStore::SaveStackPresetSnapshot(const std::string& presetName, std::string& error) const
{
return mRuntimeHost.SaveStackPreset(presetName, error);
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
const std::string safeStem = mRuntimeHost.MakeSafePresetFileStem(presetName);
if (safeStem.empty())
{
error = "Preset name must include at least one letter or number.";
return false;
}
JsonValue root = JsonValue::MakeObject();
root.set("version", JsonValue(1.0));
root.set("name", JsonValue(TrimCopy(presetName)));
root.set("layers", mRuntimeHost.SerializeLayerStackLocked());
return mRuntimeHost.WriteTextFile(mRuntimeHost.mPresetRoot / (safeStem + ".json"), SerializeJson(root, true), error);
}
bool RuntimeStore::LoadStackPresetSnapshot(const std::string& presetName, std::string& error)
{
return mRuntimeHost.LoadStackPreset(presetName, error);
std::lock_guard<std::mutex> lock(mRuntimeHost.mMutex);
const std::string safeStem = mRuntimeHost.MakeSafePresetFileStem(presetName);
if (safeStem.empty())
{
error = "Preset name must include at least one letter or number.";
return false;
}
const std::filesystem::path presetPath = mRuntimeHost.mPresetRoot / (safeStem + ".json");
std::string presetText = mRuntimeHost.ReadTextFile(presetPath, error);
if (presetText.empty())
return false;
JsonValue root;
if (!ParseJson(presetText, root, error))
return false;
const JsonValue* layersValue = root.find("layers");
if (!layersValue || !layersValue->isArray())
{
error = "Preset file is missing a valid 'layers' array.";
return false;
}
std::vector<RuntimeHost::LayerPersistentState> nextLayers;
if (!mRuntimeHost.DeserializeLayerStackLocked(*layersValue, nextLayers, error))
return false;
if (nextLayers.empty())
{
error = "Preset does not contain any valid layers.";
return false;
}
mRuntimeHost.mPersistentState.layers = nextLayers;
mRuntimeHost.mReloadRequested = true;
mRuntimeHost.MarkRenderStateDirtyLocked();
return mRuntimeHost.SavePersistentState(error);
}
const std::filesystem::path& RuntimeStore::GetRuntimeRepositoryRoot() const