Skip to content

Commit

Permalink
Add leaderboard announcements
Browse files Browse the repository at this point in the history
  • Loading branch information
matte-ek committed Dec 30, 2023
1 parent d5e23c1 commit 914458f
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 1 deletion.
6 changes: 6 additions & 0 deletions BanchoMultiplayerBot.Database/Models/Map.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace BanchoMultiplayerBot.Database.Models;

public class Map
{

}
6 changes: 6 additions & 0 deletions BanchoMultiplayerBot.Database/Repositories/MapRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace BanchoMultiplayerBot.Database.Repositories;

public class MapRepository
{

}
6 changes: 6 additions & 0 deletions BanchoMultiplayerBot.Host.Web/Extra/DTO/MapDTO.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace BanchoMultiplayerBot.Host.Web.Extra.DTO;

public class MapDTO
{

}
6 changes: 6 additions & 0 deletions BanchoMultiplayerBot.Host.Web/Extra/DataController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace BanchoMultiplayerBot.Host.Web.Extra;

public class DataController
{

}
3 changes: 2 additions & 1 deletion BanchoMultiplayerBot.Host.Web/Pages/LobbyConfigure.razor
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
<MudText Typo="Typo.h6" Class="py-2">Host Rotation</MudText>
<MudSwitch @bind-Checked="_configuration!.AutomaticallySkipAfterViolations" Label="Auto skip after violations" Color="Color.Primary" />
<MudNumericField @bind-Value="_configuration.ViolationSkipCount" Label="Violation Count" Variant="Variant.Filled" Min="1" Max="10" />
</MudPaper>
<MudSwitch @bind-Checked="_configuration!.AnnounceLeaderboardResults" Label="Announce leaderboard results" Color="Color.Primary" />
</MudPaper>
<MudPaper Class="pa-8 ma-2">
<MudText Typo="Typo.h6" GutterBottom="true">Behaviours</MudText>
<MudSelect T="string" Label="Behaviours" MultiSelection="true" Variant="Variant.Filled" @bind-SelectedValues="_selectedBehaviours">
Expand Down
78 changes: 78 additions & 0 deletions BanchoMultiplayerBot/Behaviour/FunCommandsBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ private async void OnUserMessage(PlayerMessage msg)
List<float> leaveRatio = new();
List<float> passRatio = new();

// Calculate percentages for the last 10 games
foreach (var game in recentGames)
{
if (game.PlayerPassedCount == -1)
Expand Down Expand Up @@ -161,6 +162,8 @@ private async void OnAdminMessage(IPrivateIrcMessage msg)
{
try
{
// !mvname <source> <target>
// Moves the stats from source to target
if (msg.Content.StartsWith("!mvname "))
{
using var userRepository = new UserRepository();
Expand Down Expand Up @@ -188,6 +191,42 @@ private async void OnAdminMessage(IPrivateIrcMessage msg)

_lobby.SendMessage("Successfully moved player stats.");
}

if (msg.Content.StartsWith("!setstats "))
{
using var userRepository = new UserRepository();
var args = msg.Content.Split(' ');

var user = await userRepository.FindUser(args[1]);
var playtime = int.Parse(args[2]);
var matchesPlayed = int.Parse(args[3]);
var numberOneResults = int.Parse(args[4]);

if (user == null)
{
return;
}

user.Playtime = playtime;
user.MatchesPlayed = matchesPlayed;
user.NumberOneResults = numberOneResults;

await userRepository.Save();
}

if (msg.Content.StartsWith("!getstats "))
{
using var userRepository = new UserRepository();
var args = msg.Content.Split(' ');
var user = await userRepository.FindUser(args[1]);

if (user == null)
{
return;
}

_lobby.SendMessage($"{user.Playtime} | {user.MatchesPlayed} | {user.NumberOneResults}");
}
}
catch (Exception e)
{
Expand Down Expand Up @@ -221,6 +260,7 @@ private async void OnMatchFinished()

await StoreGameData(recentScores);
await StorePlayerFinishData(recentScores);
await AnnounceLeaderboardResults(recentScores);
}
catch (Exception e)
{
Expand Down Expand Up @@ -342,6 +382,44 @@ private async Task StoreScoreData(IReadOnlyList<PlayerScoreResult> recentScores,
await scoreRepository.Save();
}

private async Task AnnounceLeaderboardResults(IReadOnlyList<PlayerScoreResult> recentScores)
{
if (_mapManagerBehaviour?.CurrentBeatmap == null ||
_hasGameData == false)
{
return;
}

var leaderboardScores = await _lobby.Bot.OsuApi.GetLeaderboardScores(_mapManagerBehaviour!.CurrentBeatmap!.Id);
if (leaderboardScores == null || !leaderboardScores.Any())
{
return;
}

foreach (var score in recentScores)
{
var leaderboardScore = leaderboardScores.FirstOrDefault(x => x?.ScoreId == score?.Score?.ScoreId);
if (leaderboardScore == null)
{
continue;
}

var leaderboardPosition = leaderboardScores.ToList().FindIndex(x => x?.ScoreId == score?.Score?.ScoreId);
if (leaderboardPosition == -1)
{
continue;
}

Log.Information($"Found leaderboard score for player: {score.Player.Name}!");

if (_lobby.Configuration.AnnounceLeaderboardResults == true)
{
_lobby.SendMessage(
$"Congratulations {score.Player.Name} for getting #{leaderboardPosition + 1} on the map's leaderboard!");
}
}
}

private async Task<IReadOnlyList<PlayerScoreResult>> GetRecentScores()
{
var players = _lobby.MultiplayerLobby.Players.Where(x => x.Id != null && x.Score > 0).ToList();
Expand Down
1 change: 1 addition & 0 deletions BanchoMultiplayerBot/Config/LobbyConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class LobbyConfiguration
// Behaviour specific
public string? PreviousQueue;
public PlaytimeRecord[]? PlayerPlaytime { get; set; }
public bool? AnnounceLeaderboardResults { get; set; }

// I really wish I didn't have to store this here, but it currently needs to be entered manually.
public string? LobbyJoinLink { get; set; }
Expand Down
57 changes: 57 additions & 0 deletions BanchoMultiplayerBot/OsuApi/LeaderboardScoreModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System.Text.Json.Serialization;

namespace BanchoMultiplayerBot.OsuApi;

public class LeaderboardScoreModel
{
[JsonPropertyName("score_id")]
public string? ScoreId { get; set; }

[JsonPropertyName("score")]
public string? Score { get; set; }

[JsonPropertyName("username")]
public string? Username { get; set; }

[JsonPropertyName("count300")]
public string? Count300 { get; set; }

[JsonPropertyName("count100")]
public string? Count100 { get; set; }

[JsonPropertyName("count50")]
public string? Count50 { get; set; }

[JsonPropertyName("countmiss")]
public string? CountMiss { get; set; }

[JsonPropertyName("maxcombo")]
public string? MaxCombo { get; set; }

[JsonPropertyName("countkatu")]
public string? CountKatu { get; set; }

[JsonPropertyName("countgeki")]
public string? CountGeki { get; set; }

[JsonPropertyName("perfect")]
public string? Perfect { get; set; }

[JsonPropertyName("enabled_mods")]
public string? EnabledMods { get; set; }

[JsonPropertyName("user_id")]
public string? UserId { get; set; }

[JsonPropertyName("date")]
public string? Date { get; set; }

[JsonPropertyName("rank")]
public string? Rank { get; set; }

[JsonPropertyName("pp")]
public string? Pp { get; set; }

[JsonPropertyName("replay_available")]
public string? ReplayAvailable { get; set; }
}
48 changes: 48 additions & 0 deletions BanchoMultiplayerBot/OsuApi/OsuApiWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,54 @@ public OsuApiWrapper(Bot bot, string osuApiKey)
}
}

public async Task<IReadOnlyList<LeaderboardScoreModel>?> GetLeaderboardScores(int beatmapId)
{
using var httpClient = new HttpClient();
using var _ = _bot.RuntimeInfo.Statistics.ApiRequestTime.NewTimer();

_bot.RuntimeInfo.Statistics.ApiRequests.Inc();

httpClient.Timeout = TimeSpan.FromSeconds(5);

try
{
var result = await httpClient.GetAsync($"https://osu.ppy.sh/api/get_scores?k={_osuApiKey}&b={beatmapId}");

if (!result.IsSuccessStatusCode)
{
Log.Error($"Error code {result.StatusCode} while getting leaderboard from map {beatmapId}!");

_bot.RuntimeInfo.Statistics.ApiErrors.Inc();

return result.StatusCode switch
{
HttpStatusCode.Unauthorized => throw new ApiKeyInvalidException(),
_ => null
};
}

var json = await result.Content.ReadAsStringAsync();
var scores = JsonSerializer.Deserialize<List<LeaderboardScoreModel>>(json);

if (scores != null && !scores.Any())
throw new BeatmapNotFoundException(); // the API returns 200 even if it got no results.

return scores;
}
catch (BeatmapNotFoundException)
{
throw;
}
catch (Exception e)
{
Log.Error($"Exception during osu!api request: {e.Message}, beatmap: {beatmapId}");

_bot.RuntimeInfo.Statistics.ApiErrors.Inc();

throw;
}
}

public async Task<List<ScoreModel?>> GetRecentScoresBatch(List<string?> players)
{
try
Expand Down

0 comments on commit 914458f

Please sign in to comment.