From 5815a873a7b425551b26ae58430ba8f2af961746 Mon Sep 17 00:00:00 2001 From: Kae <80987908+Novaenia@users.noreply.github.com> Date: Fri, 3 Nov 2023 06:51:17 +1100 Subject: [PATCH] Add more root.asset* functions --- source/base/StarAssets.cpp | 10 + source/base/StarAssets.hpp | 182 +++++++++--------- source/game/scripting/StarRootLuaBindings.cpp | 40 ++++ 3 files changed, 143 insertions(+), 89 deletions(-) diff --git a/source/base/StarAssets.cpp b/source/base/StarAssets.cpp index 7efceb3..8956ba9 100644 --- a/source/base/StarAssets.cpp +++ b/source/base/StarAssets.cpp @@ -164,6 +164,11 @@ bool Assets::assetExists(String const& path) const { return m_files.contains(path); } +Maybe Assets::assetDescriptor(String const& path) const { + MutexLocker assetsLocker(m_assetsMutex); + return m_files.maybe(path); +} + String Assets::assetSource(String const& path) const { MutexLocker assetsLocker(m_assetsMutex); if (auto p = m_files.ptr(path)) @@ -171,6 +176,11 @@ String Assets::assetSource(String const& path) const { throw AssetException(strf("No such asset '{}'", path)); } +Maybe Assets::assetSourcePath(AssetSourcePtr const& source) const { + MutexLocker assetsLocker(m_assetsMutex); + return m_assetSourcePaths.maybeLeft(source); +} + StringList Assets::scan(String const& suffix) const { if (suffix.beginsWith(".") && !suffix.substr(1).hasChar('.')) { return scanExtension(suffix); diff --git a/source/base/StarAssets.hpp b/source/base/StarAssets.hpp index 15b3b50..93c09cb 100644 --- a/source/base/StarAssets.hpp +++ b/source/base/StarAssets.hpp @@ -68,95 +68,7 @@ public: StringList digestIgnore; }; - Assets(Settings settings, StringList assetSources); - ~Assets(); - - // Returns a list of all the asset source paths used by Assets in load order. - StringList assetSources() const; - - // Return metadata for the given loaded asset source path - JsonObject assetSourceMetadata(String const& sourcePath) const; - - // An imperfect sha256 digest of the contents of all combined asset sources. - // Useful for detecting if there are mismatched assets between a client and - // server or if assets sources have changed from a previous load. - ByteArray digest() const; - - // Is there an asset associated with the given path? Path must not contain - // sub-paths or directives. - bool assetExists(String const& path) const; - - // The name of the asset source within which the path exists. - String assetSource(String const& path) const; - - // Scans for all assets with the given suffix in any directory. - StringList scan(String const& suffix) const; - // Scans for all assets matching both prefix and suffix (prefix may be, for - // example, a directory) - StringList scan(String const& prefix, String const& suffix) const; - // Scans all assets for files with the given extension, which is specially - // indexed and much faster than a normal scan. Extension may contain leading - // '.' character or it may be omitted. - StringList scanExtension(String const& extension) const; - - // Get json asset with an optional sub-path. The sub-path portion of the - // path refers to a key in the top-level object, and may use dot notation - // for deeper field access and [] notation for array access. Example: - // "/path/to/json:key1.key2.key3[4]". - Json json(String const& path) const; - - // Either returns the json v, or, if v is a string type, returns the json - // pointed to by interpreting v as a string path. - Json fetchJson(Json const& v, String const& dir = "/") const; - - // Load all the given jsons using background processing. - void queueJsons(StringList const& paths) const; - - // Returns *either* an image asset or a sub-frame. Frame files are JSON - // descriptor files that reference a particular image and label separate - // sub-rects of the image. If the given path has a ':' sub-path, then the - // assets system will look for an associated .frames named either - // .frames or default.frames, going up to assets - // root. May return the same ImageConstPtr for different paths if the paths - // are equivalent or they are aliases of other image paths. - ImageConstPtr image(AssetPath const& path) const; - // Load images using background processing - void queueImages(StringList const& paths) const; - // Return the given image *if* it is already loaded, otherwise queue it for - // loading. - ImageConstPtr tryImage(AssetPath const& path) const; - - // Returns the best associated FramesSpecification for a given image path, if - // it exists. The given path must not contain sub-paths or directives, and - // this function may return nullptr if no frames file is associated with the - // given image path. - FramesSpecificationConstPtr imageFrames(String const& path) const; - - // Returns a pointer to a shared audio asset; - AudioConstPtr audio(String const& path) const; - // Load audios using background processing - void queueAudios(StringList const& paths) const; - // Return the given audio *if* it is already loaded, otherwise queue it for - // loading. - AudioConstPtr tryAudio(String const& path) const; - - // Returns pointer to shared font asset - FontConstPtr font(String const& path) const; - - // Returns a bytes asset (Reads asset as an opaque binary blob) - ByteArrayConstPtr bytes(String const& path) const; - - // Bypass asset caching and open an asset file directly. - IODevicePtr openFile(String const& basePath) const; - - // Clear all cached assets that are not queued, persistent, or broken. - void clearCache(); - - // Run a cleanup pass and remove any assets past their time to live. - void cleanup(); - -private: - enum class AssetType { + enum class AssetType { Json, Image, Audio, @@ -243,6 +155,98 @@ private: List> patchSources; }; + Assets(Settings settings, StringList assetSources); + ~Assets(); + + // Returns a list of all the asset source paths used by Assets in load order. + StringList assetSources() const; + + // Return metadata for the given loaded asset source path + JsonObject assetSourceMetadata(String const& sourcePath) const; + + // An imperfect sha256 digest of the contents of all combined asset sources. + // Useful for detecting if there are mismatched assets between a client and + // server or if assets sources have changed from a previous load. + ByteArray digest() const; + + // Is there an asset associated with the given path? Path must not contain + // sub-paths or directives. + bool assetExists(String const& path) const; + + Maybe assetDescriptor(String const& path) const; + + // The name of the asset source within which the path exists. + String assetSource(String const& path) const; + + Maybe assetSourcePath(AssetSourcePtr const& source) const; + + // Scans for all assets with the given suffix in any directory. + StringList scan(String const& suffix) const; + // Scans for all assets matching both prefix and suffix (prefix may be, for + // example, a directory) + StringList scan(String const& prefix, String const& suffix) const; + // Scans all assets for files with the given extension, which is specially + // indexed and much faster than a normal scan. Extension may contain leading + // '.' character or it may be omitted. + StringList scanExtension(String const& extension) const; + + // Get json asset with an optional sub-path. The sub-path portion of the + // path refers to a key in the top-level object, and may use dot notation + // for deeper field access and [] notation for array access. Example: + // "/path/to/json:key1.key2.key3[4]". + Json json(String const& path) const; + + // Either returns the json v, or, if v is a string type, returns the json + // pointed to by interpreting v as a string path. + Json fetchJson(Json const& v, String const& dir = "/") const; + + // Load all the given jsons using background processing. + void queueJsons(StringList const& paths) const; + + // Returns *either* an image asset or a sub-frame. Frame files are JSON + // descriptor files that reference a particular image and label separate + // sub-rects of the image. If the given path has a ':' sub-path, then the + // assets system will look for an associated .frames named either + // .frames or default.frames, going up to assets + // root. May return the same ImageConstPtr for different paths if the paths + // are equivalent or they are aliases of other image paths. + ImageConstPtr image(AssetPath const& path) const; + // Load images using background processing + void queueImages(StringList const& paths) const; + // Return the given image *if* it is already loaded, otherwise queue it for + // loading. + ImageConstPtr tryImage(AssetPath const& path) const; + + // Returns the best associated FramesSpecification for a given image path, if + // it exists. The given path must not contain sub-paths or directives, and + // this function may return nullptr if no frames file is associated with the + // given image path. + FramesSpecificationConstPtr imageFrames(String const& path) const; + + // Returns a pointer to a shared audio asset; + AudioConstPtr audio(String const& path) const; + // Load audios using background processing + void queueAudios(StringList const& paths) const; + // Return the given audio *if* it is already loaded, otherwise queue it for + // loading. + AudioConstPtr tryAudio(String const& path) const; + + // Returns pointer to shared font asset + FontConstPtr font(String const& path) const; + + // Returns a bytes asset (Reads asset as an opaque binary blob) + ByteArrayConstPtr bytes(String const& path) const; + + // Bypass asset caching and open an asset file directly. + IODevicePtr openFile(String const& basePath) const; + + // Clear all cached assets that are not queued, persistent, or broken. + void clearCache(); + + // Run a cleanup pass and remove any assets past their time to live. + void cleanup(); + +private: static FramesSpecification parseFramesSpecification(Json const& frameConfig, String path); void queueAssets(List const& assetIds) const; diff --git a/source/game/scripting/StarRootLuaBindings.cpp b/source/game/scripting/StarRootLuaBindings.cpp index d72748f..1898fff 100644 --- a/source/game/scripting/StarRootLuaBindings.cpp +++ b/source/game/scripting/StarRootLuaBindings.cpp @@ -63,6 +63,46 @@ LuaCallbacks LuaBindings::makeRootCallbacks() { callbacks.registerCallbackWithSignature, String, Maybe>("materialMiningSound", bind(RootCallbacks::materialMiningSound, root, _1, _2)); callbacks.registerCallbackWithSignature, String, Maybe>("materialFootstepSound", bind(RootCallbacks::materialFootstepSound, root, _1, _2)); + callbacks.registerCallback("assetOrigin", [root](String const& path) { + auto assets = root->assets(); + if (auto descriptor = assets->assetDescriptor(path)) + return assets->assetSourcePath(descriptor->source); + }); + + callbacks.registerCallback("assetPatches", [root](LuaEngine& engine, String const& path) -> Maybe { + auto assets = root->assets(); + if (auto descriptor = assets->assetDescriptor(path)) { + auto& patches = descriptor->patchSources; + auto table = engine.createTable(patches.size(), 0); + for (size_t i = 0; i != patches.size(); ++i) { + auto& patch = patches.at(i); + auto patchTable = engine.createTable(2, 0); + if (auto sourcePath = assets->assetSourcePath(patch.second)) + patchTable.set(1, *sourcePath); + patchTable.set(2, patch.first); + table.set(i + 1, patchTable); + } + return table; + } + return {}; + }); + + callbacks.registerCallback("assetSourcePaths", [root](LuaEngine& engine, Maybe withMetadata) -> LuaTable { + auto assets = root->assets(); + auto assetSources = assets->assetSources(); + auto table = engine.createTable(assetSources.size(), 0); + if (withMetadata.value()) { + for (auto& assetSource : assetSources) + table.set(assetSource, assets->assetSourceMetadata(assetSource)); + } + else { + size_t i = 0; + for (auto& assetSource : assetSources) + table.set(++i, assetSource); + } + return table; + }); + callbacks.registerCallback("materialConfig", [root](String const& materialName) -> Json { auto materialId = root->materialDatabase()->materialId(materialName); if (auto path = root->materialDatabase()->materialPath(materialId))