2022-07-22 19:31:40 +00:00
-- Copyright (c) 2022 David Vogel
--
-- This software is released under the MIT License.
-- https://opensource.org/licenses/MIT
2022-07-23 15:36:21 +00:00
local JSON = require ( " libraries.noita-api.json " )
2022-07-22 19:31:40 +00:00
-------------
-- 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.
2022-07-23 15:36:21 +00:00
---@param id number|nil
2022-07-22 19:31:40 +00:00
---@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 --
-------------------------
2022-07-23 09:39:40 +00:00
---Returns a new table with all arguments stored into keys `1`, `2`, etc. and with a field `"n"` with the total number of arguments.
---@param ... any
---@return table
local function pack ( ... )
t = { ... }
t.n = select ( " # " , ... )
return t
end
2022-07-22 19:31:40 +00:00
-- 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
2022-07-23 09:39:40 +00:00
local packedResult = pack ( self : GetValue ( k ) ) -- Try to get value with correct type. Assuming nil is an error, but this is not always the case... meh.
2022-07-22 19:31:40 +00:00
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
}
2022-07-23 08:57:25 +00:00
return JSON.Marshal ( resultObject )
2022-07-22 19:31:40 +00:00
end
return ComponentAPI