diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index cadb9d5d..18fe8132 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -25,7 +25,7 @@ jobs:
- name: Start MySQL
if: ${{ matrix.os.database }}
- uses: shogo82148/actions-setup-mysql@v1.14.1
+ uses: shogo82148/actions-setup-mysql@v1.40.0
with:
mysql-version: '8.0'
root-password: ${{ env.DB_PASSWORD }}
diff --git a/.github/workflows/qodana_code_quality.yml b/.github/workflows/qodana_code_quality.yml
index b3df742b..e7b9e089 100644
--- a/.github/workflows/qodana_code_quality.yml
+++ b/.github/workflows/qodana_code_quality.yml
@@ -22,12 +22,12 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit
fetch-depth: 0 # a full history is required for pull request analysis
- name: 'Qodana Scan'
- uses: JetBrains/qodana-action@v2024.1
+ uses: JetBrains/qodana-action@v2024.3
with:
pr-mode: false
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN_1488465344 }}
QODANA_ENDPOINT: 'https://qodana.cloud'
- - uses: github/codeql-action/upload-sarif@v2
+ - uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json
diff --git a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ScoreController.cs b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ScoreController.cs
index 79ae3163..8a859fd7 100644
--- a/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ScoreController.cs
+++ b/ProjectLighthouse.Servers.GameServer/Controllers/Slots/ScoreController.cs
@@ -5,6 +5,7 @@ using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.StorableLists.Stores;
using LBPUnion.ProjectLighthouse.Types.Entities.Level;
+using LBPUnion.ProjectLighthouse.Types.Entities.Profile;
using LBPUnion.ProjectLighthouse.Types.Entities.Token;
using LBPUnion.ProjectLighthouse.Types.Levels;
using LBPUnion.ProjectLighthouse.Types.Logging;
@@ -159,7 +160,7 @@ public class ScoreController : ControllerBase
await this.database.SaveChangesAsync();
- return this.Ok(await this.GetScores(new LeaderboardOptions
+ ScoreboardResponse scores = await this.GetScores(new LeaderboardOptions
{
RootName = "scoreboardSegment",
PageSize = 5,
@@ -169,7 +170,17 @@ public class ScoreController : ControllerBase
ScoreType = score.Type,
TargetUser = token.UserId,
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 ({second.Points}) on {slot.InfoXml} with a score of {score.Points}.", true);
+ }
+
+ return this.Ok(scores);
}
[HttpGet("scoreboard/{slotType}/{id:int}")]
diff --git a/ProjectLighthouse/Database/DatabaseContext.Notifications.cs b/ProjectLighthouse/Database/DatabaseContext.Notifications.cs
index 8fefaec8..d22af72e 100644
--- a/ProjectLighthouse/Database/DatabaseContext.Notifications.cs
+++ b/ProjectLighthouse/Database/DatabaseContext.Notifications.cs
@@ -15,9 +15,10 @@ public partial class DatabaseContext
///
/// The user ID of the target user.
/// The message to send.
+ /// Prepend server name/timestamp.
/// The for the notification. Defaults to ModerationNotification.
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))
{
@@ -31,15 +32,19 @@ public partial class DatabaseContext
StringBuilder builder = new(text);
- // Prepend server name to notification text if enabled
- if (ServerConfiguration.Instance.NotificationConfiguration.ShowServerNameInText)
+ if (prefix)
{
- builder.Insert(0, $"[{ServerConfiguration.Instance.Customization.ServerName}] ");
- }
- // Prepend timestamp to notification text if enabled
- if (ServerConfiguration.Instance.NotificationConfiguration.ShowTimestampInText)
- {
- builder.Insert(0, $"[{DateTime.Now:g}] ");
+ // Prepend server name to notification text if enabled
+ if (ServerConfiguration.Instance.NotificationConfiguration.ShowServerNameInText)
+ {
+ builder.Insert(0, $"[{ServerConfiguration.Instance.Customization.ServerName}] ");
+ }
+
+ // Prepend timestamp to notification text if enabled
+ if (ServerConfiguration.Instance.NotificationConfiguration.ShowTimestampInText)
+ {
+ builder.Insert(0, $"[{DateTime.Now:g}] ");
+ }
}
NotificationEntity notification = new()
diff --git a/ProjectLighthouse/Types/Entities/Level/SlotEntity.cs b/ProjectLighthouse/Types/Entities/Level/SlotEntity.cs
index 693bf4aa..07d65c04 100644
--- a/ProjectLighthouse/Types/Entities/Level/SlotEntity.cs
+++ b/ProjectLighthouse/Types/Entities/Level/SlotEntity.cs
@@ -29,6 +29,13 @@ public class SlotEntity
public string IconHash { get; set; } = "";
+ ///
+ /// Markup that displays the level name next to its badge.
+ /// This can be used everywhere markup works ingame, e.g. news or notifications
+ ///
+ [NotMapped]
+ public string InfoXml => $"{this.Name}";
+
public bool IsAdventurePlanet { get; set; }
public string RootLevel { get; set; } = "";
diff --git a/ProjectLighthouse/Types/Entities/Profile/UserEntity.cs b/ProjectLighthouse/Types/Entities/Profile/UserEntity.cs
index 998c63b8..6fb65301 100644
--- a/ProjectLighthouse/Types/Entities/Profile/UserEntity.cs
+++ b/ProjectLighthouse/Types/Entities/Profile/UserEntity.cs
@@ -28,6 +28,13 @@ public class UserEntity
public string IconHash { get; set; }
+ ///
+ /// 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
+ ///
+ [NotMapped]
+ public string InfoXml => $"{this.Username}";
+
///
/// A user-customizable biography shown on the profile card
///