Split Noita API wrapper into several files

This commit is contained in:
David Vogel 2022-07-22 21:31:40 +02:00
parent a30c3b0cbe
commit aa99e101b4
7 changed files with 307 additions and 297 deletions

View File

@ -3,8 +3,8 @@
-- This software is released under the MIT License. -- This software is released under the MIT License.
-- https://opensource.org/licenses/MIT -- https://opensource.org/licenses/MIT
---@type NoitaAPI ---@type NoitaEntityAPI
local noitaAPI = dofile_once("mods/noita-mapcap/files/libraries/noita-api.lua") local EntityAPI = dofile_once("mods/noita-mapcap/files/libraries/noita-api/entity.lua")
---@type JSONLib ---@type JSONLib
local json = dofile_once("mods/noita-mapcap/files/libraries/json.lua") local json = dofile_once("mods/noita-mapcap/files/libraries/json.lua")
@ -78,7 +78,7 @@ end
local function captureEntities(entityFile, x, y, radius) local function captureEntities(entityFile, x, y, radius)
if not entityFile then return end 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 for _, entity in ipairs(entities) do
-- Get to the root entity, as we are exporting entire entity trees. -- Get to the root entity, as we are exporting entire entity trees.
local rootEntity = entity:GetRootEntity() local rootEntity = entity:GetRootEntity()

View File

@ -8,8 +8,8 @@
---@type Vec2 ---@type Vec2
local Vec2 = dofile_once("mods/noita-mapcap/files/libraries/vec2.lua") local Vec2 = dofile_once("mods/noita-mapcap/files/libraries/vec2.lua")
---@type NoitaAPI ---@type NoitaCameraAPI
local NoitaAPI = dofile_once("mods/noita-mapcap/files/libraries/noita-api.lua") local CameraAPI = dofile_once("mods/noita-mapcap/files/libraries/noita-api/camera.lua")
---@class Coords ---@class Coords
---@field InternalResolution Vec2 ---@field InternalResolution Vec2
@ -79,7 +79,7 @@ end
---@param viewportCenter Vec2|nil -- Result of `GameGetCameraPos()`. Will be queried automatically if set to nil. ---@param viewportCenter Vec2|nil -- Result of `GameGetCameraPos()`. Will be queried automatically if set to nil.
---@return Vec2 window ---@return Vec2 window
function Coords:ToWindow(world, viewportCenter) function Coords:ToWindow(world, viewportCenter)
viewportCenter = viewportCenter or NoitaAPI.Camera.Pos() viewportCenter = viewportCenter or CameraAPI.Pos()
local internalTopLeft, internalBottomRight = self:InternalRect() local internalTopLeft, internalBottomRight = self:InternalRect()
local pixelScale = self:PixelScale() local pixelScale = self:PixelScale()
@ -92,7 +92,7 @@ end
---@param viewportCenter Vec2|nil -- Result of `GameGetCameraPos()`. Will be queried automatically if set to nil. ---@param viewportCenter Vec2|nil -- Result of `GameGetCameraPos()`. Will be queried automatically if set to nil.
---@return Vec2 world ---@return Vec2 world
function Coords:ToWorld(window, viewportCenter) function Coords:ToWorld(window, viewportCenter)
viewportCenter = viewportCenter or NoitaAPI.Camera.Pos() viewportCenter = viewportCenter or CameraAPI.Pos()
local internalTopLeft, internalBottomRight = self:InternalRect() local internalTopLeft, internalBottomRight = self:InternalRect()
local pixelScale = self:PixelScale() local pixelScale = self:PixelScale()

View File

@ -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

View File

@ -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<string, string>|nil
function NoitaComponent:GetMembers()
return ComponentGetMembers(self.ID)
end
---Returns a string-indexed table of string or nil.
---@param objectName string
---@return table<string, string>|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

View File

@ -9,6 +9,9 @@
-- State: Working but incomplete. If something is missing, add it by hand! -- State: Working but incomplete. If something is missing, add it by hand!
-- It would be optimal to generate this API wrapper automatically... -- 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 ---@type Vec2
local Vec2 = dofile_once("mods/noita-mapcap/files/libraries/vec2.lua") 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 -- -- Classes --
------------- -------------
---@class NoitaEntityAPI
local EntityAPI = {} local EntityAPI = {}
---@class NoitaEntity ---@class NoitaEntity
---@field ID integer -- Noita entity ID. ---@field ID integer -- Noita entity ID.
local NoitaEntity = {} local NoitaEntity = {}
NoitaEntity.__index = NoitaEntity NoitaEntity.__index = NoitaEntity
EntityAPI.MetaTable = NoitaEntity
---WrapID wraps the given entity ID and returns a Noita entity object. ---WrapID wraps the given entity ID and returns a Noita entity object.
---@param id number ---@param id number
@ -34,84 +39,6 @@ function EntityAPI.WrapID(id)
return setmetatable({ ID = id }, NoitaEntity) return setmetatable({ ID = id }, NoitaEntity)
end 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 -- -- Noita API wrappers --
------------------------ ------------------------
@ -122,11 +49,7 @@ end
---@param posY number -- Y coordinate in world (virtual) pixels. ---@param posY number -- Y coordinate in world (virtual) pixels.
---@return NoitaEntity|nil ---@return NoitaEntity|nil
function EntityAPI.Load(filename, posX, posY) function EntityAPI.Load(filename, posX, posY)
local entityID = EntityLoad(filename, posX, posY) return EntityAPI.WrapID(EntityLoad(filename, posX, posY))
if entityID == nil then
return nil
end
return setmetatable({ ID = entityID }, NoitaEntity)
end end
--- ---
@ -135,11 +58,7 @@ end
---@param posY number -- Y coordinate in world (virtual) pixels. ---@param posY number -- Y coordinate in world (virtual) pixels.
---@return NoitaEntity|nil ---@return NoitaEntity|nil
function EntityAPI.LoadEndGameItem(filename, posX, posY) function EntityAPI.LoadEndGameItem(filename, posX, posY)
local entityID = EntityLoadEndGameItem(filename, posX, posY) return EntityAPI.WrapID(EntityLoadEndGameItem(filename, posX, posY))
if entityID == nil then
return nil
end
return setmetatable({ ID = entityID }, NoitaEntity)
end end
--- ---
@ -169,11 +88,7 @@ end
---@param name string ---@param name string
---@return NoitaEntity|nil ---@return NoitaEntity|nil
function EntityAPI.CreateNew(name) function EntityAPI.CreateNew(name)
local entityID = EntityCreateNew(name) return EntityAPI.WrapID(EntityCreateNew(name))
if entityID == nil then
return nil
end
return setmetatable({ ID = entityID }, NoitaEntity)
end end
--- ---
@ -192,10 +107,7 @@ end
---@return NoitaComponent|nil ---@return NoitaComponent|nil
function NoitaEntity:AddComponent(componentTypeName, tableOfComponentValues) function NoitaEntity:AddComponent(componentTypeName, tableOfComponentValues)
local componentID = EntityAddComponent(self.ID, componentTypeName, tableOfComponentValues) local componentID = EntityAddComponent(self.ID, componentTypeName, tableOfComponentValues)
if componentID == nil then return ComponentAPI.WrapID(componentID)
return nil
end
return setmetatable({ ID = componentID }, NoitaComponent)
end end
--- ---
@ -210,7 +122,7 @@ function NoitaEntity:GetAllComponents()
local componentIDs = EntityGetAllComponents(self.ID) or {} local componentIDs = EntityGetAllComponents(self.ID) or {}
local result = {} local result = {}
for _, componentID in ipairs(componentIDs) do for _, componentID in ipairs(componentIDs) do
table.insert(result, setmetatable({ ID = componentID }, NoitaComponent)) table.insert(result, ComponentAPI.WrapID(componentID))
end end
return result return result
end end
@ -228,7 +140,7 @@ function NoitaEntity:GetComponents(componentTypeName, tag)
end end
local result = {} local result = {}
for _, componentID in ipairs(componentIDs) do for _, componentID in ipairs(componentIDs) do
table.insert(result, setmetatable({ ID = componentID }, NoitaComponent)) table.insert(result, ComponentAPI.WrapID(componentID))
end end
return result return result
end end
@ -244,10 +156,7 @@ function NoitaEntity:GetFirstComponent(componentTypeName, tag)
else else
componentID = EntityGetFirstComponent(self.ID, componentTypeName) componentID = EntityGetFirstComponent(self.ID, componentTypeName)
end end
if componentID == nil then return ComponentAPI.WrapID(componentID)
return nil
end
return setmetatable({ ID = componentID }, NoitaComponent)
end end
---Sets the transform of the entity. ---Sets the transform of the entity.
@ -288,7 +197,7 @@ function NoitaEntity:GetAllChildren()
local entityIDs = EntityGetAllChildren(self.ID) or {} local entityIDs = EntityGetAllChildren(self.ID) or {}
local result = {} local result = {}
for _, entityID in ipairs(entityIDs) do for _, entityID in ipairs(entityIDs) do
table.insert(result, setmetatable({ ID = entityID }, NoitaEntity)) table.insert(result, EntityAPI.WrapID(entityID))
end end
return result return result
end end
@ -296,18 +205,13 @@ end
--- ---
---@return NoitaEntity|nil ---@return NoitaEntity|nil
function NoitaEntity:GetParent() function NoitaEntity:GetParent()
local entityID = EntityGetParent(self.ID) return EntityAPI.WrapID(EntityGetParent(self.ID))
if entityID == nil then
return nil
end
return setmetatable({ ID = entityID }, NoitaEntity)
end end
---Returns the given entity if it has no parent, otherwise walks up the parent hierarchy to the topmost parent and returns it. ---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() function NoitaEntity:GetRootEntity()
local entityID = EntityGetRootEntity(self.ID) return EntityAPI.WrapID(EntityGetRootEntity(self.ID))
return setmetatable({ ID = entityID }, NoitaEntity)
end end
--- ---
@ -360,7 +264,7 @@ function EntityAPI.GetWithTag(tag)
local entityIDs = EntityGetWithTag(tag) or {} local entityIDs = EntityGetWithTag(tag) or {}
local result = {} local result = {}
for _, entityID in ipairs(entityIDs) do for _, entityID in ipairs(entityIDs) do
table.insert(result, setmetatable({ ID = entityID }, NoitaEntity)) table.insert(result, EntityAPI.WrapID(entityID))
end end
return result return result
end end
@ -374,7 +278,7 @@ function EntityAPI.GetInRadius(posX, posY, radius)
local entityIDs = EntityGetInRadius(posX, posY, radius) or {} local entityIDs = EntityGetInRadius(posX, posY, radius) or {}
local result = {} local result = {}
for _, entityID in ipairs(entityIDs) do for _, entityID in ipairs(entityIDs) do
table.insert(result, setmetatable({ ID = entityID }, NoitaEntity)) table.insert(result, EntityAPI.WrapID(entityID))
end end
return result return result
end end
@ -389,7 +293,7 @@ function EntityAPI.GetInRadiusWithTag(posX, posY, radius, tag)
local entityIDs = EntityGetInRadiusWithTag(posX, posY, radius, tag) or {} local entityIDs = EntityGetInRadiusWithTag(posX, posY, radius, tag) or {}
local result = {} local result = {}
for _, entityID in ipairs(entityIDs) do for _, entityID in ipairs(entityIDs) do
table.insert(result, setmetatable({ ID = entityID }, NoitaEntity)) table.insert(result, EntityAPI.WrapID(entityID))
end end
return result return result
end end
@ -399,22 +303,14 @@ end
---@param posY number -- X coordinate in world (virtual) pixels. ---@param posY number -- X coordinate in world (virtual) pixels.
---@return NoitaEntity|nil ---@return NoitaEntity|nil
function EntityAPI.GetClosest(posX, posY) function EntityAPI.GetClosest(posX, posY)
local entityID = EntityGetClosest(posX, posY) return EntityAPI.WrapID(EntityGetClosest(posX, posY))
if entityID == nil then
return nil
end
return setmetatable({ ID = entityID }, NoitaEntity)
end end
--- ---
---@param name string ---@param name string
---@return NoitaEntity|nil ---@return NoitaEntity|nil
function EntityAPI.GetWithName(name) function EntityAPI.GetWithName(name)
local entityID = EntityGetWithName(name) return EntityAPI.WrapID(EntityGetWithName(name))
if entityID == nil then
return nil
end
return setmetatable({ ID = entityID }, NoitaEntity)
end end
--- ---
@ -442,61 +338,6 @@ function NoitaEntity:GetFilename()
return EntityGetFilename(self.ID) return EntityGetFilename(self.ID)
end 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'. ---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. ---'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. ---The value setting works like ComponentObjectSetValue2(), with the exception that multivalue types are not supported.
@ -507,116 +348,30 @@ end
---@return NoitaComponent|nil ---@return NoitaComponent|nil
function NoitaEntity:EntityAddComponent(componentTypeName, tableOfComponentValues) function NoitaEntity:EntityAddComponent(componentTypeName, tableOfComponentValues)
local componentID = EntityAddComponent2(self.ID, componentTypeName, tableOfComponentValues) local componentID = EntityAddComponent2(self.ID, componentTypeName, tableOfComponentValues)
if componentID == nil then return ComponentAPI.WrapID(componentID)
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<string, string>|nil
function NoitaComponent:GetMembers()
return ComponentGetMembers(self.ID)
end
---Returns a string-indexed table of string or nil.
---@param objectName string
---@return table<string, string>|nil
function NoitaComponent:ObjectGetMembers(objectName)
return ComponentObjectGetMembers(self.ID, objectName)
end
---
---@return string string
function NoitaComponent:GetTypeName()
return ComponentGetTypeName(self.ID)
end end
-- TODO: Add missing Noita API methods and functions. -- TODO: Add missing Noita API methods and functions.
--- -------------------------
---@param strength number -- JSON Implementation --
---@param position Vec2|nil -- Defaults to camera position if not set. -------------------------
function CameraAPI.Screenshake(strength, position)
if position == nil then ---MarshalJSON implements the JSON marshaler interface.
return GameScreenshake(strength) ---@return string
end function NoitaEntity:MarshalJSON()
return GameScreenshake(strength, position.x, position.y) 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 end
-- TODO: Add missing Noita API methods and functions. return EntityAPI
---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

View File

@ -3,8 +3,8 @@
-- This software is released under the MIT License. -- This software is released under the MIT License.
-- https://opensource.org/licenses/MIT -- https://opensource.org/licenses/MIT
---@type NoitaAPI ---@type NoitaEntityAPI
local noitaAPI = dofile_once("mods/noita-mapcap/files/libraries/noita-api.lua") local EntityAPI = dofile_once("mods/noita-mapcap/files/libraries/noita-api/entity.lua")
local oldPerkSpawn = perk_spawn local oldPerkSpawn = perk_spawn
@ -15,7 +15,7 @@ local oldPerkSpawn = perk_spawn
---@param dontRemoveOtherPerks boolean ---@param dontRemoveOtherPerks boolean
---@return NoitaEntity|nil ---@return NoitaEntity|nil
function perk_spawn(x, y, perkID, dontRemoveOtherPerks) 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 if entity == nil then return end
-- Remove the SpriteOffsetAnimatorComponent components from the entity. -- Remove the SpriteOffsetAnimatorComponent components from the entity.

View File

@ -5,6 +5,9 @@
dofile("mods/noita-mapcap/files/init.lua") dofile("mods/noita-mapcap/files/init.lua")
---Called in order upon loading game.
function OnModInit() end
function OnPlayerSpawned(player_entity) function OnPlayerSpawned(player_entity)
--EntityLoad("mods/noita-mapcap/files/luacomponent.xml") -- ffi isn't accessible from inside lua components, scrap that idea --EntityLoad("mods/noita-mapcap/files/luacomponent.xml") -- ffi isn't accessible from inside lua components, scrap that idea
modGUI = GuiCreate() modGUI = GuiCreate()