Shuffle Tournaments Guide¶
Overview¶
Shuffle Tournaments are a unique tournament type designed for LAN parties and individual player competitions. Unlike traditional tournaments where players compete as fixed teams, shuffle tournaments dynamically reassign players to balanced teams for each round based on their ELO ratings.
Key Features:
- Individual Competition: Players compete individually, not as fixed teams
- Dynamic Team Formation: Teams are automatically balanced and reshuffled each round
- ELO-Based Balancing: Teams are balanced by average ELO to ensure fair matchups
- Fully Automatic: System handles team balancing, match creation, and round progression automatically
- Player-Centric Scoring: Tournament winner is the individual player with the most match wins
Creating a Shuffle Tournament¶
Step 1: Tournament Setup¶
- Navigate to Tournament page
- Select "Shuffle Tournament" as the tournament type
- Enter tournament name
- Match Format is automatically set to BO1 (cannot be changed)
Step 2: Map Selection¶
- Select maps from the map pool
- Important: The number of maps you select determines the number of rounds
- Example: 5 maps = 5 rounds
- Each round uses one map (all matches in a round use the same map)
Step 3: Team Size Configuration¶
Configure the number of players per team:
- Team Size: Select number of players per team (default: 5 for 5v5)
- Range: 2-10 players per team
- Common Options: 4v4, 5v5, 6v6
- Minimum Players: Must register at least
teamSize * 2players
Step 4: Advanced Configuration¶
Configure round limits and overtime settings:
Max Rounds:
- Each match is capped at a configurable maximum number of rounds (default: 24).
- If max rounds are reached, the winner is determined by the current score.
Overtime Mode:
- Enable Overtime: Standard CS2 overtime rules (MR3 format).
- Stop at Max Rounds: Match ends when max rounds reached (no overtime; ties are allowed).
Step 4: Player Registration¶
- Minimum Requirement: At least 10 players must be registered (for 5v5 matches)
- Click "Register Players" button
- Select players from the player selection modal
- Players can be registered individually or in bulk
- Players are automatically whitelisted for match servers
Note: Players must exist in the system before registration. You can add players in several ways:
-
Via Teams Page (Recommended for predetermined teams):
-
Create a team and add players directly
- Set ELO rating for each player when adding (optional, defaults to 3000)
- Players are automatically created in the players table
-
Useful when you have predetermined teams with known ELO ratings
-
Via Players Page:
-
Create individual players
- Bulk import players (CSV/JSON supported)
- Set initial ELO ratings (default: 3000)
- Edit player ELO after creation (with warning about resetting stats)
-
Download CSV Template: player-import-example.csv
-
Bulk Import Teams (with ELO):
- Import teams via JSON with player ELO ratings included
- See Managing Teams Guide for examples
Step 6: Review and Start¶
- Review tournament configuration
- Verify player count (must be ≥ 10)
- Click "Start Tournament"
How Shuffle Tournaments Work¶
Automatic Team Balancing¶
Before each round:
- System retrieves all registered players
- Calculates current ELO for each player
- Uses team balancing algorithm to create balanced teams of 5 players
- Teams are balanced by average ELO to ensure fair matchups
Round Progression¶
-
Round Generation: System automatically generates matches for the round
-
Number of matches =
Math.floor(playerCount / (teamSize * 2)) - Example: 60 players with 5v5 (teamSize=5) =
Math.floor(60 / 10)= 6 matches per round -
Example: 40 players with 4v4 (teamSize=4) =
Math.floor(40 / 8)= 5 matches per round -
Match Creation:
-
Teams are automatically assigned to matches
- Map is assigned (same map for all matches in the round)
- Sides (CT/T) are randomly assigned
-
Servers are automatically allocated
-
Round Completion:
-
All matches in a round must complete before next round begins
- System automatically detects when all matches are complete
-
ELO ratings are updated after each match
-
Round Advancement:
- System automatically advances to next round
- Teams are reshuffled based on updated ELO ratings
- New matches are generated automatically
- Servers are automatically allocated to new matches
ELO Rating System¶
- Rating System: Uses OpenSkill (Bayesian rating system)
- Admin Interface: Simple "ELO" number (system handles conversion internally)
- Default Starting ELO: 3000 (FaceIT-style)
- Rating Updates: Based on team result (win/loss):
- All players on winning team get ELO increase
- All players on losing team get ELO decrease
- ELO change depends on opponent team's average ELO
Default ELO mode (Pure Win/Loss)¶
- Pure Win/Loss is the default template used for all tournaments (including shuffle) unless you explicitly pick another ELO template.
- With Pure Win/Loss selected:
- OpenSkill updates ratings only from the match result (win or loss).
- Individual stats (kills, ADR, MVPs, etc.) are tracked for leaderboards and exports but do not change ELO.
- This is the safest, most predictable mode and is recommended if you want Excel-style “result-only” ratings.
- Advanced ELO templates are optional:
- You can configure them in the ELO Templates admin page.
- When a non-default template is enabled and selected for a tournament, it adds stat-based adjustments on top of the OpenSkill win/loss change.
- The system ships with a Balanced Stats v1 preset, which adds a modest adjustment based on ADR, KAST, K/D, utility damage and MVPs while still letting the match result dominate.
Odd Number of Players¶
If you have an odd number of players (e.g., 61 instead of 60):
- Player Rotation: System automatically rotates players who sat out
- Players who sat out last round will play this round
- Ensures fair rotation - no player sits out multiple rounds in a row
- If rotation cannot be completed, system logs a warning
Viewing Tournament Progress¶
Public Tournament Leaderboard¶
Navigate to /tournament/:id/leaderboard (public, no authentication required)
Displays:
- Tournament name and status
- Current round number and progress
- Player leaderboard (sorted by wins, then ELO)
- Links to individual player pages
Leaderboard Columns:
- Player name and avatar
- Current ELO
- Match wins
- Match losses
- Win rate
- Average ADR (if available)
- ELO change (since tournament start)
Global vs event-only ratings¶
- Global rating model:
- Each player has one global ELO that is shared across all tournaments and matches, including shuffle tournaments and team-based events.
- When a shuffle match finishes, the rating change is applied to the player’s global ELO (not to a per-event ladder).
- Event-only ELO change on the leaderboard:
- The shuffle leaderboard’s “ELO change (since tournament start)” column shows how much each player’s global ELO has moved during this specific tournament.
- This makes it easy to answer “who gained the most ELO at this LAN?” without resetting everyone’s long-term rating.
- Why this matters for LANs:
- You can run multiple shuffle events over time while still letting players build up a long-term rating history.
- At the same time, each event has a clear per-event delta so you can crown winners based on performance in that LAN only.
Player Pages¶
Each player has a public profile page at /player/:steamId
Displays:
- Player name, avatar, and current ELO
- ELO progression chart (visual history)
- Match history with detailed stats
- Performance metrics (wins, losses, win rate, ADR)
Finding Your Player Page:
- Navigate to
/player(Find Player page) - Paste your Steam profile URL or Steam ID
- System redirects to your player page
Setting Player ELO Ratings¶
ELO ratings are crucial for shuffle tournaments as they determine team balancing. You can set ELO in several ways:
When Adding Players to Teams¶
- Go to Teams page
- Create or edit a team
- When adding a player via Steam URL:
- Enter Steam ID/URL
- Enter player name
- Enter ELO rating (optional) - Defaults to 3000 if not specified
- Click "Add" to add player to team
Bulk Import Teams with ELO¶
Import teams with player ELO ratings included. Teams must be imported in JSON format (CSV is not supported due to nested player structure):
Download JSON Template: team-import-example.json
[
{
"name": "Team Alpha",
"tag": "ALPHA",
"players": [
{ "steamId": "76561198012345678", "name": "Player One", "elo": 3200 },
{ "steamId": "76561198012345679", "name": "Player Two", "elo": 3100 },
{ "steamId": "76561198012345680", "name": "Player Three" },
{ "steamId": "76561198012345681", "name": "Player Four", "elo": 3000 }
]
}
]
Note: The elo field is optional. If omitted, players default to 3000 ELO.
Bulk Import Players with ELO¶
Import players directly via the Players page. Both JSON and CSV formats are supported.
JSON Format:
[
{
"steamId": "76561198012345678",
"name": "Player One",
"initialELO": 3200,
"avatarUrl": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/fe/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_full.jpg"
},
{
"steamId": "76561198012345679",
"name": "Player Two",
"initialELO": 3100,
"avatarUrl": "https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/ab/abcdef1234567890abcdef1234567890abcdef12_full.jpg"
},
{
"steamId": "76561198012345680",
"name": "Player Three"
}
]
CSV Format:
steamId,name,initialELO,avatarUrl
76561198012345678,Player One,3200,https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/fe/fef49e7fa7e1997310d705b2a6158ff8dc1cdfeb_full.jpg
76561198012345679,Player Two,3100,
76561198012345680,Player Three,3000,
76561198012345681,Player Four,,
CSV Column Headers:
steamIdorsteamidorsteam_id(required)name(required)initialELOorinitialeloorinitial_eloorelo(optional, defaults to 1500)avatarUrloravatarurloravatar_urloravatar(optional)
Note: The initialELO field is optional. If omitted, players default to a Skill Rating of 1500. Empty CSV cells are treated as optional fields.
Download CSV Template: player-import-example.csv
Tournament Winner¶
The tournament winner is determined by:
- Primary: Most match wins
- Tie-breaker: Highest ELO
- Additional: Average ADR or other performance metrics
Tips and Best Practices¶
Player Management¶
- Bulk Import: Use the Players page to bulk import players before tournament creation
- Initial ELO: Set accurate initial ELO for better team balancing
- Editing ELO: You can edit a player's ELO after creation by clicking on their player card and updating the ELO field. Warning: Changing a player's ELO will reset their stats and rating history. A confirmation dialog will appear before the change is applied.
- Player Names: Ensure player names are correct (they appear in match views)
Tournament Configuration¶
- Map Selection: Choose maps that work well for your player skill level
- Round Limits: Consider your time constraints when selecting round limit type
- Overtime: Enable overtime for standard CS2 experience, or disable for faster matches
During Tournament¶
- Monitor Progress: Use the public standings page to track tournament progress
- Round Status: Check the Bracket page for round completion status
- Player Stats: Players can view their individual stats on their player pages
Troubleshooting¶
"Not enough players registered"¶
- Solution: Register at least 10 players before starting the tournament
- Use the Players page to create/import players
- Then register them to the tournament
"Odd number of players" warning¶
- Normal: This is expected if you have an odd number of players
- Rotation: System automatically rotates players who sit out
- Impact: One player sits out per round (rotates each round)
Players can't connect to server¶
- Check: Players must be registered to the tournament
- Whitelisting: Registered players are automatically whitelisted
- Verify: Check that player Steam IDs are correct
Round not advancing¶
- Check: All matches in the round must be completed
- Status: Verify all matches show "completed" status
- Automatic: Round advancement happens automatically (no manual trigger needed)
Technical Details¶
Team Balancing Algorithm¶
- Uses greedy algorithm with optimization step
- Balances teams by average ELO (OpenSkill ordinal value)
- Handles edge cases (odd players, extreme ELO values)
Server Allocation¶
- Servers are automatically allocated when rounds advance
- If no servers available, system polls every 10 seconds
- Matches load automatically when servers are allocated
Match Configuration¶
- Format: Always BO1 (Best of 1)
- Veto: Disabled (no map voting)
- Sides: Randomly assigned (no knife round)
- Round Limits: Single configurable Max Rounds value (default: 24) applied to every map via
mp_maxroundsand passed to MatchZy asmaxRoundsin the match JSON. - Overtime Mode:
- Enable Overtime: Standard CS2 overtime is played when the score is tied at max rounds. We send
overtimeMode: "enabled"in the match JSON and MatchZy setsmp_overtime_enable 1. - Disable Overtime: No overtime is played. We send
overtimeMode: "disabled"and MatchZy setsmp_overtime_enable 0. - Overtime Segments (optional):
- Configured as
overtimeSegmentson the tournament and passed through in the match JSON. - Used by MatchZy as a policy hint for how ties should be handled (e.g. whether to allow a draw vs. use a performance tiebreak), not as a hard cap on the number of OT segments. When unset or 0, MatchZy’s default “unlimited OT until someone wins” behavior is used.
Winner decision & ties (when using performance tiebreaks)¶
When the MatchZy plugin is configured to use a performance-based tiebreak (total team damage), the winner is decided using the following rule. This applies equally to shuffle tournaments and manual matches that use the same plugin behavior.
Inputs¶
t1Score,t2Score: final map score (team1 vs team2).maxRounds,overtimeMode,overtimeSegmentsfrom the match config JSON:overtimeMode:"enabled"or"disabled"(or missing).overtimeSegments: integer ornull.team1Damage,team2Damage: total damage dealt by each team over the map (sum of all players’ damage).
Step 1 – Normal score‑based winner¶
If scores are not tied, the higher score wins:
if t1Score > t2Score: winner = team1
else if t2Score > t1Score: winner = team2
else: // scores are equal → go to tiebreak logic
Step 2 – Decide if we allow a draw or force a tiebreak¶
When t1Score == t2Score:
overtimeDisabled = (overtimeMode == "disabled")
hasSegments = (overtimeSegments is not null)
Case A – "No OT, no draws" (regulation only, force winner)
if overtimeDisabled && hasSegments && overtimeSegments == 0:
use performance tiebreak (see Step 3)
Case B – "OT configured with a cap" (semantic: no draws after OT)
if !overtimeDisabled && hasSegments && overtimeSegments > 0:
use performance tiebreak (see Step 3)
Case C – Everything else
// missing overtimeSegments, or negative, or overtimeMode not set
result = draw
Step 3 – Performance‑based tiebreak (damage)¶
When a performance tiebreak is requested (cases A or B):
if team1Damage > team2Damage: winner = team1
else if team2Damage > team1Damage: winner = team2
else:
// damage also tied → still a true draw
result = draw
In words:
- Primary winner: higher final map score.
- If scores are tied:
- If
overtimeMode: "disabled"andovertimeSegments: 0: no OT; force a winner by higher total team damage (or draw if damage is also equal). - If OT is enabled and
overtimeSegments > 0: if a tie persists, force a winner by higher total team damage (or draw if damage is also equal). - Otherwise: treat as a draw.
API Endpoints¶
For programmatic access, the following endpoints are available. All endpoints require Bearer token authentication unless otherwise noted. Full OpenAPI documentation is available at /api-docs when the server is running.
Tournament Management¶
Create Shuffle Tournament
POST /api/tournament/shuffle- Creates a new shuffle tournament
- Required fields:
name,mapSequence,maxRounds,overtimeMode - Optional field:
overtimeSegments(integer, >= 0)
Get Tournament
GET /api/tournament- Returns current tournament details
Player Registration¶
Register Players
POST /api/tournament/:id/register-players- Register one or more players to the tournament
- Body:
{ "playerIds": ["steamId1", "steamId2", ...] } - Returns:
{ "success": boolean, "registered": number, "errors": [...] } - Status 207 (Multi-Status) if some players failed to register
Get Registered Players
GET /api/tournament/:id/players- Returns list of all registered players with their current ELO
Leaderboards & Standings¶
Get Leaderboard
GET /api/tournament/:id/leaderboard- Returns player leaderboard sorted by wins, then ELO
- Includes: wins, losses, win rate, ELO change
Get Standings (Public)
GET /api/tournament/:id/standings- Public endpoint (no auth required)
- Returns: tournament info, leaderboard, current round status
Get Round Status
GET /api/tournament/:id/round-status- Returns current round number, map, match completion status
- Used for round progress indicators
Player Management¶
GET /api/players- List all playersPOST /api/players- Create playerPUT /api/players/:playerId- Update player (name, avatar, ELO)- Warning: Updating ELO will reset the player's stats and rating history
GET /api/players/:playerId- Get player details (public)GET /api/players/:playerId/rating-history- Get rating historyGET /api/players/:playerId/matches- Get match historyGET /api/players/find- Find player by Steam URL/ID
Example API Usage¶
# Create shuffle tournament
curl -X POST http://localhost:3000/api/tournament/shuffle \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "LAN Party 2025",
"mapSequence": ["de_dust2", "de_mirage", "de_inferno"],
"maxRounds": 24,
"overtimeMode": "enabled"
}'
# Register players
curl -X POST http://localhost:3000/api/tournament/1/register-players \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"playerIds": ["76561198000000000", "76561198000000001"]
}'
# Get standings (public, no auth)
curl http://localhost:3000/api/tournament/1/standings
See Also¶
- Managing Teams - Managing teams and players
- Running Matches - Match flow and controls
- Team Pages - Team page features