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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2024-03-25 03:46:21 +1100
committerKae <80987908+Novaenia@users.noreply.github.com>2024-03-25 03:46:21 +1100
commit560ae08424956bb495bc2453973467d138029c7c (patch)
treef506d79185388e7217af75a43074884f17349cb2
parentff6e349aef9c5504896d1249b2d4a3b862c37d09 (diff)
Add support for directly setting image assets and processing Image userdata
-rw-r--r--source/CMakeLists.txt5
-rw-r--r--source/base/CMakeLists.txt4
-rw-r--r--source/base/StarAssets.cpp20
-rw-r--r--source/base/StarAssets.hpp1
-rw-r--r--source/base/StarMemoryAssetSource.cpp59
-rw-r--r--source/base/StarMemoryAssetSource.hpp9
-rw-r--r--source/base/StarRootBase.cpp23
-rw-r--r--source/base/StarRootBase.hpp24
-rw-r--r--source/base/scripting/StarImageLuaBindings.cpp (renamed from source/core/scripting/StarImageLuaBindings.cpp)10
-rw-r--r--source/base/scripting/StarImageLuaBindings.hpp (renamed from source/core/scripting/StarImageLuaBindings.hpp)0
-rw-r--r--source/core/CMakeLists.txt2
-rw-r--r--source/game/StarRoot.cpp12
-rw-r--r--source/game/StarRoot.hpp14
13 files changed, 145 insertions, 38 deletions
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index d0fb879..68b65e8 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -532,7 +532,10 @@ add_subdirectory(core)
# Less general purpose code than core that is available to both the game and
# application modules.
-set(STAR_BASE_INCLUDES ${PROJECT_SOURCE_DIR}/base)
+set(STAR_BASE_INCLUDES
+ ${PROJECT_SOURCE_DIR}/base
+ ${PROJECT_SOURCE_DIR}/base/scripting
+)
add_subdirectory(base)
# Platform APIs that are implemented by the application module
diff --git a/source/base/CMakeLists.txt b/source/base/CMakeLists.txt
index 8f4d18b..e813e45 100644
--- a/source/base/CMakeLists.txt
+++ b/source/base/CMakeLists.txt
@@ -17,9 +17,11 @@ SET (star_base_HEADERS
StarMemoryAssetSource.hpp
StarMixer.hpp
StarPackedAssetSource.hpp
+ StarRootBase.hpp
StarVersion.hpp
StarVersionOptionParser.hpp
StarWorldGeometry.hpp
+ scripting/StarImageLuaBindings.hpp
)
SET (star_base_SOURCES
@@ -32,8 +34,10 @@ SET (star_base_SOURCES
StarMemoryAssetSource.cpp
StarMixer.cpp
StarPackedAssetSource.cpp
+ StarRootBase.cpp
StarVersionOptionParser.cpp
StarWorldGeometry.cpp
+ scripting/StarImageLuaBindings.cpp
)
CONFIGURE_FILE (StarVersion.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/StarVersion.cpp)
diff --git a/source/base/StarAssets.cpp b/source/base/StarAssets.cpp
index d4b7228..9718ec8 100644
--- a/source/base/StarAssets.cpp
+++ b/source/base/StarAssets.cpp
@@ -145,7 +145,10 @@ Assets::Assets(Settings settings, StringList assetSources) {
ByteArray bytes;
if (auto str = engine.luaMaybeTo<String>(data))
bytes = ByteArray(str->utf8Ptr(), str->utf8Size());
- else {
+ else if (auto image = engine.luaMaybeTo<Image>(data)) {
+ newFiles->set(path, std::move(*image));
+ return;
+ } else {
auto json = engine.luaTo<Json>(data).repr();
bytes = ByteArray(json.utf8Ptr(), json.utf8Size());
}
@@ -855,6 +858,19 @@ ByteArray Assets::read(String const& path) const {
throw AssetException(strf("No such asset '{}'", path));
}
+ImageConstPtr Assets::readImage(String const& path) const {
+ if (auto p = m_files.ptr(path)) {
+ ImageConstPtr image;
+ if (auto memorySource = as<MemoryAssetSource>(p->source))
+ image = memorySource->image(p->sourceName);
+ if (!image)
+ image = make_shared<Image>(Image::readPng(p->source->open(p->sourceName)));
+ return image;
+ }
+ throw AssetException(strf("No such asset '{}'", path));
+}
+
+
Json Assets::checkPatchArray(String const& path, AssetSourcePtr const& source, Json const result, JsonArray const patchData, Maybe<Json> const external) const {
auto externalRef = external.value();
auto newResult = result;
@@ -1140,7 +1156,7 @@ shared_ptr<Assets::AssetData> Assets::loadImage(AssetPath const& path) const {
} else {
auto imageData = make_shared<ImageData>();
imageData->image = unlockDuring([&]() {
- return make_shared<Image>(Image::readPng(open(path.basePath)));
+ return readImage(path.basePath);
});
imageData->frames = bestFramesSpecification(path.basePath);
diff --git a/source/base/StarAssets.hpp b/source/base/StarAssets.hpp
index 8cfbc52..952e024 100644
--- a/source/base/StarAssets.hpp
+++ b/source/base/StarAssets.hpp
@@ -275,6 +275,7 @@ private:
IODevicePtr open(String const& basePath) const;
ByteArray read(String const& basePath) const;
+ ImageConstPtr readImage(String const& path) const;
Json readJson(String const& basePath) const;
Json checkPatchArray(String const& path, AssetSourcePtr const& source, Json const result, JsonArray const patchData, Maybe<Json> const external) const;
diff --git a/source/base/StarMemoryAssetSource.cpp b/source/base/StarMemoryAssetSource.cpp
index 17e3749..a0c220d 100644
--- a/source/base/StarMemoryAssetSource.cpp
+++ b/source/base/StarMemoryAssetSource.cpp
@@ -1,7 +1,7 @@
#include "StarMemoryAssetSource.hpp"
#include "StarDataStreamDevices.hpp"
#include "StarDataStreamExtra.hpp"
-#include "StarSha256.hpp"
+#include "StarImage.hpp"
namespace Star {
@@ -21,11 +21,17 @@ StringList MemoryAssetSource::assetPaths() const {
IODevicePtr MemoryAssetSource::open(String const& path) {
struct AssetReader : public IODevice {
- AssetReader(ByteArrayPtr assetData, String name) : assetData(assetData), name(name) { setMode(IOMode::Read); }
+ AssetReader(char* assetData, size_t assetSize, String name) {
+ this->assetData = assetData;
+ this->assetSize = assetSize;
+ this->name = std::move(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);
+ len = min<StreamOffset>(len, StreamOffset(assetSize) - assetPos);
+ memcpy(data, assetData + assetPos, len);
+ assetPos += len;
return len;
}
@@ -33,25 +39,26 @@ IODevicePtr MemoryAssetSource::open(String const& path) {
throw IOException("Assets IODevices are read-only");
}
- StreamOffset size() override { return assetData->size(); }
+ StreamOffset size() override { return assetSize; }
StreamOffset pos() override { return assetPos; }
String deviceName() const override { return name; }
bool atEnd() override {
- return assetPos >= assetData->size();
+ return assetPos >= assetSize;
}
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());
+ assetPos = clamp<StreamOffset>(assetPos + p, 0, assetSize);
else
- assetPos = clamp<StreamOffset>(assetPos - p, 0, assetData->size());
+ assetPos = clamp<StreamOffset>(assetPos - p, 0, assetSize);
}
- ByteArrayPtr assetData;
+ char* assetData;
+ size_t assetSize;
StreamOffset assetPos = 0;
String name;
};
@@ -59,8 +66,12 @@ IODevicePtr MemoryAssetSource::open(String const& path) {
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);
+ else if (auto byteArray = p->ptr<ByteArray>())
+ return make_shared<AssetReader>(byteArray->ptr(), byteArray->size(), path);
+ else {
+ auto image = p->get<ImagePtr>().get();
+ return make_shared<AssetReader>((char*)image->data(), image->width() * image->height() * image->bytesPerPixel(), path);
+ }
}
bool MemoryAssetSource::empty() const {
@@ -76,15 +87,37 @@ bool MemoryAssetSource::erase(String const& path) {
}
void MemoryAssetSource::set(String const& path, ByteArray data) {
- m_files[path] = make_shared<ByteArray>(std::move(data));
+ m_files[path] = std::move(data);
+}
+
+void MemoryAssetSource::set(String const& path, Image const& image) {
+ m_files[path] = make_shared<Image>(image);
+}
+
+void MemoryAssetSource::set(String const& path, Image&& image) {
+ m_files[path] = make_shared<Image>(std::move(image));
}
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 if (auto bytes = p->ptr<ByteArray>())
+ return *bytes;
+ else {
+ Image const* image = p->get<ImagePtr>().get();
+ return ByteArray((char const*)image->data(), image->width() * image->height() * image->bytesPerPixel());
+ }
+}
+
+ImageConstPtr MemoryAssetSource::image(String const& path) {
+ auto p = m_files.ptr(path);
+ if (!p)
+ throw AssetSourceException::format("Requested file '{}' does not exist in memory", path);
+ else if (auto imagePtr = p->ptr<ImagePtr>())
+ return *imagePtr;
else
- return *p->get(); // this is a double indirection, and that freaking sucks!!
+ return nullptr;
}
}
diff --git a/source/base/StarMemoryAssetSource.hpp b/source/base/StarMemoryAssetSource.hpp
index e5ef740..1fc5733 100644
--- a/source/base/StarMemoryAssetSource.hpp
+++ b/source/base/StarMemoryAssetSource.hpp
@@ -6,6 +6,7 @@
namespace Star {
STAR_CLASS(MemoryAssetSource);
+STAR_CLASS(Image);
class MemoryAssetSource : public AssetSource {
public:
@@ -15,17 +16,23 @@ public:
JsonObject metadata() const override;
StringList assetPaths() const override;
+ // do not use the returned IODevice after the file is gone or bad things will happen
IODevicePtr open(String const& path) override;
bool empty() const;
bool contains(String const& path) const;
bool erase(String const& path);
void set(String const& path, ByteArray data);
+ void set(String const& path, Image const& image);
+ void set(String const& path, Image&& image);
ByteArray read(String const& path) override;
+ ImageConstPtr image(String const& path);
private:
+ typedef Variant<ByteArray, ImagePtr> FileEntry;
+
String m_name;
JsonObject m_metadata;
- StringMap<ByteArrayPtr> m_files;
+ StringMap<FileEntry> m_files;
};
}
diff --git a/source/base/StarRootBase.cpp b/source/base/StarRootBase.cpp
new file mode 100644
index 0000000..e6bd99d
--- /dev/null
+++ b/source/base/StarRootBase.cpp
@@ -0,0 +1,23 @@
+#include "StarRootBase.hpp"
+
+namespace Star {
+ atomic<RootBase*> RootBase::s_singleton;
+
+ RootBase* RootBase::singletonPtr() {
+ return s_singleton.load();
+ }
+
+ RootBase& RootBase::singleton() {
+ auto ptr = s_singleton.load();
+ if (!ptr)
+ throw RootException("RootBase::singleton() called with no Root instance available");
+ else
+ return *ptr;
+ }
+
+ RootBase::RootBase() {
+ RootBase* oldRoot = nullptr;
+ if (!s_singleton.compare_exchange_strong(oldRoot, this))
+ throw RootException("Singleton Root has been constructed twice");
+ }
+} \ No newline at end of file
diff --git a/source/base/StarRootBase.hpp b/source/base/StarRootBase.hpp
new file mode 100644
index 0000000..48a6a5e
--- /dev/null
+++ b/source/base/StarRootBase.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "StarAssets.hpp"
+
+namespace Star {
+
+STAR_CLASS(Configuration);
+
+STAR_EXCEPTION(RootException, StarException);
+
+class RootBase {
+public:
+ static RootBase* singletonPtr();
+ static RootBase& singleton();
+
+ virtual AssetsConstPtr assets() = 0;
+ virtual ConfigurationPtr configuration() = 0;
+protected:
+ RootBase();
+
+ static atomic<RootBase*> s_singleton;
+};
+
+} \ No newline at end of file
diff --git a/source/core/scripting/StarImageLuaBindings.cpp b/source/base/scripting/StarImageLuaBindings.cpp
index 83fb8d1..0f5d1e4 100644
--- a/source/core/scripting/StarImageLuaBindings.cpp
+++ b/source/base/scripting/StarImageLuaBindings.cpp
@@ -1,6 +1,7 @@
#include "StarImageLuaBindings.hpp"
#include "StarLuaConverters.hpp"
#include "StarImage.hpp"
+#include "StarRootBase.hpp"
namespace Star {
@@ -22,6 +23,15 @@ LuaMethods<Image> LuaUserDataMethods<Image>::make() {
return image.subImage(min, size);
});
+ methods.registerMethod("process", [](Image& image, String const& directives) {
+ return processImageOperations(parseImageOperations(directives), image, [](String const& path) -> Image const* {
+ if (auto root = RootBase::singletonPtr())
+ return root->assets()->image(path).get();
+ else
+ return nullptr;
+ });
+ });
+
return methods;
}
diff --git a/source/core/scripting/StarImageLuaBindings.hpp b/source/base/scripting/StarImageLuaBindings.hpp
index b49598d..b49598d 100644
--- a/source/core/scripting/StarImageLuaBindings.hpp
+++ b/source/base/scripting/StarImageLuaBindings.hpp
diff --git a/source/core/CMakeLists.txt b/source/core/CMakeLists.txt
index eda2acc..fb31fca 100644
--- a/source/core/CMakeLists.txt
+++ b/source/core/CMakeLists.txt
@@ -127,7 +127,6 @@ SET (star_core_HEADERS
StarWorkerPool.hpp
StarXXHash.hpp
StarZSTDCompression.hpp
- scripting/StarImageLuaBindings.hpp
scripting/StarUtilityLuaBindings.hpp
)
@@ -185,7 +184,6 @@ SET (star_core_SOURCES
StarUuid.cpp
StarWorkerPool.cpp
StarZSTDCompression.cpp
- scripting/StarImageLuaBindings.cpp
scripting/StarUtilityLuaBindings.cpp
)
diff --git a/source/game/StarRoot.cpp b/source/game/StarRoot.cpp
index e22f184..4d67563 100644
--- a/source/game/StarRoot.cpp
+++ b/source/game/StarRoot.cpp
@@ -60,25 +60,19 @@ namespace {
unsigned const RootLoadThreads = 4;
}
-atomic<Root*> Root::s_singleton;
-
Root* Root::singletonPtr() {
- return s_singleton.load();
+ return dynamic_cast<Root*>(s_singleton.load());
}
Root& Root::singleton() {
- auto ptr = s_singleton.load();
+ auto ptr = singletonPtr();
if (!ptr)
throw RootException("Root::singleton() called with no Root instance available");
else
return *ptr;
}
-Root::Root(Settings settings) {
- Root* oldRoot = nullptr;
- if (!s_singleton.compare_exchange_strong(oldRoot, this))
- throw RootException("Singleton Root has been constructed twice");
-
+Root::Root(Settings settings) : RootBase() {
m_settings = std::move(settings);
if (m_settings.runtimeConfigFile)
m_runtimeConfigFile = toStoragePath(*m_settings.runtimeConfigFile);
diff --git a/source/game/StarRoot.hpp b/source/game/StarRoot.hpp
index 576fe41..8015362 100644
--- a/source/game/StarRoot.hpp
+++ b/source/game/StarRoot.hpp
@@ -1,14 +1,13 @@
#pragma once
+#include "StarRootBase.hpp"
#include "StarJson.hpp"
#include "StarLogging.hpp"
#include "StarListener.hpp"
-#include "StarAssets.hpp"
#include "StarConfiguration.hpp"
namespace Star {
-STAR_CLASS(Configuration);
STAR_CLASS(ItemDatabase);
STAR_CLASS(MaterialDatabase);
STAR_CLASS(ObjectDatabase);
@@ -50,15 +49,13 @@ STAR_CLASS(CollectionDatabase);
STAR_CLASS(Root);
-STAR_EXCEPTION(RootException, StarException);
-
// Singleton Root object for starbound providing access to the unique
// Configuration class, as well as the assets, root factories, and databases.
// Root, and all members of Root, should be thread safe. Root initialization
// should be completed before any code dependent on Root is started in any
// thread, and all Root dependent code in any thread should be finished before
// letting Root destruct.
-class Root {
+class Root : public RootBase {
public:
struct Settings {
Assets::Settings assetsSettings;
@@ -135,8 +132,8 @@ public:
// All of the Root member accessors are safe to call at any time after Root
// initialization, if they are not loaded they will load before returning.
- AssetsConstPtr assets();
- ConfigurationPtr configuration();
+ AssetsConstPtr assets() override;
+ ConfigurationPtr configuration() override;
ObjectDatabaseConstPtr objectDatabase();
PlantDatabaseConstPtr plantDatabase();
@@ -164,7 +161,6 @@ public:
TreasureDatabaseConstPtr treasureDatabase();
DungeonDefinitionsConstPtr dungeonDefinitions();
TilesetDatabaseConstPtr tilesetDatabase();
- StatisticsDatabaseConstPtr statisicsDatabase();
StatisticsDatabaseConstPtr statisticsDatabase();
EmoteProcessorConstPtr emoteProcessor();
SpeciesDatabaseConstPtr speciesDatabase();
@@ -191,8 +187,6 @@ private:
// m_configurationMutex must be held when calling
void writeConfig();
- static atomic<Root*> s_singleton;
-
Settings m_settings;
Mutex m_modsMutex;