Notify a user when their highscore is beaten (#1083)

* Notify a user when their highscore is beaten

* formatting

Co-authored-by: sudokoko <sudo@koko.rip>

* noPrefix -> prefix

* documentation and fix closing tag

* better documentation

---------

Co-authored-by: sudokoko <sudo@koko.rip>
Co-authored-by: Josh <josh@slendy.pw>
This commit is contained in:
Kat 2025-01-10 19:44:53 -08:00 committed by GitHub
parent 301e5d0d32
commit 4f9dc2a52d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 41 additions and 11 deletions

View file

@ -5,6 +5,7 @@ using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging; using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.StorableLists.Stores; using LBPUnion.ProjectLighthouse.StorableLists.Stores;
using LBPUnion.ProjectLighthouse.Types.Entities.Level; using LBPUnion.ProjectLighthouse.Types.Entities.Level;
using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
using LBPUnion.ProjectLighthouse.Types.Entities.Token; using LBPUnion.ProjectLighthouse.Types.Entities.Token;
using LBPUnion.ProjectLighthouse.Types.Levels; using LBPUnion.ProjectLighthouse.Types.Levels;
using LBPUnion.ProjectLighthouse.Types.Logging; using LBPUnion.ProjectLighthouse.Types.Logging;
@ -159,7 +160,7 @@ public class ScoreController : ControllerBase
await this.database.SaveChangesAsync(); await this.database.SaveChangesAsync();
return this.Ok(await this.GetScores(new LeaderboardOptions ScoreboardResponse scores = await this.GetScores(new LeaderboardOptions
{ {
RootName = "scoreboardSegment", RootName = "scoreboardSegment",
PageSize = 5, PageSize = 5,
@ -169,7 +170,17 @@ public class ScoreController : ControllerBase
ScoreType = score.Type, ScoreType = score.Type,
TargetUser = token.UserId, TargetUser = token.UserId,
TargetPlayerIds = null, TargetPlayerIds = null,
})); });
if (score.Type == 1 && scores.YourRank == 1 && scores.Total > 1)
{
GameScore? second = scores.Scores[1];
UserEntity? user = await this.database.UserFromGameToken(token);
await this.database.SendNotification(second.UserId, $"{user?.InfoXml} beat your highscore (<em>{second.Points}</em>) on {slot.InfoXml} with a score of <em>{score.Points}</em>.", true);
}
return this.Ok(scores);
} }
[HttpGet("scoreboard/{slotType}/{id:int}")] [HttpGet("scoreboard/{slotType}/{id:int}")]

View file

@ -15,9 +15,10 @@ public partial class DatabaseContext
/// </summary> /// </summary>
/// <param name="userId">The user ID of the target user.</param> /// <param name="userId">The user ID of the target user.</param>
/// <param name="text">The message to send.</param> /// <param name="text">The message to send.</param>
/// <param name="prefix">Prepend server name/timestamp.</param>
/// <param name="type">The <see cref="NotificationType"/> for the notification. Defaults to <c>ModerationNotification</c>.</param> /// <param name="type">The <see cref="NotificationType"/> for the notification. Defaults to <c>ModerationNotification</c>.</param>
public async Task SendNotification public async Task SendNotification
(int userId, string text, NotificationType type = NotificationType.ModerationNotification) (int userId, string text, bool prefix = true, NotificationType type = NotificationType.ModerationNotification)
{ {
if (!await this.Users.AnyAsync(u => u.UserId == userId)) if (!await this.Users.AnyAsync(u => u.UserId == userId))
{ {
@ -31,15 +32,19 @@ public partial class DatabaseContext
StringBuilder builder = new(text); StringBuilder builder = new(text);
// Prepend server name to notification text if enabled if (prefix)
if (ServerConfiguration.Instance.NotificationConfiguration.ShowServerNameInText)
{ {
builder.Insert(0, $"[{ServerConfiguration.Instance.Customization.ServerName}] "); // Prepend server name to notification text if enabled
} if (ServerConfiguration.Instance.NotificationConfiguration.ShowServerNameInText)
// Prepend timestamp to notification text if enabled {
if (ServerConfiguration.Instance.NotificationConfiguration.ShowTimestampInText) builder.Insert(0, $"[{ServerConfiguration.Instance.Customization.ServerName}] ");
{ }
builder.Insert(0, $"[{DateTime.Now:g}] ");
// Prepend timestamp to notification text if enabled
if (ServerConfiguration.Instance.NotificationConfiguration.ShowTimestampInText)
{
builder.Insert(0, $"[{DateTime.Now:g}] ");
}
} }
NotificationEntity notification = new() NotificationEntity notification = new()

View file

@ -29,6 +29,13 @@ public class SlotEntity
public string IconHash { get; set; } = ""; public string IconHash { get; set; } = "";
/// <summary>
/// Markup that displays the level name next to its badge.
/// This can be used everywhere markup works ingame, e.g. news or notifications
/// </summary>
[NotMapped]
public string InfoXml => $"<slot type=\"{this.Type}\" id=\"{this.SlotId}\" icon=\"{this.IconHash}\">{this.Name}</slot>";
public bool IsAdventurePlanet { get; set; } public bool IsAdventurePlanet { get; set; }
public string RootLevel { get; set; } = ""; public string RootLevel { get; set; } = "";

View file

@ -28,6 +28,13 @@ public class UserEntity
public string IconHash { get; set; } public string IconHash { get; set; }
/// <summary>
/// Markup that displays the username next to a polaroid with the user's icon.
/// This can be used everywhere markup works ingame, e.g. news or notifications
/// </summary>
[NotMapped]
public string InfoXml => $"<player icon=\"{this.IconHash}\">{this.Username}</player>";
/// <summary> /// <summary>
/// A user-customizable biography shown on the profile card /// A user-customizable biography shown on the profile card
/// </summary> /// </summary>