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

summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/base/CMakeLists.txt2
-rw-r--r--source/base/StarAssets.cpp92
-rw-r--r--source/base/StarMemoryAssetSource.cpp86
-rw-r--r--source/base/StarMemoryAssetSource.hpp29
4 files changed, 187 insertions, 22 deletions
diff --git a/source/base/CMakeLists.txt b/source/base/CMakeLists.txt
index 712e201..f16257a 100644
--- a/source/base/CMakeLists.txt
+++ b/source/base/CMakeLists.txt
@@ -14,6 +14,7 @@ SET (star_base_HEADERS
StarCellularLiquid.hpp
StarConfiguration.hpp
StarDirectoryAssetSource.hpp
+ StarMemoryAssetSource.hpp
StarMixer.hpp
StarPackedAssetSource.hpp
StarVersion.hpp
@@ -27,6 +28,7 @@ SET (star_base_SOURCES
StarCellularLighting.cpp
StarConfiguration.cpp
StarDirectoryAssetSource.cpp
+ StarMemoryAssetSource.cpp
StarMixer.cpp
StarPackedAssetSource.cpp
StarVersionOptionParser.cpp
diff --git a/source/base/StarAssets.cpp b/source/base/StarAssets.cpp
index 2515b5e..9ba7029 100644
--- a/source/base/StarAssets.cpp
+++ b/source/base/StarAssets.cpp
@@ -4,6 +4,7 @@
#include "StarTime.hpp"
#include "StarDirectoryAssetSource.hpp"
#include "StarPackedAssetSource.hpp"
+#include "StarMemoryAssetSource.hpp"
#include "StarJsonBuilder.hpp"
#include "StarJsonExtra.hpp"
#include "StarJsonPatch.hpp"
@@ -108,18 +109,54 @@ Assets::Assets(Settings settings, StringList assetSources) {
m_assetSources = std::move(assetSources);
auto luaEngine = LuaEngine::create();
- auto decorateLuaContext = [this](LuaContext& context) {
+ auto decorateLuaContext = [this](LuaContext& context, MemoryAssetSourcePtr mySource) {
context.setCallbacks("sb", LuaBindings::makeUtilityCallbacks());
LuaCallbacks callbacks;
callbacks.registerCallbackWithSignature<StringSet, String>("byExtension", bind(&Assets::scanExtension, this, _1));
callbacks.registerCallbackWithSignature<Json, String>("json", bind(&Assets::json, this, _1));
+
callbacks.registerCallback("bytes", [this](String const& path) -> String {
auto assetBytes = bytes(path);
return String(assetBytes->ptr(), assetBytes->size());
});
+
callbacks.registerCallback("scan", [this](Maybe<String> const& a, Maybe<String> const& b) -> StringList {
return b ? scan(a.value(), *b) : scan(a.value());
});
+
+ callbacks.registerCallback("add", [this, &mySource](LuaEngine& engine, String const& path, LuaValue const& data) -> bool {
+ ByteArray bytes;
+ if (auto str = engine.luaMaybeTo<String>(data))
+ bytes = ByteArray(str->utf8Ptr(), str->utf8Size());
+ else {
+ auto json = engine.luaTo<Json>(data).repr();
+ bytes = ByteArray(json.utf8Ptr(), json.utf8Size());
+ }
+ return mySource->set(path, bytes);
+ });
+
+ callbacks.registerCallback("patch", [this, &mySource](String const& path, String const& patchPath) -> bool {
+ if (auto file = m_files.ptr(path)) {
+ if (mySource->contains(patchPath)) {
+ file->patchSources.append(make_pair(patchPath, mySource));
+ return true;
+ } else {
+ if (auto asset = m_files.ptr(patchPath)) {
+ file->patchSources.append(make_pair(patchPath, asset->source));
+ return true;
+ }
+ }
+ }
+ return false;
+ });
+
+ callbacks.registerCallback("erase", [this, &mySource](String const& path) -> bool {
+ bool erased = m_files.erase(path);
+ if (erased)
+ m_filesByExtension[AssetPath::extension(path).toLower()].erase(path);
+ return erased;
+ });
+
context.setCallbacks("assets", callbacks);
};
@@ -131,37 +168,46 @@ Assets::Assets(Settings settings, StringList assetSources) {
else
source = std::make_shared<PackedAssetSource>(sourcePath);
- m_assetSourcePaths.add(sourcePath, source);
-
- for (auto const& filename : source->assetPaths()) {
- if (filename.contains(AssetsPatchSuffix, String::CaseInsensitive)) {
- if (filename.endsWith(AssetsPatchSuffix, String::CaseInsensitive)) {
- auto targetPatchFile = filename.substr(0, filename.size() - strlen(AssetsPatchSuffix));
- if (auto p = m_files.ptr(targetPatchFile))
- p->patchSources.append({filename, source});
- } else {
- for (int i = 0; i < 10; i++) {
- if (filename.endsWith(AssetsPatchSuffix + toString(i), String::CaseInsensitive)) {
- auto targetPatchFile = filename.substr(0, filename.size() - strlen(AssetsPatchSuffix) + 1);
- if (auto p = m_files.ptr(targetPatchFile))
- p->patchSources.append({filename, source});
- break;
+ auto addSource = [&](String const& sourcePath, AssetSourcePtr source) {
+ m_assetSourcePaths.add(sourcePath, source);
+
+ for (auto const& filename : source->assetPaths()) {
+ if (filename.contains(AssetsPatchSuffix, String::CaseInsensitive)) {
+ if (filename.endsWith(AssetsPatchSuffix, String::CaseInsensitive)) {
+ auto targetPatchFile = filename.substr(0, filename.size() - strlen(AssetsPatchSuffix));
+ if (auto p = m_files.ptr(targetPatchFile))
+ p->patchSources.append({filename, source});
+ } else {
+ for (int i = 0; i < 10; i++) {
+ if (filename.endsWith(AssetsPatchSuffix + toString(i), String::CaseInsensitive)) {
+ auto targetPatchFile = filename.substr(0, filename.size() - strlen(AssetsPatchSuffix) + 1);
+ if (auto p = m_files.ptr(targetPatchFile))
+ p->patchSources.append({filename, source});
+ break;
+ }
}
}
}
+
+ auto& descriptor = m_files[filename];
+ descriptor.sourceName = filename;
+ descriptor.source = source;
+ m_filesByExtension[AssetPath::extension(filename).toLower()].insert(filename);
}
- auto& descriptor = m_files[filename];
- descriptor.sourceName = filename;
- descriptor.source = source;
- m_filesByExtension[AssetPath::extension(filename).toLower()].insert(filename);
- }
+ };
+ addSource(sourcePath, source);
+
auto metadata = source->metadata();
if (auto scripts = metadata.ptr("scripts")) {
if (auto onLoad = scripts->optArray("onLoad")) {
+ JsonObject memoryMetadata{
+ {"name", strf("{}.onLoad", metadata.value("name", File::baseName(sourcePath)))}
+ };
+ auto memoryAssets = make_shared<MemoryAssetSource>(memoryMetadata);
Logger::info("Running onLoad scripts {}", *onLoad);
try {
auto context = luaEngine->createContext();
- decorateLuaContext(context);
+ decorateLuaContext(context, memoryAssets);
for (auto& jPath : *onLoad) {
auto path = jPath.toString();
auto script = source->read(path);
@@ -171,6 +217,8 @@ Assets::Assets(Settings settings, StringList assetSources) {
catch (LuaException const& e) {
Logger::error("Exception while running onLoad scripts from asset source '{}': {}", sourcePath, e.what());
}
+ if (!memoryAssets->empty())
+ addSource(memoryMetadata.get("name").toString(), memoryAssets);
}
}
}
diff --git a/source/base/StarMemoryAssetSource.cpp b/source/base/StarMemoryAssetSource.cpp
new file mode 100644
index 0000000..9c777ed
--- /dev/null
+++ b/source/base/StarMemoryAssetSource.cpp
@@ -0,0 +1,86 @@
+#include "StarMemoryAssetSource.hpp"
+#include "StarDataStreamDevices.hpp"
+#include "StarDataStreamExtra.hpp"
+#include "StarSha256.hpp"
+
+namespace Star {
+
+MemoryAssetSource::MemoryAssetSource(JsonObject metadata) : m_metadata(metadata) {}
+
+JsonObject MemoryAssetSource::metadata() const {
+ return m_metadata;
+}
+
+StringList MemoryAssetSource::assetPaths() const {
+ return m_files.keys();
+}
+
+IODevicePtr MemoryAssetSource::open(String const& path) {
+ struct AssetReader : public IODevice {
+ AssetReader(ByteArrayPtr assetData, String name) : assetData(assetData), name(name) { setMode(IOMode::Read); }
+
+ size_t read(char* data, size_t len) override {
+ len = min<StreamOffset>(len, StreamOffset(assetData->size()) - assetPos);
+ assetData->copyTo(data, len);
+ return len;
+ }
+
+ size_t write(char const*, size_t) override {
+ throw IOException("Assets IODevices are read-only");
+ }
+
+ StreamOffset size() override { return assetData->size(); }
+ StreamOffset pos() override { return assetPos; }
+
+ String deviceName() const override { return name; }
+
+ bool atEnd() override {
+ return assetPos >= assetData->size();
+ }
+
+ void seek(StreamOffset p, IOSeek mode) override {
+ if (mode == IOSeek::Absolute)
+ assetPos = p;
+ else if (mode == IOSeek::Relative)
+ assetPos = clamp<StreamOffset>(assetPos + p, 0, assetData->size());
+ else
+ assetPos = clamp<StreamOffset>(assetPos - p, 0, assetData->size());
+ }
+
+ ByteArrayPtr assetData;
+ StreamOffset assetPos;
+ String name;
+ };
+
+ auto p = m_files.ptr(path);
+ if (!p)
+ throw AssetSourceException::format("Requested file '{}' does not exist in memory", path);
+
+ return make_shared<AssetReader>(*p, path);
+}
+
+bool MemoryAssetSource::empty() const {
+ return m_files.empty();
+}
+
+bool MemoryAssetSource::contains(String const& path) const {
+ return m_files.contains(path);
+}
+
+bool MemoryAssetSource::erase(String const& path) {
+ return m_files.erase(path) != 0;
+}
+
+bool MemoryAssetSource::set(String const& path, ByteArray data) {
+ return m_files.emplace(path, make_shared<ByteArray>(std::move(data))).second;
+}
+
+ByteArray MemoryAssetSource::read(String const& path) {
+ auto p = m_files.ptr(path);
+ if (!p)
+ throw AssetSourceException::format("Requested file '{}' does not exist in memory", path);
+ else
+ return *p->get(); // this is a double indirection, and that freaking sucks!!
+}
+
+}
diff --git a/source/base/StarMemoryAssetSource.hpp b/source/base/StarMemoryAssetSource.hpp
new file mode 100644
index 0000000..353a132
--- /dev/null
+++ b/source/base/StarMemoryAssetSource.hpp
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "StarAssetSource.hpp"
+#include "StarIODevice.hpp"
+
+namespace Star {
+
+STAR_CLASS(MemoryAssetSource);
+
+class MemoryAssetSource : public AssetSource {
+public:
+ MemoryAssetSource(JsonObject metadata = JsonObject());
+
+ JsonObject metadata() const override;
+ StringList assetPaths() const override;
+
+ IODevicePtr open(String const& path) override;
+
+ bool empty() const;
+ bool contains(String const& path) const;
+ bool erase(String const& path);
+ bool set(String const& path, ByteArray data);
+ ByteArray read(String const& path) override;
+private:
+ JsonObject m_metadata;
+ StringMap<ByteArrayPtr> m_files;
+};
+
+}