diff --git a/files/capture.lua b/files/capture.lua index 2b2fcff..dc87363 100644 --- a/files/capture.lua +++ b/files/capture.lua @@ -7,7 +7,7 @@ local noitaAPI = dofile_once("mods/noita-mapcap/files/noita-api.lua") ---@type JSONLib -local jsonSerialize = dofile_once("mods/noita-mapcap/files/json-serialize.lua") +local json = dofile_once("mods/noita-mapcap/files/json-serialize.lua") CAPTURE_PIXEL_SIZE = 1 -- Screen to virtual pixel ratio. CAPTURE_GRID_SIZE = 512 -- in virtual (world) pixels. There will always be exactly 4 images overlapping if the virtual resolution is 1024x1024. @@ -102,11 +102,11 @@ local function captureScreenshot(x, y, rx, ry, entityFile) -- Well, as long as it does not crash between write and flush. if entityFile:seek("end") == 0 then -- First line. - entityFile:write("[\n\t", jsonSerialize.Marshal(rootEntity), "\n", "]") + entityFile:write("[\n\t", json.Marshal(rootEntity), "\n", "]") else -- Following lines. entityFile:seek("end", -2) -- Seek a few bytes back, so we can overwrite some stuff. - entityFile:write(",\n\t", jsonSerialize.Marshal(rootEntity), "\n", "]") + entityFile:write(",\n\t", json.Marshal(rootEntity), "\n", "]") end rootEntity:AddTag("MapCaptured") -- Prevent recapturing. diff --git a/files/json-serialize.lua b/files/json-serialize.lua index a527c37..eb86d79 100644 --- a/files/json-serialize.lua +++ b/files/json-serialize.lua @@ -5,9 +5,6 @@ -- Simple library to marshal JSON values. ----@type NoitaAPI -local noitaAPI = dofile_once("mods/noita-mapcap/files/noita-api.lua") - ---@class JSONLib local lib = {} @@ -63,7 +60,7 @@ function lib.MarshalNumber(val) end ---MarshalBoolean returns the JSON representation of a boolean value. ----@param val number +---@param val boolean ---@return string function lib.MarshalBoolean(val) return tostring(val) @@ -118,37 +115,6 @@ function lib.MarshalArray(val, customMarshalFunction) return result end ----MarshalNoitaComponent returns the JSON representation of the given Noita component. ----@param component NoitaComponent ----@return string -function lib.MarshalNoitaComponent(component) - local resultObject = { - typeName = component:GetTypeName(), - members = component:GetMembers(), - --objectMembers = component:ObjectGetMembers - } - - return lib.Marshal(resultObject) -end - ----MarshalNoitaEntity returns the JSON representation of the given Noita entity. ----@param entity NoitaEntity ----@return string -function lib.MarshalNoitaEntity(entity) - local result = { - name = entity:GetName(), - filename = entity:GetFilename(), - tags = entity:GetTags(), - children = entity:GetAllChildren(), - components = entity:GetAllComponents(), - transform = {}, - } - - result.transform.x, result.transform.y, result.transform.rotation, result.transform.scaleX, result.transform.scaleY = entity:GetTransform() - - return lib.Marshal(result) -end - ---Marshal marshals any value into JSON representation. ---@param val any ---@return string @@ -164,11 +130,9 @@ function lib.Marshal(val) elseif t == "boolean" then return lib.MarshalBoolean(val) elseif t == "table" then - -- Check if object is instance of class... - if getmetatable(val) == noitaAPI.MetaTables.Component then - return lib.MarshalNoitaComponent(val) - elseif getmetatable(val) == noitaAPI.MetaTables.Entity then - return lib.MarshalNoitaEntity(val) + -- Check if object implements the JSON marshaler interface. + if val.MarshalJSON ~= nil and type(val.MarshalJSON) == "function" then + return val:MarshalJSON() end -- If not, fall back to array or object handling. diff --git a/files/noita-api.lua b/files/noita-api.lua index 1daa2a8..5d4aaa0 100644 --- a/files/noita-api.lua +++ b/files/noita-api.lua @@ -9,6 +9,13 @@ -- State: Working but incomplete. If something is missing, add it by hand! -- It would be optimal to generate this API wrapper automatically... +---@type JSONLib +local json = dofile_once("mods/noita-mapcap/files/json-serialize.lua") + +------------- +-- Classes -- +------------- + local EntityAPI = {} ---@class NoitaEntity @@ -23,6 +30,43 @@ local ComponentAPI = {} local NoitaComponent = {} NoitaComponent.__index = NoitaComponent +------------------------- +-- JSON Implementation -- +------------------------- + +---MarshalJSON implements the JSON marshaler interface. +---@return string +function NoitaComponent:MarshalJSON() + local resultObject = { + typeName = self:GetTypeName(), + members = self:GetMembers(), + --objectMembers = component:ObjectGetMembers + } + + return json.Marshal(resultObject) +end + +---MarshalJSON implements the JSON marshaler interface. +---@return string +function NoitaEntity:MarshalJSON() + local result = { + name = self:GetName(), + filename = self:GetFilename(), + tags = self:GetTags(), + children = self:GetAllChildren(), + components = self:GetAllComponents(), + transform = {}, + } + + result.transform.x, result.transform.y, result.transform.rotation, result.transform.scaleX, result.transform.scaleY = self:GetTransform() + + return json.Marshal(result) +end + +------------------------ +-- Noita API wrappers -- +------------------------ + --- ---@param filename string ---@param posX number -- X coordinate in world (virtual) pixels. @@ -458,6 +502,10 @@ end -- TODO: Add missing Noita API methods and functions. +-------------------- +-- Noita API root -- +-------------------- + ---@class NoitaAPI local api = { Component = ComponentAPI, @@ -468,6 +516,4 @@ local api = { }, } - - return api