Skip to content

Commit

Permalink
Add most played departments and jobs to leaderboards
Browse files Browse the repository at this point in the history
  • Loading branch information
Simyon264 committed May 7, 2024
1 parent d8ccfce commit 3681cf8
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 8 deletions.
22 changes: 21 additions & 1 deletion Client/Components/Pages/Leaderboard.razor
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,33 @@ else
<thead>
<tr>
<th>Position</th>
<th>Player name</th>
<th>@leaderboard.NameColumn</th>
<th>@leaderboard.TrackedData</th>
</tr>
</thead>
<tbody>
@foreach (var player in leaderboard.Data)
{
if (player.Value.Count == -1)
{
continue;
}

if (player.Value.Player?.Username == "Unknown")
{
continue;
}

if (player.Value.Player?.PlayerGuid == null)
{
<tr>
<td>@player.Value.Position</td>
<td>@player.Value.Player?.Username</td>
<td>@player.Value.Count</td>
</tr>
continue;
}

if (!IsCurrentPlayer(player.Value.Player.Username))
{
<tr>
Expand Down
77 changes: 73 additions & 4 deletions Server/Api/DataController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,22 @@ public async Task<LeaderboardData> GetLeaderboard(
Name = "Most Hunted Player",
TrackedData = "Times hunted by antags",
Data = new Dictionary<string, PlayerCount>()
}},
{"MostPlayedDepartments", new Leaderboard()
{
Name = "Most played departments",
TrackedData = "Times played",
Data = new Dictionary<string, PlayerCount>(),
Limit = int.MaxValue,
NameColumn = "Department"
}},
{"MostPlayedJobs", new Leaderboard()
{
Name = "Most played jobs",
TrackedData = "Times played",
Data = new Dictionary<string, PlayerCount>(),
Limit = int.MaxValue,
NameColumn = "Job"
}}
};

Expand All @@ -383,6 +399,9 @@ public async Task<LeaderboardData> GetLeaderboard(
};
}

var mostPlayedDepartments = new Dictionary<string, int>();
var mostPlayedJobs = new Dictionary<string, int>();

// To calculate the most seen player, we just count how many times we see a player in each RoundEndPlayer list.
// Importantly, we need to filter out in RoundEndPlayers for distinct players since players can appear multiple times there.
foreach (var dataReplay in dataReplays)
Expand All @@ -407,6 +426,16 @@ public async Task<LeaderboardData> GetLeaderboard(
if (jobList.Contains(dataReplayRoundEndPlayer.JobPrototypes.FirstOrDefault()))
{
CountUp(dataReplayRoundEndPlayer, job, ref leaderboards);

if (!mostPlayedDepartments.TryAdd(job, 1))
{
mostPlayedDepartments[job]++;
}
}

if (!mostPlayedJobs.TryAdd(dataReplayRoundEndPlayer.JobPrototypes.FirstOrDefault() ?? "Unknown", 1))
{
mostPlayedJobs[dataReplayRoundEndPlayer.JobPrototypes.FirstOrDefault() ?? "Unknown"]++;
}
}
}
Expand All @@ -430,10 +459,40 @@ public async Task<LeaderboardData> GetLeaderboard(
}
}

// Add most played departments to the leaderboard
foreach (var (department, count) in mostPlayedDepartments)
{
var didAdd = leaderboards["MostPlayedDepartments"].Data.TryAdd(department, new PlayerCount()
{
Count = count,
Player = new PlayerData() { PlayerGuid = null, Username = department }
// no player data for departments
});
if (!didAdd)
{
leaderboards["MostPlayedDepartments"].Data[department].Count++;
}
}

// Add most played jobs to the leaderboard
foreach (var (job, count) in mostPlayedJobs)
{
var didAdd = leaderboards["MostPlayedJobs"].Data.TryAdd(job, new PlayerCount()
{
Count = count,
Player = new PlayerData() { PlayerGuid = null, Username = job }
// no player data for jobs
});
if (!didAdd)
{
leaderboards["MostPlayedJobs"].Data[job].Count++;
}
}

// Need to calculate the position of every player in the leaderboard.
foreach (var leaderboard in leaderboards)
{
var leaderboardResult = await GenerateLeaderboard(leaderboard.Key, leaderboard.Key, leaderboard.Value, usernameGuid);
var leaderboardResult = await GenerateLeaderboard(leaderboard.Key, leaderboard.Key, leaderboard.Value, usernameGuid, leaderboard.Value.Limit);
leaderboards[leaderboard.Key].Data = leaderboardResult.Data;
}

Expand Down Expand Up @@ -483,7 +542,8 @@ private async Task<Leaderboard> GenerateLeaderboard(
string name,
string columnName,
Leaderboard data,
Guid targetPlayer
Guid targetPlayer,
int limit = 10
)
{
var returnValue = new Leaderboard()
Expand All @@ -500,7 +560,7 @@ Guid targetPlayer
players[i].Position = i + 1;
}

returnValue.Data = players.Take(10).ToDictionary(x => x.Player.PlayerGuid.ToString(), x => x);
returnValue.Data = players.Take(limit).ToDictionary(x => x.Player?.PlayerGuid != null ? x.Player.PlayerGuid.ToString()! : GenerateRandomGuid().ToString(), x => x);

if (targetPlayer != Guid.Empty)
{
Expand All @@ -521,13 +581,22 @@ Guid targetPlayer

foreach (var player in returnValue.Data)
{
var playerData = await FetchPlayerDataFromGuid(player.Value.Player.PlayerGuid);
if (player.Value.Player?.PlayerGuid == null)
continue;
var playerData = await FetchPlayerDataFromGuid((Guid)player.Value.Player.PlayerGuid);
player.Value.Player.Username = playerData.Username;
await Task.Delay(50); // Rate limit the API
}

return returnValue;
}

private Guid GenerateRandomGuid()
{
var guidBytes = new byte[16];
new Random().NextBytes(guidBytes);
return new Guid(guidBytes);
}

private async Task<PlayerData?> FetchPlayerDataFromGuid(Guid guid)
{
Expand Down
14 changes: 12 additions & 2 deletions Shared/LeaderboardData.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Shared;
using System.Text.Json.Serialization;

namespace Shared;

public class LeaderboardData
{
Expand All @@ -9,7 +11,7 @@ public class LeaderboardData

public class PlayerCount
{
public PlayerData Player { get; set; }
public PlayerData? Player { get; set; }
public int Count { get; set; }
public int Position { get; set; }
}
Expand All @@ -27,5 +29,13 @@ public class Leaderboard
/// Will be displayed in a small font below the name.
/// </summary>
public string? ExtraInfo { get; set; }

public string NameColumn { get; set; } = "Player Name";
public Dictionary<string, PlayerCount> Data { get; set; }

/// <summary>
/// The number of players to display on the leaderboard.
/// </summary>
[JsonIgnore]
public int Limit { get; set; } = 10;
}
2 changes: 1 addition & 1 deletion Shared/PlayerData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/// </summary>
public class PlayerData
{
public Guid PlayerGuid { get; set; }
public Guid? PlayerGuid { get; set; }

public string Username { get; set; }

Check warning on line 10 in Shared/PlayerData.cs

View workflow job for this annotation

GitHub Actions / deploy

Non-nullable property 'Username' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Expand Down

0 comments on commit 3681cf8

Please sign in to comment.