diff --git a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs
index a996612b..893648e0 100644
--- a/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs
+++ b/ProjectLighthouse.Tests/Tests/AuthenticationTests.cs
@@ -12,7 +12,7 @@ namespace LBPUnion.ProjectLighthouse.Tests
[Fact]
public async Task ShouldReturnErrorOnNoPostData()
{
- HttpResponseMessage response = await this.Client.PostAsync($"/LITTLEBIGPLANETPS3_XML/login", null!);
+ HttpResponseMessage response = await this.Client.PostAsync("/LITTLEBIGPLANETPS3_XML/login", null!);
Assert.False(response.IsSuccessStatusCode);
#if NET6_0_OR_GREATER
Assert.True(response.StatusCode == HttpStatusCode.BadRequest);
diff --git a/ProjectLighthouse.sln.DotSettings b/ProjectLighthouse.sln.DotSettings
index 9035b5a5..9bfc9063 100644
--- a/ProjectLighthouse.sln.DotSettings
+++ b/ProjectLighthouse.sln.DotSettings
@@ -103,6 +103,7 @@
True
True
True
+ True
True
True
True
diff --git a/ProjectLighthouse/Controllers/ScoreController.cs b/ProjectLighthouse/Controllers/ScoreController.cs
index 287be62c..90a710ee 100644
--- a/ProjectLighthouse/Controllers/ScoreController.cs
+++ b/ProjectLighthouse/Controllers/ScoreController.cs
@@ -1,6 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
using System.IO;
+using System.Linq;
using System.Threading.Tasks;
using System.Xml.Serialization;
+using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using Microsoft.AspNetCore.Mvc;
@@ -30,10 +35,91 @@ namespace LBPUnion.ProjectLighthouse.Controllers
score.SlotId = id;
- this.database.Scores.Add(score);
+ IQueryable existingScore = this.database.Scores.Where(s => s.SlotId == score.SlotId && s.PlayerIdCollection == score.PlayerIdCollection);
+
+ if (existingScore.Any())
+ {
+ Score first = existingScore.First(s => s.SlotId == score.SlotId);
+ score.ScoreId = first.ScoreId;
+ score.Points = Math.Max(first.Points, score.Points);
+ this.database.Entry(first).CurrentValues.SetValues(score);
+ }
+ else
+ {
+ this.database.Scores.Add(score);
+ }
await this.database.SaveChangesAsync();
return this.Ok();
}
+
+ [HttpGet("topscores/user/{slotId:int}/{type:int}")]
+ [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
+ public async Task TopScores(int slotId, int type, [FromQuery] int pageStart, [FromQuery] int pageSize)
+ {
+ // Get username
+ User user = await this.database.UserFromRequest(this.Request);
+
+ // This is hella ugly but it technically assigns the proper rank to a score
+ // var needed for Anonymous type returned from SELECT
+ var rankedScores = this.database.Scores.Where(s => s.SlotId == slotId && s.Type == type)
+ .OrderByDescending(s => s.Points)
+ .ToList()
+ .Select
+ (
+ (Score s, int rank) => new
+ {
+ Score = s,
+ Rank = rank + 1,
+ }
+ );
+
+ // Find your score, since even if you aren't in the top list your score is pinned
+ var myScore = rankedScores.Where
+ (rs => rs.Score.PlayerIdCollection.Contains(user.Username))
+ .OrderByDescending(rs => rs.Score.Points)
+ .FirstOrDefault();
+
+ // Paginated viewing
+ var pagedScores = rankedScores.Skip(pageStart - 1).Take(Math.Min(pageSize, 30));
+
+ string serializedScores = pagedScores.Aggregate
+ (
+ string.Empty,
+ (current, rs) =>
+ {
+ rs.Score.Rank = rs.Rank;
+ return current + rs.Score.Serialize();
+ }
+ );
+
+ string res;
+ if (myScore == null)
+ {
+ res = LbpSerializer.StringElement("scores", serializedScores);
+ }
+ else
+ {
+ res = LbpSerializer.TaggedStringElement
+ (
+ "scores",
+ serializedScores,
+ new Dictionary()
+ {
+ {
+ "yourScore", myScore.Score.Points
+ },
+ {
+ "yourRank", myScore.Rank
+ }, //This is the numerator of your position globally in the side menu.
+ {
+ "totalNumScores", rankedScores.Count()
+ }, // This is the denominator of your position globally in the side menu.
+ }
+ );
+ }
+
+ return this.Ok(res);
+ }
}
}
\ No newline at end of file
diff --git a/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs b/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs
index 4ed898e9..177027de 100644
--- a/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs
+++ b/ProjectLighthouse/Helpers/Extensions/StringExtensions.cs
@@ -8,11 +8,8 @@ namespace LBPUnion.ProjectLighthouse.Helpers.Extensions
{
char[] invalidPathChars = Path.GetInvalidFileNameChars();
string path = text;
-
- foreach (char c in invalidPathChars)
- {
- path = path.Replace(c.ToString(), "");
- }
+
+ foreach (char c in invalidPathChars) path = path.Replace(c.ToString(), "");
return path;
}
diff --git a/ProjectLighthouse/Logging/LighthouseFileLogger.cs b/ProjectLighthouse/Logging/LighthouseFileLogger.cs
index 31879a69..4b0e08a4 100644
--- a/ProjectLighthouse/Logging/LighthouseFileLogger.cs
+++ b/ProjectLighthouse/Logging/LighthouseFileLogger.cs
@@ -9,6 +9,7 @@ namespace LBPUnion.ProjectLighthouse.Logging
public class LighthouseFileLogger : LoggerBase
{
private static readonly string logsDirectory = Path.Combine(Environment.CurrentDirectory, "logs");
+ public override bool AllowMultiple => false;
public override void Send(LoggerLine line)
{
@@ -22,6 +23,5 @@ namespace LBPUnion.ProjectLighthouse.Logging
File.AppendAllText(Path.Combine(logsDirectory, line.LoggerLevel.Name.ToFileName() + ".log"), contentFile);
File.AppendAllText(Path.Combine(logsDirectory, "all.log"), contentAll);
}
- public override bool AllowMultiple => false;
}
}
\ No newline at end of file
diff --git a/ProjectLighthouse/ProjectLighthouse.csproj b/ProjectLighthouse/ProjectLighthouse.csproj
index 64127ba0..37dc28d0 100644
--- a/ProjectLighthouse/ProjectLighthouse.csproj
+++ b/ProjectLighthouse/ProjectLighthouse.csproj
@@ -8,19 +8,19 @@
-
-
-
-
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
-
+
diff --git a/ProjectLighthouse/Serialization/LbpSerializer.cs b/ProjectLighthouse/Serialization/LbpSerializer.cs
index 9bec4cb2..cfa64535 100644
--- a/ProjectLighthouse/Serialization/LbpSerializer.cs
+++ b/ProjectLighthouse/Serialization/LbpSerializer.cs
@@ -26,6 +26,9 @@ namespace LBPUnion.ProjectLighthouse.Serialization
public static string TaggedStringElement(string key, object value, string tagKey, object tagValue) => $"<{key} {tagKey}=\"{tagValue}\">{value}{key}>";
+ public static string TaggedStringElement(string key, object value, Dictionary attrKeyValuePairs)
+ => $"<{key} " + attrKeyValuePairs.Aggregate(string.Empty, (current, kvp) => current + $"{kvp.Key}=\"{kvp.Value}\" ") + $">{value}{key}>";
+
public static string Elements
(params KeyValuePair[] pairs)
=> pairs.Aggregate(string.Empty, (current, pair) => current + StringElement(pair));
diff --git a/ProjectLighthouse/Types/Score.cs b/ProjectLighthouse/Types/Score.cs
index 14668872..6b507e6f 100644
--- a/ProjectLighthouse/Types/Score.cs
+++ b/ProjectLighthouse/Types/Score.cs
@@ -1,6 +1,7 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Xml.Serialization;
+using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types.Levels;
namespace LBPUnion.ProjectLighthouse.Types
@@ -33,7 +34,29 @@ namespace LBPUnion.ProjectLighthouse.Types
set => this.PlayerIdCollection = string.Join(',', value);
}
+ [NotMapped]
+ [XmlElement("mainPlayer")]
+ public string MainPlayer {
+ get => this.PlayerIds[0];
+ set => this.PlayerIds[0] = value;
+ }
+
+ [NotMapped]
+ [XmlElement("rank")]
+ public int Rank { get; set; }
+
[XmlElement("score")]
public int Points { get; set; }
+
+ public string Serialize()
+ {
+ string score = LbpSerializer.StringElement("type", this.Type) +
+ LbpSerializer.StringElement("playerIds", this.PlayerIdCollection) +
+ LbpSerializer.StringElement("mainPlayer", this.MainPlayer) +
+ LbpSerializer.StringElement("rank", this.Rank) +
+ LbpSerializer.StringElement("score", this.Points);
+
+ return LbpSerializer.StringElement("playRecord", score);
+ }
}
}
\ No newline at end of file