Skip to content

Refactor game mode system to fix level data synchronization#713

Merged
JamesVanBoxtel merged 2 commits into
panel-attack:betafrom
JamesVanBoxtel:levelDataMismatchPR
Oct 25, 2025
Merged

Refactor game mode system to fix level data synchronization#713
JamesVanBoxtel merged 2 commits into
panel-attack:betafrom
JamesVanBoxtel:levelDataMismatchPR

Conversation

@JamesVanBoxtel
Copy link
Copy Markdown
Contributor

Fixes #698

Various problems existed with the style system and classic endless mode and updating settings. The style wasn't updated all the time, and it wasn't preserved when opening the game again. In addition style settings could carry over to other game types.

To fix this I have made a formal GameMode class that makes sure all the derived settings are updated when settings like style update. I also added a preferred style for tracking what the user picked, similar to how stages and characters work. The other clients only know about your "style" not preferred style, and thats only derived since we don't currently send style through the server messages.

  • Convert GameMode to proper class with methods
  • Separate UI style preference from game state style setting
  • Centralize level data updates in GameMode callbacks
  • Ensure consistent settings between client and server
  • Also fixed a challenge mode JSON serialization crash by using our JSON sanitizer again.

Fixes panel-attack#698

Various problems existed with the style system and classic endless mode and updating settings.
The style wasn't updated all the time, and it wasn't preserved when opening the game again. In addition
style settings could carry over to other game types.

To fix this I have made a formal GameMode class that makes sure all the derived settings are updated when settings like style update.
I also added a preferred style for tracking what the user picked, similar to how stages and characters work.
The other clients only know about your "style" not preferred style, and thats only derived since we don't currently send style through the server messages.

  - Convert GameMode to proper class with methods
  - Separate UI style preference from game state style setting
  - Centralize level data updates in GameMode callbacks
  - Ensure consistent settings between client and server
  - Also fixed a challenge mode JSON serialization crash by using our JSON sanitizer again.
Comment thread common/data/GameModes.lua
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.

Semantically it does not seem right to have references to the client in this file. common/data declares the intent for this to be interoperable data or a data class with no direct dependencies; adding functions that directly refer to client-side data and functions breaks with that distinction.

I think we should keep GameModes as data and instead utilize these style based update functions on the client-side only.
With their current usage it would seem most intuitive to move updateLocalPlayersDerivedSettings to BattleRoom. If GameModes keep the style flag for now, that function could simply check the flag to select the appropriate update function rather than them being baked into the GameMode itself, e.g.

function BattleRoom:updateLocalPlayersDerivedSettings(player)
  if self.mode.style == GameModes.Styles.CHOOSE then
    if self.mode.name == "endless" then
      -- updateEndlessStyleBasedSettings
    else
      -- updateStyleBasedSettings
    end
  elseif self.mode.style == GameModes.Styles.MODERN then
    -- updateModernSettings
  end
end

I think this also makes sense semantically as for the GameMode itself, the style is effectively irrelevant - style distinction is a pure client-side concern and we only communicate it server side for display purposes on spectator clients, not because it is actually relevant to the GameMode itself.
Arguing that way I realize that maybe it shouldn't be present as a flag on GameMode at all but for now it ended up there out of pragmatic concerns alongside a few other magic strings and we should try to only entangle it less with client-side concerns, not more.

Comment thread client/src/scenes/EndlessMenu.lua
UI changes → setLevelData() → levelDataChanged signal → auto-updates style/difficulty/level/UI/config
Each character select subclass knows what difficulty / level / style mean and update accordingly.
The server doesn't need to know about style at all.
LevelPresets.lua : Added classicEndless presets (5 colors for easy), getStyleAndPreset() to detect which preset a levelData matches
This lets us support more presets later and update the UI to show something reasonable when level data doesn't match a preset.
Copy link
Copy Markdown
Collaborator

@Endaris Endaris left a comment

Choose a reason for hiding this comment

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

Didn't really look over it in detail, thanks for the adjustments to the architecture.
Feel free to land if you think it's good.

@JamesVanBoxtel JamesVanBoxtel merged commit a661326 into panel-attack:beta Oct 25, 2025
2 checks passed
@JamesVanBoxtel JamesVanBoxtel deleted the levelDataMismatchPR branch October 25, 2025 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash matching garbage, GARBAGE_HOVER nil

2 participants