Added error handling, merged script, added errors and implemented MessageFactory on xml

This commit is contained in:
KiritoDv 2025-03-14 19:08:09 -06:00
parent 40e6d6b788
commit c103d0974a
14 changed files with 884 additions and 924 deletions

View file

@ -1,8 +1,8 @@
Game = {}
Assets = {}
UIWidgets = {}
Events = {}
---@alias ListenerID number
---@class Asset
local Asset = {}
@ -715,6 +715,7 @@ LaserStrength = {
}
---@class PlayerShot
PlayerShot = {}
---@field obj Object
---@field index number
---@field vel Vec3f
@ -731,9 +732,9 @@ LaserStrength = {
---@field timer number
---@field sourceId number
---@field bonus number
PlayerShot = {}
---@class ArwingInfo
ArwingInfo = {}
---@field rightWingState number
---@field leftWingState number
---@field upperRightFlapYrot number
@ -750,9 +751,9 @@ PlayerShot = {}
---@field teamFaceXrot number
---@field teamFaceYrot number
---@field cockpitGlassXrot number
ArwingInfo = {}
---@class PlayerSfx
PlayerSfx = {}
---@field levelType number
---@field form number
---@field srcPos number
@ -763,9 +764,9 @@ ArwingInfo = {}
---@field bank number
---@field zRot number
---@field roll number
PlayerSfx = {}
---@class Player
Player = {}
---@field unk_000 number
---@field unk_004 number
---@field unk_008 number
@ -925,7 +926,6 @@ PlayerSfx = {}
---@field arwing ArwingInfo
---@field aerobaticPitch number
---@field somersault boolean
Player = {}
---@return number
function Game.D_AQ_801C4188() end
@ -1704,64 +1704,68 @@ Assets.sBoostGaugeArrow7 = "__OTR__assets/textures/hud/sBoostGaugeArrow7"
---@type Asset
Assets.sBoostGaugeArrow8 = "__OTR__assets/textures/hud/sBoostGaugeArrow8"
---@class Vec3f
Vec3f = {}
---@field x number
---@field y number
---@field z number
Vec3f = {}
---@return Vec3f
function Vec3f:asRef() end
---@return f32
---@return number
function Vec3f:xRef() end
---@return f32
---@return number
function Vec3f:yRef() end
---@return f32
---@return number
function Vec3f:zRef() end
---@return number
function Vec3f:asArray() end
---@class Vec3s
Vec3s = {}
---@field x number
---@field y number
---@field z number
Vec3s = {}
---@return Vec3s
function Vec3s:asRef() end
---@return f32
---@return number
function Vec3s:xRef() end
---@return f32
---@return number
function Vec3s:yRef() end
---@return f32
---@return number
function Vec3s:zRef() end
---@return number
function Vec3s:asArray() end
---@class PosRot
PosRot = {}
---@field pos Vec3f
---@field rot Vec3f
PosRot = {}
---@return PosRot
function PosRot:asRef() end
---@class CameraPoint
CameraPoint = {}
---@field eye Vec3f
---@field at Vec3f
CameraPoint = {}
---@return CameraPoint
---@return CameraPonumber
function CameraPoint:asRef() end
---@class Triangle
---@field vtx number
Triangle = {}
---@field vtx number
---@return Triangle
function Triangle:asRef() end
---@class PlaneF
PlaneF = {}
---@field normal Vec3f
---@field dist number
PlaneF = {}
---@return PlaneF
function PlaneF:asRef() end
---@class PlaneI
PlaneI = {}
---@field normal Vec3s
---@field dist number
PlaneI = {}
---@return PlaneI
function PlaneI:asRef() end
@ -2655,6 +2659,7 @@ ScreenSize = {
}
---@class OSContPad
OSContPad = {}
---@field button number
---@field stick_x number
---@field stick_y number
@ -2663,19 +2668,18 @@ ScreenSize = {
---@field gyro_y number
---@field right_stick_x number
---@field right_stick_y number
OSContPad = {}
---@class ImVec2
ImVec2 = {}
---@field x number
---@field y number
ImVec2 = {}
---@class ImVec4
ImVec4 = {}
---@field x number
---@field y number
---@field z number
---@field w number
ImVec4 = {}
---@enum RadioCharacterId
RadioCharacterId = {
@ -4192,6 +4196,7 @@ GroundSurface = {
}
---@class Environment
Environment = {}
---@field type number
---@field unk04 number
---@field bgColor number
@ -4208,7 +4213,6 @@ GroundSurface = {
---@field ambR number
---@field ambG number
---@field ambB number
Environment = {}
---@enum SfxBankId
SfxBankId = {
@ -4843,19 +4847,19 @@ SetupDL = {
}
---@class Color_RGBA32
Color_RGBA32 = {}
---@field r number
---@field g number
---@field b number
---@field a number
Color_RGBA32 = {}
---@class Limb
Limb = {}
---@field dList Gfx
---@field trans Vec3f
---@field rot Vec3s
---@field sibling Limb
---@field child Limb
Limb = {}
---@param _void nil
---@return nil
@ -5441,21 +5445,57 @@ function Game.D_80178580(index) end
---@param index number
---@param value number
function Game.D_80178580(index, value) end
---@class PlanetStats
PlanetStats = {}
---@return number
function PlanetStats:hitCount() end
---@param value number
---@return number
function PlanetStats:hitCount(value) end
---@return number
function PlanetStats:planetId() end
---@param value number
---@return number
function PlanetStats:planetId(value) end
---@return number
function PlanetStats:hitCountOver256() end
---@param value number
---@return number
function PlanetStats:hitCountOver256(value) end
---@return number
function PlanetStats:peppyAlive() end
---@param value number
---@return number
function PlanetStats:peppyAlive(value) end
---@return number
function PlanetStats:falcoAlive() end
---@param value number
---@return number
function PlanetStats:falcoAlive(value) end
---@return number
function PlanetStats:slippyAlive() end
---@param value number
---@return number
function PlanetStats:slippyAlive(value) end
---@class SaveData
SaveData = {}
---@field planet PlanetData
---@field pad10 string
---@field soundMode number
---@field musicVolume number
---@field voiceVolume number
---@field sfxVolume number
---@field rankingRoute current
---@field rankingLives current
---@field rankingMedal current
---@field rankingRoute number
---@field rankingLives number
---@field rankingMedal number
---@field unk_EA number
---@field textLanguage number
---@field voiceLanguage number
---@field padEE string
SaveData = {}
---@return PlanetStats[]
---@param route number
function SaveData:GetPlanetStats(route) end
---@param _void nil
---@return number
@ -10363,11 +10403,11 @@ ActorCutsceneModels = {
}
---@class Object
Object = {}
---@field status number
---@field id number
---@field pos Vec3f
---@field rot Vec3f
Object = {}
---@return Actor
function Object:asActor() end
---@return Boss
@ -10386,6 +10426,7 @@ function Object:asEffect() end
function Object:asRef() end
---@class ObjectInfo
ObjectInfo = {}
---@field draw ObjectFunc
---@field dList Gfx
---@field drawType number
@ -10398,22 +10439,22 @@ function Object:asRef() end
---@field unk_19 number
---@field targetOffset number
---@field bonus number
ObjectInfo = {}
---@return ObjectInfo
function ObjectInfo:asRef() end
---@class Scenery360
Scenery360 = {}
---@field obj Object
---@field info ObjectInfo
---@field pathIndex number
---@field unk_41 string
---@field sfxSource number
---@field unk_54 number
Scenery360 = {}
---@return Scenery360
function Scenery360:asRef() end
---@class Scenery
Scenery = {}
---@field obj Object
---@field info ObjectInfo
---@field index number
@ -10426,11 +10467,11 @@ function Scenery360:asRef() end
---@field vel Vec3f
---@field sfxSource number
---@field pad7C string
Scenery = {}
---@return Scenery
function Scenery:asRef() end
---@class Sprite
Sprite = {}
---@field obj Object
---@field info ObjectInfo
---@field index number
@ -10438,11 +10479,11 @@ function Scenery:asRef() end
---@field sceneryId number
---@field destroy number
---@field toLeft number
Sprite = {}
---@return Sprite
function Sprite:asRef() end
---@class Item
Item = {}
---@field obj Object
---@field info ObjectInfo
---@field index number
@ -10457,11 +10498,11 @@ function Sprite:asRef() end
---@field unk_58 number
---@field sfxSource number
---@field width number
Item = {}
---@return Item
function Item:asRef() end
---@class Effect
Effect = {}
---@field obj Object
---@field info ObjectInfo
---@field index number
@ -10482,11 +10523,11 @@ function Item:asRef() end
---@field unk_7A number
---@field pad7C string
---@field sfxSource number
Effect = {}
---@return Effect
function Effect:asRef() end
---@class Boss
Boss = {}
---@field obj Object
---@field info ObjectInfo
---@field index number
@ -10517,11 +10558,11 @@ function Effect:asRef() end
---@field vwork Vec3f
---@field scale number
---@field sfxSource number
Boss = {}
---@return Boss
function Boss:asRef() end
---@class Actor
Actor = {}
---@field obj Object
---@field info ObjectInfo
---@field index number
@ -10560,7 +10601,6 @@ function Boss:asRef() end
---@field scale number
---@field fwork number
---@field vwork Vec3f
Actor = {}
---@return Actor
function Actor:asRef() end
@ -28318,14 +28358,17 @@ EventPriority = {
}
---@class IEvent
---@field cancelled boolean
IEvent = {}
---@field cancelled boolean
---@class EventListener
EventListener = {}
---@field priority EventPriority
---@field function SmartFunctionCallback
EventListener = {}
---@param _name string
---@return std::shared_ptr<Ship::CVar>
function CVarGet(_name) end
---@param _name string
---@param defaultValue number
---@return number
@ -28336,7 +28379,7 @@ function CVarGetInteger(_name, defaultValue) end
function CVarGetFloat(_name, defaultValue) end
---@param _name string
---@param defaultValue string
---@return number
---@return
function CVarGetString(_name, defaultValue) end
---@param _name string
---@param defaultValue Color_RGBA8
@ -28524,6 +28567,25 @@ function UIWidgets.EnhancementCheckbox(_text, cvarName, disabled, disabledToolti
---@param defaultValue boolean
---@return boolean
function UIWidgets.PaddedEnhancementCheckbox(_text, cvarName, padTop, padBottom, disabled, disabledTooltipText, disabledGraphic, defaultValue) end
---@param _cvarName string
---@param _std::span<char any
---@param comboArray std::dynamic_extent>
---@param defaultIndex number
---@param disabled boolean
---@param disabledTooltipText string
---@param disabledValue number
---@return boolean
function UIWidgets.EnhancementCombobox(_cvarName, _std::span<char, comboArray, defaultIndex, disabled, disabledTooltipText, disabledValue) end
---@param _label string
---@param cvarName string
---@param _std::span<char any
---@param comboArray std::dynamic_extent>
---@param defaultIndex number
---@param disabled boolean
---@param disabledTooltipText string
---@param disabledValue number
---@return boolean
function UIWidgets.LabeledRightAlignedEnhancementCombobox(_label, cvarName, _std::span<char, comboArray, defaultIndex, disabled, disabledTooltipText, disabledValue) end
---@param _text string
---@param padTop boolean
---@param padBottom boolean
@ -28641,6 +28703,12 @@ function UIWidgets.PopStyleButton(_) end
---@param options ButtonOptions
---@return boolean
function UIWidgets.Button(_label, options) end
---@param _label string
---@param cvarName string
---@param windowPtr std::shared_ptr<Ship::GuiWindow>
---@param options ButtonOptions
---@return boolean
function UIWidgets.WindowButton(_label, cvarName, windowPtr, options) end
---@param _tooltip string
---@return CheckboxOptions
function UIWidgets.DefaultCheckboxOptions(_tooltip) end
@ -28666,6 +28734,20 @@ function UIWidgets.PushStyleCombobox(arg0) end
---@param _ any
---@return nil
function UIWidgets.PopStyleCombobox(_) end
---@param _label string
---@param value number
---@param _std::span<char any
---@param comboArray std::dynamic_extent>
---@param options ComboboxOptions
---@return boolean
function UIWidgets.Combobox(_label, value, _std::span<char, comboArray, options) end
---@param _label string
---@param cvarName string
---@param _std::span<char any
---@param comboArray std::dynamic_extent>
---@param options ComboboxOptions
---@return boolean
function UIWidgets.CVarCombobox(_label, cvarName, _std::span<char, comboArray, options) end
---@param arg0 color
---@return nil
function UIWidgets.PushStyleSlider(arg0) end
@ -28706,7 +28788,7 @@ function UIWidgets.CVarSliderFloat(_label, cvarName, min, max, defaultValue, opt
---@return number
function ResourceGetCrcByName(_name) end
---@param _crc number
---@return number
---@return
function ResourceGetNameByCrc(_crc) end
---@param _name string
---@return number
@ -28773,187 +28855,183 @@ function ResourceHasGameVersion(_hash) end
---@param _ any
---@return number
function IsResourceManagerLoaded(_) end
---@class ItemDropEvent
---@field event IEvent
---@field item Item
lua.new_usertype<ItemDropEvent>("ItemDropEvent",
"event", sol::property(&ItemDropEvent::event, &ItemDropEvent::event),
"item", sol::property(&ItemDropEvent::item, &ItemDropEvent::item)
);
lua.new_usertype<PlayerActionBoostEvent>("PlayerActionBoostEvent",
"event", sol::property(&PlayerActionBoostEvent::event, &PlayerActionBoostEvent::event),
"player", sol::property(&PlayerActionBoostEvent::player, &PlayerActionBoostEvent::player)
);
---@class PlayerActionBoostEvent
---@field event IEvent
---@field player Player
lua.new_usertype<PlayerActionBrakeEvent>("PlayerActionBrakeEvent",
"event", sol::property(&PlayerActionBrakeEvent::event, &PlayerActionBrakeEvent::event),
"player", sol::property(&PlayerActionBrakeEvent::player, &PlayerActionBrakeEvent::player)
);
---@class PlayerActionBrakeEvent
---@field event IEvent
---@field player Player
lua.new_usertype<PlayerActionPreShootEvent>("PlayerActionPreShootEvent",
"event", sol::property(&PlayerActionPreShootEvent::event, &PlayerActionPreShootEvent::event),
"player", sol::property(&PlayerActionPreShootEvent::player, &PlayerActionPreShootEvent::player),
"laser", sol::property(&PlayerActionPreShootEvent::laser, &PlayerActionPreShootEvent::laser)
);
---@class PlayerActionPreShootEvent
---@field event IEvent
---@field player Player
---@field laser LaserStrength
lua.new_usertype<PlayerActionPostShootEvent>("PlayerActionPostShootEvent",
"event", sol::property(&PlayerActionPostShootEvent::event, &PlayerActionPostShootEvent::event),
"player", sol::property(&PlayerActionPostShootEvent::player, &PlayerActionPostShootEvent::player),
"shot", sol::property(&PlayerActionPostShootEvent::shot, &PlayerActionPostShootEvent::shot)
);
---@class PlayerActionPostShootEvent
---@field event IEvent
---@field player Player
---@field shot PlayerShot
lua.new_usertype<PlayerActionPreShootChargedEvent>("PlayerActionPreShootChargedEvent",
"event", sol::property(&PlayerActionPreShootChargedEvent::event, &PlayerActionPreShootChargedEvent::event),
"player", sol::property(&PlayerActionPreShootChargedEvent::player, &PlayerActionPreShootChargedEvent::player)
);
---@class PlayerActionPreShootChargedEvent
---@field event IEvent
---@field player Player
lua.new_usertype<PlayerActionPostShootChargedEvent>("PlayerActionPostShootChargedEvent",
"event", sol::property(&PlayerActionPostShootChargedEvent::event, &PlayerActionPostShootChargedEvent::event),
"player", sol::property(&PlayerActionPostShootChargedEvent::player, &PlayerActionPostShootChargedEvent::player)
);
---@class PlayerActionPostShootChargedEvent
---@field event IEvent
---@field player Player
lua.new_usertype<PlayerActionPreBombEvent>("PlayerActionPreBombEvent",
"event", sol::property(&PlayerActionPreBombEvent::event, &PlayerActionPreBombEvent::event),
"player", sol::property(&PlayerActionPreBombEvent::player, &PlayerActionPreBombEvent::player)
);
---@class PlayerActionPreBombEvent
---@field event IEvent
---@field player Player
lua.new_usertype<PlayerActionPostBombEvent>("PlayerActionPostBombEvent",
"event", sol::property(&PlayerActionPostBombEvent::event, &PlayerActionPostBombEvent::event),
"player", sol::property(&PlayerActionPostBombEvent::player, &PlayerActionPostBombEvent::player)
);
---@class PlayerActionPostBombEvent
---@field event IEvent
---@field player Player
lua.new_usertype<EngineInitEvent>("EngineInitEvent",
"event", sol::property(&EngineInitEvent::event, &EngineInitEvent::event)
);
lua.new_usertype<EngineExitEvent>("EngineExitEvent",
"event", sol::property(&EngineExitEvent::event, &EngineExitEvent::event)
);
---@class EngineInitEvent
---@field event IEvent
lua.new_usertype<EngineRenderMenubarEvent>("EngineRenderMenubarEvent",
"event", sol::property(&EngineRenderMenubarEvent::event, &EngineRenderMenubarEvent::event)
);
---@class EngineExitEvent
---@field event IEvent
lua.new_usertype<DisplayPreUpdateEvent>("DisplayPreUpdateEvent",
"event", sol::property(&DisplayPreUpdateEvent::event, &DisplayPreUpdateEvent::event)
);
---@class EngineRenderMenubarEvent
---@field event IEvent
lua.new_usertype<DisplayPostUpdateEvent>("DisplayPostUpdateEvent",
"event", sol::property(&DisplayPostUpdateEvent::event, &DisplayPostUpdateEvent::event)
);
---@class DisplayPreUpdateEvent
---@field event IEvent
lua.new_usertype<GamePreUpdateEvent>("GamePreUpdateEvent",
"event", sol::property(&GamePreUpdateEvent::event, &GamePreUpdateEvent::event)
);
---@class DisplayPostUpdateEvent
---@field event IEvent
lua.new_usertype<GamePostUpdateEvent>("GamePostUpdateEvent",
"event", sol::property(&GamePostUpdateEvent::event, &GamePostUpdateEvent::event)
);
---@class GamePreUpdateEvent
---@field event IEvent
lua.new_usertype<PlayUpdateEvent>("PlayUpdateEvent",
"event", sol::property(&PlayUpdateEvent::event, &PlayUpdateEvent::event)
);
---@class GamePostUpdateEvent
---@field event IEvent
lua.new_usertype<PlayerPreUpdateEvent>("PlayerPreUpdateEvent",
"event", sol::property(&PlayerPreUpdateEvent::event, &PlayerPreUpdateEvent::event),
"player", sol::property(&PlayerPreUpdateEvent::player, &PlayerPreUpdateEvent::player)
);
---@class PlayUpdateEvent
---@field event IEvent
lua.new_usertype<PlayerPostUpdateEvent>("PlayerPostUpdateEvent",
"event", sol::property(&PlayerPostUpdateEvent::event, &PlayerPostUpdateEvent::event),
"player", sol::property(&PlayerPostUpdateEvent::player, &PlayerPostUpdateEvent::player)
);
---@class PlayerPreUpdateEvent
---@field event IEvent
---@field player Player
lua.new_usertype<DrawRadarHUDEvent>("DrawRadarHUDEvent",
"event", sol::property(&DrawRadarHUDEvent::event, &DrawRadarHUDEvent::event)
);
---@class PlayerPostUpdateEvent
---@field event IEvent
---@field player Player
lua.new_usertype<DrawRadarMarkArwingEvent>("DrawRadarMarkArwingEvent",
"event", sol::property(&DrawRadarMarkArwingEvent::event, &DrawRadarMarkArwingEvent::event),
"colorIdx", sol::property(&DrawRadarMarkArwingEvent::colorIdx, &DrawRadarMarkArwingEvent::colorIdx)
);
---@class DrawRadarHUDEvent
---@field event IEvent
lua.new_usertype<DrawRadarMarkWolfenEvent>("DrawRadarMarkWolfenEvent",
"event", sol::property(&DrawRadarMarkWolfenEvent::event, &DrawRadarMarkWolfenEvent::event)
);
---@class DrawRadarMarkArwingEvent
---@field event IEvent
---@field colorIdx number
lua.new_usertype<DrawBoostGaugeHUDEvent>("DrawBoostGaugeHUDEvent",
"event", sol::property(&DrawBoostGaugeHUDEvent::event, &DrawBoostGaugeHUDEvent::event)
);
---@class DrawRadarMarkWolfenEvent
---@field event IEvent
lua.new_usertype<DrawBombCounterHUDEvent>("DrawBombCounterHUDEvent",
"event", sol::property(&DrawBombCounterHUDEvent::event, &DrawBombCounterHUDEvent::event)
);
---@class DrawBoostGaugeHUDEvent
---@field event IEvent
lua.new_usertype<DrawIncomingMsgHUDEvent>("DrawIncomingMsgHUDEvent",
"event", sol::property(&DrawIncomingMsgHUDEvent::event, &DrawIncomingMsgHUDEvent::event)
);
---@class DrawBombCounterHUDEvent
---@field event IEvent
lua.new_usertype<PreSetupRadioMsgEvent>("PreSetupRadioMsgEvent",
"event", sol::property(&PreSetupRadioMsgEvent::event, &PreSetupRadioMsgEvent::event),
"radioRedBox", sol::property(&PreSetupRadioMsgEvent::radioRedBox, &PreSetupRadioMsgEvent::radioRedBox)
);
---@class DrawIncomingMsgHUDEvent
---@field event IEvent
lua.new_usertype<DrawGoldRingsHUDEvent>("DrawGoldRingsHUDEvent",
"event", sol::property(&DrawGoldRingsHUDEvent::event, &DrawGoldRingsHUDEvent::event)
);
---@class PreSetupRadioMsgEvent
---@field event IEvent
---@field radioRedBox number
lua.new_usertype<DrawLivesCounterHUDEvent>("DrawLivesCounterHUDEvent",
"event", sol::property(&DrawLivesCounterHUDEvent::event, &DrawLivesCounterHUDEvent::event)
);
---@class DrawGoldRingsHUDEvent
---@field event IEvent
lua.new_usertype<DrawTrainingRingPassCountHUDEvent>("DrawTrainingRingPassCountHUDEvent",
"event", sol::property(&DrawTrainingRingPassCountHUDEvent::event, &DrawTrainingRingPassCountHUDEvent::event)
);
---@class DrawLivesCounterHUDEvent
---@field event IEvent
lua.new_usertype<DrawEdgeArrowsHUDEvent>("DrawEdgeArrowsHUDEvent",
"event", sol::property(&DrawEdgeArrowsHUDEvent::event, &DrawEdgeArrowsHUDEvent::event)
);
---@class DrawTrainingRingPassCountHUDEvent
---@field event IEvent
lua.new_usertype<DrawBossHealthHUDEvent>("DrawBossHealthHUDEvent",
"event", sol::property(&DrawBossHealthHUDEvent::event, &DrawBossHealthHUDEvent::event)
);
---@class DrawEdgeArrowsHUDEvent
---@field event IEvent
lua.new_usertype<DrawGlobalHUDPreEvent>("DrawGlobalHUDPreEvent",
"event", sol::property(&DrawGlobalHUDPreEvent::event, &DrawGlobalHUDPreEvent::event)
);
---@class DrawBossHealthHUDEvent
---@field event IEvent
lua.new_usertype<DrawGlobalHUDPostEvent>("DrawGlobalHUDPostEvent",
"event", sol::property(&DrawGlobalHUDPostEvent::event, &DrawGlobalHUDPostEvent::event)
);
---@class DrawGlobalHUDPreEvent
---@field event IEvent
lua.new_usertype<ObjectInitEvent>("ObjectInitEvent",
"event", sol::property(&ObjectInitEvent::event, &ObjectInitEvent::event),
"type", sol::property(&ObjectInitEvent::type, &ObjectInitEvent::type),
"object", sol::property(&ObjectInitEvent::object, &ObjectInitEvent::object)
);
---@class DrawGlobalHUDPostEvent
---@field event IEvent
lua.new_usertype<ObjectUpdateEvent>("ObjectUpdateEvent",
"event", sol::property(&ObjectUpdateEvent::event, &ObjectUpdateEvent::event),
"type", sol::property(&ObjectUpdateEvent::type, &ObjectUpdateEvent::type),
"object", sol::property(&ObjectUpdateEvent::object, &ObjectUpdateEvent::object)
);
lua.new_usertype<ObjectDrawPreSetupEvent>("ObjectDrawPreSetupEvent",
"event", sol::property(&ObjectDrawPreSetupEvent::event, &ObjectDrawPreSetupEvent::event),
"type", sol::property(&ObjectDrawPreSetupEvent::type, &ObjectDrawPreSetupEvent::type),
"object", sol::property(&ObjectDrawPreSetupEvent::object, &ObjectDrawPreSetupEvent::object)
);
---@class ObjectInitEvent
---@field event IEvent
---@field type ObjectEventType
---@field object Object
---@class ObjectUpdateEvent
---@field event IEvent
---@field type ObjectEventType
---@field object Object
---@class ObjectDrawPreSetupEvent
---@field event IEvent
---@field type ObjectEventType
---@field object Object
---@class ObjectDrawPostSetupEvent
---@field event IEvent
---@field type ObjectEventType
---@field object Object
---@class ObjectDestroyEvent
---@field event IEvent
---@field type ObjectEventType
---@field object Object
lua.new_usertype<ObjectDrawPostSetupEvent>("ObjectDrawPostSetupEvent",
"event", sol::property(&ObjectDrawPostSetupEvent::event, &ObjectDrawPostSetupEvent::event),
"type", sol::property(&ObjectDrawPostSetupEvent::type, &ObjectDrawPostSetupEvent::type),
"object", sol::property(&ObjectDrawPostSetupEvent::object, &ObjectDrawPostSetupEvent::object)
);
lua.new_usertype<ObjectDestroyEvent>("ObjectDestroyEvent",
"event", sol::property(&ObjectDestroyEvent::event, &ObjectDestroyEvent::event),
"type", sol::property(&ObjectDestroyEvent::type, &ObjectDestroyEvent::type),
"object", sol::property(&ObjectDestroyEvent::object, &ObjectDestroyEvent::object)
);
---@enum EventID
EventID = {
ItemDropEvent = -1,
PlayerActionBoostEvent = -1,
PlayerActionBrakeEvent = -1,
PlayerActionPreShootEvent = -1,
PlayerActionPostShootEvent = -1,
PlayerActionPreShootChargedEvent = -1,
PlayerActionPostShootChargedEvent = -1,
PlayerActionPreBombEvent = -1,
PlayerActionPostBombEvent = -1,
EngineInitEvent = -1,
EngineExitEvent = -1,
EngineRenderMenubarEvent = -1,
DisplayPreUpdateEvent = -1,
DisplayPostUpdateEvent = -1,
GamePreUpdateEvent = -1,
GamePostUpdateEvent = -1,
PlayUpdateEvent = -1,
PlayerPreUpdateEvent = -1,
PlayerPostUpdateEvent = -1,
DrawRadarHUDEvent = -1,
DrawRadarMarkArwingEvent = -1,
DrawRadarMarkWolfenEvent = -1,
DrawBoostGaugeHUDEvent = -1,
DrawBombCounterHUDEvent = -1,
DrawIncomingMsgHUDEvent = -1,
PreSetupRadioMsgEvent = -1,
DrawGoldRingsHUDEvent = -1,
DrawLivesCounterHUDEvent = -1,
DrawTrainingRingPassCountHUDEvent = -1,
DrawEdgeArrowsHUDEvent = -1,
DrawBossHealthHUDEvent = -1,
DrawGlobalHUDPreEvent = -1,
DrawGlobalHUDPostEvent = -1,
ObjectInitEvent = -1,
ObjectUpdateEvent = -1,
ObjectDrawPreSetupEvent = -1,
ObjectDrawPostSetupEvent = -1,
ObjectDestroyEvent = -1
}

View file

@ -325,7 +325,7 @@ extern Vec3f gTeamArrowsViewPos[10];
// extern f32 D_ctx_80178028[65];
// extern f32 D_ctx_80178130[65];
// extern u8 D_ctx_80178238[65];
extern Player* gPlayer;
extern Player* gPlayer; // sol:array
extern f32* gStarOffsetsX;
extern f32* gStarOffsetsY;
extern u32* gStarFillColors;

View file

@ -13,10 +13,11 @@ typedef struct Vec3f {
/* 0x4 */ f32 y;
/* 0x8 */ f32 z;
#ifdef __cplusplus
Vec3f* asRef() { return this; } // sol:ignore
f32* xRef() { return &x; } // sol:ignore
f32* yRef() { return &y; } // sol:ignore
f32* zRef() { return &z; } // sol:ignore
Vec3f* asRef() { return this; } // sol:not_global
f32* xRef() { return &x; } // sol:not_global
f32* yRef() { return &y; } // sol:not_global
f32* zRef() { return &z; } // sol:not_global
f32* asArray() { if(this) return nullptr; return (f32*) this; } // sol:not_global
#endif
} Vec3f; // size = 0xC
@ -25,10 +26,11 @@ typedef struct Vec3s {
/* 0x2 */ s16 y;
/* 0x4 */ s16 z;
#ifdef __cplusplus
Vec3s* asRef() { return this; } // sol:ignore
s16* xRef() { return &x; } // sol:ignore
s16* yRef() { return &y; } // sol:ignore
s16* zRef() { return &z; } // sol:ignore
Vec3s* asRef() { return this; } // sol:not_global
s16* xRef() { return &x; } // sol:not_global
s16* yRef() { return &y; } // sol:not_global
s16* zRef() { return &z; } // sol:not_global
s16* asArray() { if(this) return nullptr; return (s16*) this; } // sol:not_global
#endif
} Vec3s; // size = 0x6;
@ -36,7 +38,7 @@ typedef struct PosRot {
/* 0x00 */ Vec3f pos;
/* 0x0C */ Vec3f rot;
#ifdef __cplusplus
PosRot* asRef() { return this; } // sol:ignore
PosRot* asRef() { return this; } // sol:not_global
#endif
} PosRot; // size = 0x18
@ -44,14 +46,14 @@ typedef struct CameraPoint {
/* 0x00 */ Vec3f eye;
/* 0x0C */ Vec3f at;
#ifdef __cplusplus
CameraPoint* asRef() { return this; } // sol:ignore
CameraPoint* asRef() { return this; } // sol:not_global
#endif
} CameraPoint; // size = 0x18
typedef struct Triangle {
/* 0x0 */ s16 vtx[3];
#ifdef __cplusplus
Triangle* asRef() { return this; } // sol:ignore
Triangle* asRef() { return this; } // sol:not_global
#endif
} Triangle; // size = 0x6
@ -59,7 +61,7 @@ typedef struct PlaneF {
/* 0x0 */ Vec3f normal;
/* 0xC */ f32 dist;
#ifdef __cplusplus
PlaneF* asRef() { return this; } // sol:ignore
PlaneF* asRef() { return this; } // sol:not_global
#endif
} PlaneF; // size = 0x10
@ -67,7 +69,7 @@ typedef struct PlaneI {
/* 0x0 */ Vec3s normal;
/* 0x8 */ s32 dist;
#ifdef __cplusplus
PlaneI* asRef() { return this; } // sol:ignore
PlaneI* asRef() { return this; } // sol:not_global
#endif
} PlaneI; // size = 0xC

View file

@ -149,14 +149,14 @@ typedef struct Object {
/* 0x04 */ Vec3f pos;
/* 0x10 */ Vec3f rot;
#ifdef __cplusplus
Actor* asActor() { return (Actor*)this; } // sol:ignore
Boss* asBoss() { return (Boss*)this; } // sol:ignore
Scenery* asScenery() { return (Scenery*)this; } // sol:ignore
Scenery360* asScenery360() { return (Scenery360*)this; } // sol:ignore
Sprite* asSprite() { return (Sprite*)this; } // sol:ignore
Item* asItem() { return (Item*)this; } // sol:ignore
Effect* asEffect() { return (Effect*)this; } // sol:ignore
Object* asRef() { return this; } // sol:ignore
Actor* asActor() { if(this) return nullptr; return (Actor*)this; } // sol:not_global
Boss* asBoss() { if(this) return nullptr; return (Boss*)this; } // sol:not_global
Scenery* asScenery() { if(this) return nullptr; return (Scenery*)this; } // sol:not_global
Scenery360* asScenery360() { if(this) return nullptr; return (Scenery360*)this; } // sol:not_global
Sprite* asSprite() { if(this) return nullptr; return (Sprite*)this; } // sol:not_global
Item* asItem() { if(this) return nullptr; return (Item*)this; } // sol:not_global
Effect* asEffect() { if(this) return nullptr; return (Effect*)this; } // sol:not_global
Object* asRef() { if(this) return nullptr; return this; } // sol:not_global
#endif
} Object; // size = 0x1C
@ -171,14 +171,14 @@ typedef struct ObjectInfo {
/* 0x08 */ ObjectFunc action; // argument must have object type.
/* 0x0C */ f32* hitbox;
/* 0x10 */ f32 cullDistance; // z coordinate of something
/* 0x14 */ s16 unk_14; // can be -1, 0, 1. governs camera-related behavior in effects (billboarding?)
/* 0x14 */ s16 unk_14; // can be -1, 0, 1. governs camera-related behavior in effects
/* 0x16 */ s16 unk_16; // can be 0, 1, 2. affects death behavior?
/* 0x18 */ u8 damage;
/* 0x19 */ u8 unk_19; // can be 0, 1, 2. Also camera-related?
/* 0x1C */ f32 targetOffset; // target lock y offset. 0.0f can't be targeted
/* 0x20 */ u8 bonus; // hits when killed. numbers above 1 indicate the hit+ bonus
#ifdef __cplusplus
ObjectInfo* asRef() { return this; } // sol:ignore
ObjectInfo* asRef() { if(this) return nullptr; return this; } // sol:not_global
#endif
} ObjectInfo; // size = 0x24
@ -190,7 +190,7 @@ typedef struct Scenery360 {
/* 0x48 */ f32 sfxSource[3];
/* 0x54 */ f32 unk_54;
#ifdef __cplusplus
Scenery360* asRef() { return this; } // sol:ignore
Scenery360* asRef() { if(this) return nullptr; return this; } // sol:not_global
#endif
} Scenery360; // size = 0x58
@ -208,7 +208,7 @@ typedef struct Scenery {
/* 0x70 */ f32 sfxSource[3];
/* 0x7C */ char pad7C[4];
#ifdef __cplusplus
Scenery* asRef() { return this; } // sol:ignore
Scenery* asRef() { if(this) return nullptr; return this; } // sol:not_global
#endif
} Scenery; // size = 0x80
@ -221,7 +221,7 @@ typedef struct Sprite {
/* 0x46 */ s8 destroy;
/* 0x48 */ s32 toLeft;
#ifdef __cplusplus
Sprite* asRef() { return this; } // sol:ignore
Sprite* asRef() { if(this) return nullptr; return this; } // sol:not_global
#endif
} Sprite; // size = 0x4C
@ -241,7 +241,7 @@ typedef struct Item {
/* 0x5C */ f32 sfxSource[3];
/* 0x68 */ f32 width;
#ifdef __cplusplus
Item* asRef() { return this; } // sol:ignore
Item* asRef() { if(this) return nullptr; return this; } // sol:not_global
#endif
} Item; // size 0x6C
@ -267,7 +267,7 @@ typedef struct Effect {
/* 0x7C */ char pad7C[4];
/* 0x80 */ f32 sfxSource[3];
#ifdef __cplusplus
Effect* asRef() { return this; } // sol:ignore
Effect* asRef() { if(this) return nullptr; return this; } // sol:not_global
#endif
} Effect; // size 0x8C
@ -303,7 +303,7 @@ typedef struct Boss {
/* 0x3F8 */ f32 scale;
/* 0x3FC */ f32 sfxSource[3];
#ifdef __cplusplus
Boss* asRef() { return this; } // sol:ignore
Boss* asRef() { if(this) return nullptr; return this; } // sol:not_global
#endif
} Boss; // size = 0x408
@ -354,7 +354,7 @@ typedef struct Actor {
/* 0x114 */ f32 fwork[30];
/* 0x18C */ Vec3f vwork[30];
#ifdef __cplusplus
Actor* asRef() { return this; } // sol:ignore
Actor* asRef() { if(this) return nullptr; return this; } // sol:not_global
#endif
} Actor; // size = 0x2F4

View file

@ -34,6 +34,10 @@ typedef struct PlanetStats {
(hitCount > 255 ? hitCount - 256 : hitCount), \
((planetId) | ((hitCount > 255 ? 1 : 0) << 4) | (peppyAlive << 5) | (falcoAlive << 6) | (slippyAlive << 7))
#ifdef __cplusplus
#include <vector>
#endif
typedef struct SaveData {
/* 0x00 */ PlanetData planet[16];
/* 0x10 */ char pad10[0x4];
@ -50,6 +54,11 @@ typedef struct SaveData {
/* 0xEB */ u8 textLanguage; // EU Only text language selection
/* 0xEC */ u8 voiceLanguage; // EU Only voice language selection
/* 0xED */ char padEE[0x11];
#ifdef __cplusplus
std::vector<PlanetStats> GetPlanetStats(uint32_t route) { // sol:not_global
std::vector<PlanetStats> result; for (auto & stat : stats) result.push_back(stat[route]); return result; // sol:ignore
} // sol:ignore
#endif
} SaveData; // size = 0xFE
typedef struct {

View file

@ -919,50 +919,52 @@ lua["Assets"]["sBoostGaugeArrow8"] = Asset{ sBoostGaugeArrow8 };
lua.new_usertype<Vec3f>("Vec3f",
"x", sol::property(&Vec3f::x, &Vec3f::x),
"y", sol::property(&Vec3f::y, &Vec3f::y),
"z", sol::property(&Vec3f::z, &Vec3f::z)
,"asRef", &Vec3f::asRef
,"xRef", &Vec3f::xRef,
"z", sol::property(&Vec3f::z, &Vec3f::z),
"asRef", &Vec3f::asRef,
"xRef", &Vec3f::xRef,
"yRef", &Vec3f::yRef,
"zRef", &Vec3f::zRef
"zRef", &Vec3f::zRef,
"asArray", &Vec3f::asArray
);
lua.new_usertype<Vec3s>("Vec3s",
"x", sol::property(&Vec3s::x, &Vec3s::x),
"y", sol::property(&Vec3s::y, &Vec3s::y),
"z", sol::property(&Vec3s::z, &Vec3s::z)
,"asRef", &Vec3s::asRef
,"xRef", &Vec3s::xRef,
"z", sol::property(&Vec3s::z, &Vec3s::z),
"asRef", &Vec3s::asRef,
"xRef", &Vec3s::xRef,
"yRef", &Vec3s::yRef,
"zRef", &Vec3s::zRef
"zRef", &Vec3s::zRef,
"asArray", &Vec3s::asArray
);
lua.new_usertype<PosRot>("PosRot",
"pos", sol::property(&PosRot::pos, &PosRot::pos),
"rot", sol::property(&PosRot::rot, &PosRot::rot)
,"asRef", &PosRot::asRef
"rot", sol::property(&PosRot::rot, &PosRot::rot),
"asRef", &PosRot::asRef
);
lua.new_usertype<CameraPoint>("CameraPoint",
"eye", sol::property(&CameraPoint::eye, &CameraPoint::eye),
"at", sol::property(&CameraPoint::at, &CameraPoint::at)
,"asRef", &CameraPoint::asRef
"at", sol::property(&CameraPoint::at, &CameraPoint::at),
"asRef", &CameraPoint::asRef
);
lua.new_usertype<Triangle>("Triangle",
"vtx", sol::property(&Triangle::vtx, &Triangle::vtx)
,"asRef", &Triangle::asRef
"vtx", sol::property(&Triangle::vtx, &Triangle::vtx),
"asRef", &Triangle::asRef
);
lua.new_usertype<PlaneF>("PlaneF",
"normal", sol::property(&PlaneF::normal, &PlaneF::normal),
"dist", sol::property(&PlaneF::dist, &PlaneF::dist)
,"asRef", &PlaneF::asRef
"dist", sol::property(&PlaneF::dist, &PlaneF::dist),
"asRef", &PlaneF::asRef
);
lua.new_usertype<PlaneI>("PlaneI",
"normal", sol::property(&PlaneI::normal, &PlaneI::normal),
"dist", sol::property(&PlaneI::dist, &PlaneI::dist)
,"asRef", &PlaneI::asRef
"dist", sol::property(&PlaneI::dist, &PlaneI::dist),
"asRef", &PlaneI::asRef
);
lua["Game"]["gIdentityMtx"] = sol::overload([]() -> Mtx { return gIdentityMtx; }, [](Mtx value) { gIdentityMtx = value; });
@ -3288,6 +3290,15 @@ lua.set_function("RCP_SetupDL_50", RCP_SetupDL_50);
lua.set_function("RCP_SetupDL_61", RCP_SetupDL_61);
lua["Game"]["gRcpSetupDLs"] = sol::overload([](int index1, int index2) -> Gfx { return gRcpSetupDLs[index1][index2]; }, [](int index1, int index2, Gfx value) { gRcpSetupDLs[index1][index2] = value; });
lua["Game"]["D_80178580"] = sol::overload([](int index) -> u8 { return D_80178580[index]; }, [](int index, u8 value) { D_80178580[index] = value; });
lua.new_usertype<PlanetStats>("PlanetStats",
"hitCount", sol::property([] (PlanetStats& self) -> u16 { return self.hitCount; }, [] (PlanetStats& self, u16 value) { self.hitCount = value; }),
"planetId", sol::property([] (PlanetStats& self) -> u8 { return self.planetId; }, [] (PlanetStats& self, u8 value) { self.planetId = value; }),
"hitCountOver256", sol::property([] (PlanetStats& self) -> u8 { return self.hitCountOver256; }, [] (PlanetStats& self, u8 value) { self.hitCountOver256 = value; }),
"peppyAlive", sol::property([] (PlanetStats& self) -> u8 { return self.peppyAlive; }, [] (PlanetStats& self, u8 value) { self.peppyAlive = value; }),
"falcoAlive", sol::property([] (PlanetStats& self) -> u8 { return self.falcoAlive; }, [] (PlanetStats& self, u8 value) { self.falcoAlive = value; }),
"slippyAlive", sol::property([] (PlanetStats& self) -> u8 { return self.slippyAlive; }, [] (PlanetStats& self, u8 value) { self.slippyAlive = value; })
);
lua.new_usertype<SaveData>("SaveData",
"planet", sol::property(&SaveData::planet, &SaveData::planet),
"pad10", sol::property(&SaveData::pad10, &SaveData::pad10),
@ -4876,8 +4887,8 @@ lua.new_usertype<Object>("Object",
"status", sol::property(&Object::status, &Object::status),
"id", sol::property(&Object::id, &Object::id),
"pos", sol::property(&Object::pos, &Object::pos),
"rot", sol::property(&Object::rot, &Object::rot)
,"asActor", &Object::asActor,
"rot", sol::property(&Object::rot, &Object::rot),
"asActor", &Object::asActor,
"asBoss", &Object::asBoss,
"asScenery", &Object::asScenery,
"asScenery360", &Object::asScenery360,
@ -4899,8 +4910,8 @@ lua.new_usertype<ObjectInfo>("ObjectInfo",
"damage", sol::property(&ObjectInfo::damage, &ObjectInfo::damage),
"unk_19", sol::property(&ObjectInfo::unk_19, &ObjectInfo::unk_19),
"targetOffset", sol::property(&ObjectInfo::targetOffset, &ObjectInfo::targetOffset),
"bonus", sol::property(&ObjectInfo::bonus, &ObjectInfo::bonus)
,"asRef", &ObjectInfo::asRef
"bonus", sol::property(&ObjectInfo::bonus, &ObjectInfo::bonus),
"asRef", &ObjectInfo::asRef
);
lua.new_usertype<Scenery360>("Scenery360",
@ -4909,8 +4920,8 @@ lua.new_usertype<Scenery360>("Scenery360",
"pathIndex", sol::property(&Scenery360::pathIndex, &Scenery360::pathIndex),
"unk_41", sol::property(&Scenery360::unk_41, &Scenery360::unk_41),
"sfxSource", sol::property(&Scenery360::sfxSource, &Scenery360::sfxSource),
"unk_54", sol::property(&Scenery360::unk_54, &Scenery360::unk_54)
,"asRef", &Scenery360::asRef
"unk_54", sol::property(&Scenery360::unk_54, &Scenery360::unk_54),
"asRef", &Scenery360::asRef
);
lua.new_usertype<Scenery>("Scenery",
@ -4925,8 +4936,8 @@ lua.new_usertype<Scenery>("Scenery",
"effectVel", sol::property(&Scenery::effectVel, &Scenery::effectVel),
"vel", sol::property(&Scenery::vel, &Scenery::vel),
"sfxSource", sol::property(&Scenery::sfxSource, &Scenery::sfxSource),
"pad7C", sol::property(&Scenery::pad7C, &Scenery::pad7C)
,"asRef", &Scenery::asRef
"pad7C", sol::property(&Scenery::pad7C, &Scenery::pad7C),
"asRef", &Scenery::asRef
);
lua.new_usertype<Sprite>("Sprite",
@ -4936,8 +4947,8 @@ lua.new_usertype<Sprite>("Sprite",
"pad44", sol::property(&Sprite::pad44, &Sprite::pad44),
"sceneryId", sol::property(&Sprite::sceneryId, &Sprite::sceneryId),
"destroy", sol::property(&Sprite::destroy, &Sprite::destroy),
"toLeft", sol::property(&Sprite::toLeft, &Sprite::toLeft)
,"asRef", &Sprite::asRef
"toLeft", sol::property(&Sprite::toLeft, &Sprite::toLeft),
"asRef", &Sprite::asRef
);
lua.new_usertype<Item>("Item",
@ -4954,8 +4965,8 @@ lua.new_usertype<Item>("Item",
"unk_54", sol::property(&Item::unk_54, &Item::unk_54),
"unk_58", sol::property(&Item::unk_58, &Item::unk_58),
"sfxSource", sol::property(&Item::sfxSource, &Item::sfxSource),
"width", sol::property(&Item::width, &Item::width)
,"asRef", &Item::asRef
"width", sol::property(&Item::width, &Item::width),
"asRef", &Item::asRef
);
lua.new_usertype<Effect>("Effect",
@ -4978,8 +4989,8 @@ lua.new_usertype<Effect>("Effect",
"unk_78", sol::property(&Effect::unk_78, &Effect::unk_78),
"unk_7A", sol::property(&Effect::unk_7A, &Effect::unk_7A),
"pad7C", sol::property(&Effect::pad7C, &Effect::pad7C),
"sfxSource", sol::property(&Effect::sfxSource, &Effect::sfxSource)
,"asRef", &Effect::asRef
"sfxSource", sol::property(&Effect::sfxSource, &Effect::sfxSource),
"asRef", &Effect::asRef
);
lua.new_usertype<Boss>("Boss",
@ -5012,8 +5023,8 @@ lua.new_usertype<Boss>("Boss",
"fwork", sol::property(&Boss::fwork, &Boss::fwork),
"vwork", sol::property(&Boss::vwork, &Boss::vwork),
"scale", sol::property(&Boss::scale, &Boss::scale),
"sfxSource", sol::property(&Boss::sfxSource, &Boss::sfxSource)
,"asRef", &Boss::asRef
"sfxSource", sol::property(&Boss::sfxSource, &Boss::sfxSource),
"asRef", &Boss::asRef
);
lua.new_usertype<Actor>("Actor",
@ -5054,8 +5065,8 @@ lua.new_usertype<Actor>("Actor",
"gravity", sol::property(&Actor::gravity, &Actor::gravity),
"scale", sol::property(&Actor::scale, &Actor::scale),
"fwork", sol::property(&Actor::fwork, &Actor::fwork),
"vwork", sol::property(&Actor::vwork, &Actor::vwork)
,"asRef", &Actor::asRef
"vwork", sol::property(&Actor::vwork, &Actor::vwork),
"asRef", &Actor::asRef
);
lua.set_function("Game_SpawnActor", Game_SpawnActor);

View file

@ -188,6 +188,8 @@ GameEngine::GameEngine() {
"Limb", static_cast<uint32_t>(SF64::ResourceType::Limb), 0);
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryMessageV0>(), RESOURCE_FORMAT_BINARY,
"Message", static_cast<uint32_t>(SF64::ResourceType::Message), 0);
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryXMLMessageV0>(), RESOURCE_FORMAT_XML,
"Message", static_cast<uint32_t>(SF64::ResourceType::Message), 0);
loader->RegisterResourceFactory(std::make_shared<SF64::ResourceFactoryBinaryMessageLookupV0>(),
RESOURCE_FORMAT_BINARY, "MessageTable",
static_cast<uint32_t>(SF64::ResourceType::MessageTable), 0);

View file

@ -2,6 +2,7 @@
#include <stdexcept>
#include <algorithm>
#include "port/hooks/Events.h"
#include "port/notification/notification.h"
EventSystem* EventSystem::Instance = new EventSystem();
@ -46,11 +47,16 @@ void EventSystem::CallEvent(EventID id, IEvent* event) {
std::get<EventCallback>(listener.function)(event);
}
if(is_type(listener.function, sol::function)){
if(is_type(listener.function, sol::protected_function)){
#undef DEFINE_EVENT
#define DEFINE_EVENT(eventName, ...) \
if(id == eventName##ID) { \
std::get<sol::function>(listener.function)((eventName*)event); \
auto result = std::get<sol::protected_function>(listener.function)((eventName*)event); \
if(!result.valid()) { \
sol::error err = result; \
SPDLOG_ERROR(std::string(err.what())); \
Notification::Emit({ .message = "Mod error, check log for details", .messageColor = ImVec4(1.0f, 0.5f, 0.5f, 1.0f), .remainingTime = 7.0f }); \
} \
}
#define __LUA__
#include "port/hooks/EventList.h"

View file

@ -71,7 +71,7 @@ typedef void (*EventCallback)(IEvent*);
#include <unordered_map>
#include <sol/sol.hpp>
typedef std::variant<EventCallback, sol::function> SmartFunctionCallback;
typedef std::variant<EventCallback, sol::protected_function> SmartFunctionCallback;
#define is_type(var, type) std::holds_alternative<type>((var))
struct EventListener {

View file

@ -14,6 +14,7 @@
#include "port/resource/type/ResourceType.h"
#include "port/resource/type/Text.h"
#include "port/Engine.h"
#include "port/notification/notification.h"
#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
@ -29,6 +30,9 @@ struct Asset {
template<typename T>
T* Get() {
if(this == nullptr){
return nullptr;
}
return (T*) path.data();
}
@ -38,7 +42,7 @@ struct Asset {
static Asset Register(const std::string path) {
std::string full = "__OTR__" + path;
return Asset{full};
return Asset{ full };
}
};
@ -173,6 +177,7 @@ void ScriptingLayer::Init() {
}
} catch (const sol::error& e) {
SPDLOG_ERROR(std::string(e.what()));
Notification::Emit({ .message = "Mod error, check log for details", .messageColor = ImVec4(1.0f, 0.5f, 0.5f, 1.0f), .remainingTime = 7.0f });
return;
}
}

View file

@ -1,8 +1,25 @@
#include "MessageFactory.h"
#include "../type/Message.h"
#include "spdlog/spdlog.h"
#include <vector>
namespace SF64 {
std::vector<std::string> gASCIIFullTable = {
"\0", "\n", "{NP:2}", "{NP:3}", "{NP:4}", "{NP:5}", "{NP:6}", "{NP:7}",
"{PRI:0}", "{PRI:1}", "{PRI:2}", "{PRI:3}", " ", "{HSP}", "{QSP}", "{NXT}",
"{C:<}", "{C:^}", "{C:>}", "{C:v}", "{^}", "{<}", "{v}", "{>}",
"A", "B", "C", "D", "E", "F", "G", "H",
"I", "J", "K", "L", "M", "N", "O", "P",
"Q", "R", "S", "T", "U", "V", "W", "X",
"Y", "Z", "a", "b", "c", "d", "e", "f",
"g", "h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u", "v",
"w", "x", "y", "z", "!", "?", "-", ",",
".", "0", "1", "2", "3", "4", "5", "6",
"7", "8", "9", "'", "(", ")", ":", "|",
};
std::shared_ptr<Ship::IResource> ResourceFactoryBinaryMessageV0::ReadResource(std::shared_ptr<Ship::File> file,
std::shared_ptr<Ship::ResourceInitData> initData) {
if (!FileHasValidFormatAndReader(file, initData)) {
@ -20,4 +37,50 @@ std::shared_ptr<Ship::IResource> ResourceFactoryBinaryMessageV0::ReadResource(st
return msg;
}
std::shared_ptr<Ship::IResource> ResourceFactoryXMLMessageV0::ReadResource(std::shared_ptr<Ship::File> file) {
if (!FileHasValidFormatAndReader(file)) {
return nullptr;
}
auto msg = std::make_shared<Message>(file->InitData);
auto parent = std::get<std::shared_ptr<tinyxml2::XMLDocument>>(file->Reader)->FirstChildElement("Message");
tinyxml2::XMLElement* element = parent->FirstChildElement("Line");
while (element != nullptr) {
const char* raw = element->GetText();
if (raw == nullptr) {
element = element->NextSiblingElement("Line");
msg->mMessage.push_back(1);
continue;
}
auto text = std::string(raw);
std::string key;
for (size_t i = 0; i < text.size(); i++) {
auto c = text[i];
if (c == '{') {
auto end = text.find('}', i);
if (end == std::string::npos) {
continue;
}
key = text.substr(i, end - i + 1);
i = end;
} else {
key = text.substr(i, 1);
}
auto it = std::find(gASCIIFullTable.begin(), gASCIIFullTable.end(), key);
if (it != gASCIIFullTable.end()) {
msg->mMessage.push_back(it - gASCIIFullTable.begin());
} else {
SPDLOG_ERROR("Unknown key: {}", key);
}
}
msg->mMessage.push_back(1);
element = element->NextSiblingElement("Line");
} // end
msg->mMessage.push_back(0);
return msg;
}
} // namespace LUS

View file

@ -1,6 +1,7 @@
#pragma once
#include "Resource.h"
#include "ResourceFactoryXML.h"
#include "ResourceFactoryBinary.h"
namespace SF64 {
@ -9,4 +10,9 @@ class ResourceFactoryBinaryMessageV0 : public Ship::ResourceFactoryBinary {
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file,
std::shared_ptr<Ship::ResourceInitData> initData) override;
};
class ResourceFactoryXMLMessageV0 : public Ship::ResourceFactoryXML {
public:
std::shared_ptr<Ship::IResource> ReadResource(std::shared_ptr<Ship::File> file) override;
};
}; // namespace LUS

View file

@ -1,365 +1,19 @@
import re
import os
import sys
from enum import Enum
blacklist = [
'audio',
'portable-file-dialogs.h',
'rmonint.h',
'PR/',
'libultra/',
'libc/',
'dbgproto',
'prevent',
'piint',
'siint',
'sf64dma',
'osint',
'FrameInterpolation',
'mods.h'
]
class OutputType(Enum):
NONE = 0
LUA = 1
CPP = 2
event_list = []
def parse_enums(header, as_value=False):
try:
with open(header, 'r') as file:
lines = file.readlines()
except IOError:
raise RuntimeError("Failed to open header files for enums node in config")
# Regex pattern to match enum declarations
enum_regex = re.compile(r"enum\s+(\w+)\s*(?:\s*:\s*(\w+))?[\s\n\r]*\{")
in_enum = False
enum_index = None
enum_name = ""
enum = {}
for line in lines:
line = line.strip()
if not in_enum:
# Check if the line matches the enum declaration pattern
match = enum_regex.search(line)
if match and len(match.groups()) > 1:
enum_name = match.group(1)
enum[enum_name] = []
in_enum = True
enum_index = -1
continue
if '}' in line:
in_enum = False
continue
# Remove any comments and non-alphanumeric characters
line = re.sub(r'(/\*.*?\*/)|(//.*$)|([^a-zA-Z0-9=_\-\.])', '', line)
if len(line) == 0:
continue
if '=' in line:
# Extract the value after the '=' sign
value = line.split('=')[1].strip()
# Extract the name before the '=' sign
name = line.split('=')[0].strip()
enum_index = int(value, 0) # Convert the value to an integer with base 0 (detects hex, oct, etc.)
enum[enum_name].append({
'name': name,
'value': enum_index
})
else:
# Increment the enum index if no '=' is found
enum_index += 1
enum[enum_name].append({
'name': line,
'value': enum_index
})
for enum_name, values in enum.items():
print(f'---@enum {enum_name}')
print(f'{enum_name} = {{')
for i, entry in enumerate(values):
key = entry['name']
value = entry['value']
if 'ifdef' in key or 'endif' in entry['name'] or 'else' in key:
continue
key_name = key
key_name = key_name.replace('EVENT_PRIORITY_', '')
key_name = key_name.replace('SF64_VER_', '')
print(f' {key_name} = {value}{"," if i < len(values) - 1 else ""}')
print('}')
print('')
def sanitize_type(member_type):
member_type = member_type.strip()
if len(member_type) == 0:
return 'any'
member_type = member_type.replace('uint8_t', 'number')
member_type = member_type.replace('uint16_t', 'number')
member_type = member_type.replace('uint32_t', 'number')
member_type = member_type.replace('uint64_t', 'number')
member_type = member_type.replace('int8_t', 'number')
member_type = member_type.replace('int16_t', 'number')
member_type = member_type.replace('int32_t', 'number')
member_type = member_type.replace('int64_t', 'number')
member_type = member_type.replace('size_t', 'number')
member_type = member_type.replace('uintptr_t', 'number')
member_type = member_type.replace('...', 'string')
member_type = member_type.replace('*', '')
member_type = member_type.replace('&', '')
member_type = member_type.replace('const', '')
member_type = member_type.replace('bool', 'boolean')
member_type = member_type.replace('int', 'number')
member_type = member_type.replace('float', 'number')
member_type = member_type.replace('char', 'string')
member_type = member_type.replace('unsigned', 'number')
member_type = member_type.replace('u8', 'number')
member_type = member_type.replace('u16', 'number')
member_type = member_type.replace('u32', 'number')
member_type = member_type.replace('u64', 'number')
member_type = member_type.replace('s8', 'number')
member_type = member_type.replace('s16', 'number')
member_type = member_type.replace('s32', 'number')
member_type = member_type.replace('s64', 'number')
member_type = member_type.replace('void', 'nil')
member_type = member_type.replace('f32', 'number')
member_type = member_type.replace('f64', 'number')
member_type = member_type.replace('double', 'number')
member_type = member_type.replace('CONTROLLERBUTTONS_T', 'number')
return member_type
def parse_structs(header):
try:
with open(header, 'r') as file:
lines = file.readlines()
except IOError:
raise RuntimeError("Failed to open header files for structs node in config")
struct_regex = re.compile(r"struct\s+(\w+)\s*(?:\s*:\s*(\w+))?[\s\n\r]*\{")
in_struct = False
struct_name = ""
found_union = False
struct = {}
for line in lines:
line = line.strip()
if not in_struct:
match = struct_regex.search(line)
if match and len(match.groups()) > 1:
struct_name = match.group(1)
struct[struct_name] = []
in_struct = True
continue
if 'union' in line:
found_union = True
continue
if '}' in line and not found_union:
in_struct = False
continue
if '}' in line and found_union:
found_union = False
continue
line = re.sub(r'(/\*.*?\*/)', '', line)
if ';' in line and not ':' in line:
# if ':' in line:
# member_name = line.split(' ')[-3].split(':')[0]
# continue
if '[' in line:
if len(line.split('[')) > 2:
continue
member_name = line.split('[')[0].split(' ')[-1]
member_type = line.split(' ')[-2]
else:
member_name = line.split(';')[0].split(' ')[-1]
member_type = line.split(';')[0].split(' ')[-2]
struct[struct_name].append(member_name + ' ' + sanitize_type(member_type))
for struct_name, members in struct.items():
if len(members) == 0:
continue
# TODO: Add support for functions
print(f'---@class {struct_name}')
for i, key in enumerate(members):
key = key.replace('*', '')
print(f'---@field {key}')
print(f'{struct_name} = {{}}')
if struct_name == 'Object':
print(f'---@return Actor')
print(f'function {struct_name}:asActor() end')
print(f'---@return Boss')
print(f'function {struct_name}:asBoss() end')
print(f'---@return Scenery')
print(f'function {struct_name}:asScenery() end')
print(f'---@return Scenery360')
print(f'function {struct_name}:asScenery360() end')
print(f'---@return Sprite')
print(f'function {struct_name}:asSprite() end')
print(f'---@return Item')
print(f'function {struct_name}:asItem() end')
print(f'---@return Effect')
print(f'function {struct_name}:asEffect() end')
print(f'---@return {struct_name}')
print(f'function {struct_name}:asRef() end')
elif struct_name == 'Object' or struct_name == 'ObjectInfo' or struct_name == 'Actor' or struct_name == 'Boss' or struct_name == 'Scenery' or struct_name == 'Scenery360' or struct_name == 'Sprite' or struct_name == 'Item' or struct_name == 'Effect':
print(f'---@return {struct_name}')
print(f'function {struct_name}:asRef() end')
elif struct_name.startswith('Vec') or struct_name.startswith('Plane') or struct_name == 'PosRot' or struct_name == 'CameraPoint' or struct_name == 'Triangle':
print(f'---@return {struct_name}')
print(f'function {struct_name}:asRef() end')
if struct_name.startswith('Vec'):
print(f'---@return f32')
print(f'function {struct_name}:xRef() end')
print(f'---@return f32')
print(f'function {struct_name}:yRef() end')
print(f'---@return f32')
print(f'function {struct_name}:zRef() end')
print('')
def parse_events(header):
try:
with open(header, 'r') as file:
lines = file.readlines()
except IOError:
raise RuntimeError("Failed to open header files for events node in config")
global event_list
in_event = False
event_name = ""
event = {}
for line in lines:
line = line.strip()
if not in_event:
if 'DEFINE_EVENT' in line:
if ');' in line:
event_name = line.split('DEFINE_EVENT(')[1].split(')')[0].strip()
event[event_name] = ['event IEvent']
continue
event_name = line.split('DEFINE_EVENT(')[1].split(',')[0].strip()
event[event_name] = ['event IEvent']
in_event = True
continue
if ');' in line:
in_event = False
continue
if len(line) == 0:
continue
if ';' in line:
member_name = line.split(';')[0].split(' ')[-1]
member_type = line.split(';')[0].split(' ')[-2]
event[event_name].append(member_name + ' ' + sanitize_type(member_type))
for event_name, members in event.items():
print(f'---@class {event_name}')
event_list.append(event_name)
for i, key in enumerate(members):
key = key.replace('*', '')
print(f'---@field {key}')
print('')
print('')
def parse_externs(header, namespace=None):
try:
with open(header, 'r') as file:
lines = file.readlines()
except IOError:
raise RuntimeError("Failed to open header files for events node in config")
for line in lines:
line = re.sub(r'\s+', ' ', line.strip())
if line.startswith('extern') and not 'void*' in line and not '"C"' in line or ('(' in line and ';' in line):
if not '(' in line and not '[' in line:
var_type = line.split(' ')[1]
var_name = line.split(' ')[2].split(';')[0]
print(f'---@return {sanitize_type(var_type)}')
print(f'function Game.{var_name}() end')
print(f'---@param value {sanitize_type(var_type)}')
print(f'function Game.{var_name}(value) end')
elif '[' in line and not '(' in line:
dimension_len = len(line.split('[')) - 1
var_name = line.split('[')[0].split(' ')[-1]
var_type = line.split(' ')[1]
print(f'---@param index number')
print(f'---@return {sanitize_type(var_type)}[{dimension_len}]')
print(f'function Game.{var_name}(index) end')
print(f'---@param index number')
print(f'---@param value {sanitize_type(var_type)}')
print(f'function Game.{var_name}(index, value) end')
elif '(' in line:
if 'ALIGN_ASSET' in line:
var_name = line.split('[')[0].split(' ')[-1]
value = line.split('=')[-1].split(';')[0]
print('---@type Asset')
print(f'Assets.{var_name} = {value.strip()}')
continue
if 'define' in line or '\\' in line or 'typedef' in line or '[' in line or 'OSMesg' in line or 'Framebuffer' in line or 'TimerAction' in line or 'TimerTask' in line:
continue
if '_DEG' in line or 'Fault' in line or 'sol:ignore' in line or '<T>' in line or '<' in line:
continue
func_name = line.split('(')[0].split(' ')[-1]
if len(func_name) == 0:
continue
if 'CVarExists' in func_name or 'ResourceLoad' in func_name or 'void*' in func_name or 'ResourceClearCache' in func_name: # Report this to LUS
continue
return_type = line.split(' ')[0]
args = line.split('(')[1].split(')')[0].strip().split(',')
for i, arg in enumerate(args):
arg = arg.replace('const ', '')
arg = arg.replace(' *', '* ')
arg = arg.replace('...', 'varargs')
if len(arg.split(' ')) > 2:
if '=' in arg:
arg = arg.split('=')[0]
name = arg.split(' ')[2]
type = arg.split(' ')[1]
else:
name = arg.split(' ')[-1]
type = arg.split(' ')[-2]
else:
name = '_'+arg.split(' ')[-1]
type = arg.split(' ')[0]
name = name.replace('*', '')
name = name.replace('end', '_end')
if(len(name) == 0):
name = f'arg{i}'
args[i] = { 'name': name, 'type': type }
for i, arg in enumerate(args):
print(f'---@param {arg["name"]} {sanitize_type(arg["type"])}')
print(f'---@return {sanitize_type(return_type)}')
if namespace:
print(f'function {namespace}.{func_name}({', '.join([f'{arg["name"]}' for arg in args])}) end')
else:
print(f'function {func_name}({', '.join([f'{arg["name"]}' for arg in args])}) end')
def is_blacklisted(file):
for item in blacklist:
if item in file:
return True
return False
if __name__ == "__main__":
print("Game = {}")
print("Assets = {}")
print("UIWidgets = {}")
print("Events = {}")
header = """
def write_lua_header():
print("""
Game = {}
Assets = {}
UIWidgets = {}
Events = {}
---@alias ListenerID number
---@class Asset
local Asset = {}
@ -424,8 +78,432 @@ function gRefGfxMatrix() end
---@param b number
---@param a number
function gDPSetPrimColor(m, l, r, g, b, a) end
"""
print(header)
""")
export_type = OutputType.NONE
event_list = []
def sanitize_type(member_type):
global export_type
member_type = member_type.strip()
if export_type == OutputType.CPP:
return member_type
if len(member_type) == 0:
return 'any'
member_type = member_type.replace('uint8_t', 'number')
member_type = member_type.replace('uint16_t', 'number')
member_type = member_type.replace('uint32_t', 'number')
member_type = member_type.replace('uint64_t', 'number')
member_type = member_type.replace('int8_t', 'number')
member_type = member_type.replace('int16_t', 'number')
member_type = member_type.replace('int32_t', 'number')
member_type = member_type.replace('int64_t', 'number')
member_type = member_type.replace('size_t', 'number')
member_type = member_type.replace('uintptr_t', 'number')
member_type = member_type.replace('...', 'string')
member_type = member_type.replace('*', '')
member_type = member_type.replace('&', '')
member_type = member_type.replace('const', '')
member_type = member_type.replace('bool', 'boolean')
member_type = member_type.replace('int', 'number')
member_type = member_type.replace('float', 'number')
member_type = member_type.replace('char', 'string')
member_type = member_type.replace('unsigned', 'number')
member_type = member_type.replace('u8', 'number')
member_type = member_type.replace('u16', 'number')
member_type = member_type.replace('u32', 'number')
member_type = member_type.replace('u64', 'number')
member_type = member_type.replace('s8', 'number')
member_type = member_type.replace('s16', 'number')
member_type = member_type.replace('s32', 'number')
member_type = member_type.replace('s64', 'number')
member_type = member_type.replace('void', 'nil')
member_type = member_type.replace('f32', 'number')
member_type = member_type.replace('f64', 'number')
member_type = member_type.replace('double', 'number')
member_type = member_type.replace('CONTROLLERBUTTONS_T', 'number')
return member_type
blacklist = [
'audio',
'portable-file-dialogs.h',
'rmonint.h',
'PR/',
'libultra/',
'libc/',
'dbgproto',
'prevent',
'piint',
'siint',
'sf64dma',
'osint',
'FrameInterpolation',
'mods.h'
]
def parse_enums(header, as_value=False):
try:
with open(header, 'r') as file:
lines = file.readlines()
except IOError:
raise RuntimeError("Failed to open header files for enums node in config")
# Regex pattern to match enum declarations
enum_regex = re.compile(r"enum\s+(\w+)\s*(?:\s*:\s*(\w+))?[\s\n\r]*\{")
in_enum = False
enum_index = None
enum_name = ""
enum = {}
global export_type
for line in lines:
line = line.strip()
if not in_enum:
# Check if the line matches the enum declaration pattern
match = enum_regex.search(line)
if match and len(match.groups()) > 1:
enum_name = match.group(1)
enum[enum_name] = []
in_enum = True
enum_index = -1
continue
if '}' in line:
in_enum = False
continue
# Remove any comments and non-alphanumeric characters
line = re.sub(r'(/\*.*?\*/)|(//.*$)|([^a-zA-Z0-9=_\-\.])', '', line)
if len(line) == 0:
continue
if '=' in line:
# Extract the value after the '=' sign
value = line.split('=')[1].strip()
# Extract the name before the '=' sign
name = line.split('=')[0].strip()
enum_index = int(value, 0) # Convert the value to an integer with base 0 (detects hex, oct, etc.)
enum[enum_name].append({
'name': name,
'value': enum_index
})
else:
# Increment the enum index if no '=' is found
enum_index += 1
enum[enum_name].append({
'name': line,
'value': enum_index
})
for enum_name, values in enum.items():
if export_type == OutputType.CPP:
print(f'auto enum_{enum_name} = lua["{enum_name}"].force();')
for i, entry in enumerate(values):
key = entry['name']
value = entry['value']
if 'ifdef' in key or 'endif' in entry['name'] or 'else' in key:
continue
key_name = key
key_name = key_name.replace('EVENT_PRIORITY_', '')
key_name = key_name.replace('SF64_VER_', '')
print(f'enum_{enum_name}["{key_name}"] = (uint32_t) {value if as_value else key};')
print('')
elif export_type == OutputType.LUA:
print(f'---@enum {enum_name}')
print(f'{enum_name} = {{')
for i, entry in enumerate(values):
key = entry['name']
value = entry['value']
if 'ifdef' in key or 'endif' in entry['name'] or 'else' in key:
continue
key_name = key
key_name = key_name.replace('EVENT_PRIORITY_', '')
key_name = key_name.replace('SF64_VER_', '')
print(f' {key_name} = {value}{"," if i < len(values) - 1 else ""}')
print('}')
print('')
def parse_structs(header):
try:
with open(header, 'r') as file:
lines = file.readlines()
except IOError:
raise RuntimeError("Failed to open header files for structs node in config")
struct_regex = re.compile(r"struct\s+(\w+)\s*(?:\s*:\s*(\w+))?[\s\n\r]*\{")
in_struct = False
struct_name = ""
found_union = False
struct = {}
global export_type
for line in lines:
line = line.strip()
if not in_struct:
match = struct_regex.search(line)
if match and len(match.groups()) > 1:
struct_name = match.group(1)
struct[struct_name] = []
in_struct = True
continue
if 'union' in line:
found_union = True
continue
if '}' in line and not '{' in line and not found_union:
in_struct = False
continue
if '}' in line and found_union:
found_union = False
continue
line = re.sub(r'(/\*.*?\*/)', '', line)
if ';' in line:
if ':' in line and not 'sol:not_global' in line and not '::' in line:
line = line.replace(' : ', ':')
bitfield = line.split(':')[1].split(';')[0].strip()
size = int(bitfield)
struct[struct_name].append({
'name': line.split(':')[0].split(' ')[-1],
'export': 'bitfield',
'type': sanitize_type('u8' if size < 8 else 'u16' if size < 16 else 'u32' if size < 32 else 'u64')
})
elif '(' in line:
struct[struct_name].append({
'name': f'{line.split('(')[0].split(' ')[-1]}',
'export': 'function',
'type': sanitize_type(line.split('(')[0].split(' ')[-2])
})
elif '[' in line:
if len(line.split('[')) > 2:
continue
struct[struct_name].append({
'name': line.split('[')[0].split(' ')[-1],
'export': 'variable',
'type': sanitize_type(line.split('[')[0].split(' ')[-2])
})
else:
struct[struct_name].append({
'name': line.split(';')[0].split(' ')[-1],
'export': 'variable',
'type': sanitize_type(line.split(';')[0].split(' ')[-2])
})
for struct_name, members in struct.items():
if len(members) == 0:
continue
if export_type == OutputType.CPP:
print(f'lua.new_usertype<{struct_name}>("{struct_name}",')
for i, member in enumerate(members):
key = member['name'].replace('*', '')
export = member['export']
type = member['type']
if export == 'bitfield':
print(f' "{key}", sol::property([] ({struct_name}& self) -> {type} {{ return self.{key}; }}, [] ({struct_name}& self, {type} value) {{ self.{key} = value; }}){"," if i < len(members) - 1 else ""}')
elif export == 'function':
print(f' "{key}", &{struct_name}::{key}{"," if i < len(members) - 1 else ""}')
else:
print(f' "{key}", sol::property(&{struct_name}::{key}, &{struct_name}::{key}){"," if i < len(members) - 1 else ""}')
print(');')
print('')
elif export_type == OutputType.LUA:
print(f'---@class {struct_name}')
print(f'{struct_name} = {{}}')
for i, member in enumerate(members):
key = member['name'].replace('*', '')
export = member['export']
type = member['type']
if export == 'bitfield':
print(f'---@return {type}')
print(f'function {struct_name}:{key}() end')
print(f'---@param value {type}')
print(f'---@return {type}')
print(f'function {struct_name}:{key}(value) end')
elif export == 'function':
print(f'---@return {type}')
print(f'function {struct_name}:{key}() end')
else:
print(f'---@field {key} {type}')
print('')
def parse_events(header):
try:
with open(header, 'r') as file:
lines = file.readlines()
except IOError:
raise RuntimeError("Failed to open header files for events node in config")
in_event = False
event_name = ""
event = {}
global export_type
for line in lines:
line = line.strip()
if not in_event:
if 'DEFINE_EVENT' in line:
if ');' in line:
event_name = line.split('DEFINE_EVENT(')[1].split(')')[0].strip()
event[event_name] = ['event']
continue
event_name = line.split('DEFINE_EVENT(')[1].split(',')[0].strip()
event[event_name] = ['event']
in_event = True
continue
if ');' in line:
in_event = False
continue
if len(line) == 0:
continue
if ';' in line:
member_name = line.split(';')[0].split(' ')[-1]
event[event_name].append(member_name)
for event_name, members in event.items():
print(f'lua.new_usertype<{event_name}>("{event_name}",')
for i, key in enumerate(members):
key = key.replace('*', '')
print(f' "{key}", sol::property(&{event_name}::{key}, &{event_name}::{key}){"," if i < len(members) - 1 else ""}')
print(');')
print('')
def parse_externs(header, namespace=None):
try:
with open(header, 'r') as file:
lines = file.readlines()
except IOError:
raise RuntimeError("Failed to open header files for events node in config")
global export_type
for line in lines:
line = re.sub(r'\s+', ' ', line.strip())
if line.startswith('extern') and not 'void*' in line and not '"C"' in line or ('(' in line and ';' in line):
if not '(' in line and not '[' in line:
var_type = line.split(' ')[1]
var_name = line.split(' ')[2].split(';')[0]
if export_type == OutputType.CPP:
print(f'lua["Game"]["{var_name}"] = sol::overload([]() -> {var_type} {{ return {var_name}; }}, []({var_type} value) {{ {var_name} = value; }});')
elif export_type == OutputType.LUA:
print(f'---@return {sanitize_type(var_type)}')
print(f'function Game.{var_name}() end')
print(f'---@param value {sanitize_type(var_type)}')
print(f'function Game.{var_name}(value) end')
elif '[' in line and not '(' in line:
dimension_len = len(line.split('[')) - 1
var_name = line.split('[')[0].split(' ')[-1]
var_type = line.split(' ')[1]
is_pointer = True #'*' in line
if export_type == OutputType.CPP:
if dimension_len == 1:
print(f'lua["Game"]["{var_name}"] = sol::overload([](int index) -> {var_type}{'' if is_pointer else '*'} {{ return {'' if is_pointer else '&'}{var_name}[index]; }}, [](int index, {var_type} value) {{ {var_name}[index] = value; }});')
elif dimension_len == 2:
print(f'lua["Game"]["{var_name}"] = sol::overload([](int index1, int index2) -> {var_type}{'' if is_pointer else '*'} {{ return {'' if is_pointer else '&'}{var_name}[index1][index2]; }}, [](int index1, int index2, {var_type} value) {{ {var_name}[index1][index2] = value; }});')
elif dimension_len == 3:
print('Unsupported 3D array')
exit()
elif export_type == OutputType.LUA:
print(f'---@param index number')
print(f'---@return {sanitize_type(var_type)}[{dimension_len}]')
print(f'function Game.{var_name}(index) end')
print(f'---@param index number')
print(f'---@param value {sanitize_type(var_type)}')
print(f'function Game.{var_name}(index, value) end')
elif '(' in line:
if 'ALIGN_ASSET' in line:
var_name = line.split('[')[0].split(' ')[-1]
value = line.split('=')[-1].split(';')[0]
if export_type == OutputType.CPP:
print(f'lua["Assets"]["{var_name}"] = Asset{{ {var_name} }};')
elif export_type == OutputType.LUA:
print('---@type Asset')
print(f'Assets.{var_name} = {value.strip()}')
continue
if 'define' in line or '\\' in line or 'typedef' in line or '[' in line or 'OSMesg' in line or 'Framebuffer' in line or 'TimerAction' in line or 'TimerTask' in line:
continue
if '_DEG' in line or 'Fault' in line or 'sol:ignore' in line or 'sol:not_global' in line or '<T>' in line:
continue
func_name = line.split('(')[0].split(' ')[-1]
if len(func_name) == 0:
continue
if 'CVarExists' in func_name or 'ResourceLoad' in func_name or 'void*' in func_name or 'ResourceClearCache' in func_name: # Report this to LUS
continue
if export_type == OutputType.CPP:
if namespace:
print(f'lua["{namespace}"]["{func_name}"] = {namespace}::{func_name};')
else:
print(f'lua.set_function("{func_name}", {func_name});')
elif export_type == OutputType.LUA:
return_type = line.split(' ')[0]
args = line.split('(')[1].split(')')[0].strip().split(',')
for i, arg in enumerate(args):
arg = arg.replace('const ', '')
arg = arg.replace(' *', '* ')
arg = arg.replace('...', 'varargs')
if len(arg.split(' ')) > 2:
if '=' in arg:
arg = arg.split('=')[0]
name = arg.split(' ')[2]
type = arg.split(' ')[1]
else:
name = arg.split(' ')[-1]
type = arg.split(' ')[-2]
else:
name = '_'+arg.split(' ')[-1]
type = arg.split(' ')[0]
name = name.replace('*', '')
name = name.replace('end', '_end')
if(len(name) == 0):
name = f'arg{i}'
args[i] = { 'name': name, 'type': type }
for i, arg in enumerate(args):
print(f'---@param {arg["name"]} {sanitize_type(arg["type"])}')
print(f'---@return {sanitize_type(return_type)}')
if namespace:
print(f'function {namespace}.{func_name}({', '.join([f'{arg["name"]}' for arg in args])}) end')
else:
print(f'function {func_name}({', '.join([f'{arg["name"]}' for arg in args])}) end')
def is_blacklisted(file):
for item in blacklist:
if item in file:
return True
return False
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python autobind.py <output_type>")
exit()
export_type = OutputType.LUA if sys.argv[1] == 'lua' else OutputType.CPP
if export_type == OutputType.LUA:
write_lua_header()
for root, dirs, files in os.walk("include"):
for file in files:
# Join root and file to get full path
@ -451,6 +529,7 @@ function gDPSetPrimColor(m, l, r, g, b, a) end
for file in files:
parse_events(os.path.join(root, file))
if export_type == OutputType.LUA:
print('---@enum EventID')
print('EventID = {')
for event_name in event_list:

View file

@ -1,301 +0,0 @@
import re
import os
blacklist = [
'audio',
'portable-file-dialogs.h',
'rmonint.h',
'PR/',
'libultra/',
'libc/',
'dbgproto',
'prevent',
'piint',
'siint',
'sf64dma',
'osint',
'FrameInterpolation',
'mods.h'
]
def parse_enums(header, as_value=False):
try:
with open(header, 'r') as file:
lines = file.readlines()
except IOError:
raise RuntimeError("Failed to open header files for enums node in config")
# Regex pattern to match enum declarations
enum_regex = re.compile(r"enum\s+(\w+)\s*(?:\s*:\s*(\w+))?[\s\n\r]*\{")
in_enum = False
enum_index = None
enum_name = ""
enum = {}
for line in lines:
line = line.strip()
if not in_enum:
# Check if the line matches the enum declaration pattern
match = enum_regex.search(line)
if match and len(match.groups()) > 1:
enum_name = match.group(1)
enum[enum_name] = []
in_enum = True
enum_index = -1
continue
if '}' in line:
in_enum = False
continue
# Remove any comments and non-alphanumeric characters
line = re.sub(r'(/\*.*?\*/)|(//.*$)|([^a-zA-Z0-9=_\-\.])', '', line)
if len(line) == 0:
continue
if '=' in line:
# Extract the value after the '=' sign
value = line.split('=')[1].strip()
# Extract the name before the '=' sign
name = line.split('=')[0].strip()
enum_index = int(value, 0) # Convert the value to an integer with base 0 (detects hex, oct, etc.)
enum[enum_name].append({
'name': name,
'value': enum_index
})
else:
# Increment the enum index if no '=' is found
enum_index += 1
enum[enum_name].append({
'name': line,
'value': enum_index
})
for enum_name, values in enum.items():
print(f'auto enum_{enum_name} = lua["{enum_name}"].force();')
for i, entry in enumerate(values):
key = entry['name']
value = entry['value']
if 'ifdef' in key or 'endif' in entry['name'] or 'else' in key:
continue
key_name = key
key_name = key_name.replace('EVENT_PRIORITY_', '')
key_name = key_name.replace('SF64_VER_', '')
print(f'enum_{enum_name}["{key_name}"] = (uint32_t) {value if as_value else key};')
print('')
def parse_structs(header):
try:
with open(header, 'r') as file:
lines = file.readlines()
except IOError:
raise RuntimeError("Failed to open header files for structs node in config")
struct_regex = re.compile(r"struct\s+(\w+)\s*(?:\s*:\s*(\w+))?[\s\n\r]*\{")
in_struct = False
struct_name = ""
found_union = False
struct = {}
for line in lines:
line = line.strip()
if not in_struct:
match = struct_regex.search(line)
if match and len(match.groups()) > 1:
struct_name = match.group(1)
struct[struct_name] = []
in_struct = True
continue
if 'union' in line:
found_union = True
continue
if '}' in line and not found_union:
in_struct = False
continue
if '}' in line and found_union:
found_union = False
continue
line = re.sub(r'(/\*.*?\*/)', '', line)
if ';' in line and not ':' in line:
# if ':' in line:
# member_name = line.split(' ')[-3].split(':')[0]
# continue
if '[' in line:
if len(line.split('[')) > 2:
continue
member_name = line.split('[')[0].split(' ')[-1]
else:
member_name = line.split(';')[0].split(' ')[-1]
struct[struct_name].append(member_name)
for struct_name, members in struct.items():
if len(members) == 0:
continue
# TODO: Add support for functions
print(f'lua.new_usertype<{struct_name}>("{struct_name}",')
for i, key in enumerate(members):
key = key.replace('*', '')
print(f' "{key}", sol::property(&{struct_name}::{key}, &{struct_name}::{key}){"," if i < len(members) - 1 else ""}')
if struct_name == 'Object':
print(f' ,"asActor", &{struct_name}::asActor,')
print(f' "asBoss", &{struct_name}::asBoss,')
print(f' "asScenery", &{struct_name}::asScenery,')
print(f' "asScenery360", &{struct_name}::asScenery360,')
print(f' "asSprite", &{struct_name}::asSprite,')
print(f' "asItem", &{struct_name}::asItem,')
print(f' "asEffect", &{struct_name}::asEffect,')
print(f' "asRef", &{struct_name}::asRef')
elif struct_name == 'Object' or struct_name == 'ObjectInfo' or struct_name == 'Actor' or struct_name == 'Boss' or struct_name == 'Scenery' or struct_name == 'Scenery360' or struct_name == 'Sprite' or struct_name == 'Item' or struct_name == 'Effect':
print(f' ,"asRef", &{struct_name}::asRef')
elif struct_name.startswith('Vec') or struct_name.startswith('Plane') or struct_name == 'PosRot' or struct_name == 'CameraPoint' or struct_name == 'Triangle':
print(f' ,"asRef", &{struct_name}::asRef')
if struct_name.startswith('Vec'):
print(f' ,"xRef", &{struct_name}::xRef,')
print(f' "yRef", &{struct_name}::yRef,')
print(f' "zRef", &{struct_name}::zRef')
print(');')
print('')
def parse_events(header):
try:
with open(header, 'r') as file:
lines = file.readlines()
except IOError:
raise RuntimeError("Failed to open header files for events node in config")
in_event = False
event_name = ""
event = {}
for line in lines:
line = line.strip()
if not in_event:
if 'DEFINE_EVENT' in line:
if ');' in line:
event_name = line.split('DEFINE_EVENT(')[1].split(')')[0].strip()
event[event_name] = ['event']
continue
event_name = line.split('DEFINE_EVENT(')[1].split(',')[0].strip()
event[event_name] = ['event']
in_event = True
continue
if ');' in line:
in_event = False
continue
if len(line) == 0:
continue
if ';' in line:
member_name = line.split(';')[0].split(' ')[-1]
event[event_name].append(member_name)
for event_name, members in event.items():
# print(f'lua["{event_name}ID"] = {event_name}ID;')
print(f'lua.new_usertype<{event_name}>("{event_name}",')
for i, key in enumerate(members):
key = key.replace('*', '')
print(f' "{key}", sol::property(&{event_name}::{key}, &{event_name}::{key}){"," if i < len(members) - 1 else ""}')
print(');')
print('')
def parse_externs(header, namespace=None):
try:
with open(header, 'r') as file:
lines = file.readlines()
except IOError:
raise RuntimeError("Failed to open header files for events node in config")
for line in lines:
line = re.sub(r'\s+', ' ', line.strip())
if line.startswith('extern') and not 'void*' in line and not '"C"' in line or ('(' in line and ';' in line):
if not '(' in line and not '[' in line:
var_type = line.split(' ')[1]
var_name = line.split(' ')[2].split(';')[0]
# if '*' in line:
# print(f'lua["Game"]["{var_name}"] = {var_name};')
# else:
# print(f'lua["Game"]["{var_name}"] = &{var_name};')
print(f'lua["Game"]["{var_name}"] = sol::overload([]() -> {var_type} {{ return {var_name}; }}, []({var_type} value) {{ {var_name} = value; }});')
# print(f'context["{var_name}"] = sol::property([]() -> {var_type} {{ return {var_name}; }}, []({var_type} value) {{ {var_name} = value; }});')
# print(f'lua["{var_name}"] = std::ref({var_name});')
# print(f'lua["{var_name}"] = sol::as_pointer({var_name});')
# print(f'lua.set("{var_name}", sol::var({var_name}));')
elif '[' in line and not '(' in line:
dimension_len = len(line.split('[')) - 1
var_name = line.split('[')[0].split(' ')[-1]
var_type = line.split(' ')[1]
is_pointer = True #'*' in line
if dimension_len == 1:
print(f'lua["Game"]["{var_name}"] = sol::overload([](int index) -> {var_type}{'' if is_pointer else '*'} {{ return {'' if is_pointer else '&'}{var_name}[index]; }}, [](int index, {var_type} value) {{ {var_name}[index] = value; }});')
elif dimension_len == 2:
print(f'lua["Game"]["{var_name}"] = sol::overload([](int index1, int index2) -> {var_type}{'' if is_pointer else '*'} {{ return {'' if is_pointer else '&'}{var_name}[index1][index2]; }}, [](int index1, int index2, {var_type} value) {{ {var_name}[index1][index2] = value; }});')
elif dimension_len == 3:
print('Unsupported 3D array')
exit()
elif '(' in line:
if 'ALIGN_ASSET' in line:
var_name = line.split('[')[0].split(' ')[-1]
# print(f'lua["Assets"]["{var_name}"] = {var_name};')
print(f'lua["Assets"]["{var_name}"] = Asset{{ {var_name} }};')
continue
if 'define' in line or '\\' in line or 'typedef' in line or '[' in line or 'OSMesg' in line or 'Framebuffer' in line or 'TimerAction' in line or 'TimerTask' in line:
continue
if '_DEG' in line or 'Fault' in line or 'sol:ignore' in line or '<T>' in line:
continue
func_name = line.split('(')[0].split(' ')[-1]
# print('Function:', func_name)
if len(func_name) == 0:
continue
if 'CVarExists' in func_name or 'ResourceLoad' in func_name or 'void*' in func_name or 'ResourceClearCache' in func_name: # Report this to LUS
continue
if namespace:
print(f'lua["{namespace}"]["{func_name}"] = {namespace}::{func_name};')
else:
print(f'lua.set_function("{func_name}", {func_name});')
def is_blacklisted(file):
for item in blacklist:
if item in file:
return True
return False
if __name__ == "__main__":
for root, dirs, files in os.walk("include"):
for file in files:
# Join root and file to get full path
file_path = os.path.join(root, file)
# Check if the file is blacklisted
if(is_blacklisted(file_path)):
continue
parse_enums(file_path, True if 'scripting.h' in file_path else False)
parse_structs(file_path)
parse_externs(file_path)
parse_enums("src/port/hooks/impl/EventSystem.h")
parse_structs("src/port/hooks/impl/EventSystem.h")
parse_externs("libultraship/src/public/bridge/consolevariablebridge.h")
parse_enums("src/port/Engine.h")
parse_externs("src/port/Engine.h")
parse_externs("src/port/ui/UIWidgets.h", 'UIWidgets')
parse_externs("libultraship/src/public/bridge/resourcebridge.h")
for root, dirs, files in os.walk("src/port/hooks/list"):
for file in files:
parse_events(os.path.join(root, file))