Lua patches

This commit is contained in:
Kae 2024-03-21 00:57:49 +11:00
parent a096fa3ffc
commit 57ca6776e4
7 changed files with 116 additions and 48 deletions

View File

@ -0,0 +1,19 @@
local function modLight(light)
for i = 1, #light do
light[i] = light[i] * 0.4
end
end
function patch(object, path)
if object.lightColor then
modLight(object.lightColor)
object.pointLight = true
return object;
elseif object.lightColors then
for i, v in pairs(object.lightColors) do
modLight(v)
end
object.pointLight = true
return object;
end
end

View File

@ -1,4 +1,4 @@
-- revert cursor frames if a mod replaced cursors.png with a SD version again
-- Revert cursor frames if a mod replaced cursors.png with a SD version again
if assets.image("/cursors/cursors.png"):size()[1] == 64 then
local path = "/cursors/opensb/revert.cursor.patch"
assets.add(path, '{"scale":null}')
@ -8,4 +8,11 @@ if assets.image("/cursors/cursors.png"):size()[1] == 64 then
path = "/cursors/opensb/revert.frames.patch"
assets.add(path, '{"frameGrid":{"size":[16,16]}}')
assets.patch("/cursors/cursors.frames", path)
end
-- Add object patches
local objects = assets.byExtension("object")
local path = "/objects/opensb/object.patch.lua"
for i = 1, #objects do
assets.patch(objects[i], path)
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

View File

@ -110,8 +110,15 @@ Assets::Assets(Settings settings, StringList assetSources) {
m_assetSources = std::move(assetSources);
auto luaEngine = LuaEngine::create();
m_luaEngine = luaEngine;
auto pushGlobalContext = [&luaEngine](String const& name, LuaCallbacks & callbacks) {
auto table = luaEngine->createTable();
for (auto const& p : callbacks.callbacks())
table.set(p.first, luaEngine->createWrappedFunction(p.second));
luaEngine->setGlobal(name, table);
};
pushGlobalContext("sb", LuaBindings::makeUtilityCallbacks());
auto decorateLuaContext = [this](LuaContext& context, MemoryAssetSourcePtr newFiles) {
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));
@ -133,38 +140,40 @@ Assets::Assets(Settings settings, StringList assetSources) {
return b ? scan(a.value(), *b) : scan(a.value());
});
callbacks.registerCallback("add", [this, &newFiles](LuaEngine& engine, String const& path, LuaValue const& data) {
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());
}
newFiles->set(path, bytes);
});
if (newFiles) {
callbacks.registerCallback("add", [this, &newFiles](LuaEngine& engine, String const& path, LuaValue const& data) {
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());
}
newFiles->set(path, bytes);
});
callbacks.registerCallback("patch", [this, &newFiles](String const& path, String const& patchPath) -> bool {
if (auto file = m_files.ptr(path)) {
if (newFiles->contains(patchPath)) {
file->patchSources.append(make_pair(patchPath, newFiles));
return true;
} else {
if (auto asset = m_files.ptr(patchPath)) {
file->patchSources.append(make_pair(patchPath, asset->source));
callbacks.registerCallback("patch", [this, &newFiles](String const& path, String const& patchPath) -> bool {
if (auto file = m_files.ptr(path)) {
if (newFiles->contains(patchPath)) {
file->patchSources.append(make_pair(patchPath, newFiles));
return true;
} else {
if (auto asset = m_files.ptr(patchPath)) {
file->patchSources.append(make_pair(patchPath, asset->source));
return true;
}
}
}
}
return false;
});
return false;
});
callbacks.registerCallback("erase", [this](String const& path) -> bool {
bool erased = m_files.erase(path);
if (erased)
m_filesByExtension[AssetPath::extension(path).toLower()].erase(path);
return erased;
});
callbacks.registerCallback("erase", [this](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);
};
@ -883,21 +892,35 @@ Json Assets::readJson(String const& path) const {
try {
Json result = inputUtf8Json(streamData.begin(), streamData.end(), false);
for (auto const& pair : m_files.get(path).patchSources) {
auto patchStream = pair.second->read(pair.first);
auto patchJson = inputUtf8Json(patchStream.begin(), patchStream.end(), false);
if (patchJson.isType(Json::Type::Array)) {
auto patchData = patchJson.toArray();
try {
result = checkPatchArray(pair.first, pair.second, result, patchData, {});
} catch (JsonPatchTestFail const& e) {
Logger::debug("Patch test failure from file {} in source: '{}' at '{}'. Caused by: {}", pair.first, pair.second->metadata().value("name", ""), m_assetSourcePaths.getLeft(pair.second), e.what());
} catch (JsonPatchException const& e) {
Logger::error("Could not apply patch from file {} in source: '{}' at '{}'. Caused by: {}", pair.first, pair.second->metadata().value("name", ""), m_assetSourcePaths.getLeft(pair.second), e.what());
auto& patchPath = pair.first;
auto& patchSource = pair.second;
auto patchStream = patchSource->read(patchPath);
if (pair.first.endsWith(".lua")) {
MutexLocker luaLocker(m_luaMutex);
// Kae: i don't like that lock. perhaps have a LuaEngine and patch context cache per worker thread later on?
LuaContextPtr& context = m_patchContexts[patchPath];
if (!context) {
context = make_shared<LuaContext>(as<LuaEngine>(m_luaEngine.get())->createContext());
context->load(patchStream, patchPath);
}
auto newResult = context->invokePath<Json>("patch", result, path);
if (newResult)
result = std::move(newResult);
} else {
auto patchJson = inputUtf8Json(patchStream.begin(), patchStream.end(), false);
if (patchJson.isType(Json::Type::Array)) {
auto patchData = patchJson.toArray();
try {
result = checkPatchArray(patchPath, patchSource, result, patchData, {});
} catch (JsonPatchTestFail const& e) {
Logger::debug("Patch test failure from file {} in source: '{}' at '{}'. Caused by: {}", patchPath, patchSource->metadata().value("name", ""), m_assetSourcePaths.getLeft(patchSource), e.what());
} catch (JsonPatchException const& e) {
Logger::error("Could not apply patch from file {} in source: '{}' at '{}'. Caused by: {}", patchPath, patchSource->metadata().value("name", ""), m_assetSourcePaths.getLeft(patchSource), e.what());
}
} else if (patchJson.isType(Json::Type::Object)) {//Kae: Do a good ol' json merge instead if the .patch file is a Json object
result = jsonMergeNulling(result, patchJson.toObject());
}
}
} else if (patchJson.isType(Json::Type::Object)) { //Kae: Do a good ol' json merge instead if the .patch file is a Json object
auto patchData = patchJson.toObject();
result = jsonMergeNulling(result, patchData);
}
}
return result;
} catch (std::exception const& e) {

View File

@ -7,6 +7,7 @@
#include "StarThread.hpp"
#include "StarAssetSource.hpp"
#include "StarAssetPath.hpp"
#include "StarRefPtr.hpp"
namespace Star {
@ -16,6 +17,8 @@ STAR_CLASS(Image);
STAR_STRUCT(FramesSpecification);
STAR_CLASS(Assets);
STAR_CLASS(LuaContext);
STAR_EXCEPTION(AssetException, StarException);
// The contents of an assets .frames file, which can be associated with one or
@ -313,6 +316,11 @@ private:
mutable StringMap<String> m_bestFramesFiles;
mutable StringMap<FramesSpecificationConstPtr> m_framesSpecifications;
// Lua
RefPtr<RefCounter> m_luaEngine; // dumb but to avoid including Lua.hpp in here...
mutable StringMap<LuaContextPtr> m_patchContexts;
mutable Mutex m_luaMutex;
// Paths of all used asset sources, in load order.
StringList m_assetSources;

View File

@ -27,6 +27,7 @@ public:
void set(unsigned x, unsigned y, float v);
void set(unsigned x, unsigned y, Vec3F const& v);
void add(unsigned x, unsigned y, Vec3F const& v);
Vec3F get(unsigned x, unsigned y) const;
bool empty() const;
@ -64,6 +65,16 @@ inline void Lightmap::set(unsigned x, unsigned y, Vec3F const& v) {
ptr[2] = v.z();
}
inline void Lightmap::add(unsigned x, unsigned y, Vec3F const& v) {
if (x >= m_width || y >= m_height) {
throw LightmapException(strf("[{}, {}] out of range in Lightmap::add", x, y));
return;
}
float* ptr = m_data.get() + (y * m_width * 3 + x * 3);
ptr[0] += v.x();
ptr[1] += v.y();
ptr[2] += v.z();
}
inline Vec3F Lightmap::get(unsigned x, unsigned y) const {
if (x >= m_width || y >= m_height) {
@ -74,6 +85,7 @@ inline Vec3F Lightmap::get(unsigned x, unsigned y) const {
return Vec3F(ptr[0], ptr[1], ptr[2]);
}
inline bool Lightmap::empty() const {
return m_width == 0 || m_height == 0;
}

View File

@ -1382,7 +1382,8 @@ bool WorldClient::waitForLighting(WorldRenderData* renderData) {
for (auto& previewTile : m_previewTiles) {
if (previewTile.updateLight) {
Vec2I lightArrayPos = m_geometry.diff(previewTile.position, m_lightMinPosition);
if (lightArrayPos[0] >= 0 && lightArrayPos[0] < (int)m_lightMap.width() && lightArrayPos[1] >= 0 && lightArrayPos[1] < (int)m_lightMap.height())
if (lightArrayPos[0] >= 0 && lightArrayPos[0] < (int)m_lightMap.width()
&& lightArrayPos[1] >= 0 && lightArrayPos[1] < (int)m_lightMap.height())
m_lightMap.set(lightArrayPos[0], lightArrayPos[1], Color::v3bToFloat(previewTile.light));
}
}
@ -1654,15 +1655,13 @@ void WorldClient::lightingCalc() {
if (light.pointLight)
m_lightingCalculator.addPointLight(position, light.color, light.pointBeam, light.beamAngle, light.beamAmbience);
else {
m_lightingCalculator.addSpreadLight(position, light.color * 0.6f);
m_lightingCalculator.addPointLight(position, light.color * 0.4f, 0.0f, 0.0f, 1.0f);
m_lightingCalculator.addSpreadLight(position, light.color);
}
}
for (auto const& lightPair : particleLights) {
Vec2F position = m_geometry.nearestTo(Vec2F(m_lightingCalculator.calculationRegion().min()), lightPair.first);
m_lightingCalculator.addSpreadLight(position, lightPair.second * 0.6f);
m_lightingCalculator.addPointLight(position, lightPair.second * 0.4f, 0.0f, 0.0f, 1.0f);
m_lightingCalculator.addSpreadLight(position, lightPair.second);
}
m_lightingCalculator.calculate(m_pendingLightMap);