[v0.1.0-beta.2] Added static variables; improved UI
- Added api.getVersion() - Added static variables - Improved UI - Added buttons to show/hide UI elements - Added button to reload managers
This commit is contained in:
parent
5449b8f03d
commit
393a9fcd2f
21 changed files with 846 additions and 101 deletions
|
@ -1,4 +1,10 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
## v0.1.0-beta.2 (2023/07/24)
|
||||||
|
- Added api.getVersion()
|
||||||
|
- Added static variables
|
||||||
|
- Improved UI
|
||||||
|
- Added buttons to show/hide UI elements
|
||||||
|
- Added button to reload managers
|
||||||
## v0.1.0-beta.1 (2023/07/23)
|
## v0.1.0-beta.1 (2023/07/23)
|
||||||
- Implemented ObjectViewer
|
- Implemented ObjectViewer
|
||||||
- load/reload `ObjectParameters/*.json`
|
- load/reload `ObjectParameters/*.json`
|
||||||
|
|
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -854,7 +854,7 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sup-smsac"
|
name = "sup-smsac"
|
||||||
version = "0.1.0-beta.1"
|
version = "0.1.0-beta.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "sup-smsac"
|
name = "sup-smsac"
|
||||||
version = "0.1.0-beta.1"
|
version = "0.1.0-beta.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
authors = ["sup39 <sms@sup39.dev>"]
|
authors = ["sup39 <sms@sup39.dev>"]
|
||||||
|
|
47
res/ObjectParameters/J3DFrameCtrl.json
Normal file
47
res/ObjectParameters/J3DFrameCtrl.json
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"J3DFrameCtrl": {
|
||||||
|
"size": 20,
|
||||||
|
"offsets": [
|
||||||
|
{
|
||||||
|
"offset": "0",
|
||||||
|
"type": "void*",
|
||||||
|
"name": "vtable",
|
||||||
|
"notes": "",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "4",
|
||||||
|
"type": "u8",
|
||||||
|
"name": "field_0x4",
|
||||||
|
"notes": "",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "5",
|
||||||
|
"type": "u8",
|
||||||
|
"format": "hex",
|
||||||
|
"name": "Flag",
|
||||||
|
"notes": "",
|
||||||
|
"hidden": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "8",
|
||||||
|
"type": "s16",
|
||||||
|
"name": "Length",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "c",
|
||||||
|
"type": "float",
|
||||||
|
"name": "Step",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "10",
|
||||||
|
"type": "float",
|
||||||
|
"name": "Counter",
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,8 @@
|
||||||
"offset": "20",
|
"offset": "20",
|
||||||
"type": "JStage::TActor",
|
"type": "JStage::TActor",
|
||||||
"name": "Inherited fields",
|
"name": "Inherited fields",
|
||||||
"notes": ""
|
"notes": "",
|
||||||
|
"hidden": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"offset": "24",
|
"offset": "24",
|
||||||
|
|
31
res/ObjectParameters/MActor.json
Normal file
31
res/ObjectParameters/MActor.json
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"MActor": {
|
||||||
|
"size": 72,
|
||||||
|
"offsets": [
|
||||||
|
{
|
||||||
|
"offset": "0",
|
||||||
|
"type": "MActorAnmData*",
|
||||||
|
"name": "",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "4",
|
||||||
|
"type": "J3DModel*",
|
||||||
|
"name": "",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "c",
|
||||||
|
"type": "MActorAnmBck*",
|
||||||
|
"name": "Current Animation",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "28",
|
||||||
|
"type": "MActorAnmBck**",
|
||||||
|
"name": "Animations?",
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
19
res/ObjectParameters/MActorAnmBck.json
Normal file
19
res/ObjectParameters/MActorAnmBck.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"MActorAnmBck": {
|
||||||
|
"size": 60,
|
||||||
|
"offsets": [
|
||||||
|
{
|
||||||
|
"offset": "0",
|
||||||
|
"type": "s32",
|
||||||
|
"name": "id",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "4",
|
||||||
|
"type": "J3DFrameCtrl",
|
||||||
|
"name": "Frame *",
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
59
res/ObjectParameters/TApplication.json
Normal file
59
res/ObjectParameters/TApplication.json
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
{
|
||||||
|
"TApplication": {
|
||||||
|
"size": 80,
|
||||||
|
"offsets": [
|
||||||
|
{
|
||||||
|
"offset": "0",
|
||||||
|
"type": "TApplication*",
|
||||||
|
"name": "Pointer to itself",
|
||||||
|
"notes": "",
|
||||||
|
"hidden": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "4",
|
||||||
|
"type": "TDirector*",
|
||||||
|
"name": "Current director",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "8",
|
||||||
|
"type": "u8",
|
||||||
|
"name": "Director type",
|
||||||
|
"notes": "Director type\n2: [null] setup for 3? (after boot)\n3: [TGCLogoDir] Show Nintendo logo\n4: [TMovieDirector] Title screen FMV\n5: [TMarDirector/TMovieDirector] Regular game play (including most FMV)\n6: [TMovieDirector] other independent FMV (e.g. FLUDD tutorial, BH2 warp zone)\n7: Error? \n8: [TSelectDir] shine select\n9: [TMenuDirector] level select (for debug purpose?)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "a",
|
||||||
|
"type": "u16",
|
||||||
|
"format": "hex",
|
||||||
|
"name": "Previous area",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "e",
|
||||||
|
"type": "u16",
|
||||||
|
"format": "hex",
|
||||||
|
"name": "Current area",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "12",
|
||||||
|
"type": "u16",
|
||||||
|
"format": "hex",
|
||||||
|
"name": "Next area",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "18",
|
||||||
|
"type": "u16",
|
||||||
|
"name": "Current FMV",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "38",
|
||||||
|
"type": "s32",
|
||||||
|
"name": "Current save file",
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
55
res/ObjectParameters/TBiancoGateKeeper.json
Normal file
55
res/ObjectParameters/TBiancoGateKeeper.json
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
{
|
||||||
|
"TBiancoGateKeeper": {
|
||||||
|
"size": 672,
|
||||||
|
"offsets": [
|
||||||
|
{
|
||||||
|
"offset": "0",
|
||||||
|
"type": "TSpineEnemy",
|
||||||
|
"name": "Inherited fields",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "13c",
|
||||||
|
"type": "u8",
|
||||||
|
"name": "HP",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "154",
|
||||||
|
"type": "u32",
|
||||||
|
"name": "Received water count",
|
||||||
|
"notes": "Increased in TGateKeeperBase::receiveMessage()\nReset in TGateKeeperBase::perform() every frame"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "17c",
|
||||||
|
"type": "s16",
|
||||||
|
"name": "Total water damage (~255)",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "17e",
|
||||||
|
"type": "s16",
|
||||||
|
"name": "Water damage timer (QF)",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "292",
|
||||||
|
"type": "u8",
|
||||||
|
"name": "GateKeeper type",
|
||||||
|
"notes": "[0] in AP\n[1] in BH [2] BH unlock\n[3] RH unlock\n[4] GB unlock"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "296",
|
||||||
|
"type": "s16",
|
||||||
|
"name": "Death count",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "298",
|
||||||
|
"type": "s16",
|
||||||
|
"name": "Timer to launch Goro (BH only)",
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,14 +61,15 @@
|
||||||
"offset": "60",
|
"offset": "60",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"name": "Entry radius",
|
"name": "Entry radius",
|
||||||
"notes": ""
|
"notes": "",
|
||||||
|
"hidden": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"offset": "64",
|
"offset": "64",
|
||||||
"type": "u32",
|
"type": "u32",
|
||||||
"format": "hex",
|
"format": "hex",
|
||||||
"name": "Collision flag\n (0) active / (1) no collision",
|
"name": "Collision flag",
|
||||||
"notes": ""
|
"notes": "(0) active / (1) no collision"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,32 +18,22 @@
|
||||||
{
|
{
|
||||||
"offset": "74",
|
"offset": "74",
|
||||||
"type": "MActor*",
|
"type": "MActor*",
|
||||||
"name": "",
|
"name": "MActor",
|
||||||
"notes": ""
|
"notes": "",
|
||||||
|
"hidden": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"offset": ["74", "c", "0"],
|
"offset": ["74", "c", "0"],
|
||||||
"type": "s32",
|
"type": "MActorAnmBck",
|
||||||
"name": "Animation id",
|
"name": "Current Animation *",
|
||||||
"notes": ""
|
"notes": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"offset": ["74", "28", "0", "14"],
|
"offset": ["74", "28", "0", "0"],
|
||||||
"type": "float",
|
"type": "MActorAnmBck",
|
||||||
"name": "Animation frame counter",
|
"name": "Animations[0] *",
|
||||||
"notes": ""
|
"notes": "",
|
||||||
},
|
"hidden": true
|
||||||
{
|
|
||||||
"offset": ["74", "28", "0", "c"],
|
|
||||||
"type": "s16",
|
|
||||||
"name": "Animation frame length",
|
|
||||||
"notes": ""
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"offset": ["74", "28", "0", "10"],
|
|
||||||
"type": "float",
|
|
||||||
"name": "Animation frame rate",
|
|
||||||
"notes": ""
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"offset": "7c",
|
"offset": "7c",
|
||||||
|
@ -70,7 +60,8 @@
|
||||||
"offset": "8c",
|
"offset": "8c",
|
||||||
"type": "TSpineBase<TLiveActor>*",
|
"type": "TSpineBase<TLiveActor>*",
|
||||||
"name": "AI",
|
"name": "AI",
|
||||||
"notes": ""
|
"notes": "",
|
||||||
|
"hidden": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"offset": ["8c", "1c", "0"],
|
"offset": ["8c", "1c", "0"],
|
||||||
|
@ -94,37 +85,43 @@
|
||||||
"offset": "94",
|
"offset": "94",
|
||||||
"type": "JGeometry::TVec3<float>",
|
"type": "JGeometry::TVec3<float>",
|
||||||
"name": "* Movement (unit/step)",
|
"name": "* Movement (unit/step)",
|
||||||
"notes": ""
|
"notes": "",
|
||||||
|
"hidden": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"offset": "ac",
|
"offset": "ac",
|
||||||
"type": "JGeometry::TVec3<float>",
|
"type": "JGeometry::TVec3<float>",
|
||||||
"name": "* Speed (unit/step)",
|
"name": "* Speed (unit/step)",
|
||||||
"notes": ""
|
"notes": "",
|
||||||
|
"hidden": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"offset": "bc",
|
"offset": "bc",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"name": "Wall hitbox width",
|
"name": "Wall hitbox width",
|
||||||
"notes": ""
|
"notes": "",
|
||||||
|
"hidden": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"offset": "c4",
|
"offset": "c4",
|
||||||
"type": "TBGCheckData*",
|
"type": "TBGCheckData*",
|
||||||
"name": "",
|
"name": "Ground",
|
||||||
"notes": ""
|
"notes": "",
|
||||||
|
"hidden": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"offset": "c8",
|
"offset": "c8",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"name": "Ground Height",
|
"name": "Ground Height",
|
||||||
"notes": ""
|
"notes": "",
|
||||||
|
"hidden": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"offset": "cc",
|
"offset": "cc",
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"name": "Gravity (unit/step²)",
|
"name": "Gravity (unit/step²)",
|
||||||
"notes": ""
|
"notes": "",
|
||||||
|
"hidden": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"offset": "f0",
|
"offset": "f0",
|
||||||
|
|
62
res/ObjectParameters/TMarDirector TDemoInfo.json
Normal file
62
res/ObjectParameters/TMarDirector TDemoInfo.json
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
{
|
||||||
|
"TMarDirector::TDemoInfo": {
|
||||||
|
"size": 34,
|
||||||
|
"offsets": [
|
||||||
|
{
|
||||||
|
"offset": "0",
|
||||||
|
"type": "string",
|
||||||
|
"name": "BCK name",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": ["4", "0"],
|
||||||
|
"type": "JGeometry::TVec3<float>",
|
||||||
|
"name": "location.*",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "8",
|
||||||
|
"type": "s32",
|
||||||
|
"name": "",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "c",
|
||||||
|
"type": "float",
|
||||||
|
"name": "",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "10",
|
||||||
|
"type": "u8",
|
||||||
|
"name": "",
|
||||||
|
"notes": "bool"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "14",
|
||||||
|
"type": "void*",
|
||||||
|
"name": "Callback",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "18",
|
||||||
|
"type": "u32",
|
||||||
|
"format": "hex",
|
||||||
|
"name": "Callback parameter",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "1c",
|
||||||
|
"type": "TActor*",
|
||||||
|
"name": "TActor*",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "20",
|
||||||
|
"type": "s16",
|
||||||
|
"name": "flag",
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
166
res/ObjectParameters/TMarDirector.json
Normal file
166
res/ObjectParameters/TMarDirector.json
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
{
|
||||||
|
"TMarDirector": {
|
||||||
|
"size": 616,
|
||||||
|
"offsets": [
|
||||||
|
{
|
||||||
|
"offset": "4c",
|
||||||
|
"type": "u16",
|
||||||
|
"format": "hex",
|
||||||
|
"name": "Game mode flags",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "4e",
|
||||||
|
"type": "u16",
|
||||||
|
"format": "hex",
|
||||||
|
"name": "",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "50",
|
||||||
|
"type": "u16",
|
||||||
|
"format": "hex",
|
||||||
|
"name": "",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "54",
|
||||||
|
"type": "u32",
|
||||||
|
"name": "QF synchronizer",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "58",
|
||||||
|
"type": "u32",
|
||||||
|
"name": "Game QF",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "5c",
|
||||||
|
"type": "u32",
|
||||||
|
"name": "Global QF",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "60",
|
||||||
|
"type": "u32",
|
||||||
|
"name": "Started QF of cutscene",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "64",
|
||||||
|
"type": "u8",
|
||||||
|
"name": "Game state",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "7c",
|
||||||
|
"type": "s8",
|
||||||
|
"name": "Current stage",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "7d",
|
||||||
|
"type": "s8",
|
||||||
|
"name": "Current episode",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "b4",
|
||||||
|
"type": "u8",
|
||||||
|
"name": "Next director type",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "124",
|
||||||
|
"type": "u8",
|
||||||
|
"name": "Current game mode state",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "125",
|
||||||
|
"type": "u8",
|
||||||
|
"name": "Previous game mode state",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "126",
|
||||||
|
"type": "u8",
|
||||||
|
"name": "Next game mode state",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "12c",
|
||||||
|
"type": "TMarDirector::TDemoInfo",
|
||||||
|
"name": "slot0 *",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "150",
|
||||||
|
"type": "TMarDirector::TDemoInfo",
|
||||||
|
"name": "slot1 *",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "174",
|
||||||
|
"type": "TMarDirector::TDemoInfo",
|
||||||
|
"name": "slot2 *",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "198",
|
||||||
|
"type": "TMarDirector::TDemoInfo",
|
||||||
|
"name": "slot3 *",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "1bc",
|
||||||
|
"type": "TMarDirector::TDemoInfo",
|
||||||
|
"name": "slot4 *",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "1e0",
|
||||||
|
"type": "TMarDirector::TDemoInfo",
|
||||||
|
"name": "slot5 *",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "204",
|
||||||
|
"type": "TMarDirector::TDemoInfo",
|
||||||
|
"name": "slot6 *",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "228",
|
||||||
|
"type": "TMarDirector::TDemoInfo",
|
||||||
|
"name": "slot7 *",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "24c",
|
||||||
|
"type": "u8",
|
||||||
|
"name": "Next cutscene index to assign",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "24d",
|
||||||
|
"type": "u8",
|
||||||
|
"name": "Next cutscene index to play",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "260",
|
||||||
|
"type": "u8",
|
||||||
|
"name": "Stage load done",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "261",
|
||||||
|
"type": "s8",
|
||||||
|
"name": "Prompt id",
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
19
res/ObjectParameters/TMarDirector@QF.json
Normal file
19
res/ObjectParameters/TMarDirector@QF.json
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"TMarDirector@QF": {
|
||||||
|
"size": 616,
|
||||||
|
"offsets": [
|
||||||
|
{
|
||||||
|
"offset": "58",
|
||||||
|
"type": "u32",
|
||||||
|
"name": "Game QF",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "5c",
|
||||||
|
"type": "u32",
|
||||||
|
"name": "Global QF",
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
131
res/ObjectParameters/TMario.json
Normal file
131
res/ObjectParameters/TMario.json
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
{
|
||||||
|
"TMario": {
|
||||||
|
"size": 17040,
|
||||||
|
"offsets": [
|
||||||
|
{
|
||||||
|
"offset": "0",
|
||||||
|
"type": "TTakeActor",
|
||||||
|
"name": "Inherited fields",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "7c",
|
||||||
|
"type": "u32",
|
||||||
|
"format": "hex",
|
||||||
|
"name": "Current state",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "80",
|
||||||
|
"type": "u32",
|
||||||
|
"format": "hex",
|
||||||
|
"name": "Previous state",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "84",
|
||||||
|
"type": "u16",
|
||||||
|
"name": "Substate",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "86",
|
||||||
|
"type": "u16",
|
||||||
|
"name": "Substate timer",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "8c",
|
||||||
|
"type": "float",
|
||||||
|
"name": "Base acceleration (0-32)",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "90",
|
||||||
|
"type": "s16",
|
||||||
|
"name": "Acceleration direction",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "94",
|
||||||
|
"type": "s16",
|
||||||
|
"name": "X angle",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "96",
|
||||||
|
"type": "s16",
|
||||||
|
"name": "Y angle (yaw)",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "98",
|
||||||
|
"type": "s16",
|
||||||
|
"name": "Z angle",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "a4",
|
||||||
|
"type": "JGeometry::TVec3<float>",
|
||||||
|
"name": "* Speed",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "b0",
|
||||||
|
"type": "float",
|
||||||
|
"name": "Forward speed",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "e0",
|
||||||
|
"type": "TBGCheckData*",
|
||||||
|
"name": "Floor triangle under Mario",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "e8",
|
||||||
|
"type": "float",
|
||||||
|
"name": "Height of the ceiling above Mario",
|
||||||
|
"notes": "9,999,999 if none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "ec",
|
||||||
|
"type": "float",
|
||||||
|
"name": "Height of the floor below Mario",
|
||||||
|
"notes": "-32,767 if none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "f0",
|
||||||
|
"type": "float",
|
||||||
|
"name": "Height of the water surface at Mario’s position",
|
||||||
|
"notes": "Y position if none"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "118",
|
||||||
|
"type": "u32",
|
||||||
|
"name": "Mario flags",
|
||||||
|
"format": "hex",
|
||||||
|
"notes": "& 0x00000001: \n& 0x00000002: Above a sewer floor?\n& 0x00000004: Is visible?\n& 0x00000008: Talking to NPC?\n& 0x00000010: Left water recently?\n& 0x00000020: Is in shadow\n& 0x00000040: Is in goop\n& 0x00000080: Filling FLUDD\n& 0x00000100: Is NOT on wire (starts off?)\n& 0x00000200: \n& 0x00000400: Is \"TOO BAD!\"?\n& 0x00000800: Is Ground Pound sit up?\n& 0x00001000: Has helmet?\n& 0x00002000: \n& 0x00004000: Is turbo boosting\n& 0x00008000: Has FLUDD?\n& 0x00010000: Is standing in water?\n& 0x00020000: Is in water?\n& 0x00040000: Is above sand?\n& 0x00080000: \n& 0x00100000: \n& 0x00200000: \n& 0x00400000: \n& 0x00800000: \n& 0x01000000: \n& 0x02000000: \n& 0x04000000: \n& 0x08000000: \n& 0x10000000: \n& 0x20000000: \n& 0x40000000: \n& 0x80000000: \n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "11C",
|
||||||
|
"type": "u32",
|
||||||
|
"format": "hex",
|
||||||
|
"name": "Previous Mario flags",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "120",
|
||||||
|
"type": "s16",
|
||||||
|
"name": "HP",
|
||||||
|
"notes": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"offset": "12c",
|
||||||
|
"type": "float",
|
||||||
|
"name": "Underwater HP",
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -263,6 +263,11 @@ pub async fn handle_command(
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"getVersion" => {
|
||||||
|
let_dolphin!(d);
|
||||||
|
Ok(json!(d.ver().to_string()))
|
||||||
|
},
|
||||||
|
|
||||||
"reload" => {
|
"reload" => {
|
||||||
let mut lock_obj_params = env.obj_params_result.lock().await;
|
let mut lock_obj_params = env.obj_params_result.lock().await;
|
||||||
load_obj_params(&env.obj_params_dir)
|
load_obj_params(&env.obj_params_dir)
|
||||||
|
|
|
@ -5,7 +5,11 @@
|
||||||
pub enum SMSVersion {
|
pub enum SMSVersion {
|
||||||
GMSJ01, GMSE01, GMSP01, GMSJ0A,
|
GMSJ01, GMSE01, GMSP01, GMSJ0A,
|
||||||
}
|
}
|
||||||
pub mod vt;
|
impl std::fmt::Display for SMSVersion {
|
||||||
|
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
|
||||||
|
std::fmt::Debug::fmt(self, fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
use crate::addr::Addr;
|
use crate::addr::Addr;
|
||||||
use crate::dolphin::{DolphinMemory, Dolphin};
|
use crate::dolphin::{DolphinMemory, Dolphin};
|
||||||
|
@ -20,6 +24,7 @@ impl Dolphin for SMSDolphin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod vt;
|
||||||
impl SMSDolphin {
|
impl SMSDolphin {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn pid(&self) -> usize {
|
pub fn pid(&self) -> usize {
|
||||||
|
|
20
www/api.js
20
www/api.js
|
@ -4,6 +4,7 @@
|
||||||
// @ts-check
|
// @ts-check
|
||||||
/**
|
/**
|
||||||
* @typedef {number|number[]} ReqAddr
|
* @typedef {number|number[]} ReqAddr
|
||||||
|
* @typedef {'GMSJ01'|'GMSE01'|'GMSP01'|'GMSJ0A'} SMSVersion
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @param {string} s */
|
/** @param {string} s */
|
||||||
|
@ -27,10 +28,10 @@ function Client({onClose = null}={}) {
|
||||||
/**
|
/**
|
||||||
* @template T
|
* @template T
|
||||||
* @param {string} action
|
* @param {string} action
|
||||||
* @param {any} payload
|
* @param {any} [payload]
|
||||||
* @returns {Promise<T>}
|
* @returns {Promise<T>}
|
||||||
*/
|
*/
|
||||||
const request = (action, payload) => new Promise((rsv, rjt) => {
|
const request = (action, payload=null) => new Promise((rsv, rjt) => {
|
||||||
if (ws == null) throw Error('Client is not connected to server. Use `client.connect()` first.');
|
if (ws == null) throw Error('Client is not connected to server. Use `client.connect()` first.');
|
||||||
const id = nextId++;
|
const id = nextId++;
|
||||||
reqs.set(id, {rsv, rjt});
|
reqs.set(id, {rsv, rjt});
|
||||||
|
@ -62,7 +63,7 @@ function Client({onClose = null}={}) {
|
||||||
/**
|
/**
|
||||||
* @returns {Promise<number|null>}
|
* @returns {Promise<number|null>}
|
||||||
*/
|
*/
|
||||||
init: () => request('init', null),
|
init: () => request('init'),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ReqAddr} addr
|
* @param {ReqAddr} addr
|
||||||
|
@ -123,16 +124,19 @@ function Client({onClose = null}={}) {
|
||||||
*/
|
*/
|
||||||
getFields: type => request('getFields', type),
|
getFields: type => request('getFields', type),
|
||||||
|
|
||||||
getManagers: () => request('getManagers', 0)
|
getManagers: () => request('getManagers')
|
||||||
.then((/**@type{[addr: number, cls: string, name: string, count: number][]}*/rows) =>
|
.then((/**@type{[addr: number, type: string, name: string, count: number][]|null}*/rows) =>
|
||||||
rows.map(row => ({addr: row[0], cls: row[1], name: row[2], count: row[3]}))),
|
rows?.map(row => ({addr: row[0], type: row[1], name: row[2], count: row[3]})) ?? []),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {ReqAddr} addr
|
* @param {ReqAddr} addr
|
||||||
*/
|
*/
|
||||||
getManagees: addr => request('getManagees', addr)
|
getManagees: addr => request('getManagees', addr)
|
||||||
.then((/**@type{[addr: number, cls: string, name: string][]}*/rows) =>
|
.then((/**@type{[addr: number, type: string, name: string][]|null}*/rows) =>
|
||||||
rows.map(row => ({addr: row[0], cls: row[1], name: row[2]}))),
|
rows?.map(row => ({addr: row[0], type: row[1], name: row[2]})) ?? []),
|
||||||
|
|
||||||
|
/** @returns {Promise<SMSVersion>} */
|
||||||
|
getVersion: () => request('getVersion'),
|
||||||
|
|
||||||
reload: () => request('reload', null),
|
reload: () => request('reload', null),
|
||||||
},
|
},
|
||||||
|
|
|
@ -36,18 +36,28 @@ table.list td {
|
||||||
padding: 1px 0.3em;
|
padding: 1px 0.3em;
|
||||||
white-space: pre-line;
|
white-space: pre-line;
|
||||||
}
|
}
|
||||||
#managers td:nth-child(1),
|
#managerList td:nth-child(1),
|
||||||
#managers td:nth-child(5) {
|
#managerList td:nth-child(5) {
|
||||||
padding: 0 2px
|
padding: 0 2px
|
||||||
}
|
}
|
||||||
#managers tr.managee > td:nth-child(2) {
|
#managerList tr.managee > td:nth-child(2) {
|
||||||
padding-left: 1em
|
padding-left: 1em
|
||||||
}
|
}
|
||||||
|
|
||||||
#fields-viewer td:nth-child(1),
|
#fieldsViewer h3 {
|
||||||
#fields-viewer td:nth-child(3) {
|
margin-block-start: 0;
|
||||||
|
margin-block-end: 0.5em;
|
||||||
|
}
|
||||||
|
#fieldsViewer td:nth-child(1),
|
||||||
|
#fieldsViewer td:nth-child(3) {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
#fieldsViewer td:nth-child(4) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#fieldsViewer.showNotes td:nth-child(4) {
|
||||||
|
display: unset;
|
||||||
|
}
|
||||||
|
|
||||||
.flex {
|
.flex {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -55,11 +65,23 @@ table.list td {
|
||||||
}
|
}
|
||||||
.flex > * {
|
.flex > * {
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
|
margin-block-end: 1em;
|
||||||
}
|
}
|
||||||
|
body.wrap .flex {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
body.ready main {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
|
@ -68,7 +90,7 @@ body {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
body.disconnected #msg {
|
body.error #msg {
|
||||||
background: var(--bg-red);
|
background: var(--bg-red);
|
||||||
}
|
}
|
||||||
h1 {
|
h1 {
|
||||||
|
@ -83,6 +105,10 @@ header {
|
||||||
margin-block-end: 0.75em;
|
margin-block-end: 0.75em;
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
}
|
}
|
||||||
|
section {
|
||||||
|
margin-block-end: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
details {
|
details {
|
||||||
border: solid 1px var(--fg);
|
border: solid 1px var(--fg);
|
||||||
padding: 0.5em 1em;
|
padding: 0.5em 1em;
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>SMS Web Object Viewer (v0.1.0-beta.1)</title>
|
<title>SMS Web Object Viewer (v0.1.0-beta.2)</title>
|
||||||
<link rel="stylesheet" type="text/css" href="index.css">
|
<link rel="stylesheet" type="text/css" href="index.css">
|
||||||
<link rel="icon" type="image/svg+xml" href="icon.svg">
|
<link rel="icon" type="image/svg+xml" href="icon.svg">
|
||||||
<script src="api.js"></script>
|
<script src="api.js"></script>
|
||||||
<script src="index.js"></script>
|
<script src="index.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>SMS Web Object Viewer</h1>
|
<h1>SMS Web Object Viewer (v0.1.0-beta.2)</h1>
|
||||||
<header>
|
<header>
|
||||||
<div id="msg"></div>
|
<div id="msg"></div>
|
||||||
<details>
|
<details>
|
||||||
|
@ -20,13 +20,27 @@
|
||||||
<iframe id="license" src="/LICENSE.html" title="license"></iframe>
|
<iframe id="license" src="/LICENSE.html" title="license"></iframe>
|
||||||
</details>
|
</details>
|
||||||
</header>
|
</header>
|
||||||
<section>
|
<main>
|
||||||
<button id="btn-reload" class="hidden">Reload Object Parameters</button>
|
<section>
|
||||||
</section>
|
<button id="btnReloadManagers">Reload Managers</button>
|
||||||
<section class="flex-wrapper">
|
<input type="checkbox" id="cbShowManagers" checked>
|
||||||
<div class="flex">
|
<label for="cbShowManagers">Show Manager List</label>
|
||||||
<table id="managers" class="list"></table>
|
<input type="checkbox" id="cbShowObjParamsNotes">
|
||||||
<table id="fields-viewer" class="list"></table>
|
<label for="cbShowObjParamsNotes">Show Notes of Object Parameters</label>
|
||||||
</div>
|
<input type="checkbox" id="cbWrapFlex">
|
||||||
</section>
|
<label for="cbWrapFlex">Wrap UI</label>
|
||||||
|
<button id="btnReloadObjParams">Reload ObjectParameters</button>
|
||||||
|
</section>
|
||||||
|
<section class="flex-wrapper">
|
||||||
|
<div class="flex">
|
||||||
|
<div id="managerList">
|
||||||
|
<table class="list"></table>
|
||||||
|
</div>
|
||||||
|
<div id="fieldsViewer" class="hidden">
|
||||||
|
<h3></h3>
|
||||||
|
<table class="list"></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
</body>
|
</body>
|
||||||
|
|
179
www/index.js
179
www/index.js
|
@ -3,8 +3,8 @@
|
||||||
|
|
||||||
// @ts-check
|
// @ts-check
|
||||||
/**
|
/**
|
||||||
* @typedef {{addr: number, cls: string, name: string, count: number}} Manager
|
* @typedef {{addr: number, type: string, name: string, count: number}} Manager
|
||||||
* @typedef {{addr: number, cls: string, name: string}} Managee
|
* @typedef {{addr: number, type: string, name: string}} Managee
|
||||||
* @typedef {(td: HTMLTableCellElement) => void} CellFactory
|
* @typedef {(td: HTMLTableCellElement) => void} CellFactory
|
||||||
* @typedef {CellFactory[]} RowFactory
|
* @typedef {CellFactory[]} RowFactory
|
||||||
* @typedef {{name: string, notes: string, offset: string|string[], type: string}} Field
|
* @typedef {{name: string, notes: string, offset: string|string[], type: string}} Field
|
||||||
|
@ -16,12 +16,6 @@
|
||||||
const fmt = {
|
const fmt = {
|
||||||
/** @param {number} x */
|
/** @param {number} x */
|
||||||
hex: x => x.toString(16).toUpperCase(),
|
hex: x => x.toString(16).toUpperCase(),
|
||||||
/** @type {(x: number) => string} */
|
|
||||||
float: (LOG_10_2 => x => {
|
|
||||||
const u = Math.floor(LOG_10_2*(Math.log2(Math.abs(x))-23));
|
|
||||||
return x === 0 ? '0.0' : u > 0 || u < -8 ? x.toExponential(7) :
|
|
||||||
x.toFixed(-u);
|
|
||||||
})(Math.log10(2)),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,38 +23,113 @@ const fmt = {
|
||||||
* @param {((td: HTMLTableCellElement)=>void)[][]} gTable
|
* @param {((td: HTMLTableCellElement)=>void)[][]} gTable
|
||||||
*/
|
*/
|
||||||
function initTable(table, gTable) {
|
function initTable(table, gTable) {
|
||||||
const nRow = gTable.length;
|
const nRow0 = table.rows.length;
|
||||||
for (let r=table.rows.length; r<nRow; r++) table.insertRow();
|
for (let r=0; r<nRow0; r++) table.deleteRow(-1);
|
||||||
for (let r=table.rows.length; r>nRow; r--) table.deleteRow(-1);
|
gTable.forEach(gRow => {
|
||||||
gTable.forEach((gRow, r) => {
|
const row = table.insertRow();
|
||||||
const row = table.rows[r];
|
gRow.forEach(g => g(row.insertCell()));
|
||||||
const nCol = gRow.length;
|
|
||||||
for (let c=row.cells.length; c<nCol; c++) row.insertCell();
|
|
||||||
for (let c=row.cells.length; c>nCol; c--) row.deleteCell(-1);
|
|
||||||
gRow.forEach((g, c) => g(row.cells[c]));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', async () => {
|
document.addEventListener('DOMContentLoaded', async () => {
|
||||||
const elmMsg = /**@type {HTMLDivElement}*/(document.getElementById('msg'));
|
const elmMsg = /**@type {HTMLDivElement}*/(document.getElementById('msg'));
|
||||||
const btnReload = /**@type {HTMLButtonElement}*/(document.getElementById('btn-reload'));
|
const btnReloadObjParams = /**@type {HTMLButtonElement}*/(document.getElementById('btnReloadObjParams'));
|
||||||
const elmManagers = /**@type {HTMLTableElement}*/(document.getElementById('managers'));
|
const btnReloadManagers = /**@type {HTMLButtonElement}*/(document.getElementById('btnReloadManagers'));
|
||||||
const elmFieldsViewer = /**@type {HTMLTableElement}*/(document.getElementById('fields-viewer'));
|
const cbShowManagers = /**@type {HTMLInputElement}*/(document.getElementById('cbShowManagers'));
|
||||||
|
const cbShowObjParamsNotes = /**@type {HTMLInputElement}*/(document.getElementById('cbShowObjParamsNotes'));
|
||||||
|
const cbWrapFlex = /**@type {HTMLInputElement}*/(document.getElementById('cbWrapFlex'));
|
||||||
|
|
||||||
|
/** @param {string} msg */
|
||||||
|
function showError(msg) {
|
||||||
|
elmMsg.textContent = msg;
|
||||||
|
document.body.classList.add('error');
|
||||||
|
}
|
||||||
const client = Client({
|
const client = Client({
|
||||||
onClose() {
|
onClose: () => showError(`Disconnected from server. Please reload the page.`),
|
||||||
elmMsg.textContent = `Disconnected from server. Please reload the page.`;
|
|
||||||
document.body.classList.add('disconnected');
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
const {api} = client;
|
const {api} = client;
|
||||||
Object.assign(window, {client, api}); // TODO
|
Object.assign(window, {client, api}); // TODO
|
||||||
|
|
||||||
/**************** UI definition ****************/
|
/**************** UI definition ****************/
|
||||||
/**
|
/**
|
||||||
* @param {HTMLTableElement} elm
|
* @param {HTMLElement|null} elm
|
||||||
|
*/
|
||||||
|
function ManagerList(elm) {
|
||||||
|
if (elm == null) throw new Error('ManagerList not found');
|
||||||
|
const elmTable = (() => {
|
||||||
|
const e = elm.querySelector('table');
|
||||||
|
if (e == null) throw new Error('table should present in ManagerList');
|
||||||
|
return e;
|
||||||
|
})();
|
||||||
|
// TODO put in a json file
|
||||||
|
const staticVariables = [
|
||||||
|
{
|
||||||
|
name: 'gpApplication',
|
||||||
|
addrs: [0x803E6000, 0x803E9700, 0x803E10C0, 0x803DA8E0],
|
||||||
|
type: 'TApplication',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'gpMarDirector',
|
||||||
|
addrs: [0x8040A2A8, 0x8040E178, 0x80405840, 0x803FF018],
|
||||||
|
type: 'TMarDirector*',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'QF',
|
||||||
|
addrs: [0x8040A2A8, 0x8040E178, 0x80405840, 0x803FF018],
|
||||||
|
type: 'TMarDirector@QF*',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'マリオ',
|
||||||
|
addrs: [0x8040A378, 0x8040E0E8, 0x804057B0, 0x803FEF88],
|
||||||
|
type: 'TMario*',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
return {
|
||||||
|
get classList() {
|
||||||
|
return elm.classList;
|
||||||
|
},
|
||||||
|
async reload() {
|
||||||
|
const [vars, managers] = await Promise.all([
|
||||||
|
api.getVersion().then(async ver => {
|
||||||
|
const iver = ['GMSJ01', 'GMSE01', 'GMSP01', 'GMSJ0A'].indexOf(ver);
|
||||||
|
return await Promise.all(staticVariables.map(async o => {
|
||||||
|
const ptrlv = o.type.match(/\*+$/)?.[0].length ?? 0;
|
||||||
|
const type = o.type.substring(0, o.type.length-ptrlv);
|
||||||
|
const addr0 = o.addrs[iver];
|
||||||
|
const addr = ptrlv === 0 ? addr0 : await api.readBytes(
|
||||||
|
[addr0].concat(...Array(ptrlv-1).fill(0)), 4,
|
||||||
|
).then(dv => dv?.getUint32(0) ?? 0);
|
||||||
|
return {name: o.name, addr, type};
|
||||||
|
}));
|
||||||
|
}),
|
||||||
|
api.getManagers(),
|
||||||
|
]);
|
||||||
|
fieldsViewer.reset();
|
||||||
|
initTable(elmTable, [
|
||||||
|
...vars.map(o => makeManageesRowFactory(o)),
|
||||||
|
...managers.map(makeManagersRowFactory),
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const managerList = ManagerList(document.getElementById('managerList'));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {HTMLElement|null} elm
|
||||||
*/
|
*/
|
||||||
function FieldsViewer(elm) {
|
function FieldsViewer(elm) {
|
||||||
|
if (elm == null) throw new Error('FieldsViewer not found');
|
||||||
|
const elmTitle = (() => {
|
||||||
|
const e = elm.querySelector('h3');
|
||||||
|
if (e == null) throw new Error('h3 should present in FieldsViewer');
|
||||||
|
return e;
|
||||||
|
})();
|
||||||
|
const elmTable = (() => {
|
||||||
|
const e = elm.querySelector('table');
|
||||||
|
if (e == null) throw new Error('table should present in FieldsViewer');
|
||||||
|
return e;
|
||||||
|
})();
|
||||||
|
// states
|
||||||
const tdidxVal = 2;
|
const tdidxVal = 2;
|
||||||
let hAnm = NaN;
|
let hAnm = NaN;
|
||||||
let t0 = 0;
|
let t0 = 0;
|
||||||
|
@ -68,19 +137,22 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
let target = null;
|
let target = null;
|
||||||
async function readValues() {
|
async function readValues() {
|
||||||
if (target == null) return [];
|
if (target == null) return [];
|
||||||
const values = await api.read([target.addr], target.cls);
|
const values = await api.read([target.addr], target.type);
|
||||||
return values instanceof Array ? values : [values];
|
return values instanceof Array ? values : [values];
|
||||||
}
|
}
|
||||||
/** @param {DOMHighResTimeStamp} t */
|
/** @param {DOMHighResTimeStamp} t */
|
||||||
async function render(t) {
|
async function render(t) {
|
||||||
if (t-t0 >= 33) { // TODO configurable fps
|
if (t-t0 >= 33) { // TODO configurable fps
|
||||||
(await readValues())
|
(await readValues())
|
||||||
.forEach((s, i) => elm.rows[i].cells[tdidxVal].textContent = s);
|
.forEach((s, i) => elmTable.rows[i].cells[tdidxVal].textContent = s);
|
||||||
t0 = t;
|
t0 = t;
|
||||||
}
|
}
|
||||||
hAnm = requestAnimationFrame(render);
|
hAnm = requestAnimationFrame(render);
|
||||||
}
|
}
|
||||||
const methods = {
|
const methods = {
|
||||||
|
get classList() {
|
||||||
|
return elm.classList;
|
||||||
|
},
|
||||||
reload() {
|
reload() {
|
||||||
api.reload().then(() => {
|
api.reload().then(() => {
|
||||||
target != null && methods.view(target);
|
target != null && methods.view(target);
|
||||||
|
@ -88,34 +160,55 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
elmMsg.textContent = err;
|
elmMsg.textContent = err;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
reset() {
|
||||||
|
elm.classList.add('hidden');
|
||||||
|
},
|
||||||
/** @param {Manager|Managee} o */
|
/** @param {Manager|Managee} o */
|
||||||
async view(o) {
|
async view(o) {
|
||||||
btnReload.classList.remove('hidden');
|
|
||||||
cancelAnimationFrame(hAnm);
|
cancelAnimationFrame(hAnm);
|
||||||
target = o;
|
target = o;
|
||||||
const fields = await api.getFields(o.cls);
|
elmTitle.textContent = `${o.name} (${o.type}) [${fmt.hex(o.addr)}]`;
|
||||||
|
const fields = await api.getFields(o.type);
|
||||||
const values = readValues();
|
const values = readValues();
|
||||||
initTable(elm, fields.map((r, i) => [
|
initTable(elmTable, fields.map((r, i) => [
|
||||||
td => td.textContent = r[0],
|
td => td.textContent = r[0],
|
||||||
td => td.textContent = r[1],
|
td => td.textContent = r[1],
|
||||||
td => td.textContent = values[i],
|
td => td.textContent = values[i],
|
||||||
// td => td.textContent = r[2], // TODO
|
td => td.textContent = r[2],
|
||||||
td => td.textContent = r[3],
|
td => td.textContent = r[3],
|
||||||
td => td.textContent = r[4],
|
td => td.textContent = r[4],
|
||||||
]));
|
]));
|
||||||
|
elm.classList.remove('hidden');
|
||||||
if (fields.length) hAnm = requestAnimationFrame(render);
|
if (fields.length) hAnm = requestAnimationFrame(render);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return methods;
|
return methods;
|
||||||
}
|
}
|
||||||
const fieldsViewer = FieldsViewer(elmFieldsViewer);
|
const fieldsViewer = FieldsViewer(document.getElementById('fieldsViewer'));
|
||||||
btnReload.addEventListener('click', () => {
|
btnReloadObjParams.addEventListener('click', () => {
|
||||||
fieldsViewer.reload();
|
fieldsViewer.reload();
|
||||||
});
|
});
|
||||||
|
btnReloadManagers.addEventListener('click', async () => {
|
||||||
|
managerList.reload();
|
||||||
|
});
|
||||||
|
cbShowManagers.addEventListener('change', function () {
|
||||||
|
managerList.classList[this.checked ? 'remove' : 'add']('hidden');
|
||||||
|
});
|
||||||
|
cbShowObjParamsNotes.addEventListener('change', function () {
|
||||||
|
fieldsViewer.classList[this.checked ? 'add' : 'remove']('showNotes');
|
||||||
|
});
|
||||||
|
cbWrapFlex.addEventListener('change', function () {
|
||||||
|
// TODO
|
||||||
|
document.body.classList[this.checked ? 'add' : 'remove']('wrap');
|
||||||
|
});
|
||||||
|
|
||||||
/** @type {(o: Manager) => RowFactory} */
|
/** @type {(o: Manager) => RowFactory} */
|
||||||
const makeManagersRowFactory = o => [
|
const makeManagersRowFactory = o => [
|
||||||
td => {
|
td => {
|
||||||
|
// remove old button
|
||||||
|
const btn0 = td.querySelector('button');
|
||||||
|
if (btn0) td.removeChild(btn0);
|
||||||
|
// create new button
|
||||||
const btn = document.createElement('button');
|
const btn = document.createElement('button');
|
||||||
let open = false;
|
let open = false;
|
||||||
/** @type {HTMLTableRowElement[] | null} */
|
/** @type {HTMLTableRowElement[] | null} */
|
||||||
|
@ -146,22 +239,26 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
td.appendChild(btn);
|
td.appendChild(btn);
|
||||||
},
|
},
|
||||||
td => td.textContent = `${o.name} (${o.count})`,
|
td => td.textContent = `${o.name} (${o.count})`,
|
||||||
td => td.textContent = `${o.cls}`,
|
td => td.textContent = `${o.type}`,
|
||||||
td => td.textContent = `${fmt.hex(o.addr)}`,
|
td => td.textContent = `${fmt.hex(o.addr)}`,
|
||||||
makeViewerNavigatorFactory(o),
|
makeViewerNavigatorFactory(o),
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @type {(o: Managee, i: number) => ((td: HTMLTableCellElement) => void)[]} */
|
/** @type {(o: Managee, i?: number) => ((td: HTMLTableCellElement) => void)[]} */
|
||||||
const makeManageesRowFactory = (o, i) => [
|
const makeManageesRowFactory = (o, i) => [
|
||||||
_ => {},
|
_ => {},
|
||||||
td => td.textContent = `${i}: (${o.name})`,
|
td => td.textContent = i == null ? o.name : `${i}: ${o.name}`,
|
||||||
td => td.textContent = `${o.cls}`,
|
td => td.textContent = `${o.type}`,
|
||||||
td => td.textContent = `${fmt.hex(o.addr)}`,
|
td => td.textContent = `${fmt.hex(o.addr)}`,
|
||||||
makeViewerNavigatorFactory(o),
|
makeViewerNavigatorFactory(o),
|
||||||
];
|
];
|
||||||
|
|
||||||
/** @type {(o: Manager|Managee) => CellFactory} */
|
/** @type {(o: Manager|Managee) => CellFactory} */
|
||||||
const makeViewerNavigatorFactory = o => td => {
|
const makeViewerNavigatorFactory = o => td => {
|
||||||
|
// remove old button
|
||||||
|
const btn0 = td.querySelector('button');
|
||||||
|
if (btn0) td.removeChild(btn0);
|
||||||
|
// create new button
|
||||||
const btn = document.createElement('button');
|
const btn = document.createElement('button');
|
||||||
btn.textContent = '>';
|
btn.textContent = '>';
|
||||||
btn.addEventListener('click', () => {
|
btn.addEventListener('click', () => {
|
||||||
|
@ -175,11 +272,11 @@ document.addEventListener('DOMContentLoaded', async () => {
|
||||||
await client.connect(); // TODO url
|
await client.connect(); // TODO url
|
||||||
const pid = await api.init();
|
const pid = await api.init();
|
||||||
console.log('pid:', pid);
|
console.log('pid:', pid);
|
||||||
|
document.body.classList.add('ready');
|
||||||
|
|
||||||
const managers = await api.getManagers();
|
await managerList.reload();
|
||||||
initTable(elmManagers, managers.map(makeManagersRowFactory));
|
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
elmMsg.textContent = e;
|
console.log(e);
|
||||||
return; // TODO
|
showError(e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue