From aa99e101b46ae3117f29b9f6d80d70eb4a6c8db8 Mon Sep 17 00:00:00 2001 From: David Vogel Date: Fri, 22 Jul 2022 21:31:40 +0200 Subject: [PATCH] Split Noita API wrapper into several files --- files/capture.lua | 6 +- files/libraries/coordinates.lua | 8 +- files/libraries/noita-api/camera.lua | 63 ++++ files/libraries/noita-api/component.lua | 189 ++++++++++ .../{noita-api.lua => noita-api/entity.lua} | 329 +++--------------- files/overrides/perks/perk.lua | 6 +- init.lua | 3 + 7 files changed, 307 insertions(+), 297 deletions(-) create mode 100644 files/libraries/noita-api/camera.lua create mode 100644 files/libraries/noita-api/component.lua rename files/libraries/{noita-api.lua => noita-api/entity.lua} (52%) diff --git a/files/capture.lua b/files/capture.lua index 70a8e75..d6fe224 100644 --- a/files/capture.lua +++ b/files/capture.lua @@ -3,8 +3,8 @@ -- This software is released under the MIT License. -- https://opensource.org/licenses/MIT ----@type NoitaAPI -local noitaAPI = dofile_once("mods/noita-mapcap/files/libraries/noita-api.lua") +---@type NoitaEntityAPI +local EntityAPI = dofile_once("mods/noita-mapcap/files/libraries/noita-api/entity.lua") ---@type JSONLib local json = dofile_once("mods/noita-mapcap/files/libraries/json.lua") @@ -78,7 +78,7 @@ end local function captureEntities(entityFile, x, y, radius) if not entityFile then return end - local entities = noitaAPI.Entity.GetInRadius(x, y, radius) + local entities = EntityAPI.GetInRadius(x, y, radius) for _, entity in ipairs(entities) do -- Get to the root entity, as we are exporting entire entity trees. local rootEntity = entity:GetRootEntity() diff --git a/files/libraries/coordinates.lua b/files/libraries/coordinates.lua index 0b4b026..8cdb51b 100644 --- a/files/libraries/coordinates.lua +++ b/files/libraries/coordinates.lua @@ -8,8 +8,8 @@ ---@type Vec2 local Vec2 = dofile_once("mods/noita-mapcap/files/libraries/vec2.lua") ----@type NoitaAPI -local NoitaAPI = dofile_once("mods/noita-mapcap/files/libraries/noita-api.lua") +---@type NoitaCameraAPI +local CameraAPI = dofile_once("mods/noita-mapcap/files/libraries/noita-api/camera.lua") ---@class Coords ---@field InternalResolution Vec2 @@ -79,7 +79,7 @@ end ---@param viewportCenter Vec2|nil -- Result of `GameGetCameraPos()`. Will be queried automatically if set to nil. ---@return Vec2 window function Coords:ToWindow(world, viewportCenter) - viewportCenter = viewportCenter or NoitaAPI.Camera.Pos() + viewportCenter = viewportCenter or CameraAPI.Pos() local internalTopLeft, internalBottomRight = self:InternalRect() local pixelScale = self:PixelScale() @@ -92,7 +92,7 @@ end ---@param viewportCenter Vec2|nil -- Result of `GameGetCameraPos()`. Will be queried automatically if set to nil. ---@return Vec2 world function Coords:ToWorld(window, viewportCenter) - viewportCenter = viewportCenter or NoitaAPI.Camera.Pos() + viewportCenter = viewportCenter or CameraAPI.Pos() local internalTopLeft, internalBottomRight = self:InternalRect() local pixelScale = self:PixelScale() diff --git a/files/libraries/noita-api/camera.lua b/files/libraries/noita-api/camera.lua new file mode 100644 index 0000000..c0769d1 --- /dev/null +++ b/files/libraries/noita-api/camera.lua @@ -0,0 +1,63 @@ +-- Copyright (c) 2022 David Vogel +-- +-- This software is released under the MIT License. +-- https://opensource.org/licenses/MIT + +-- Noita modding API, but a bit more beautiful. +-- Current modding API version: 7 + +-- State: Working but incomplete. If something is missing, add it by hand! +-- It would be optimal to generate this API wrapper automatically... + +---@type Vec2 +local Vec2 = dofile_once("mods/noita-mapcap/files/libraries/vec2.lua") + +------------- +-- Classes -- +------------- + +---@class NoitaCameraAPI +local CameraAPI = {} + +------------------------ +-- Noita API wrappers -- +------------------------ + +--- +---@param strength number +---@param position Vec2|nil -- Defaults to camera position if not set. +function CameraAPI.Screenshake(strength, position) + if position == nil then + return GameScreenshake(strength) + end + return GameScreenshake(strength, position.x, position.y) +end + +---Returns the center position of the viewport in world/virtual coordinates. +---@return Vec2 +function CameraAPI.Pos() + return Vec2(GameGetCameraPos()) +end + +---Sets the center position of the viewport in world/virtual coordinates. +---@param position Vec2 +function CameraAPI.SetPos(position) + return GameSetCameraPos(position.x, position.y) +end + +--- +---@param isFree boolean +function CameraAPI.SetCameraFree(isFree) + return GameSetCameraFree(isFree) +end + +---Returns the camera boundary rectangle in world/virtual coordinates. +---This may not be 100% pixel perfect with regards to what you see on the screen. +---@return Vec2 topLeft +---@return Vec2 bottomRight +function CameraAPI.Bounds() + local x, y, w, h = GameGetCameraBounds() + return Vec2(x, y), Vec2(x + w, y + h) +end + +return CameraAPI diff --git a/files/libraries/noita-api/component.lua b/files/libraries/noita-api/component.lua new file mode 100644 index 0000000..369eb04 --- /dev/null +++ b/files/libraries/noita-api/component.lua @@ -0,0 +1,189 @@ +-- Copyright (c) 2022 David Vogel +-- +-- This software is released under the MIT License. +-- https://opensource.org/licenses/MIT + +-- Noita modding API, but a bit more beautiful. +-- Current modding API version: 7 + +-- 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/libraries/json.lua") + +------------- +-- Classes -- +------------- + +---@class NoitaComponentAPI +local ComponentAPI = {} + +---@class NoitaComponent +---@field ID integer -- Noita component ID. +local NoitaComponent = {} +NoitaComponent.__index = NoitaComponent +ComponentAPI.MetaTable = NoitaComponent + +---WrapID wraps the given component ID and returns a Noita component object. +---@param id number +---@return NoitaComponent|nil +function ComponentAPI.WrapID(id) + if id == nil or type(id) ~= "number" then return nil end + return setmetatable({ ID = id }, NoitaComponent) +end + +------------------------ +-- Noita API wrappers -- +------------------------ + +--- +---@param tag string +function NoitaComponent:AddTag(tag) + return ComponentAddTag(self.ID, tag) +end + +--- +---@param tag string +function NoitaComponent:RemoveTag(tag) + return ComponentRemoveTag(self.ID, tag) +end + +--- +---@param tag string +---@return boolean +function NoitaComponent:HasTag(tag) + return ComponentHasTag(self.ID, tag) +end + +---Returns one or many values matching the type or subtypes of the requested field. +---Reports error and returns nil if the field type is not supported or field was not found. +---@param fieldName string +---@return any|nil +function NoitaComponent:GetValue(fieldName) + return ComponentGetValue2(self.ID, fieldName) -- TODO: Rework Noita API to handle vectors, and return a vector instead of some shitty multi value result +end + +---Sets the value of a field. Value(s) should have a type matching the field type. +---Reports error if the values weren't given in correct type, the field type is not supported, or the component does not exist. +---@param fieldName string +---@param ... any|nil -- Vectors use one argument per dimension. +function NoitaComponent:SetValue(fieldName, ...) + return ComponentSetValue2(self.ID, fieldName, ...) -- TODO: Rework Noita API to handle vectors, and use a vector instead of shitty multi value arguments +end + +---Returns one or many values matching the type or subtypes of the requested field in a component subobject. +---Reports error and returns nil if the field type is not supported or 'object_name' is not a metaobject. +--- +---Reporting errors means that it spams the stdout with messages, instead of using the lua error handling. Thanks Nolla. +---@param objectName string +---@param fieldName string +---@return any|nil +function NoitaComponent:ObjectGetValue(objectName, fieldName) + return ComponentObjectGetValue2(self.ID, objectName, fieldName) -- TODO: Rework Noita API to handle vectors, and return a vector instead of some shitty multi value result +end + +---Sets the value of a field in a component subobject. Value(s) should have a type matching the field type. +---Reports error if the values weren't given in correct type, the field type is not supported or 'object_name' is not a metaobject. +---@param objectName string +---@param fieldName string +---@param ... any|nil -- Vectors use one argument per dimension. +function NoitaComponent:ObjectSetValue(objectName, fieldName, ...) + return ComponentObjectSetValue2(self.ID, objectName, fieldName, ...) -- TODO: Rework Noita API to handle vectors, and use a vector instead of shitty multi value arguments +end + +--- +---@param arrayMemberName string +---@param typeStoredInVector "int"|"float"|"string" +---@return number +function NoitaComponent:GetVectorSize(arrayMemberName, typeStoredInVector) + return ComponentGetVectorSize(self.ID, arrayMemberName, typeStoredInVector) +end + +--- +---@param arrayName string +---@param typeStoredInVector "int"|"float"|"string" +---@param index number +---@return number|number|string|nil +function NoitaComponent:GetVectorValue(arrayName, typeStoredInVector, index) + return ComponentGetVectorValue(self.ID, arrayName, typeStoredInVector, index) +end + +--- +---@param arrayName string +---@param typeStoredInVector "int"|"float"|"string" +---@return number[]|number|string|nil +function NoitaComponent:GetVector(arrayName, typeStoredInVector) + return ComponentGetVector(self.ID, arrayName, typeStoredInVector) +end + +---Returns true if the given component exists and is enabled, else false. +---@return boolean +function NoitaComponent:GetIsEnabled() + return ComponentGetIsEnabled(self.ID) +end + +---Returns a string-indexed table of string. +---@return table|nil +function NoitaComponent:GetMembers() + return ComponentGetMembers(self.ID) +end + +---Returns a string-indexed table of string or nil. +---@param objectName string +---@return table|nil +function NoitaComponent:ObjectGetMembers(objectName) + return ComponentObjectGetMembers(self.ID, objectName) +end + +--- +---@return string string +function NoitaComponent:GetTypeName() + return ComponentGetTypeName(self.ID) +end + +------------------------- +-- JSON Implementation -- +------------------------- + +-- Set of component keys that would return an "invalid type" error when called with ComponentGetValue2(). +-- This is more or less to get around console error spam that otherwise can't be prevented when iterating over component members. +-- Only used inside the JSON marshaler, until there is a better solution. +local componentValueKeysWithInvalidType = {} + +---MarshalJSON implements the JSON marshaler interface. +---@return string +function NoitaComponent:MarshalJSON() + -- Get list of members, but with correct type (instead of string values). + local membersTable = self:GetMembers() + local members = {} + if membersTable then + for k, v in pairs(membersTable) do + if not componentValueKeysWithInvalidType[k] then + local packedResult = table.pack(self:GetValue(k)) -- Try to get value with correct type. Assuming nil is an error, but this is not always the case... meh. + if packedResult.n == 0 then + members[k] = nil -- Write no result as nil. Basically do nothing. + elseif packedResult.n == 1 then + members[k] = packedResult[1] -- Write single value result as single value. + else + packedResult.n = nil -- Discard n field, otherwise this is not a pure array. + members[k] = packedResult -- Write multi value result as array. + end + end + if members[k] == nil then + componentValueKeysWithInvalidType[k] = true + --members[k] = v -- Fall back to string value of self:GetMembers(). + end + end + end + + local resultObject = { + typeName = self:GetTypeName(), + members = members, + --objectMembers = component:ObjectGetMembers + } + + return json.Marshal(resultObject) +end + +return ComponentAPI diff --git a/files/libraries/noita-api.lua b/files/libraries/noita-api/entity.lua similarity index 52% rename from files/libraries/noita-api.lua rename to files/libraries/noita-api/entity.lua index e069895..ffdc709 100644 --- a/files/libraries/noita-api.lua +++ b/files/libraries/noita-api/entity.lua @@ -9,6 +9,9 @@ -- State: Working but incomplete. If something is missing, add it by hand! -- It would be optimal to generate this API wrapper automatically... +---@type NoitaComponentAPI +local ComponentAPI = dofile_once("mods/noita-mapcap/files/libraries/noita-api/component.lua") + ---@type Vec2 local Vec2 = dofile_once("mods/noita-mapcap/files/libraries/vec2.lua") @@ -19,12 +22,14 @@ local json = dofile_once("mods/noita-mapcap/files/libraries/json.lua") -- Classes -- ------------- +---@class NoitaEntityAPI local EntityAPI = {} ---@class NoitaEntity ---@field ID integer -- Noita entity ID. local NoitaEntity = {} NoitaEntity.__index = NoitaEntity +EntityAPI.MetaTable = NoitaEntity ---WrapID wraps the given entity ID and returns a Noita entity object. ---@param id number @@ -34,84 +39,6 @@ function EntityAPI.WrapID(id) return setmetatable({ ID = id }, NoitaEntity) end -local ComponentAPI = {} - ----@class NoitaComponent ----@field ID integer -- Noita component ID. -local NoitaComponent = {} -NoitaComponent.__index = NoitaComponent - ----WrapID wraps the given component ID and returns a Noita component object. ----@param id number ----@return NoitaComponent|nil -function ComponentAPI.WrapID(id) - if id == nil or type(id) ~= "number" then return nil end - return setmetatable({ ID = id }, NoitaComponent) -end - -local CameraAPI = {} - -------------------------- --- JSON Implementation -- -------------------------- - --- Set of component keys that would return an "invalid type" error when called with ComponentGetValue2(). --- This is more or less to get around console error spam that otherwise can't be prevented when iterating over component members. --- Only used inside the JSON marshaler, until there is a better solution. -local componentValueKeysWithInvalidType = {} - ----MarshalJSON implements the JSON marshaler interface. ----@return string -function NoitaComponent:MarshalJSON() - -- Get list of members, but with correct type (instead of string values). - local membersTable = self:GetMembers() - local members = {} - if membersTable then - for k, v in pairs(membersTable) do - if not componentValueKeysWithInvalidType[k] then - local packedResult = table.pack(self:GetValue(k)) -- Try to get value with correct type. Assuming nil is an error, but this is not always the case... meh. - if packedResult.n == 0 then - members[k] = nil -- Write no result as nil. Basically do nothing. - elseif packedResult.n == 1 then - members[k] = packedResult[1] -- Write single value result as single value. - else - packedResult.n = nil -- Discard n field, otherwise this is not a pure array. - members[k] = packedResult -- Write multi value result as array. - end - end - if members[k] == nil then - componentValueKeysWithInvalidType[k] = true - --members[k] = v -- Fall back to string value of self:GetMembers(). - end - end - end - - local resultObject = { - typeName = self:GetTypeName(), - members = members, - --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 -- ------------------------ @@ -122,11 +49,7 @@ end ---@param posY number -- Y coordinate in world (virtual) pixels. ---@return NoitaEntity|nil function EntityAPI.Load(filename, posX, posY) - local entityID = EntityLoad(filename, posX, posY) - if entityID == nil then - return nil - end - return setmetatable({ ID = entityID }, NoitaEntity) + return EntityAPI.WrapID(EntityLoad(filename, posX, posY)) end --- @@ -135,11 +58,7 @@ end ---@param posY number -- Y coordinate in world (virtual) pixels. ---@return NoitaEntity|nil function EntityAPI.LoadEndGameItem(filename, posX, posY) - local entityID = EntityLoadEndGameItem(filename, posX, posY) - if entityID == nil then - return nil - end - return setmetatable({ ID = entityID }, NoitaEntity) + return EntityAPI.WrapID(EntityLoadEndGameItem(filename, posX, posY)) end --- @@ -169,11 +88,7 @@ end ---@param name string ---@return NoitaEntity|nil function EntityAPI.CreateNew(name) - local entityID = EntityCreateNew(name) - if entityID == nil then - return nil - end - return setmetatable({ ID = entityID }, NoitaEntity) + return EntityAPI.WrapID(EntityCreateNew(name)) end --- @@ -192,10 +107,7 @@ end ---@return NoitaComponent|nil function NoitaEntity:AddComponent(componentTypeName, tableOfComponentValues) local componentID = EntityAddComponent(self.ID, componentTypeName, tableOfComponentValues) - if componentID == nil then - return nil - end - return setmetatable({ ID = componentID }, NoitaComponent) + return ComponentAPI.WrapID(componentID) end --- @@ -210,7 +122,7 @@ function NoitaEntity:GetAllComponents() local componentIDs = EntityGetAllComponents(self.ID) or {} local result = {} for _, componentID in ipairs(componentIDs) do - table.insert(result, setmetatable({ ID = componentID }, NoitaComponent)) + table.insert(result, ComponentAPI.WrapID(componentID)) end return result end @@ -228,7 +140,7 @@ function NoitaEntity:GetComponents(componentTypeName, tag) end local result = {} for _, componentID in ipairs(componentIDs) do - table.insert(result, setmetatable({ ID = componentID }, NoitaComponent)) + table.insert(result, ComponentAPI.WrapID(componentID)) end return result end @@ -244,10 +156,7 @@ function NoitaEntity:GetFirstComponent(componentTypeName, tag) else componentID = EntityGetFirstComponent(self.ID, componentTypeName) end - if componentID == nil then - return nil - end - return setmetatable({ ID = componentID }, NoitaComponent) + return ComponentAPI.WrapID(componentID) end ---Sets the transform of the entity. @@ -288,7 +197,7 @@ function NoitaEntity:GetAllChildren() local entityIDs = EntityGetAllChildren(self.ID) or {} local result = {} for _, entityID in ipairs(entityIDs) do - table.insert(result, setmetatable({ ID = entityID }, NoitaEntity)) + table.insert(result, EntityAPI.WrapID(entityID)) end return result end @@ -296,18 +205,13 @@ end --- ---@return NoitaEntity|nil function NoitaEntity:GetParent() - local entityID = EntityGetParent(self.ID) - if entityID == nil then - return nil - end - return setmetatable({ ID = entityID }, NoitaEntity) + return EntityAPI.WrapID(EntityGetParent(self.ID)) end ---Returns the given entity if it has no parent, otherwise walks up the parent hierarchy to the topmost parent and returns it. ----@return NoitaEntity +---@return NoitaEntity|nil function NoitaEntity:GetRootEntity() - local entityID = EntityGetRootEntity(self.ID) - return setmetatable({ ID = entityID }, NoitaEntity) + return EntityAPI.WrapID(EntityGetRootEntity(self.ID)) end --- @@ -360,7 +264,7 @@ function EntityAPI.GetWithTag(tag) local entityIDs = EntityGetWithTag(tag) or {} local result = {} for _, entityID in ipairs(entityIDs) do - table.insert(result, setmetatable({ ID = entityID }, NoitaEntity)) + table.insert(result, EntityAPI.WrapID(entityID)) end return result end @@ -374,7 +278,7 @@ function EntityAPI.GetInRadius(posX, posY, radius) local entityIDs = EntityGetInRadius(posX, posY, radius) or {} local result = {} for _, entityID in ipairs(entityIDs) do - table.insert(result, setmetatable({ ID = entityID }, NoitaEntity)) + table.insert(result, EntityAPI.WrapID(entityID)) end return result end @@ -389,7 +293,7 @@ function EntityAPI.GetInRadiusWithTag(posX, posY, radius, tag) local entityIDs = EntityGetInRadiusWithTag(posX, posY, radius, tag) or {} local result = {} for _, entityID in ipairs(entityIDs) do - table.insert(result, setmetatable({ ID = entityID }, NoitaEntity)) + table.insert(result, EntityAPI.WrapID(entityID)) end return result end @@ -399,22 +303,14 @@ end ---@param posY number -- X coordinate in world (virtual) pixels. ---@return NoitaEntity|nil function EntityAPI.GetClosest(posX, posY) - local entityID = EntityGetClosest(posX, posY) - if entityID == nil then - return nil - end - return setmetatable({ ID = entityID }, NoitaEntity) + return EntityAPI.WrapID(EntityGetClosest(posX, posY)) end --- ---@param name string ---@return NoitaEntity|nil function EntityAPI.GetWithName(name) - local entityID = EntityGetWithName(name) - if entityID == nil then - return nil - end - return setmetatable({ ID = entityID }, NoitaEntity) + return EntityAPI.WrapID(EntityGetWithName(name)) end --- @@ -442,61 +338,6 @@ function NoitaEntity:GetFilename() return EntityGetFilename(self.ID) end ---- ----@param tag string -function NoitaComponent:AddTag(tag) - return ComponentAddTag(self.ID, tag) -end - ---- ----@param tag string -function NoitaComponent:RemoveTag(tag) - return ComponentRemoveTag(self.ID, tag) -end - ---- ----@param tag string ----@return boolean -function NoitaComponent:HasTag(tag) - return ComponentHasTag(self.ID, tag) -end - ----Returns one or many values matching the type or subtypes of the requested field. ----Reports error and returns nil if the field type is not supported or field was not found. ----@param fieldName string ----@return any|nil -function NoitaComponent:GetValue(fieldName) - return ComponentGetValue2(self.ID, fieldName) -- TODO: Rework Noita API to handle vectors, and return a vector instead of some shitty multi value result -end - ----Sets the value of a field. Value(s) should have a type matching the field type. ----Reports error if the values weren't given in correct type, the field type is not supported, or the component does not exist. ----@param fieldName string ----@param ... any|nil -- Vectors use one argument per dimension. -function NoitaComponent:SetValue(fieldName, ...) - return ComponentSetValue2(self.ID, fieldName, ...) -- TODO: Rework Noita API to handle vectors, and use a vector instead of shitty multi value arguments -end - ----Returns one or many values matching the type or subtypes of the requested field in a component subobject. ----Reports error and returns nil if the field type is not supported or 'object_name' is not a metaobject. ---- ----Reporting errors means that it spams the stdout with messages, instead of using the lua error handling. Thanks Nolla. ----@param objectName string ----@param fieldName string ----@return any|nil -function NoitaComponent:ObjectGetValue(objectName, fieldName) - return ComponentObjectGetValue2(self.ID, objectName, fieldName) -- TODO: Rework Noita API to handle vectors, and return a vector instead of some shitty multi value result -end - ----Sets the value of a field in a component subobject. Value(s) should have a type matching the field type. ----Reports error if the values weren't given in correct type, the field type is not supported or 'object_name' is not a metaobject. ----@param objectName string ----@param fieldName string ----@param ... any|nil -- Vectors use one argument per dimension. -function NoitaComponent:ObjectSetValue(objectName, fieldName, ...) - return ComponentObjectSetValue2(self.ID, objectName, fieldName, ...) -- TODO: Rework Noita API to handle vectors, and use a vector instead of shitty multi value arguments -end - ---Creates a component of type 'component_type_name' and adds it to 'entity_id'. ---'table_of_component_values' should be a string-indexed table, where keys are field names and values are field values of correct type. ---The value setting works like ComponentObjectSetValue2(), with the exception that multivalue types are not supported. @@ -507,116 +348,30 @@ end ---@return NoitaComponent|nil function NoitaEntity:EntityAddComponent(componentTypeName, tableOfComponentValues) local componentID = EntityAddComponent2(self.ID, componentTypeName, tableOfComponentValues) - if componentID == nil then - return nil - end - return setmetatable({ ID = componentID }, NoitaComponent) -end - ---- ----@param arrayMemberName string ----@param typeStoredInVector "int"|"float"|"string" ----@return number -function NoitaComponent:GetVectorSize(arrayMemberName, typeStoredInVector) - return ComponentGetVectorSize(self.ID, arrayMemberName, typeStoredInVector) -end - ---- ----@param arrayName string ----@param typeStoredInVector "int"|"float"|"string" ----@param index number ----@return number|number|string|nil -function NoitaComponent:GetVectorValue(arrayName, typeStoredInVector, index) - return ComponentGetVectorValue(self.ID, arrayName, typeStoredInVector, index) -end - ---- ----@param arrayName string ----@param typeStoredInVector "int"|"float"|"string" ----@return number[]|number|string|nil -function NoitaComponent:GetVector(arrayName, typeStoredInVector) - return ComponentGetVector(self.ID, arrayName, typeStoredInVector) -end - ----Returns true if the given component exists and is enabled, else false. ----@return boolean -function NoitaComponent:GetIsEnabled() - return ComponentGetIsEnabled(self.ID) -end - ----Returns a string-indexed table of string. ----@return table|nil -function NoitaComponent:GetMembers() - return ComponentGetMembers(self.ID) -end - ----Returns a string-indexed table of string or nil. ----@param objectName string ----@return table|nil -function NoitaComponent:ObjectGetMembers(objectName) - return ComponentObjectGetMembers(self.ID, objectName) -end - ---- ----@return string string -function NoitaComponent:GetTypeName() - return ComponentGetTypeName(self.ID) + return ComponentAPI.WrapID(componentID) end -- TODO: Add missing Noita API methods and functions. ---- ----@param strength number ----@param position Vec2|nil -- Defaults to camera position if not set. -function CameraAPI.Screenshake(strength, position) - if position == nil then - return GameScreenshake(strength) - end - return GameScreenshake(strength, position.x, position.y) +------------------------- +-- JSON Implementation -- +------------------------- + +---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 --- TODO: Add missing Noita API methods and functions. - ----Returns the center position of the viewport in world/virtual coordinates. ----@return Vec2 -function CameraAPI.Pos() - return Vec2(GameGetCameraPos()) -end - ----Sets the center position of the viewport in world/virtual coordinates. ----@param position Vec2 -function CameraAPI.SetPos(position) - return GameSetCameraPos(position.x, position.y) -end - ---- ----@param isFree boolean -function CameraAPI.SetCameraFree(isFree) - return GameSetCameraFree(isFree) -end - ----Returns the camera boundaries rectangle in world/virtual coordinates. ----This may not be 100% pixel perfect with regards to what you see on the screen. ----@return Vec2 topLeft ----@return Vec2 bottomRight -function CameraAPI.Bounds() - local x, y, w, h = GameGetCameraBounds() - return Vec2(x, y), Vec2(x + w, y + h) -end - --------------------- --- Noita API root -- --------------------- - ----@class NoitaAPI -local api = { - Component = ComponentAPI, - Entity = EntityAPI, - Camera = CameraAPI, - MetaTables = { - Component = NoitaComponent, - Entity = NoitaEntity, - }, -} - -return api +return EntityAPI diff --git a/files/overrides/perks/perk.lua b/files/overrides/perks/perk.lua index 2e621f3..23f087d 100644 --- a/files/overrides/perks/perk.lua +++ b/files/overrides/perks/perk.lua @@ -3,8 +3,8 @@ -- This software is released under the MIT License. -- https://opensource.org/licenses/MIT ----@type NoitaAPI -local noitaAPI = dofile_once("mods/noita-mapcap/files/libraries/noita-api.lua") +---@type NoitaEntityAPI +local EntityAPI = dofile_once("mods/noita-mapcap/files/libraries/noita-api/entity.lua") local oldPerkSpawn = perk_spawn @@ -15,7 +15,7 @@ local oldPerkSpawn = perk_spawn ---@param dontRemoveOtherPerks boolean ---@return NoitaEntity|nil function perk_spawn(x, y, perkID, dontRemoveOtherPerks) - local entity = noitaAPI.Entity.WrapID(oldPerkSpawn(x, y, perkID, dontRemoveOtherPerks)) + local entity = EntityAPI.WrapID(oldPerkSpawn(x, y, perkID, dontRemoveOtherPerks)) if entity == nil then return end -- Remove the SpriteOffsetAnimatorComponent components from the entity. diff --git a/init.lua b/init.lua index 31b1c36..72a5288 100644 --- a/init.lua +++ b/init.lua @@ -5,6 +5,9 @@ dofile("mods/noita-mapcap/files/init.lua") +---Called in order upon loading game. +function OnModInit() end + function OnPlayerSpawned(player_entity) --EntityLoad("mods/noita-mapcap/files/luacomponent.xml") -- ffi isn't accessible from inside lua components, scrap that idea modGUI = GuiCreate()