Skip to content

Auto sort multiplayer fields by turn order#9723

Open
MostCromulent wants to merge 14 commits intoCard-Forge:masterfrom
MostCromulent:NetworkPlay/sortfields
Open

Auto sort multiplayer fields by turn order#9723
MostCromulent wants to merge 14 commits intoCard-Forge:masterfrom
MostCromulent:NetworkPlay/sortfields

Conversation

@MostCromulent
Copy link
Contributor

Summary

Adds an "Auto Sort Multiplayer Fields" option for 3+ player games on desktop in the Layout > View menu. When enabled, player fields are automatically reordered to follow turn order at the start of each match. Supports multiple layout modes to suit individual user preferences. Intended to reduce user friction of getting fields set up for multiplayer games.

The Problem

In multiplayer games (3+ players), by default the desktop client assigns player fields to panels in a fixed alternating pattern with no awareness of turn order or seating position. This means opponents appear in arbitrary panel positions that don't reflect the actual game flow, making it difficult to track who acts next or to visually follow the turn sequence around the table. The user has to manually re-order fields to address this each game.

The Solution

  • Turn order sorting: In 3+ player games, player fields are automatically reordered at the start of each match so the local player is at index 0 and opponents follow in turn order.
  • Preference is off by default. Enabled via toggle in Layout > View > Auto Sort Multiplayer Fields.
  • Supports different modes reflecting common user layout setups:
    • Layout:
      • Grid: Player field is in bottom left and turn order flows counterclockwise through a grid (bottom-left, top-left, top-right, bottom-right).
      • Rows: Player field alone on the bottom row, all opponents on the top row in turn order
    • Panel styles:
      • Tabbed: Multiple players in the same row share a panel and appear as tabs
      • Split: Each player gets their own visible panel, shown side by side
  • All preferences are switchable mid-game via the Layout > View menu. Layout will immediately update to reflect changed preferences. Menu items stay open when toggling options so multiple settings can be changed without reopening the menu.

Menu Options
Menu

Layout/Style Options

Split Tabbed
Grid Grid-Split Grid-Tabbed
Rows Rows-Split Rows-Tabbed

Technical Implementation

The existing DragCell layout system only supports two field panels (FIELD_0 and FIELD_1) loaded from XML layout files. Extra players (index 2+) are by default added as tabs to alternating panels with no turn-order awareness. Supporting configurable layouts for 3+ players required working within the constraint that saved layouts only define positions for two field cells.

The approach is a cleanup-and-reconstruct cycle: on each layout pass, extra field documents are stripped from their parent cells, emptied cells are removed (with adjacent cells expanded to fill gaps via fillGap), and the two base field cells are restored to their full available width. Available space is computed dynamically by scanning all non-field DragCells to find horizontal boundaries at each field row's vertical position, making the layout independent of any particular saved XML layout.

After cleanup, extra fields are assigned to cells based on the current preferences. In split mode, the base cell's percentage-based rough bounds are divided evenly and new DragCells are created for each extra player, making the layout resolution-independent. In rows mode, if the two base cells share the same row (e.g. after gap-filling absorbs a removed row), they are rearranged vertically before splitting.

Player sort order is computed in CMatchUI.sortPlayersForMultiplayer() at game start. Grid mode interleaves players across top and bottom rows for a counterclockwise visual flow; rows mode uses simple turn order.

Testing

  • Manually tested with 3 - 6 player local games
  • All preference combinations verified: Grid/Rows/Off x Tabbed/Split
  • Mid-game switching between all modes via Layout menu
  • Verified re-entering the match screen (e.g. after minimize/restore) preserves layout correctly
  • Verified saved layouts with persisted extra field cells are cleaned up correctly on reload
  • Have tested against several custom XML layout variants with success, but given very wide variety of user layouts cannot guarantee this works universally. However the implementation should be agnostic to any specific XML layout.

🤖 Code authored by Claude (Opus 4.6) under human direction.

MostCromulent and others added 10 commits February 10, 2026 21:42
Reorder player panels in 3+ player games so turns flow
counterclockwise through the visual layout (bottom-left to
top-left to top-right to bottom-right) instead of zigzagging.
Controlled by a toggleable Layout > View menu preference,
enabled by default.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace single sort toggle with two-axis preference system:
- Layout (Off/Grid/Rows) controls which cell opponents go in
- Panel Style (Tabbed/Split) controls tabs vs side-by-side panels

Grid mode uses counterclockwise flow; rows mode puts all opponents
on top. Split mode creates dynamic DragCells with percentage-based
bounds. Live relayout when preferences change mid-game. Fix duplicate
tab bug by restoring parentCell null guard in assignExtraFieldsToCells.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add early return in assignExtraFieldsToCells() when all extra fields
already have parent cells, preventing base bounds restoration from
expanding c0/c1 while dynamic cells still exist. Also reconstruct
base bounds via fillGap() instead of using stale saved values, and
add debug logging throughout the split layout path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace fragile baseRoughBounds save/restore with on-demand computation.
cleanupDynamicCells() now removes any emptied non-base cell (including
cells persisted in saved layouts) and computeFieldRegion() scans
adjacent cells to find available space. Removes all debug logging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rewrite computeFieldRegion to only skip the target cell so the
  other base cell acts as a boundary in same-row layouts
- Add fillGap before removing emptied cells to reclaim vacant space
- Sync rough bounds from pixel positions before computing field regions
- Rearrange c0/c1 vertically in ROWS mode when they share a row
- Add stay-open behavior to multiplayer field preference menu items

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rename menu label to "Auto Sort Multiplayer Fields"
- Change default layout preference from GRID to OFF
- Change default panel style from TABBED to SPLIT

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When there are 3 (or other odd number of) players, the extra
opponent is placed on the top row so the local player is alone
on the bottom row.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@tool4ever
Copy link
Contributor

I tried to rebase it on #9637
not sure I did it right?
will give this a shot in a bit

@tool4ever tool4ever added the GUI label Feb 12, 2026
@MostCromulent
Copy link
Contributor Author

I tried to rebase it on #9637 not sure I did it right?

Just tested and seems to be working properly, both with auto-sort enabled and disabled.

Separately, I was thinking may be worth including something in the wiki documentation to point this feature out but not sure where it should go? I don't think it's worth its own page like Network Play or the Yield Rework options, so maybe added as a small section in the User Guide?

(I might have a crack at fleshing out the user guide documentation a bit more thoroughly when I get time).

@tool4ever
Copy link
Contributor

sure, I did collect information about various features here:
https://github.com/Card-Forge/forge/wiki/User-Guide#Gameplay
(though technically this is not exactly that category 🤷‍♂️)

Documents the desktop drag-cell layout system (rearranging, saving/loading
XML layouts) and the new auto-sort multiplayer fields feature (sort toggle,
grid/rows layout, tabbed/split panels). Also adds a table of contents.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Contributor

@tool4ever tool4ever left a comment

Choose a reason for hiding this comment

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

seems to break loading of custom layouts even with the preference off

master:
Image

this branch:
Image

test.xml

Guard the entire sort fields workflow in populate() behind the
preference check, restoring master's i%2 tabbed behavior when OFF.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@MostCromulent
Copy link
Contributor Author

seems to break loading of custom layouts even with the preference off

This should now be fixed if you want to re-test. Original version included a preference guard but it was located in the wrong place so missed part of the cleanup workflow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants