Skip to content

Commit 1ae837f

Browse files
committed
Allow Admins to create match config ( #43 #44)
1 parent c519ef6 commit 1ae837f

File tree

12 files changed

+262
-14
lines changed

12 files changed

+262
-14
lines changed

PugSharp.Config/ConfigCreator.cs

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
namespace PugSharp.Config;
2+
3+
public class ConfigCreator
4+
{
5+
public ConfigCreator()
6+
{
7+
Config = new MatchConfig
8+
{
9+
// TODO Maybe use guid for demo, ...
10+
MatchId = "CustomMatch",
11+
Team1 = new Team
12+
{
13+
Name = "Team 1",
14+
15+
},
16+
Team2 = new Team
17+
{
18+
Name = "Team 2",
19+
},
20+
TeamMode = TeamMode.Scramble,
21+
};
22+
}
23+
24+
public MatchConfig Config { get; }
25+
}

PugSharp.Config/MatchConfig.cs

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace PugSharp.Config;
55
public class MatchConfig
66
{
77
[JsonPropertyName("maplist")]
8-
public required string[] Maplist { get; init; }
8+
public IList<string> Maplist { get; } = new List<string>();
99

1010
[JsonPropertyName("team1")]
1111
public required Team Team1 { get; init; }
@@ -60,4 +60,7 @@ public class MatchConfig
6060

6161
[JsonPropertyName("server_locale")]
6262
public string ServerLocale { get; init; } = "en";
63+
64+
[JsonPropertyName("team_mode")]
65+
public TeamMode TeamMode { get; set; }
6366
}

PugSharp.Config/Team.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace PugSharp.Config;
55
public class Team
66
{
77
[JsonPropertyName("name")]
8-
public required string Name { get; init; }
8+
public required string Name { get; set; }
99

1010
[JsonPropertyName("tag")]
1111
public string Tag { get; init; } = string.Empty;
@@ -14,5 +14,5 @@ public class Team
1414
public string Flag { get; init; } = string.Empty;
1515

1616
[JsonPropertyName("players")]
17-
public required IDictionary<ulong, string> Players { get; init; }
17+
public IDictionary<ulong, string> Players { get; init; } = new Dictionary<ulong, string>();
1818
}

PugSharp.Config/TeamMode.cs

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace PugSharp.Config;
2+
3+
public enum TeamMode
4+
{
5+
// Take Teams as they are
6+
Default,
7+
8+
// Scramble Teams afte all players are joined
9+
Scramble,
10+
}

PugSharp.Match.Contract/MatchCommand.cs

+1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ public enum MatchCommand
1414
CompleteMap,
1515
Pause,
1616
Unpause,
17+
TeamsDefined,
1718
}

PugSharp.Match.Contract/MatchState.cs

+1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,5 @@ public enum MatchState
1414
MapCompleted,
1515
MatchCompleted,
1616
RestoreMatch,
17+
DefineTeams,
1718
}

PugSharp.Match.Tests/MatchTests.cs

+9-3
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ private static async Task VoteTeam(ICsServer csServer, MatchConfig config, Match
160160

161161
private static IPlayer VoteForMap(MatchConfig config, Match match, IPlayer player1, IPlayer player2)
162162
{
163-
var matchCount = config.Maplist.Length;
163+
var matchCount = config.Maplist.Count;
164164
var votePlayer = player1;
165165

166166
Assert.False(match.BanMap(votePlayer, matchCount));
@@ -210,7 +210,7 @@ private static MatchConfig CreateExampleConfig(IEnumerable<string>? mapList = nu
210210
mapListInternal = mapList;
211211
}
212212

213-
return new MatchConfig
213+
var matchConfig = new MatchConfig
214214
{
215215
MatchId = "1337",
216216
PlayersPerTeam = 1,
@@ -232,8 +232,14 @@ private static MatchConfig CreateExampleConfig(IEnumerable<string>? mapList = nu
232232
{ 1,"Def" },
233233
},
234234
},
235-
Maplist = mapListInternal.ToArray(),
236235
};
236+
237+
foreach (var map in mapListInternal)
238+
{
239+
matchConfig.Maplist.Add(map);
240+
}
241+
242+
return matchConfig;
237243
}
238244

239245
private static IPlayer CreatePlayerSub(ulong steamId, int playerId)

PugSharp.Match/Match.cs

+47-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using PugSharp.ApiStats;
88
using PugSharp.Match.Contract;
99
using PugSharp.Server.Contract;
10+
using PugSharp.Shared;
1011
using PugSharp.Translation;
1112
using PugSharp.Translation.Properties;
1213

@@ -85,7 +86,7 @@ private void Initialize(MatchInfo matchInfo)
8586
throw new NotSupportedException("Initialize can onyl be called once!");
8687
}
8788

88-
if (matchInfo.Config.Maplist.Length < matchInfo.Config.NumMaps)
89+
if (matchInfo.Config.Maplist.Count < matchInfo.Config.NumMaps)
8990
{
9091
throw new NotSupportedException($"Can not create Match without the required number of maps! At lease {matchInfo.Config.NumMaps} are required!");
9192
}
@@ -129,12 +130,17 @@ private void InitializeStateMachine()
129130
.PermitDynamicIf(MatchCommand.LoadMatch, () => HasRestoredMatch() ? MatchState.RestoreMatch : MatchState.WaitingForPlayersConnectedReady);
130131

131132
_MatchStateMachine.Configure(MatchState.WaitingForPlayersConnectedReady)
132-
.PermitDynamicIf(MatchCommand.PlayerReady, () => HasRestoredMatch() ? MatchState.MatchRunning : MatchState.MapVote, AllPlayersAreReady)
133+
.PermitDynamicIf(MatchCommand.PlayerReady, () => HasRestoredMatch() ? MatchState.MatchRunning : MatchState.DefineTeams, AllPlayersAreReady)
133134
.OnEntry(StartWarmup)
134135
.OnEntry(SetAllPlayersNotReady)
135136
.OnEntry(StartReadyReminder)
136137
.OnExit(StopReadyReminder);
137138

139+
_MatchStateMachine.Configure(MatchState.DefineTeams)
140+
.Permit(MatchCommand.TeamsDefined, MatchState.MapVote)
141+
.OnEntry(ContinueIfDefault)
142+
.OnEntry(ScrambleTeams);
143+
138144
_MatchStateMachine.Configure(MatchState.MapVote)
139145
.PermitReentryIf(MatchCommand.VoteMap, MapIsNotSelected)
140146
.PermitIf(MatchCommand.VoteMap, MatchState.TeamVote, MapIsSelected)
@@ -200,6 +206,30 @@ private void InitializeStateMachine()
200206
_MatchStateMachine.Fire(MatchCommand.LoadMatch);
201207
}
202208

209+
private void ScrambleTeams()
210+
{
211+
if (MatchInfo.Config.TeamMode == Config.TeamMode.Scramble)
212+
{
213+
var randomizedPlayers = AllMatchPlayers.Randomize().ToList();
214+
215+
MatchInfo.MatchTeam1.Players.Clear();
216+
MatchInfo.MatchTeam1.Players.AddRange(randomizedPlayers.Take(randomizedPlayers.Count.Half()));
217+
218+
MatchInfo.MatchTeam2.Players.Clear();
219+
MatchInfo.MatchTeam2.Players.AddRange(randomizedPlayers.Skip(randomizedPlayers.Count.Half()));
220+
221+
TryFireState(MatchCommand.TeamsDefined);
222+
}
223+
}
224+
225+
private void ContinueIfDefault()
226+
{
227+
if (MatchInfo.Config.TeamMode == Config.TeamMode.Default)
228+
{
229+
TryFireState(MatchCommand.TeamsDefined);
230+
}
231+
}
232+
203233
private void StartWarmup()
204234
{
205235
_CsServer.LoadAndExecuteConfig("warmup.cfg");
@@ -664,7 +694,7 @@ private void SendRemainingMapsToVotingTeam()
664694
}
665695

666696
// If only one map is configured
667-
if (MatchInfo.Config.Maplist.Length == 1)
697+
if (MatchInfo.Config.Maplist.Count == 1)
668698
{
669699
_MapsToSelect = MatchInfo.Config.Maplist.Select(x => new Vote(x)).ToList();
670700
TryFireState(MatchCommand.VoteMap);
@@ -900,12 +930,18 @@ private MatchPlayer GetMatchPlayer(ulong steamID)
900930

901931
public bool TryAddPlayer(IPlayer player)
902932
{
933+
if (!PlayerBelongsToMatch(player.SteamID))
934+
{
935+
_Logger.LogInformation("Player with steam id {steamId} is no member of this match!", player.SteamID);
936+
return false;
937+
}
938+
903939
var isTeam1 = MatchInfo.Config.Team1.Players.ContainsKey(player.SteamID);
904940
var isTeam2 = !isTeam1 && MatchInfo.Config.Team2.Players.ContainsKey(player.SteamID);
905941
if (!isTeam1 && !isTeam2)
906942
{
907-
_Logger.LogInformation("Player with steam id {steamId} is no member of this match!", player.SteamID);
908-
return false;
943+
// if no team is configured add player to team with less players
944+
isTeam1 = MatchInfo.MatchTeam1.Players.Count < MatchInfo.MatchTeam2.Players.Count;
909945
}
910946

911947
var team = isTeam1 ? MatchInfo.MatchTeam1 : MatchInfo.MatchTeam2;
@@ -1205,6 +1241,12 @@ public void CompleteMap(int tPoints, int ctPoints)
12051241

12061242
public bool PlayerBelongsToMatch(ulong steamId)
12071243
{
1244+
if (MatchInfo.Config.Team1.Players.Count == 0 && MatchInfo.Config.Team2.Players.Count == 0)
1245+
{
1246+
// Allow matches without player configuration wait for the first 10 players
1247+
return true;
1248+
}
1249+
12081250
return MatchInfo.Config.Team1.Players.Any(x => x.Key.Equals(steamId))
12091251
|| MatchInfo.Config.Team2.Players.Any(x => x.Key.Equals(steamId));
12101252
}

PugSharp.Match/PugSharp.Match.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<ProjectReference Include="..\PugSharp.Config\PugSharp.Config.csproj" />
1616
<ProjectReference Include="..\PugSharp.Match.Contract\PugSharp.Match.Contract.csproj" />
1717
<ProjectReference Include="..\PugSharp.Server.Contract\PugSharp.Server.Contract.csproj" />
18+
<ProjectReference Include="..\PugSharp.Shared\PugSharp.Shared.csproj" />
1819
<ProjectReference Include="..\PugSharp.Translation\PugSharp.Translation.csproj" />
1920
</ItemGroup>
2021

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
namespace PugSharp.Shared
2+
{
3+
public static class EnumerableExtensions
4+
{
5+
public static IEnumerable<T> Randomize<T>(this IEnumerable<T> source)
6+
{
7+
if (source == null) throw new ArgumentNullException(nameof(source));
8+
9+
return source.RandomizeInternal();
10+
}
11+
12+
private static IEnumerable<T> RandomizeInternal<T>(
13+
this IEnumerable<T> source)
14+
{
15+
var buffer = source.ToList();
16+
for (int i = 0; i < buffer.Count; i++)
17+
{
18+
int j = Random.Shared.Next(i, buffer.Count);
19+
yield return buffer[j];
20+
21+
buffer[j] = buffer[i];
22+
}
23+
}
24+
25+
public static void AddRange<T>(this IList<T> items, IEnumerable<T> itemsToAdd)
26+
{
27+
foreach (var item in itemsToAdd)
28+
{
29+
items.Add(item);
30+
}
31+
}
32+
}
33+
}

PugSharp/NumericExtensions.cs PugSharp.Shared/NumericExtensions.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
namespace PugSharp
1+
namespace PugSharp.Shared
22
{
3-
internal static class NumericExtensions
3+
public static class NumericExtensions
44
{
55
private const double _HalfFactor = 0.5;
66
public static int Half(this int value)

0 commit comments

Comments
 (0)