Skip to content

Rename the stage id enums to the game's own grkind/stkind - #2969

Merged
ribbanya merged 9 commits into
doldecomp:masterfrom
MarkMcCaskey:rename-grkind-stkind
Jul 25, 2026
Merged

Rename the stage id enums to the game's own grkind/stkind#2969
ribbanya merged 9 commits into
doldecomp:masterfrom
MarkMcCaskey:rename-grkind-stkind

Conversation

@MarkMcCaskey

@MarkMcCaskey MarkMcCaskey commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

@ribbanya noticed that via a debug print that these have existing names we can use. This PR follows up on #2939 to use these names which is more consistent with the style of this repo.

From Claude:

ground.c reports a failed stage-param lookup as "not found stage param in DAT(grkind=%d stkind=%d,num=%d)", filling the varargs from stage_info.internal_stage_id and StageIdPair::external_id (GALE01 0x801C2A48). So grkind is what this tree calls InternalStageId and stkind is ExternalStageId.

The stkind reading is independently checkable off the disc: the list Ground_801C28CC searches is the archive's grGroundParam public symbol, so its keys ship in the Gr??.dat files. Across the 279 stage_id_map entries whose two ids differ, 271 archives are keyed by the external id and none by the internal one; GrSt.dat is grkind 10 keyed 0x08, GrCs.dat is grkind 2 keyed 0x04, and GrNBa.dat holds 18 rows, one per mode variant built on that ground. Forcing the lookup to miss in Dolphin reports grkind=22 stkind=26,num=9 for the second Icicle Mountain entry, matching the live internal id and the selected external id.

Only the enum type names and the InternalStageID_/ExternalStageID_ member prefixes change; the unprefixed stage names and all field names are untouched. All 21 affected translation units compile byte-identical.

Field names (internal_stage_id, internal_id, external_id) are untouched; that's ~106 sites across 19 TUs if review wants the terms carried through there too.

More in depth evidence here https://github.com/MarkMcCaskey/melee-runtime-audits/blob/main/grkind-stkind/README.md

From Claude:

This is also why the lookup exists: one grkind (one ground archive) carries many stkind rows — Battlefield's file holds 18, one per 1P/event variant that reuses that ground.

Also renamed the variable / member names that still say internal/external. And applied findings downstream of this; there's evidence for some more names for followups:

  1. grGroundParam for the type currently called UnkStage6B0 (stage_info.param). Not inferred at all — it's the literal archive symbol the game looks up: HSD_ArchiveGetPublicAddress(sp14, "grGroundParam") in grdatfiles.c.
  2. Its xB0 / xB4 are the stage-param row array and its count — the same message names them: "not found stage param… num=%d", and xB4 is exactly the loop bound over xB0.
  3. UnkBgmStruct is a stage-param row, not a BGM struct, and its x0 is the stkind key — the sibling message prints each row's x0 as " stageid=%d", and both search loops (Ground_801C28CC, Ground_801C24F8) match it against a stkind. BGM is just one field on the row (x4). Provenance for the row data is in the message too: StageParam.csv / StageItem.csv, stdata.c.

ground.c reports a failed stage-param lookup as "not found stage param in DAT(grkind=%d stkind=%d,num=%d)", filling the varargs from stage_info.internal_stage_id and StageIdPair::external_id (GALE01 0x801C2A48). So grkind is what this tree calls InternalStageId and stkind is ExternalStageId.

The stkind reading is independently checkable off the disc: the list Ground_801C28CC searches is the archive's grGroundParam public symbol, so its keys ship in the Gr??.dat files. Across the 279 stage_id_map entries whose two ids differ, 271 archives are keyed by the external id and none by the internal one; GrSt.dat is grkind 10 keyed 0x08, GrCs.dat is grkind 2 keyed 0x04, and GrNBa.dat holds 18 rows, one per mode variant built on that ground. Forcing the lookup to miss in Dolphin reports grkind=22 stkind=26,num=9 for the second Icicle Mountain entry, matching the live internal id and the selected external id.

Only the enum type names and the InternalStageID_/ExternalStageID_ member prefixes change; the unprefixed stage names and all field names are untouched. All 21 affected translation units compile byte-identical.
@MarkMcCaskey MarkMcCaskey added the ai-assisted Utilizes a LLM to do the heavy lifting label Jul 25, 2026
@decomp-dev

decomp-dev Bot commented Jul 25, 2026

Copy link
Copy Markdown

Report for GALE01 (9d9c8b7 - 6a1afcf)

No changes

@MarkMcCaskey
MarkMcCaskey marked this pull request as ready for review July 25, 2026 01:11

@ribbanya ribbanya left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's do another renaming pass. We need to rename internal_stage_id wherever it shows up to grkind and external_stage_id to stkind. If something is a shortened form like stage_id now, we can just rename that to kind. Examples in comments below.

Comment thread src/melee/gr/ground.c Outdated
Comment thread src/melee/gm/gm_1832.c Outdated
Comment thread src/melee/gr/stage.h Outdated
@MarkMcCaskey
MarkMcCaskey marked this pull request as draft July 25, 2026 01:29

@ribbanya ribbanya left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apply these too.

  1. grGroundParam for the type currently called UnkStage6B0 (stage_info.param). Not inferred at all — it's the literal archive symbol the game looks up: HSD_ArchiveGetPublicAddress(sp14, "grGroundParam") in grdatfiles.c.
  2. Its xB0 / xB4 are the stage-param row array and its count — the same message names them: "not found stage param… num=%d", and xB4 is exactly the loop bound over xB0.
  3. UnkBgmStruct is a stage-param row, not a BGM struct, and its x0 is the stkind key — the sibling message prints each row's x0 as " stageid=%d", and both search loops (Ground_801C28CC, Ground_801C24F8) match it against a stkind. BGM is just one field on the row (x4). Provenance for the row data is in the message too: StageParam.csv / StageItem.csv, stdata.c.

grdatfiles.c fetches StageInfo::param by name: HSD_ArchiveGetPublicAddress(archive, "grGroundParam"), so UnkStage6B0 is the archive's grGroundParam and is renamed GroundParam.

ground.c names the rows it points at. Ground_801C28CC reports a miss as "not found stage param in DAT(grkind=%d stkind=%d,num=%d)" followed by "check StageParam.csv or StageItem.csv, stdata.c", and then lists every row as " stageid=%d" -- printing the field this tree called UnkBgmStruct::x0. num is the loop bound, so xB0/xB4 are the stage param array and its count, and x0 is the key both searches compare against. That key is a stkind: Ground_801C0754 passes StageIdPair::external_id, and every Gr??.dat on the disc is keyed the same way (271 of the 279 stage_id_map entries whose two ids differ are keyed by the external id, none by the internal one). Hence StageParam::stkind, GroundParam::stage_params and GroundParam::stage_param_count.

BGM is one field on such a row rather than the point of the struct, so the local named bgm in Ground_801C28CC becomes param. grdatfiles.c's no-archive fallback fits: a one-row list (stage_param_count 1) whose row is stkind 0 with BGM -1.

ground.c and grdatfiles.c compile byte-identical.

@ribbanya ribbanya left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could be wrong but it doesn't look like any of the GrKind enum members appear in asserts, in which case they should be renamed with the GrKind prefix. Both enums should use upper camel case instead of all-caps.

For what it's worth, the stage names mostly appear in if/soundtest starting at un_803FAB10:

TEST    
Izumi   
PStadium
Castle  
Kongo   
Zebes   
Corneria
Story   
Onett   
MuteCity
RCruise 
Garden  
GreatBay
Shrine  
Kraid   
Yoster  
Greens  
Fourside
Inishie1
Inishie2
Akaneia 
Venom   
Pura    
BigBlue 
Icemt   
Icetop  
Flatzone
old ppp 
old yosh
old kong
battle  
last    
TMario  
TCaptain
TClink  
TDonkey 
TDrmario
TFalco  
TFox    
TIceclim
TKirby  
TKoopa  
TLink   
TLuigi  
TMars   
TMewtwo 
TNess   
TPeach  
TPichu  
TPikachu
TPurin  
TSamus  
TSeak   
TYoshi  
TZelda  
TGamewat
TEmblem 
TGanon  

Follows the review on doldecomp#2969: internal_stage_id becomes grkind, external stage ids become stkind, and shortened forms like stage_id become kind where the enum type already says which space it is.

StageInfo::grkind, StageData::grkind, StageIdPair::{grkind,stkind}, the stage_id_map entry and selection fields, the Stage_ setup parameters, and the preload cache's stkind all follow their types. The four ground.c lookups that search StageParam::stkind take a named StKind parameter now, and gm_80187F48_GetStageId becomes gm_GetStKind over a stkind field, as suggested in review.

Fighter-side internal_id in ft/ and pl/ is an unrelated character id and is untouched; StartMeleeRules::xE keeps its offset name.

All 37 affected translation units compile byte-identical.
@MarkMcCaskey

Copy link
Copy Markdown
Collaborator Author

@ribbanya For code style do you prefer inline comments justifying names or should that just be left in git history? Don't want to spam unnecessary comments but I can see how this could be helpful info for determining that this is a correct and justified name.

@MarkMcCaskey

Copy link
Copy Markdown
Collaborator Author

Comments like

/// The numbering used by #StartMeleeRules::xE and Stage_802251E8.
/// #stage_id_map converts it to #GrKind, and each archive's @c grGroundParam
/// list is keyed by it; entries 0x21+ are single-player, event, and other mode
/// variants.
///
/// Both names come from ground.c's report
/// `not found stage param in DAT(grkind=%d stkind=%d,num=%d)`, which passes
/// #StageInfo::grkind and then this value.
typedef enum StKind {

Are borderline LLM slop just due to length. It is useful info but it's also encoding a lot of info that's not directly relevant to the type.

@ribbanya

ribbanya commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

It's... slop. But it's all immediately verifiable. If anything, it just needs an editing pass and/or for the information to be spread out across different members in the docs. For now just change it to a multiline doc comment:

/** @remarks
 * The numbering used by #StartMeleeRules::xE and Stage_802251E8.
 * #stage_id_map converts it to #GrKind, and each archive's @c grGroundParam
 * list is keyed by it; entries 0x21+ are single-player, event, and other mode
 * variants.
 *
 * Both names come from ground.c's report
 * `not found stage param in DAT(grkind=%d stkind=%d,num=%d)`, which passes
 * #StageInfo::grkind and then this value.
 */

@MarkMcCaskey

MarkMcCaskey commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator Author

I could be wrong but it doesn't look like any of the GrKind enum members appear in asserts, in which case they should be renamed with the GrKind prefix. Both enums should use upper camel case instead of all-caps.

For what it's worth, the stage names mostly appear in if/soundtest starting at un_803FAB10:

...

Sounds good, yeah they're unjustified. 2 stages appear in all caps anywhere in the DOL it seems but it's not a consistent thing. Is GrKind fine or should it be Gr_Kind like It_Kind_*'s style?

@ribbanya

Copy link
Copy Markdown
Collaborator

Oh right, I forgot about It_Kind_. That's from asserts, so yeah, go with that.

@ribbanya

Copy link
Copy Markdown
Collaborator

@ribbanya For code style do you prefer inline comments justifying names or should that just be left in git history? Don't want to spam unnecessary comments but I can see how this could be helpful info for determining that this is a correct and justified name.

I missed this earlier. I think it's preferable to have it live in the repo in some form so that it can be cleaned up later. I consider issues, PRs, Discord, and even the wiki to be transient. If it's kind of sus then you can always put it in .dox or a whole separate page in /docs/ if necessary.

The ALL-CAPS spellings were invented: of 41 probed, only TEST (verbatim in the develop-mode stage list) and BATTLE (inside grbattle.c's i<BATTLE_BG_MAX assert) appear in main.dol at all, and none as enum members. Two sources do name these stages, so the members follow them, prefixed like It_Kind_ per CONTRIBUTING.

GrKind takes the per-stage gr*.c module names the asserts embed, which 70 of its 71 members already matched; the exception was ICEMTN, whose module is gricemt.c, so it becomes Gr_Kind_Icemt. StKind takes the develop-mode stage list (strings at 0x803FAB04, pointers at 0x803FAF0C, 86 entries indexed 0x00..0x55, aligning with stkind: 0x02 Izumi, 0x49 8-1bbroute, 0x55 heal). That list names three holes: 0x00 Dummy, 0x15 Akaneia, 0x1A Icetop, the last being one of the two stkinds with no grGroundParam row.

The two sources disagree on Yoshi's Island, so St_Kind_Yoster follows the list and Gr_Kind_Yorster follows gryorster.c, with a note at the member. Entries the list names beyond 0x20 are not added here.

Also gives both enums hex value prefixes and moves the multi-line doc comments to block style. All 83 affected translation units compile byte-identical.
Comment thread src/melee/mp/mplib.c Outdated
Comment thread src/melee/mp/mplib.c Outdated
Comment thread src/melee/gr/grcorneria.c Outdated
Comment thread src/melee/gr/forward.h Outdated
…rectives

The two /// clang-format off|on lines in mplib.c never did anything: clang-format only honours the // and /* */ forms, so the table they wrapped was being reflowed regardless.
@ribbanya

Copy link
Copy Markdown
Collaborator

I probably don't have time to merge it tonight but looks good to me at first glance.

@ribbanya ribbanya left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you do me a favor and have Claude output everything it renamed in this PR in the form of FROM:TO (melee-replace-symbols format) including field names, locals, etc.? I have a parallel PR that is going to conflict with this so it would help a lot.

@MarkMcCaskey

Copy link
Copy Markdown
Collaborator Author

I probably don't have time to merge it tonight but looks good to me at first glance.

Sounds good, take your time! And I really appreciate all the feedback and help!

I'll self review it as a whole as well and take it out of draft mode after I do if it looks good to me.

@MarkMcCaskey

Copy link
Copy Markdown
Collaborator Author

Could you do me a favor and have Claude output everything it renamed in this PR in the form of FROM:TO (melee-replace-symbols format) including field names, locals, etc.? I have a parallel PR that is going to conflict with this so it would help a lot.

Here's the list (with commentary) from Claude:

# PR #2969 renames, FROM:TO (tools/replace-symbols)
#
# Section 1 is safe to feed straight in: every one of these old names
# occurs only in files this PR touches.

InternalStageId:GrKind
ExternalStageId:StKind
UnkStage6B0:GroundParam
UnkBgmStruct:StageParam
gm_80187F48_GetStageId:gm_GetStKind
internal_stage_id:grkind
InternalStageID_Unk00:Gr_Kind_Unk00
CASTLE:Gr_Kind_Castle
RCRUISE:Gr_Kind_RCruise
KONGO:Gr_Kind_Kongo
GARDEN:Gr_Kind_Garden
GREATBAY:Gr_Kind_GreatBay
SHRINE:Gr_Kind_Shrine
ZEBES:Gr_Kind_Zebes
KRAID:Gr_Kind_Kraid
STORY:Gr_Kind_Story
YORSTER:Gr_Kind_Yorster
IZUMI:Gr_Kind_Izumi
GREENS:Gr_Kind_Greens
CORNERIA:Gr_Kind_Corneria
VENOM:Gr_Kind_Venom
PSTADIUM:Gr_Kind_PStadium
PURA:Gr_Kind_Pura
MUTECITY:Gr_Kind_MuteCity
BIGBLUE:Gr_Kind_BigBlue
ONETT:Gr_Kind_Onett
FOURSIDE:Gr_Kind_Fourside
ICEMTN:Gr_Kind_Icemt
InternalStageID_Unk23:Gr_Kind_Unk23
INISHIE1:Gr_Kind_Inishie1
INISHIE2:Gr_Kind_Inishie2
InternalStageID_Unk26:Gr_Kind_Unk26
FLATZONE:Gr_Kind_Flatzone
OLDPUPUPU:Gr_Kind_OldPupupu
OLDYOSHI:Gr_Kind_OldYoshi
OLDKONGO:Gr_Kind_OldKongo
KINOKOROUTE:Gr_Kind_KinokoRoute
SHRINEROUTE:Gr_Kind_ShrineRoute
ZEBESROUTE:Gr_Kind_ZebesRoute
BIGBLUEROUTE:Gr_Kind_BigBlueRoute
InternalStageID_Unk35:Gr_Kind_Unk35
BATTLE:Gr_Kind_Battle
LAST:Gr_Kind_Last
FIGUREGET:Gr_Kind_FigureGet
PUSHON:Gr_Kind_Pushon
TMARIO:Gr_Kind_TMario
TCAPTAIN:Gr_Kind_TCaptain
TCLINK:Gr_Kind_TClink
TDONKEY:Gr_Kind_TDonkey
TDRMARIO:Gr_Kind_TDrmario
TFALCO:Gr_Kind_TFalco
TFOX:Gr_Kind_TFox
TICECLIMBER:Gr_Kind_TIceclimber
TKIRBY:Gr_Kind_TKirby
TKOOPA:Gr_Kind_TKoopa
TLINK:Gr_Kind_TLink
TLUIGI:Gr_Kind_TLuigi
TMARS:Gr_Kind_TMars
TMEWTWO:Gr_Kind_TMewtwo
TNESS:Gr_Kind_TNess
TPEACH:Gr_Kind_TPeach
TPICHU:Gr_Kind_TPichu
TPIKACHU:Gr_Kind_TPikachu
TPURIN:Gr_Kind_TPurin
TSAMUS:Gr_Kind_TSamus
TSEAK:Gr_Kind_TSeak
TYOSHI:Gr_Kind_TYoshi
TZELDA:Gr_Kind_TZelda
TGAMEWATCH:Gr_Kind_TGamewatch
TEMBLEM:Gr_Kind_TEmblem
TGANON:Gr_Kind_TGanon
HEAL:Gr_Kind_Heal
HOMERUN:Gr_Kind_Homerun
FIGURE1:Gr_Kind_Figure1
FIGURE2:Gr_Kind_Figure2
FIGURE3:Gr_Kind_Figure3
ExternalStageID_Unk00:St_Kind_Dummy
ExternalStageID_TEST:St_Kind_Test
ExternalStageID_IZUMI:St_Kind_Izumi
ExternalStageID_PSTADIUM:St_Kind_PStadium
ExternalStageID_CASTLE:St_Kind_Castle
ExternalStageID_KONGO:St_Kind_Kongo
ExternalStageID_ZEBES:St_Kind_Zebes
ExternalStageID_CORNERIA:St_Kind_Corneria
ExternalStageID_STORY:St_Kind_Story
ExternalStageID_ONETT:St_Kind_Onett
ExternalStageID_MUTECITY:St_Kind_MuteCity
ExternalStageID_RCRUISE:St_Kind_RCruise
ExternalStageID_GARDEN:St_Kind_Garden
ExternalStageID_GREATBAY:St_Kind_GreatBay
ExternalStageID_SHRINE:St_Kind_Shrine
ExternalStageID_KRAID:St_Kind_Kraid
ExternalStageID_YORSTER:St_Kind_Yoster
ExternalStageID_GREENS:St_Kind_Greens
ExternalStageID_FOURSIDE:St_Kind_Fourside
ExternalStageID_INISHIE1:St_Kind_Inishie1
ExternalStageID_INISHIE2:St_Kind_Inishie2
ExternalStageID_Unk21:St_Kind_Akaneia
ExternalStageID_VENOM:St_Kind_Venom
ExternalStageID_PURA:St_Kind_Pura
ExternalStageID_BIGBLUE:St_Kind_BigBlue
ExternalStageID_ICEMTN:St_Kind_Icemt
ExternalStageID_Unk26:St_Kind_Icetop
ExternalStageID_FLATZONE:St_Kind_Flatzone
ExternalStageID_OLDPUPUPU:St_Kind_OldPupupu
ExternalStageID_OLDYOSHI:St_Kind_OldYoshi
ExternalStageID_OLDKONGO:St_Kind_OldKongo
ExternalStageID_BATTLE:St_Kind_Battle
ExternalStageID_LAST:St_Kind_Last
ExternalStageID_BIGBLUEROUTE:St_Kind_BigBlueRoute
ExternalStageID_HEAL:St_Kind_Heal

# ---------------------------------------------------------------------
# Section 2: same rename, but the old name also appears somewhere this PR
# did NOT touch, so a global replace would hit unrelated code.

# TEST:Gr_Kind_Test   <-- also in: src/melee/ft/ft_0877.c

# ---------------------------------------------------------------------
# Section 3: struct fields whose old name is generic. Scope, not global.

# internal_id:grkind   [StageIdPair, StageIdMapEntry (gr/ only; ft/ and pl/ have an unrelated fighter internal_id)]
# external_id:stkind   [StageIdPair, StageSelection]
# stage_id:stkind   [game_cache (lb/types.h), TmVsData (gm/types.h), gm_80187F48_EnterData (gm_1832.c)]
# x0:stkind   [StageParam only]
# xB0:stage_params   [GroundParam only]
# xB4:stage_param_count   [GroundParam only]

# ---------------------------------------------------------------------
# Section 4: locals and parameters. Same old name maps to different new
# names depending on which id space the variable holds.

# stage_id:kind   [locals in ground.c, camera.c (get_stage_floor_height param), ftCo_0A01.c]
# stage_id:stkind   [locals/params in gm_1601.c (gm_80164504), gm_1B14.c, gmclassic.c]
# stage_id:grkind   [local in gmregclear.c holding a Stage_8022519C result]
# internal_id:grkind   [local in gm_1601.c]
# external_id:stkind   [parameters of Stage_8022519C/802251B4/802251E8/802252E4/8022532C]
# arg0:stkind   [Ground_801C24F8, Ground_801C28AC, Ground_801C2AE8]
# arg1:stkind   [Ground_801C28CC]
# arg0:stkind   [lbAudioAx_80026EBC]
# bgm:param   [local in Ground_801C28CC (it walks stage params, not BGM)]
# id:grkind   [local in lbAudioAx_80026EBC]
# stage:stkind   [local in lbAudioAx_8002785C]

But feel free to land your changes first. Happy to replay these changes myself if master changes a lot.

@MarkMcCaskey MarkMcCaskey left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than the comments I mentioned and some cases where constants could be replaced by enums / better typed this is fine. I'll do a bit more clean up but otherwise looks good

Comment thread src/melee/gm/gm_1601.c
Comment thread src/melee/gm/gmhomerun.c
Replace the remaining 32-bit grkind/stkind declarations and obvious raw stage values in the rename diff with GrKind/StKind members.
@MarkMcCaskey
MarkMcCaskey marked this pull request as ready for review July 25, 2026 03:35
@ribbanya
ribbanya enabled auto-merge (squash) July 25, 2026 12:21
@ribbanya
ribbanya merged commit 6384b64 into doldecomp:master Jul 25, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-assisted Utilizes a LLM to do the heavy lifting naming

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants