Skip to main content
The Round entity defines a stage of the tournament (e.g., “Round of 16”, “Qualifiers”, “Grand Finals”). It encapsulates the rules, ban system, best-of format, and the map pool for that stage.

Class Definition

Namespace: ss.Internal.Management.Server.AutoRef Table: rounds Source: /home/daytona/workspace/source/ss.Integrated.Management.Server/Database/Models.cs:234
[Table("rounds")]
public class Round
{
    // Properties...
}

Properties

Id
int
required
The unique identifier for the round.Column: id (Primary Key)
DisplayName
string
required
The human-readable name for this tournament stage.Examples: “Qualifiers”, “Round of 16”, “Quarterfinals”, “Grand Finals”Column: name
BanRounds
int
required
The number of bans allowed per team in this round.
  • 0: No bans (typically qualifiers)
  • 1: Each team bans 1 map
  • 2: Each team bans 2 maps
Column: ban_rounds
Mode
BansType
required
Defines the ban strategy for this round.See BansType enum for possible values.Column: ban_mode
BestOf
int
required
The maximum number of maps that can be played (e.g., 7 for Best of 7).Winner is first to reach (BestOf + 1) / 2 points.Examples:
  • BestOf = 5: First to 3 wins
  • BestOf = 7: First to 4 wins
  • BestOf = 9: First to 5 wins
Column: best_of
MapPool
List<RoundBeatmap>
required
The list of beatmaps available to be picked in this round.Stored as JSON in the database. See RoundBeatmap structure.Column: map_poolStorage: JSON array

Enumerations

BansType Enum

Defines the ban strategy for a round. Source: /home/daytona/workspace/source/ss.Integrated.Management.Server/Database/Models.cs:103
public enum BansType
{
    SpanishShowdown = 0,  // Standard snake draft or fixed order
    Other = 1
}
BansType.SpanishShowdown
0
Standard snake draft or fixed ban order used in Spanish Showdown format.
BansType.Other
1
Alternative ban format.

MatchType Enum

Differentiates between tournament modes. Source: /home/daytona/workspace/source/ss.Integrated.Management.Server/Database/Models.cs:113
public enum MatchType
{
    EliminationStage = 0,
    QualifiersStage = 1
}
MatchType.EliminationStage
0
Head-to-head matches between teams with picks and bans.
MatchType.QualifiersStage
1
Individual players competing on a fixed map pool.

Nested Types

RoundBeatmap Structure

Defines a beatmap in the round’s map pool. Source: /home/daytona/workspace/source/ss.Integrated.Management.Server/Database/Models.cs:391
public class RoundBeatmap
{
    public int BeatmapID { get; set; }
    public string Slot { get; set; }
}
BeatmapID
int
required
The osu! beatmap ID from https://osu.ppy.sh/beatmaps/{BeatmapID}
Slot
string
required
The mod bracket and position identifier.Common formats:
  • NM1, NM2, NM3, … (No Mod)
  • HD1, HD2, … (Hidden)
  • HR1, HR2, … (Hard Rock)
  • DT1, DT2, … (Double Time)
  • FM1, FM2, … (Free Mod)
  • TB1 (Tiebreaker)
Example JSON:
[
  { "BeatmapID": 3194334, "Slot": "NM1" },
  { "BeatmapID": 2785506, "Slot": "NM2" },
  { "BeatmapID": 1925845, "Slot": "HD1" },
  { "BeatmapID": 3501490, "Slot": "HR1" },
  { "BeatmapID": 2891626, "Slot": "DT1" },
  { "BeatmapID": 3408093, "Slot": "FM1" },
  { "BeatmapID": 2927590, "Slot": "TB1" }
]

RoundChoice Structure

Records a pick or ban action during a match. Used by MatchRoom. Source: /home/daytona/workspace/source/ss.Integrated.Management.Server/Database/Models.cs:397
public class RoundChoice
{
    public string Slot { get; set; }
    public TeamColor TeamColor { get; set; }
    public TeamColor? Winner { get; set; }
}
Slot
string
required
References a slot from the round’s MapPool (e.g., “NM1”, “HD2”).
TeamColor
TeamColor
required
Which team picked or banned this map.
Winner
TeamColor?
Which team won this map (only used for picks, not bans).

Usage Examples

Creating a Qualifier Round

var qualifiers = new Round
{
    DisplayName = "Qualifiers",
    BanRounds = 0,  // No bans in qualifiers
    Mode = BansType.SpanishShowdown,
    BestOf = 0,  // Not applicable for qualifiers
    MapPool = new List<RoundBeatmap>
    {
        new() { BeatmapID = 3194334, Slot = "NM1" },
        new() { BeatmapID = 2785506, Slot = "NM2" },
        new() { BeatmapID = 3027432, Slot = "NM3" },
        new() { BeatmapID = 1925845, Slot = "HD1" },
        new() { BeatmapID = 2891626, Slot = "DT1" }
    }
};

context.Rounds.Add(qualifiers);
await context.SaveChangesAsync();

Creating an Elimination Round

var grandFinals = new Round
{
    DisplayName = "Grand Finals",
    BanRounds = 2,  // Each team bans 2 maps
    Mode = BansType.SpanishShowdown,
    BestOf = 13,  // First to 7 wins
    MapPool = new List<RoundBeatmap>
    {
        // 5 No Mod
        new() { BeatmapID = 3194334, Slot = "NM1" },
        new() { BeatmapID = 2785506, Slot = "NM2" },
        new() { BeatmapID = 3027432, Slot = "NM3" },
        new() { BeatmapID = 2891520, Slot = "NM4" },
        new() { BeatmapID = 3501490, Slot = "NM5" },
        // 3 Hidden
        new() { BeatmapID = 1925845, Slot = "HD1" },
        new() { BeatmapID = 3408093, Slot = "HD2" },
        new() { BeatmapID = 2927590, Slot = "HD3" },
        // 3 Hard Rock
        new() { BeatmapID = 3501491, Slot = "HR1" },
        new() { BeatmapID = 2785507, Slot = "HR2" },
        new() { BeatmapID = 3194335, Slot = "HR3" },
        // 3 Double Time
        new() { BeatmapID = 2891626, Slot = "DT1" },
        new() { BeatmapID = 1925846, Slot = "DT2" },
        new() { BeatmapID = 3027433, Slot = "DT3" },
        // 2 Free Mod
        new() { BeatmapID = 3408094, Slot = "FM1" },
        new() { BeatmapID = 2927591, Slot = "FM2" },
        // Tiebreaker
        new() { BeatmapID = 3194336, Slot = "TB1" }
    }
};

context.Rounds.Add(grandFinals);
await context.SaveChangesAsync();

Querying a Round with Map Pool

var round = await context.Rounds
    .FirstOrDefaultAsync(r => r.DisplayName == "Grand Finals");

Console.WriteLine($"{round.DisplayName} - Best of {round.BestOf}");
Console.WriteLine($"Bans: {round.BanRounds} per team");
Console.WriteLine($"\nMap Pool:");

foreach (var map in round.MapPool)
{
    Console.WriteLine($"  {map.Slot}: https://osu.ppy.sh/beatmaps/{map.BeatmapID}");
}

Finding Matches in a Round

var roundId = 5;  // Grand Finals

var matches = await context.MatchRooms
    .Include(m => m.TeamRed).ThenInclude(u => u.OsuData)
    .Include(m => m.TeamBlue).ThenInclude(u => u.OsuData)
    .Where(m => m.RoundId == roundId)
    .ToListAsync();

foreach (var match in matches)
{
    Console.WriteLine($"{match.Id}: {match.TeamRed.DisplayName} vs {match.TeamBlue.DisplayName}");
}

Map Pool Validation

When validating picks and bans, check against the round’s MapPool:
public bool IsValidSlot(Round round, string slot)
{
    return round.MapPool.Any(map => map.Slot == slot);
}

public int GetBeatmapId(Round round, string slot)
{
    return round.MapPool
        .FirstOrDefault(map => map.Slot == slot)
        ?.BeatmapID ?? 0;
}
  • MatchRoom - Elimination matches governed by this round
  • QualifierRoom - Qualifier lobbies using this round’s map pool
  • ScoreResults - Individual scores associated with this round

Build docs developers (and LLMs) love