Decompile ~30 level functions (census sweep: init/collide/spawn/state-machine handlers) - #136
Open
Tokatta007 wants to merge 39 commits into
Open
Decompile ~30 level functions (census sweep: init/collide/spawn/state-machine handlers)#136Tokatta007 wants to merge 39 commits into
Tokatta007 wants to merge 39 commits into
Conversation
BSPTree event dispatch: outer switch on bsp->_06 (cases 4, 1), inner switch on bsp->_04 (cases 2, 1, 5) with duplicated ApplyMatrixT arms that cross-jump. Key derivations: the shared final store goes through a z-value temp (m2c's var_v0) so it tail-merges across arms; the temp is int (ushort narrows the LVECTOR load to the low half) with an (unsigned short) cast on the globalOffset.z read for the lhu.
…unc_801616D4, 156 insns each) Per-face particle init twins (the 7th-arg callback of func_800170E8): copies the spawn position, builds two vertex-delta rows scaled by D_80078244 with the third row zeroed, shares the AF30-family texture flags block, and seeds rand tumble + a rotation matrix in data+0xC. Key derivations: the three def indices load into int locals up front (def[1] stays registered until vc), the posX store stretches past the va address math via a ushort px0 local, and unk34=0 sits after unk30. KUNGFU gains the ParticleData typedef from LOONEY.
- MOOSHU func_8015D190_C5B10 (44 insns): moodam intro-flag scan loop - RTA func_8015B4EC_DBB5C (47 insns): particle ground-bounce callback. New GCC 2.7.2 recipes recorded in CLAUDE.md: store-before-reread forces a genuine field reload (cse conservative memory invalidation), inline compound RMWs evict the param to a2 via local-alloc pressure, and A += A*2 vs A *= 3 addu operand-order/dest differences.
- func_80162024/80162118/80162214 (61/63/52): rotation-transform trio, siblings of func_80161F4C with vec=(0,±0x40,0) and by-value SVECTOR offset - func_801622E4 (62): camera-key switcher — ternary condition with per-arm flag tests, base pointer kept live across func_8000B054 call - func_8016257C (52): camera-key prober — duplicated store tails, two-statement lock mask clears
- rta_zshark_OnCreate (58): flags-guarded matrix transform; 16-byte SharkVector struct copy, RotMatrixFull + ApplyMatrixLV into work6-8 - rta_zwleak_OnCollide (60): player-data impulse writeback with signed div-by-15 magic multiplies. Matched via extern void declarations for func_8000B054/func_800256A8 — implicit-int callees reserve a phantom v0 return pseudo that flips mflo temp coalescing ties (new recipe)
Target/Position HUD readouts (X/Y/Z via the 4-digit hex formatter). Three linked recipes: D_800BDEE4 as a separate scalar extern (per-store assembler-macro sw) alongside the D_800BDEE0 array (cached base); pointer-deref arg spelling to keep the coordinate loads below the global stores (array-index form hoists them and loses the hazard nop); per-print constants routed through a rotating local
…atBourgon#132) - final_finaltv_OnUpdate (44): abs() clamp condition - looney_funguy_OnCreate (38): early-cached work0 pointer - circuit_orbplat_OnCreate (60): plain inline transforms, ascending work-store order; (short) casts added for our implicit sin/cos decls
- func_8015CDF0 (70): Coordinates/Subject debug print (print-twin recipes) - func_8015CF08 (68): debug rect frame draw; first store shares the call-arg address register, remaining stores via separate scalar externs - func_8015D018 (116): 30x remsfx particle spawner. Dead reassignment of the lifetime local blocks loop-invariant motion from stealing a saved register from the callback addresses (commented in code). Added OBTABLE.h include with (int) casts at existing callers
Spline-driven skeleton hand (66 insns): parent-death kill, spline process with plain-death + sound, and a work6 event-list scanner. The event counter store rides the jal delay via a postincrement call argument; work0 frame compare reads the short half
Spline segment-offset accumulator (67 insns): walks the intro group writing per-instance work3 offsets from the multispline frame-length table, with an introData skip-list. Outer goto-loop per the LIM rule; inner accumulate loop uses while (++frame < end) so the increment fills the lhu delay slot
- func_8015E5E0 (69): rotation-target smoother, p = (p*3 + offset)/4 per axis through three LVECTOR locals; dead 16-byte local for the 0x60 frame - func_8015B220 (69): animation-frame advancer with wrap flags; short f = ++currentAnimFrame shares one sign-extension across both range compares
Waypoint trap mover init (70 insns, matched first try): default intro/object-data blob fallbacks, waypoint index advance with wrap, aim via the ratan2 SVECTOR-delta idiom with cached &work0 pointer
- func_8015B8B0 (72): mooelec spawner/attach with birth-and-link. Signed (Instance*, GameTracker*) with gameTracker unused to match the caller mooshu_moolevr_OnCollide, whose 2-arg call is part of its already-matched codegen (Object* typing on FindObject) - rezop_crnkplt_OnUpdate (72): crank-plate spring physics. Intro unk14 is position.z; both clamp compares evaluate the pos+shift side first; shared int one for the state pair with a literal 1 in the spline compare to keep its register at t1
Camera-follow state machine (73 insns): intro-flag gated flag toggle, countdown, spline-signal dispatch on currentMainState. The trailing state increment reads the field inline to reload into the right register (a reused local kept its pseudo live)
Water-leak init (77 insns): memset the work block, sin/cos launch vector from intro angle, three magic-mult offset writes. Compute work8 into an int first (front-loads its mult to match the ROM schedule) and cast position.z unsigned for the lhu the truncated store allows
Bullet-vs-target collision (74 insns): player passthrough, parentName G2String match, hit-state advance. Caches &work0 as long* for the work1 store, casts the rand spread to short for func_80050508
Spline-ride mount init (76 insns): freeze-flag early-out, spline setup with quaternion-to-matrix seeding, frame-count spline set. Caches player->intro into a local to hoist its load ahead of the flag store, matching the ROM schedule
Cow collision handler (77 insns): player-spline match sets flag bits, then two state branches (moodam charge vs generic bump). Passes the collision struct pointer to func_80022714/38 (keeps a3 live so the byte checks reload), and int flags to coalesce onto the arg register
Switch collision handler (75 insns, leaf): player-hit gated state machine with goto cross-jumps for the three activation paths, toggling intro flag 0x800 on a match. D_8015EE00/EDFE typed unsigned short so the reads emit lhu (a lh/lhu diff the reloc-masked per-function differ missed; caught by the clean ROM)
Swing pendulum init (78 insns): randomized phase, amplitude from object data with a signed short divide, an amplitude^2 rounding step, and the position->work unaligned SVECTOR copy. int (not short) abs temp negates in-register and avoids an 8-byte frame spill
horror_drawer_OnUpdate: goto cross-jump state machine (scale-pulse door), duplicated shared tails into each arm per the cross-jump rule. kungfu_kbgen_OnUpdate: OBTABLE/BirthObject spawner; in-place work0 increment forwards without reload, cached unk8 load fills the branch delay slot.
Init handler: caches instance->parent, reloads parent->0xF6 for each 0x2000/0x1000 division into work1/scale, and a rand-seeded work9.
Scale-pulse boss state machine; states 1/2 share a scale.y/scale.z store tail (block_9), reproduced by duplicating the tail into each arm per the cross-jump rule. arg1->0xC is gameTracker->player.
Projectile: gravity clamp, ground check, cos/sin movement (state 0), spawn + lifetime kill (state 1). Ground-check comparison written position-first to match the target's load order. Corrected func_8015D7B4_C6134 to 1-arg (its gameTracker param was unused and the sole caller passes only instance->parent).
Switch-based sound state machine; the work0 respawn call (block_16) is duplicated into both else-arms per the cross-jump rule, and GCC merges them. intro->_2C gate sets state 2; case 0 falls through to case 1.
Switch init: shared-variable flag ORs (flags|0x400, flags|0x480), intro flag gates, memset of the work block, and a D_8015EDFE sound-bit toggle. soundBit is int (forces lh); storing to the global directly per arm (no temp) lets GCC hoist the nor into the branch delay slot.
Player-collision handler: 4-clause guard (bsp->_06, instanceSpline==player,
currentMainState not in {1,2}, globalOffset.x), then swaps player position.y/x
with work1 by state, and fires COLLIDE_HandleSignal once (work4 latch).
bsp->_06 cached as the shared '1' value across the compares.
Save-state: copies 25 transform fields from arg0 into the D_8015EED0 buffer. Consolidated the consecutive destination globals into one array (links identically to the separate symbols); last field (0x54) is an int copy, the rest short.
Restore twin of func_8015E27C: copies the D_8015EED0 save buffer back into arg0's 25 transform fields. Int field (0x54, D_8015EF08) goes last in source (m2c ordered it from the schedule); rest are short via the consolidated array.
Particle-vertex RMW: adjusts the 6 vertex deltas (or 3 positions by velocity) on the particle and its linked twin (arg0->unk4). Reassigning the same pointer (p = p->unk4) reuses s0 and blocks the early hoist of the twin-pointer load.
Camera-lock setup (twin of func_8015ADC4): saves player state to D_800785C8, forces state 5, CAMERA_SetMode, builds the mid/rot vectors, sets the camera position, and mirrors the core vectors. gameTracker8 cached in a local for the position sets; rot.z written last to match the load scheduling.
Bubble spawner: births a blububl_ when currentModelAnim is 0xB/0xC, sets its rotation/position from oldMatrix[5] (euler + translation) or the instance position (SVECTOR assignment for the unaligned copy). arg1->unk98 reloaded inline each store to match.
Animation state machine: frame advance (speed==0) or accumulator-driven (acc<<16>>18) with a two-way ternary clamp. frame0 is int (forces lh); clamp tail (flags2 |= 0x10) duplicated into both arms per cross-jump; func_80050400 takes the 0x5F byte (currentAnimFrame high byte).
Spline object spawner: births a cached object, gates on the object name (G2String vs ppathd__), then seeds position/scale from the two splines of ((Intro**)intro->_04)[1]->multiSpline via SplineGetFirstPoint. Cached &_04[1] as the surviving base to match the strength-reduced addressing.
… position fields) Pre-emptively applies PR MatBourgon#134 review feedback to july20's debug-print functions (func_8015CDF0 new here), which had independently reproduced the D_800BDEE4 split and raw position-deref patterns the leader corrected.
Spline midpoint/direction check. Reads arg3 via leftover a3 (callers pass 3 args); unprototyped forward decl keeps the 3-arg call sites clean. Key levers: load dir after the count call (avoids an extra saved reg), unsigned short frame, short count for per-arm re-extension, and (short)frame-first operand order in both comparison arms.
…uly20 # Conflicts: # src/level/HORROR.c # src/level/KUNGFU.c # src/level/LOONEY.c # src/level/MOOSHU.c # src/level/RTA.c
splat64 0.50.0 stopped generating nonmatchings .s files for c segments, breaking INCLUDE_ASM builds in CI (requirements.txt was unpinned at >=0.38.0). 0.41.1 (what master's passing CI used) generates them correctly.
MatBourgon
reviewed
Aug 18, 2026
| func_8015D780_84960(instance, gameTracker); | ||
| } else if (state == -1) { | ||
| if (func_800257B4(gameTracker->player) != 0) { | ||
| v = ((int*)instance->introData); |
MatBourgon
reviewed
Aug 18, 2026
| obj->position.y = pt->y; | ||
| obj->position.z = pt->z; | ||
| } | ||
| spline2 = ((int*)v1[0]->multiSpline)[0x8/4]; |
Owner
There was a problem hiding this comment.
Should probably be v1[0]->multiSpline->scaling
MatBourgon
reviewed
Aug 18, 2026
| INSTANCE_InsertInstanceWithFlagsCleared(obj, 0xF000); | ||
| } | ||
| obj->work4 = 0; | ||
| pt = SplineGetFirstPoint(((Spline**)v1[0]->multiSpline)[0], (SplineDef*)&obj->work0); |
Owner
There was a problem hiding this comment.
Should probably be v1[0]->multiSpline->positional
MatBourgon
reviewed
Aug 18, 2026
| sum = 0; | ||
| n = d[0] - 1; | ||
| if (((Intro**)d)[1]->multiSpline != 0) { | ||
| sd = ((int**)((Intro**)d)[1]->multiSpline)[0]; |
MatBourgon
reviewed
Aug 18, 2026
| void func_8015DB80_84D60(Instance* instance) { | ||
| int* d; | ||
| int* sd; | ||
| int* intro2; |
Owner
There was a problem hiding this comment.
intro2 but no intro or intro1?
MatBourgon
reviewed
Aug 18, 2026
| } | ||
|
|
||
| INCLUDE_ASM("asm/nonmatchings/level/CIRCUIT", func_8015DB80_84D60); | ||
| void func_8015DB80_84D60(Instance* instance) { |
Owner
There was a problem hiding this comment.
This function is kind of a mess, especially with the not really obviously named variables, but at least it matches.
MatBourgon
reviewed
Aug 18, 2026
| Instance* born; | ||
| short count; | ||
|
|
||
| intro = instance->object->data; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Census-sweep batch stacked on the merged #134 — ~30 level functions across CIRCUIT, FINAL, GEXZIL, HORROR, KUNGFU, LOONEY, MOOSHU, REZOP, and RTA. The bulk are structural handlers (OnCreate/OnCollide/OnUpdate init, spawn, and state-machine functions), where the hit rate is much higher than the low-70s math/physics tier. All verified with a clean
make build && make diff(No differences found).Functions
CIRCUIT —
func_8015D7F0(spline object spawner),func_8015DB80,circuit_follow_OnUpdateFINAL —
func_8015AC70(camera-lock),func_8015CDF0/func_8015CF08(debug HUD),func_8015D018(particle spawner),final_lectro_OnUpdateGEXZIL —
func_8015C208(anim state machine),func_8015E8C0(bubble spawner),func_8015B220HORROR —
horror_skelh_OnUpdate,horror_drawer_OnUpdate,horror_polter_OnUpdate,horror_fltchst_OnCollideKUNGFU —
kungfu_kbgen_OnUpdate,kungfu_swing_OnCreate,kungfu_joyride_OnCreate,kungfu_dragflm_OnCreateLOONEY —
looney_bullet_OnCollide,looney_trapmuv_OnCreateMOOSHU —
func_8015B39C(spline midpoint check),func_8015B8B0,mooshu_moo_OnCollide,mooshu_moosprk_OnUpdateREZOP —
func_8015ECB8(particle RMW),rezop_crnkplt_OnUpdateRTA —
func_8015E27C/func_8015E3AC(save/restore twins),func_8015E5E0,func_8015B4EC,rta_zwleak_OnCreate,rta_zswitch_OnCreate/_OnCollideTechniques
func_8015B39C): callee readsa3while callers pass 3 args; an unprototyped forward decl keeps the call sites warning-free.</>split).unsigned short/shortreturn-type matching to reproduce the target'slhuvslhand per-arm promotions.