mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-08-01 17:48:41 +00:00
Merge branch 'main' into smtp
This commit is contained in:
commit
ff19bc6ffd
42 changed files with 490 additions and 218 deletions
2
.idea/.idea.ProjectLighthouse/.idea/discord.xml
generated
2
.idea/.idea.ProjectLighthouse/.idea/discord.xml
generated
|
@ -2,6 +2,8 @@
|
|||
<project version="4">
|
||||
<component name="DiscordProjectSettings">
|
||||
<option name="show" value="PROJECT_FILES" />
|
||||
<option name="nameOverrideEnabled" value="true" />
|
||||
<option name="nameOverrideText" value="Project Lighthouse" />
|
||||
<option name="description" value="" />
|
||||
</component>
|
||||
</project>
|
|
@ -16,8 +16,8 @@ public class DatabaseTests : LighthouseServerTest
|
|||
await using Database database = new();
|
||||
int rand = new Random().Next();
|
||||
|
||||
User userA = await database.CreateUser("createUserTwiceTest" + rand, HashHelper.GenerateAuthToken());
|
||||
User userB = await database.CreateUser("createUserTwiceTest" + rand, HashHelper.GenerateAuthToken());
|
||||
User userA = await database.CreateUser("unitTestUser" + rand, HashHelper.GenerateAuthToken());
|
||||
User userB = await database.CreateUser("unitTestUser" + rand, HashHelper.GenerateAuthToken());
|
||||
|
||||
Assert.NotNull(userA);
|
||||
Assert.NotNull(userB);
|
||||
|
|
|
@ -133,6 +133,7 @@
|
|||
<s:Boolean x:Key="/Default/UserDictionary/Words/=PCSA/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=PCSD/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=PCSF/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Sublevels/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Swingy/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=thumbsup/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=topscores/@EntryIndexedValue">True</s:Boolean>
|
||||
|
@ -144,4 +145,5 @@
|
|||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unheart/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unpublish/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Unpushed/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=yourlbp/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=yourthumb/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
|
@ -1,10 +1,13 @@
|
|||
#nullable enable
|
||||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Types;
|
||||
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
// ReSharper disable RouteTemplates.ActionRoutePrefixCanBeExtractedToControllerRoute
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers.Api;
|
||||
|
||||
/// <summary>
|
||||
|
@ -36,4 +39,21 @@ public class UserEndpoints : ApiEndpointController
|
|||
|
||||
return this.Ok(user);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a user and their information from the database.
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the user</param>
|
||||
/// <returns>The user's status</returns>
|
||||
/// <response code="200">The user's status, if successful.</response>
|
||||
/// <response code="404">The user could not be found.</response>
|
||||
[HttpGet("user/{id:int}/status")]
|
||||
[ProducesResponseType(typeof(UserStatus), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||
public async Task<IActionResult> GetUserStatus(int id)
|
||||
{
|
||||
UserStatus userStatus = new(this.database, id);
|
||||
|
||||
return this.Ok(userStatus);
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Types;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
|
@ -39,14 +38,13 @@ public class CommentController : ControllerBase
|
|||
return this.Ok();
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("comments/user/{slotId:int}")]
|
||||
[HttpGet("userComments/{username}")]
|
||||
public async Task<IActionResult> GetComments([FromQuery] int pageStart, [FromQuery] int pageSize, string? username, int? slotId)
|
||||
{
|
||||
User? user = await this.database.UserFromGameRequest(this.Request);
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
|
||||
|
||||
int targetId = slotId.GetValueOrDefault();
|
||||
CommentType type = CommentType.Level;
|
||||
if (!string.IsNullOrWhiteSpace(username))
|
||||
|
@ -55,24 +53,24 @@ public class CommentController : ControllerBase
|
|||
type = CommentType.Profile;
|
||||
}
|
||||
|
||||
List<Comment> comments = await this.database.Comments
|
||||
.Include(c => c.Poster)
|
||||
List<Comment> comments = await this.database.Comments.Include
|
||||
(c => c.Poster)
|
||||
.Where(c => c.TargetId == targetId && c.Type == type)
|
||||
.OrderByDescending(c => c.Timestamp)
|
||||
.Skip(pageStart - 1)
|
||||
.Take(Math.Min(pageSize,
|
||||
30))
|
||||
.Take(Math.Min(pageSize, 30))
|
||||
.ToListAsync();
|
||||
|
||||
string outputXml = comments.Aggregate(string.Empty, (current, comment) => current +
|
||||
comment.Serialize(this.getReaction(user.UserId, comment.CommentId).Result));
|
||||
string outputXml = comments.Aggregate
|
||||
(string.Empty, (current, comment) => current + comment.Serialize(this.getReaction(user.UserId, comment.CommentId).Result));
|
||||
return this.Ok(LbpSerializer.StringElement("comments", outputXml));
|
||||
}
|
||||
|
||||
public async Task<int> getReaction(int userId, int commentId)
|
||||
private async Task<int> getReaction(int userId, int commentId)
|
||||
{
|
||||
Reaction? reaction = await this.database.Reactions.FirstOrDefaultAsync(r => r.UserId == userId && r.TargetId == commentId);
|
||||
if (reaction == null) return 0;
|
||||
|
||||
return reaction.Rating;
|
||||
}
|
||||
|
||||
|
@ -80,11 +78,11 @@ public class CommentController : ControllerBase
|
|||
[HttpPost("postComment/user/{slotId:int}")]
|
||||
public async Task<IActionResult> PostComment(string? username, int? slotId)
|
||||
{
|
||||
this.Request.Body.Position = 0;
|
||||
this.Request.Body.Position = 0;
|
||||
string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
|
||||
|
||||
XmlSerializer serializer = new(typeof(Comment));
|
||||
Comment? comment = (Comment?) serializer.Deserialize(new StringReader(bodyString));
|
||||
Comment? comment = (Comment?)serializer.Deserialize(new StringReader(bodyString));
|
||||
|
||||
CommentType type = (slotId.GetValueOrDefault() == 0 ? CommentType.Profile : CommentType.Level);
|
||||
|
||||
|
@ -112,6 +110,7 @@ public class CommentController : ControllerBase
|
|||
|
||||
Comment? comment = await this.database.Comments.FirstOrDefaultAsync(c => c.CommentId == commentId);
|
||||
if (comment == null) return this.NotFound();
|
||||
|
||||
// if you are not the poster
|
||||
if (comment.PosterUserId != user.UserId)
|
||||
{
|
||||
|
|
|
@ -34,10 +34,6 @@ public class LoginController : ControllerBase
|
|||
await this.Request.Body.CopyToAsync(ms);
|
||||
byte[] loginData = ms.ToArray();
|
||||
|
||||
#if DEBUG
|
||||
await IOFile.WriteAllBytesAsync($"npTicket-{TimestampHelper.TimestampMillis}.txt", loginData);
|
||||
#endif
|
||||
|
||||
NPTicket? npTicket;
|
||||
try
|
||||
{
|
||||
|
@ -145,7 +141,7 @@ public class LoginController : ControllerBase
|
|||
await this.database.SaveChangesAsync();
|
||||
|
||||
// Create a new room on LBP2/3/Vita
|
||||
if (token.GameVersion != GameVersion.LittleBigPlanet1) RoomHelper.CreateRoom(user, token.GameVersion);
|
||||
if (token.GameVersion != GameVersion.LittleBigPlanet1) RoomHelper.CreateRoom(user, token.GameVersion, token.Platform);
|
||||
|
||||
return this.Ok
|
||||
(
|
||||
|
|
|
@ -74,14 +74,14 @@ public class MatchController : ControllerBase
|
|||
|
||||
#endregion
|
||||
|
||||
await LastContactHelper.SetLastContact(user, gameToken.GameVersion);
|
||||
await LastContactHelper.SetLastContact(user, gameToken.GameVersion, gameToken.Platform);
|
||||
|
||||
#region Process match data
|
||||
|
||||
if (matchData is UpdateMyPlayerData playerData)
|
||||
{
|
||||
MatchHelper.SetUserLocation(user.UserId, gameToken.UserLocation);
|
||||
Room? room = RoomHelper.FindRoomByUser(user, gameToken.GameVersion, true);
|
||||
Room? room = RoomHelper.FindRoomByUser(user, gameToken.GameVersion, gameToken.Platform, true);
|
||||
|
||||
if (playerData.RoomState != null)
|
||||
if (room != null && Equals(room.Host, user))
|
||||
|
@ -90,7 +90,7 @@ public class MatchController : ControllerBase
|
|||
|
||||
if (matchData is FindBestRoom && MatchHelper.UserLocations.Count > 1)
|
||||
{
|
||||
FindBestRoomResponse? response = RoomHelper.FindBestRoom(user, gameToken.GameVersion, gameToken.UserLocation);
|
||||
FindBestRoomResponse? response = RoomHelper.FindBestRoom(user, gameToken.GameVersion, gameToken.Platform, gameToken.UserLocation);
|
||||
|
||||
if (response == null) return this.NotFound();
|
||||
|
||||
|
@ -112,7 +112,7 @@ public class MatchController : ControllerBase
|
|||
}
|
||||
|
||||
// Create a new one as requested
|
||||
RoomHelper.CreateRoom(users, gameToken.GameVersion, createRoom.RoomSlot);
|
||||
RoomHelper.CreateRoom(users, gameToken.GameVersion, gameToken.Platform, createRoom.RoomSlot);
|
||||
}
|
||||
|
||||
if (matchData is UpdatePlayersInRoom updatePlayersInRoom)
|
||||
|
|
|
@ -33,10 +33,13 @@ public class PublishController : ControllerBase
|
|||
[HttpPost("startPublish")]
|
||||
public async Task<IActionResult> StartPublish()
|
||||
{
|
||||
User? user = await this.database.UserFromGameRequest(this.Request);
|
||||
if (user == null) return this.StatusCode(403, "");
|
||||
(User, GameToken)? userAndToken = await this.database.UserAndGameTokenFromRequest(this.Request);
|
||||
|
||||
if (user.UsedSlots >= ServerSettings.Instance.EntitledSlots) return this.BadRequest();
|
||||
if (userAndToken == null) return this.StatusCode(403, "");
|
||||
|
||||
// ReSharper disable once PossibleInvalidOperationException
|
||||
User user = userAndToken.Value.Item1;
|
||||
GameToken gameToken = userAndToken.Value.Item2;
|
||||
|
||||
Slot? slot = await this.getSlotFromBody();
|
||||
if (slot == null) return this.BadRequest(); // if the level cant be parsed then it obviously cant be uploaded
|
||||
|
@ -52,6 +55,10 @@ public class PublishController : ControllerBase
|
|||
if (oldSlot == null) return this.NotFound();
|
||||
if (oldSlot.CreatorId != user.UserId) return this.BadRequest();
|
||||
}
|
||||
else if (user.GetUsedSlotsForGame(gameToken.GameVersion, database) > ServerSettings.Instance.EntitledSlots)
|
||||
{
|
||||
return this.StatusCode(403, "");
|
||||
}
|
||||
|
||||
slot.ResourceCollection += "," + slot.IconHash; // tells LBP to upload icon after we process resources here
|
||||
|
||||
|
@ -76,9 +83,6 @@ public class PublishController : ControllerBase
|
|||
// ReSharper disable once PossibleInvalidOperationException
|
||||
User user = userAndToken.Value.Item1;
|
||||
GameToken gameToken = userAndToken.Value.Item2;
|
||||
|
||||
if (user.UsedSlots >= ServerSettings.Instance.EntitledSlots) return this.BadRequest();
|
||||
|
||||
Slot? slot = await this.getSlotFromBody();
|
||||
if (slot?.Location == null) return this.BadRequest();
|
||||
|
||||
|
@ -133,6 +137,11 @@ public class PublishController : ControllerBase
|
|||
return this.Ok(oldSlot.Serialize(gameToken.GameVersion));
|
||||
}
|
||||
|
||||
if (user.GetUsedSlotsForGame(gameToken.GameVersion, database) > ServerSettings.Instance.EntitledSlots)
|
||||
{
|
||||
return this.StatusCode(403, "");
|
||||
}
|
||||
|
||||
//TODO: parse location in body
|
||||
Location l = new()
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace LBPUnion.ProjectLighthouse.Controllers.GameApi.Slots;
|
|||
|
||||
[ApiController]
|
||||
[Route("LITTLEBIGPLANETPS3_XML/")]
|
||||
[Produces("text/plain")]
|
||||
[Produces("text/xml")]
|
||||
public class ReviewController : ControllerBase
|
||||
{
|
||||
private readonly Database database;
|
||||
|
@ -141,51 +141,19 @@ public class ReviewController : ControllerBase
|
|||
|
||||
GameVersion gameVersion = gameToken.GameVersion;
|
||||
|
||||
Random rand = new();
|
||||
|
||||
Review? yourReview = await this.database.Reviews.FirstOrDefaultAsync
|
||||
(r => r.ReviewerId == user.UserId && r.SlotId == slotId && r.Slot.GameVersion <= gameVersion);
|
||||
|
||||
VisitedLevel? visitedLevel = await this.database.VisitedLevels.FirstOrDefaultAsync
|
||||
(v => v.UserId == user.UserId && v.SlotId == slotId && v.Slot.GameVersion <= gameVersion);
|
||||
|
||||
Slot? slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == slotId);
|
||||
if (slot == null) return this.BadRequest();
|
||||
|
||||
bool canNowReviewLevel = slot.CreatorId != user.UserId && visitedLevel != null && yourReview == null;
|
||||
if (canNowReviewLevel)
|
||||
{
|
||||
RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync
|
||||
(r => r.UserId == user.UserId && r.SlotId == slotId && r.Slot.GameVersion <= gameVersion);
|
||||
|
||||
yourReview = new Review();
|
||||
yourReview.ReviewerId = user.UserId;
|
||||
yourReview.Reviewer = user;
|
||||
yourReview.Thumb = ratedLevel?.Rating ?? 0;
|
||||
yourReview.Slot = slot;
|
||||
yourReview.SlotId = slotId;
|
||||
yourReview.Deleted = false;
|
||||
yourReview.DeletedBy = DeletedBy.None;
|
||||
yourReview.Text = "You haven't reviewed this level yet. Edit this to write one!";
|
||||
yourReview.LabelCollection = "";
|
||||
yourReview.Timestamp = TimeHelper.UnixTimeMilliseconds();
|
||||
}
|
||||
|
||||
IQueryable<Review?> reviews = this.database.Reviews.Where(r => r.SlotId == slotId && r.Slot.GameVersion <= gameVersion)
|
||||
.Include(r => r.Reviewer)
|
||||
.Include(r => r.Slot)
|
||||
.OrderByDescending(r => r.ThumbsUp)
|
||||
.ThenByDescending(_ => EF.Functions.Random())
|
||||
.ThenByDescending(r => r.Timestamp)
|
||||
.Skip(pageStart - 1)
|
||||
.Take(pageSize);
|
||||
|
||||
IEnumerable<Review?> prependedReviews;
|
||||
if (canNowReviewLevel) // this can only be true if you have not posted a review but have visited the level
|
||||
// prepend the fake review to the top of the list to be easily edited
|
||||
prependedReviews = reviews.ToList().Prepend(yourReview);
|
||||
else prependedReviews = reviews.ToList();
|
||||
|
||||
string inner = prependedReviews.Aggregate
|
||||
string inner = reviews.ToList().Aggregate
|
||||
(
|
||||
string.Empty,
|
||||
(current, review) =>
|
||||
|
|
|
@ -64,7 +64,9 @@ public class ScoreController : ControllerBase
|
|||
break;
|
||||
}
|
||||
|
||||
IQueryable<Score> existingScore = this.database.Scores.Where(s => s.SlotId == score.SlotId && s.PlayerIdCollection == score.PlayerIdCollection);
|
||||
IQueryable<Score> existingScore = this.database.Scores.Where(s => s.SlotId == score.SlotId)
|
||||
.Where(s => s.PlayerIdCollection == score.PlayerIdCollection)
|
||||
.Where(s => s.Type == score.Type);
|
||||
|
||||
if (existingScore.Any())
|
||||
{
|
||||
|
@ -80,7 +82,7 @@ public class ScoreController : ControllerBase
|
|||
|
||||
await this.database.SaveChangesAsync();
|
||||
|
||||
string myRanking = this.getScores(score.SlotId, score.Type, user);
|
||||
string myRanking = this.getScores(score.SlotId, score.Type, user, -1, 5, "scoreboardSegment");
|
||||
|
||||
return this.Ok(myRanking);
|
||||
}
|
||||
|
@ -103,7 +105,7 @@ public class ScoreController : ControllerBase
|
|||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]
|
||||
private string getScores(int slotId, int type, User user, int pageStart = -1, int pageSize = 5)
|
||||
private string getScores(int slotId, int type, User user, int pageStart = -1, int pageSize = 5, string rootName = "scores")
|
||||
{
|
||||
// This is hella ugly but it technically assigns the proper rank to a score
|
||||
// var needed for Anonymous type returned from SELECT
|
||||
|
@ -136,11 +138,11 @@ public class ScoreController : ControllerBase
|
|||
);
|
||||
|
||||
string res;
|
||||
if (myScore == null) res = LbpSerializer.StringElement("scores", serializedScores);
|
||||
if (myScore == null) res = LbpSerializer.StringElement(rootName, serializedScores);
|
||||
else
|
||||
res = LbpSerializer.TaggedStringElement
|
||||
(
|
||||
"scores",
|
||||
rootName,
|
||||
serializedScores,
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
|
|
|
@ -4,9 +4,11 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Types;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
using LBPUnion.ProjectLighthouse.Types.Reviews;
|
||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -24,18 +26,6 @@ public class SlotsController : ControllerBase
|
|||
this.database = database;
|
||||
}
|
||||
|
||||
private IQueryable<Slot> getSlots(GameVersion gameVersion)
|
||||
{
|
||||
IQueryable<Slot> query = this.database.Slots.Include(s => s.Creator).Include(s => s.Location);
|
||||
|
||||
if (gameVersion == GameVersion.LittleBigPlanetVita || gameVersion == GameVersion.LittleBigPlanetPSP || gameVersion == GameVersion.Unknown)
|
||||
{
|
||||
return query.Where(s => s.GameVersion == gameVersion && !s.SubLevel);
|
||||
}
|
||||
|
||||
return query.Where(s => s.GameVersion <= gameVersion && !s.SubLevel);
|
||||
}
|
||||
|
||||
[HttpGet("slots/by")]
|
||||
public async Task<IActionResult> SlotsBy([FromQuery] string u, [FromQuery] int pageStart, [FromQuery] int pageSize)
|
||||
{
|
||||
|
@ -49,8 +39,7 @@ public class SlotsController : ControllerBase
|
|||
|
||||
string response = Enumerable.Aggregate
|
||||
(
|
||||
this.getSlots
|
||||
(gameVersion)
|
||||
this.database.Slots.ByGameVersion(gameVersion, token.UserId == user.UserId)
|
||||
.Where(s => s.Creator!.Username == user.Username)
|
||||
.Skip(pageStart - 1)
|
||||
.Take(Math.Min(pageSize, ServerSettings.Instance.EntitledSlots)),
|
||||
|
@ -88,13 +77,14 @@ public class SlotsController : ControllerBase
|
|||
|
||||
GameVersion gameVersion = token.GameVersion;
|
||||
|
||||
Slot? slot = await this.getSlots(gameVersion).FirstOrDefaultAsync(s => s.SlotId == id);
|
||||
Slot? slot = await this.database.Slots.ByGameVersion(gameVersion, true).FirstOrDefaultAsync(s => s.SlotId == id);
|
||||
|
||||
if (slot == null) return this.NotFound();
|
||||
|
||||
RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == id && r.UserId == user.UserId);
|
||||
VisitedLevel? visitedLevel = await this.database.VisitedLevels.FirstOrDefaultAsync(r => r.SlotId == id && r.UserId == user.UserId);
|
||||
return this.Ok(slot.Serialize(gameVersion, ratedLevel, visitedLevel));
|
||||
Review? review = await this.database.Reviews.FirstOrDefaultAsync(r => r.SlotId == id && r.ReviewerId == user.UserId);
|
||||
return this.Ok(slot.Serialize(gameVersion, ratedLevel, visitedLevel, review));
|
||||
}
|
||||
|
||||
[HttpGet("slots/cool")]
|
||||
|
@ -129,7 +119,11 @@ public class SlotsController : ControllerBase
|
|||
|
||||
GameVersion gameVersion = token.GameVersion;
|
||||
|
||||
IQueryable<Slot> slots = this.getSlots(gameVersion).OrderByDescending(s => s.FirstUploaded).Skip(pageStart - 1).Take(Math.Min(pageSize, 30));
|
||||
IQueryable<Slot> slots = this.database.Slots.ByGameVersion
|
||||
(gameVersion)
|
||||
.OrderByDescending(s => s.FirstUploaded)
|
||||
.Skip(pageStart - 1)
|
||||
.Take(Math.Min(pageSize, 30));
|
||||
|
||||
string response = Enumerable.Aggregate(slots, string.Empty, (current, slot) => current + slot.Serialize(gameVersion));
|
||||
|
||||
|
@ -160,7 +154,7 @@ public class SlotsController : ControllerBase
|
|||
|
||||
GameVersion gameVersion = token.GameVersion;
|
||||
|
||||
IQueryable<Slot> slots = this.getSlots(gameVersion)
|
||||
IQueryable<Slot> slots = this.database.Slots.ByGameVersion(gameVersion)
|
||||
.Where(s => s.TeamPick)
|
||||
.OrderByDescending(s => s.LastUpdated)
|
||||
.Skip(pageStart - 1)
|
||||
|
@ -194,7 +188,7 @@ public class SlotsController : ControllerBase
|
|||
|
||||
GameVersion gameVersion = token.GameVersion;
|
||||
|
||||
IEnumerable<Slot> slots = this.getSlots(gameVersion).OrderBy(_ => EF.Functions.Random()).Take(Math.Min(pageSize, 30));
|
||||
IEnumerable<Slot> slots = this.database.Slots.ByGameVersion(gameVersion).OrderBy(_ => EF.Functions.Random()).Take(Math.Min(pageSize, 30));
|
||||
|
||||
string response = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize(gameVersion));
|
||||
|
||||
|
@ -383,7 +377,7 @@ public class SlotsController : ControllerBase
|
|||
{
|
||||
if (version == GameVersion.LittleBigPlanetVita || version == GameVersion.LittleBigPlanetPSP || version == GameVersion.Unknown)
|
||||
{
|
||||
return this.getSlots(version);
|
||||
return this.database.Slots.ByGameVersion(version);
|
||||
}
|
||||
|
||||
string _dateFilterType = dateFilterType ?? "";
|
||||
|
|
|
@ -62,10 +62,7 @@ public class AdminSlotController : ControllerBase
|
|||
|
||||
if (slot.Location == null) throw new ArgumentNullException();
|
||||
|
||||
this.database.Locations.Remove(slot.Location);
|
||||
this.database.Slots.Remove(slot);
|
||||
|
||||
await this.database.SaveChangesAsync();
|
||||
await this.database.RemoveSlot(slot);
|
||||
|
||||
return this.Ok();
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ public class RoomVisualizerController : ControllerBase
|
|||
return this.NotFound();
|
||||
#else
|
||||
List<User> users = await this.database.Users.OrderByDescending(_ => EF.Functions.Random()).Take(2).ToListAsync();
|
||||
RoomHelper.CreateRoom(users, GameVersion.LittleBigPlanet2);
|
||||
RoomHelper.CreateRoom(users, GameVersion.LittleBigPlanet2, Platform.PS3);
|
||||
|
||||
foreach (User user in users)
|
||||
{
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#nullable enable
|
||||
using System.Threading.Tasks;
|
||||
using Kettu;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
@ -34,15 +36,20 @@ public class SlotPageController : ControllerBase
|
|||
return this.Redirect($"~/slot/{id}#{commentId}");
|
||||
}
|
||||
|
||||
[HttpGet("postComment")]
|
||||
public async Task<IActionResult> PostComment([FromRoute] int id, [FromQuery] string? msg)
|
||||
[HttpPost("postComment")]
|
||||
public async Task<IActionResult> PostComment([FromRoute] int id, [FromForm] string? msg)
|
||||
{
|
||||
User? user = this.database.UserFromWebRequest(this.Request);
|
||||
if (user == null) return this.Redirect("~/login");
|
||||
|
||||
if (msg == null) return this.Redirect("~/slot/" + id);
|
||||
if (msg == null)
|
||||
{
|
||||
Logger.Log($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", LoggerLevelComments.Instance);
|
||||
return this.Redirect("~/slot/" + id);
|
||||
}
|
||||
|
||||
await this.database.PostComment(user, id, CommentType.Level, msg);
|
||||
Logger.Log($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", LoggerLevelComments.Instance);
|
||||
|
||||
return this.Redirect("~/slot/" + id);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Kettu;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types;
|
||||
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.CodeAnalysis;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Controllers.Website;
|
||||
|
@ -20,20 +19,6 @@ public class UserPageController : ControllerBase
|
|||
this.database = database;
|
||||
}
|
||||
|
||||
[HttpGet("heart")]
|
||||
public async Task<IActionResult> HeartUser([FromRoute] int id)
|
||||
{
|
||||
User? user = this.database.UserFromWebRequest(this.Request);
|
||||
if (user == null) return this.Redirect("~/login");
|
||||
|
||||
User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||
if (heartedUser == null) return this.NotFound();
|
||||
|
||||
await this.database.HeartUser(user, heartedUser);
|
||||
|
||||
return this.Redirect("~/user/" + id);
|
||||
}
|
||||
|
||||
[HttpGet("rateComment")]
|
||||
public async Task<IActionResult> RateComment([FromRoute] int id, [FromQuery] int? commentId, [FromQuery] int? rating)
|
||||
{
|
||||
|
@ -45,15 +30,34 @@ public class UserPageController : ControllerBase
|
|||
return this.Redirect($"~/user/{id}#{commentId}");
|
||||
}
|
||||
|
||||
[HttpGet("postComment")]
|
||||
public async Task<IActionResult> PostComment([FromRoute] int id, [FromQuery] string? msg)
|
||||
[HttpPost("postComment")]
|
||||
public async Task<IActionResult> PostComment([FromRoute] int id, [FromForm] string? msg)
|
||||
{
|
||||
User? user = this.database.UserFromWebRequest(this.Request);
|
||||
if (user == null) return this.Redirect("~/login");
|
||||
|
||||
if (msg == null) return this.Redirect("~/user/" + id);
|
||||
if (msg == null)
|
||||
{
|
||||
Logger.Log($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", LoggerLevelComments.Instance);
|
||||
return this.Redirect("~/user/" + id);
|
||||
}
|
||||
|
||||
await this.database.PostComment(user, id, CommentType.Profile, msg);
|
||||
Logger.Log($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", LoggerLevelComments.Instance);
|
||||
|
||||
return this.Redirect("~/user/" + id);
|
||||
}
|
||||
|
||||
[HttpGet("heart")]
|
||||
public async Task<IActionResult> HeartUser([FromRoute] int id)
|
||||
{
|
||||
User? user = this.database.UserFromWebRequest(this.Request);
|
||||
if (user == null) return this.Redirect("~/login");
|
||||
|
||||
User? heartedUser = await this.database.Users.FirstOrDefaultAsync(u => u.UserId == id);
|
||||
if (heartedUser == null) return this.NotFound();
|
||||
|
||||
await this.database.HeartUser(user, heartedUser);
|
||||
|
||||
return this.Redirect("~/user/" + id);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Types;
|
||||
|
@ -46,7 +47,17 @@ public class Database : DbContext
|
|||
|
||||
public async Task<User> CreateUser(string username, string password)
|
||||
{
|
||||
if (!password.StartsWith("$")) throw new ArgumentException(nameof(password) + " is not a BCrypt hash");
|
||||
if (!password.StartsWith('$')) throw new ArgumentException(nameof(password) + " is not a BCrypt hash");
|
||||
|
||||
// 16 is PSN max, 3 is PSN minimum
|
||||
if (!ServerStatics.IsUnitTesting || !username.StartsWith("unitTestUser"))
|
||||
{
|
||||
if (username.Length > 16 || username.Length < 3) throw new ArgumentException(nameof(username) + " is either too long or too short");
|
||||
|
||||
Regex regex = new("^[a-zA-Z0-9_.-]*$");
|
||||
|
||||
if (!regex.IsMatch(username)) throw new ArgumentException(nameof(username) + " does not match the username regex");
|
||||
}
|
||||
|
||||
User user;
|
||||
if ((user = await this.Users.Where(u => u.Username == username).FirstOrDefaultAsync()) != null) return user;
|
||||
|
@ -82,6 +93,7 @@ public class Database : DbContext
|
|||
UserId = user.UserId,
|
||||
UserLocation = userLocation,
|
||||
GameVersion = npTicket.GameVersion,
|
||||
Platform = npTicket.Platform,
|
||||
};
|
||||
|
||||
this.GameTokens.Add(gameToken);
|
||||
|
@ -143,6 +155,8 @@ public class Database : DbContext
|
|||
|
||||
public async Task<bool> PostComment(User user, int targetId, CommentType type, string message)
|
||||
{
|
||||
if (message.Length > 100) return false;
|
||||
|
||||
if (type == CommentType.Profile)
|
||||
{
|
||||
User? targetUser = await this.Users.FirstOrDefaultAsync(u => u.UserId == targetId);
|
||||
|
@ -151,7 +165,7 @@ public class Database : DbContext
|
|||
else
|
||||
{
|
||||
Slot? targetSlot = await this.Slots.FirstOrDefaultAsync(u => u.SlotId == targetId);
|
||||
if(targetSlot == null) return false;
|
||||
if (targetSlot == null) return false;
|
||||
}
|
||||
|
||||
this.Comments.Add
|
||||
|
|
31
ProjectLighthouse/Helpers/Extensions/SlotsExtensions.cs
Normal file
31
ProjectLighthouse/Helpers/Extensions/SlotsExtensions.cs
Normal file
|
@ -0,0 +1,31 @@
|
|||
using System.Linq;
|
||||
using LBPUnion.ProjectLighthouse.Types;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||
|
||||
public static class SlotsExtensions
|
||||
{
|
||||
public static IQueryable<Slot> ByGameVersion
|
||||
(this DbSet<Slot> set, GameVersion gameVersion, bool includeSublevels = false)
|
||||
=> set.AsQueryable().ByGameVersion(gameVersion, includeSublevels);
|
||||
|
||||
public static IQueryable<Slot> ByGameVersion(this IQueryable<Slot> queryable, GameVersion gameVersion, bool includeSublevels = false)
|
||||
{
|
||||
IQueryable<Slot> query = queryable.Include(s => s.Creator).Include(s => s.Location);
|
||||
|
||||
if (gameVersion == GameVersion.LittleBigPlanetVita || gameVersion == GameVersion.LittleBigPlanetPSP || gameVersion == GameVersion.Unknown)
|
||||
{
|
||||
query = query.Where(s => s.GameVersion == gameVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = query.Where(s => s.GameVersion <= gameVersion);
|
||||
}
|
||||
|
||||
if (!includeSublevels) query = query.Where(s => !s.SubLevel);
|
||||
|
||||
return query;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,13 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Kettu;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types.Files;
|
||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||
|
||||
|
@ -101,4 +107,44 @@ public static class FileHelper
|
|||
}
|
||||
|
||||
public static string[] ResourcesNotUploaded(params string[] hashes) => hashes.Where(hash => !ResourceExists(hash)).ToArray();
|
||||
|
||||
public static void ConvertAllTexturesToPng()
|
||||
{
|
||||
EnsureDirectoryCreated(Path.Combine(Environment.CurrentDirectory, "png"));
|
||||
if (Directory.Exists("r"))
|
||||
{
|
||||
Logger.Log
|
||||
("Converting all textures to PNG. This may take a while if this is the first time running this operation...", LoggerLevelStartup.Instance);
|
||||
|
||||
ConcurrentQueue<string> fileQueue = new();
|
||||
|
||||
foreach (string filename in Directory.GetFiles("r")) fileQueue.Enqueue(filename);
|
||||
|
||||
for(int i = 0; i < Environment.ProcessorCount; i++)
|
||||
{
|
||||
Task.Factory.StartNew
|
||||
(
|
||||
() =>
|
||||
{
|
||||
while (fileQueue.TryDequeue(out string? filename))
|
||||
{
|
||||
LbpFile? file = LbpFile.FromHash(filename.Replace("r" + Path.DirectorySeparatorChar, ""));
|
||||
if (file == null) continue;
|
||||
|
||||
if (file.FileType == LbpFileType.Jpeg || file.FileType == LbpFileType.Png || file.FileType == LbpFileType.Texture)
|
||||
{
|
||||
ImageHelper.LbpFileToPNG(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
while (!fileQueue.IsEmpty)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -11,7 +11,7 @@ public static class LastContactHelper
|
|||
{
|
||||
private static readonly Database database = new();
|
||||
|
||||
public static async Task SetLastContact(User user, GameVersion gameVersion)
|
||||
public static async Task SetLastContact(User user, GameVersion gameVersion, Platform platform)
|
||||
{
|
||||
LastContact? lastContact = await database.LastContacts.Where(l => l.UserId == user.UserId).FirstOrDefaultAsync();
|
||||
|
||||
|
@ -28,6 +28,7 @@ public static class LastContactHelper
|
|||
|
||||
lastContact.Timestamp = TimestampHelper.Timestamp;
|
||||
lastContact.GameVersion = gameVersion;
|
||||
lastContact.Platform = platform;
|
||||
|
||||
await database.SaveChangesAsync();
|
||||
}
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kettu;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
using LBPUnion.ProjectLighthouse.Types.Match;
|
||||
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Helpers;
|
||||
|
||||
|
@ -22,9 +24,25 @@ public class RoomHelper
|
|||
|
||||
private static int roomIdIncrement;
|
||||
|
||||
public static void StartCleanupThread()
|
||||
{
|
||||
// ReSharper disable once FunctionNeverReturns
|
||||
Task.Factory.StartNew
|
||||
(
|
||||
async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
CleanupRooms();
|
||||
await Task.Delay(10000);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
internal static int RoomIdIncrement => roomIdIncrement++;
|
||||
|
||||
public static FindBestRoomResponse? FindBestRoom(User? user, GameVersion roomVersion, string? location)
|
||||
public static FindBestRoomResponse? FindBestRoom(User? user, GameVersion roomVersion, Platform? platform, string? location)
|
||||
{
|
||||
if (roomVersion == GameVersion.LittleBigPlanet1 || roomVersion == GameVersion.LittleBigPlanetPSP)
|
||||
{
|
||||
|
@ -42,6 +60,7 @@ public class RoomHelper
|
|||
}
|
||||
|
||||
rooms = rooms.Where(r => r.RoomVersion == roomVersion).ToList();
|
||||
if (platform != null) rooms = rooms.Where(r => r.RoomPlatform == platform).ToList();
|
||||
|
||||
foreach (Room room in rooms)
|
||||
// Look for rooms looking for players before moving on to rooms that are idle.
|
||||
|
@ -115,7 +134,7 @@ public class RoomHelper
|
|||
return null;
|
||||
}
|
||||
|
||||
public static Room CreateRoom(User user, GameVersion roomVersion, RoomSlot? slot = null)
|
||||
public static Room CreateRoom(User user, GameVersion roomVersion, Platform roomPlatform, RoomSlot? slot = null)
|
||||
=> CreateRoom
|
||||
(
|
||||
new List<User>
|
||||
|
@ -123,9 +142,10 @@ public class RoomHelper
|
|||
user,
|
||||
},
|
||||
roomVersion,
|
||||
roomPlatform,
|
||||
slot
|
||||
);
|
||||
public static Room CreateRoom(List<User> users, GameVersion roomVersion, RoomSlot? slot = null)
|
||||
public static Room CreateRoom(List<User> users, GameVersion roomVersion, Platform roomPlatform, RoomSlot? slot = null)
|
||||
{
|
||||
Room room = new()
|
||||
{
|
||||
|
@ -134,6 +154,7 @@ public class RoomHelper
|
|||
State = RoomState.Idle,
|
||||
Slot = slot ?? PodSlot,
|
||||
RoomVersion = roomVersion,
|
||||
RoomPlatform = roomPlatform,
|
||||
};
|
||||
|
||||
CleanupRooms(room.Host, room);
|
||||
|
@ -143,13 +164,22 @@ public class RoomHelper
|
|||
return room;
|
||||
}
|
||||
|
||||
public static Room? FindRoomByUser(User user, GameVersion roomVersion, bool createIfDoesNotExist = false)
|
||||
public static Room? FindRoomByUser(User user, GameVersion roomVersion, Platform roomPlatform, bool createIfDoesNotExist = false)
|
||||
{
|
||||
lock(Rooms)
|
||||
foreach (Room room in Rooms.Where(room => room.Players.Any(player => user == player)))
|
||||
return room;
|
||||
|
||||
return createIfDoesNotExist ? CreateRoom(user, roomVersion) : null;
|
||||
return createIfDoesNotExist ? CreateRoom(user, roomVersion, roomPlatform) : null;
|
||||
}
|
||||
|
||||
public static Room? FindRoomByUserId(int userId)
|
||||
{
|
||||
lock(Rooms)
|
||||
foreach (Room room in Rooms.Where(room => room.Players.Any(player => player.UserId == userId)))
|
||||
return room;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "InvertIf")]
|
||||
|
@ -157,6 +187,16 @@ public class RoomHelper
|
|||
{
|
||||
lock(Rooms)
|
||||
{
|
||||
int roomCountBeforeCleanup = Rooms.Count;
|
||||
|
||||
// Remove offline players from rooms
|
||||
foreach (Room room in Rooms)
|
||||
{
|
||||
// do not shorten, this prevents collection modified errors
|
||||
List<User> playersToRemove = room.Players.Where(player => player.Status.StatusType == StatusType.Offline).ToList();
|
||||
foreach (User user in playersToRemove) room.Players.Remove(user);
|
||||
}
|
||||
|
||||
// Delete old rooms based on host
|
||||
if (host != null)
|
||||
try
|
||||
|
@ -179,6 +219,13 @@ public class RoomHelper
|
|||
|
||||
Rooms.RemoveAll(r => r.Players.Count == 0); // Remove empty rooms
|
||||
Rooms.RemoveAll(r => r.Players.Count > 4); // Remove obviously bogus rooms
|
||||
|
||||
int roomCountAfterCleanup = Rooms.Count;
|
||||
|
||||
if (roomCountBeforeCleanup != roomCountAfterCleanup)
|
||||
{
|
||||
Logger.Log($"Cleaned up {roomCountBeforeCleanup - roomCountAfterCleanup} rooms.", LoggerLevelMatch.Instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -63,6 +63,12 @@ public class LoggerLevelInflux : LoggerLevel
|
|||
public override string Name => "Influx";
|
||||
}
|
||||
|
||||
public class LoggerLevelComments : LoggerLevel
|
||||
{
|
||||
public static readonly LoggerLevelComments Instance = new();
|
||||
public override string Name => "Comments";
|
||||
}
|
||||
|
||||
public class LoggerLevelAspNet : LoggerLevel
|
||||
{
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
using LBPUnion.ProjectLighthouse;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ProjectLighthouse.Migrations
|
||||
{
|
||||
[DbContext(typeof(Database))]
|
||||
[Migration("20220217045519_AddPlatformForLastContactsAndGameTokens")]
|
||||
public partial class AddPlatformForLastContactsAndGameTokens : Migration
|
||||
{
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Platform",
|
||||
table: "LastContacts",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: -1);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Platform",
|
||||
table: "GameTokens",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: -1);
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Platform",
|
||||
table: "LastContacts");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Platform",
|
||||
table: "GameTokens");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -81,6 +81,9 @@ namespace ProjectLighthouse.Migrations
|
|||
b.Property<int>("GameVersion")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Platform")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("Used")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
|
@ -458,6 +461,9 @@ namespace ProjectLighthouse.Migrations
|
|||
b.Property<int>("GameVersion")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Platform")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("Timestamp")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
{
|
||||
if (version == GameVersion.LittleBigPlanet1 || version == GameVersion.LittleBigPlanetPSP || version == GameVersion.Unknown) continue;
|
||||
|
||||
FindBestRoomResponse? response = RoomHelper.FindBestRoom(null, version, null);
|
||||
FindBestRoomResponse? response = RoomHelper.FindBestRoom(null, version, null, null);
|
||||
string text = response == null ? "No room found." : "Room " + response.RoomId;
|
||||
|
||||
<p><b>Best room for @version.ToPrettyString()</b>: @text</p>
|
||||
|
@ -72,7 +72,7 @@
|
|||
<b>You are currently in this room.</b>
|
||||
</p>
|
||||
}
|
||||
<p>@room.Players.Count players, state is @room.State, version is @room.RoomVersion.ToPrettyString()</p>
|
||||
<p>@room.Players.Count players, state is @room.State, version is @room.RoomVersion.ToPrettyString()on paltform @room.RoomPlatform</p>
|
||||
<p>Slot type: @room.Slot.SlotType, slot id: @room.Slot.SlotId</p>
|
||||
@foreach (User player in room.Players)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
@using System.IO
|
||||
@using System.Web
|
||||
@using LBPUnion.ProjectLighthouse.Types.Profiles
|
||||
|
||||
<div class="ui yellow segment" id="comments">
|
||||
<style>
|
||||
.comment {
|
||||
|
@ -23,18 +22,35 @@
|
|||
}
|
||||
else if (!Model.CommentsEnabled)
|
||||
{
|
||||
<b><i>Comments are disabled</i></b>
|
||||
<b>
|
||||
<i>Comments are disabled.</i>
|
||||
</b>
|
||||
}
|
||||
|
||||
@for (int i = 0; i < Model.Comments.Count; i++)
|
||||
@if (Model.CommentsEnabled && Model.User != null)
|
||||
{
|
||||
<div class="ui divider"></div>
|
||||
<form class="ui reply form" action="@Url.RouteUrl(ViewContext.RouteData.Values)/postComment" method="post">
|
||||
<div class="field">
|
||||
<textarea style="min-height: 70px; height: 70px; max-height:120px" name="msg"></textarea>
|
||||
</div>
|
||||
<input type="submit" class="ui blue button">
|
||||
</form>
|
||||
<br>
|
||||
}
|
||||
|
||||
@for(int i = 0; i < Model.Comments.Count; i++)
|
||||
{
|
||||
Comment comment = Model.Comments[i];
|
||||
DateTimeOffset timestamp = DateTimeOffset.FromUnixTimeSeconds(comment.Timestamp / 1000);
|
||||
StringWriter messageWriter = new();
|
||||
HttpUtility.HtmlDecode(comment.getComment(), messageWriter);
|
||||
|
||||
string decodedMessage = messageWriter.ToString();
|
||||
string url = Url.RouteUrl(ViewContext.RouteData.Values);
|
||||
|
||||
int rating = comment.ThumbsUp - comment.ThumbsDown;
|
||||
|
||||
<div style="display: flex" id="@comment.CommentId">
|
||||
<div class="voting">
|
||||
<a href="@url/rateComment?commentId=@(comment.CommentId)&rating=@(comment.YourThumb == 1 ? 0 : 1)">
|
||||
|
@ -50,7 +66,9 @@
|
|||
<b><a href="/user/@comment.PosterUserId">@comment.Poster.Username</a>: </b>
|
||||
@if (comment.Deleted)
|
||||
{
|
||||
<i><span>@decodedMessage</span></i>
|
||||
<i>
|
||||
<span>@decodedMessage</span>
|
||||
</i>
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -66,13 +84,4 @@
|
|||
</div>
|
||||
</div>
|
||||
}
|
||||
@if(Model.CommentsEnabled && Model.User != null){
|
||||
<div class="ui divider"></div>
|
||||
<form class="ui reply form" action="@Url.RouteUrl(ViewContext.RouteData.Values)/postComment">
|
||||
<div class="field">
|
||||
<textarea style="min-height: 70px; height: 70px; max-height:120px" name="msg"></textarea>
|
||||
</div>
|
||||
<input type="submit" class="ui blue button">
|
||||
</form>
|
||||
}
|
||||
</div>
|
|
@ -38,7 +38,7 @@
|
|||
<div class="field">
|
||||
<label>Username</label>
|
||||
<div class="ui left icon input">
|
||||
<input type="text" name="username" id="text" placeholder="Username">
|
||||
<input type="text" name="username" id="text" placeholder="Username" pattern="^[a-zA-Z0-9_.-]*$" minlength="3" maxlength="16">
|
||||
<i class="user icon"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Kettu;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Logging;
|
||||
using LBPUnion.ProjectLighthouse.Types.Files;
|
||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
@ -82,41 +78,10 @@ public static class Program
|
|||
return;
|
||||
}
|
||||
|
||||
FileHelper.EnsureDirectoryCreated(Path.Combine(Environment.CurrentDirectory, "png"));
|
||||
if (Directory.Exists("r"))
|
||||
{
|
||||
Logger.Log
|
||||
("Converting all textures to PNG. This may take a while if this is the first time running this operation...", LoggerLevelStartup.Instance);
|
||||
FileHelper.ConvertAllTexturesToPng();
|
||||
|
||||
ConcurrentQueue<string> fileQueue = new();
|
||||
|
||||
foreach (string filename in Directory.GetFiles("r")) fileQueue.Enqueue(filename);
|
||||
|
||||
for(int i = 0; i < Environment.ProcessorCount; i++)
|
||||
{
|
||||
Task.Factory.StartNew
|
||||
(
|
||||
() =>
|
||||
{
|
||||
while (fileQueue.TryDequeue(out string? filename))
|
||||
{
|
||||
LbpFile? file = LbpFile.FromHash(filename.Replace("r" + Path.DirectorySeparatorChar, ""));
|
||||
if (file == null) continue;
|
||||
|
||||
if (file.FileType == LbpFileType.Jpeg || file.FileType == LbpFileType.Png || file.FileType == LbpFileType.Texture)
|
||||
{
|
||||
ImageHelper.LbpFileToPNG(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
while (!fileQueue.IsEmpty)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
}
|
||||
}
|
||||
Logger.Log("Starting room cleanup thread...", LoggerLevelStartup.Instance);
|
||||
RoomHelper.StartCleanupThread();
|
||||
|
||||
stopwatch.Stop();
|
||||
Logger.Log($"Ready! Startup took {stopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...", LoggerLevelStartup.Instance);
|
||||
|
|
|
@ -250,7 +250,8 @@ public class Startup
|
|||
|
||||
if (gameToken != null && gameToken.GameVersion == GameVersion.LittleBigPlanet1)
|
||||
// Ignore UserFromGameToken null because user must exist for a token to exist
|
||||
await LastContactHelper.SetLastContact((await database.UserFromGameToken(gameToken))!, GameVersion.LittleBigPlanet1);
|
||||
await LastContactHelper.SetLastContact
|
||||
((await database.UserFromGameToken(gameToken))!, GameVersion.LittleBigPlanet1, gameToken.Platform);
|
||||
}
|
||||
#nullable disable
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||
namespace LBPUnion.ProjectLighthouse.Types;
|
||||
|
||||
[ApiController]
|
||||
[Route("/api/v1/")]
|
||||
[Route("/api/v1")]
|
||||
[Produces("application/json")]
|
||||
public class ApiEndpointController : ControllerBase
|
||||
{}
|
|
@ -1,6 +1,7 @@
|
|||
#nullable enable
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Categories;
|
||||
|
@ -34,6 +35,8 @@ public class CustomCategory : Category
|
|||
public sealed override string IconHash { get; set; }
|
||||
public sealed override string Endpoint { get; set; }
|
||||
public override Slot? GetPreviewSlot(Database database) => database.Slots.FirstOrDefault(s => s.SlotId == this.SlotIds[0]);
|
||||
public override IEnumerable<Slot> GetSlots(Database database, int pageStart, int pageSize) => database.Slots.Where(s => this.SlotIds.Contains(s.SlotId));
|
||||
public override IEnumerable<Slot> GetSlots
|
||||
(Database database, int pageStart, int pageSize)
|
||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3).Where(s => this.SlotIds.Contains(s.SlotId));
|
||||
public override int GetTotalSlots(Database database) => this.SlotIds.Count;
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
|
@ -16,5 +17,11 @@ public class HeartedCategory : CategoryWithUser
|
|||
public override Slot? GetPreviewSlot(Database database, User user) => database.HeartedLevels.FirstOrDefault(h => h.UserId == user.UserId)?.Slot;
|
||||
public override int GetTotalSlots(Database database, User user) => database.HeartedLevels.Count(h => h.UserId == user.UserId);
|
||||
public override IEnumerable<Slot> GetSlots(Database database, User user, int pageStart, int pageSize)
|
||||
=> database.HeartedLevels.Where(h => h.UserId == user.UserId).Include(h => h.Slot).Select(h => h.Slot).Skip(pageStart).Take(Math.Min(pageSize, 20));
|
||||
=> database.HeartedLevels.Where
|
||||
(h => h.UserId == user.UserId)
|
||||
.Include(h => h.Slot)
|
||||
.Select(h => h.Slot)
|
||||
.ByGameVersion(GameVersion.LittleBigPlanet3)
|
||||
.Skip(pageStart)
|
||||
.Take(Math.Min(pageSize, 20));
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Categories;
|
||||
|
@ -15,6 +16,6 @@ public class NewestLevelsCategory : Category
|
|||
public override Slot? GetPreviewSlot(Database database) => database.Slots.OrderByDescending(s => s.FirstUploaded).FirstOrDefault();
|
||||
public override IEnumerable<Slot> GetSlots
|
||||
(Database database, int pageStart, int pageSize)
|
||||
=> database.Slots.OrderByDescending(s => s.FirstUploaded).Skip(pageStart - 1).Take(Math.Min(pageSize, 20));
|
||||
=> database.Slots.ByGameVersion(GameVersion.LittleBigPlanet3).OrderByDescending(s => s.FirstUploaded).Skip(pageStart - 1).Take(Math.Min(pageSize, 20));
|
||||
public override int GetTotalSlots(Database database) => database.Slots.Count();
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
|
@ -18,7 +19,13 @@ public class QueueCategory : CategoryWithUser
|
|||
public override Slot? GetPreviewSlot(Database database, User user)
|
||||
=> database.QueuedLevels.Include(q => q.Slot).FirstOrDefault(q => q.UserId == user.UserId)?.Slot;
|
||||
public override IEnumerable<Slot> GetSlots(Database database, User user, int pageStart, int pageSize)
|
||||
=> database.QueuedLevels.Include(q => q.Slot).Include(q => q.Slot.Location).Select(q => q.Slot).Skip(pageStart - 1).Take(Math.Min(pageSize, 20));
|
||||
=> database.QueuedLevels.Include
|
||||
(q => q.Slot)
|
||||
.Include(q => q.Slot.Location)
|
||||
.Select(q => q.Slot)
|
||||
.ByGameVersion(GameVersion.LittleBigPlanet3)
|
||||
.Skip(pageStart - 1)
|
||||
.Take(Math.Min(pageSize, 20));
|
||||
|
||||
public override int GetTotalSlots(Database database, User user) => database.QueuedLevels.Count(q => q.UserId == user.UserId);
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Categories;
|
||||
|
@ -15,6 +16,11 @@ public class TeamPicksCategory : Category
|
|||
public override Slot? GetPreviewSlot(Database database) => database.Slots.OrderByDescending(s => s.FirstUploaded).FirstOrDefault(s => s.TeamPick);
|
||||
public override IEnumerable<Slot> GetSlots
|
||||
(Database database, int pageStart, int pageSize)
|
||||
=> database.Slots.OrderByDescending(s => s.FirstUploaded).Where(s => s.TeamPick).Skip(pageStart - 1).Take(Math.Min(pageSize, 20));
|
||||
=> database.Slots.ByGameVersion
|
||||
(GameVersion.LittleBigPlanet3)
|
||||
.OrderByDescending(s => s.FirstUploaded)
|
||||
.Where(s => s.TeamPick)
|
||||
.Skip(pageStart - 1)
|
||||
.Take(Math.Min(pageSize, 20));
|
||||
public override int GetTotalSlots(Database database) => database.Slots.Count(s => s.TeamPick);
|
||||
}
|
|
@ -20,6 +20,8 @@ public class GameToken
|
|||
|
||||
public GameVersion GameVersion { get; set; }
|
||||
|
||||
public Platform Platform { get; set; }
|
||||
|
||||
// Set by /authentication webpage
|
||||
public bool Approved { get; set; }
|
||||
|
||||
|
|
|
@ -299,29 +299,41 @@ public class Slot
|
|||
LbpSerializer.StringElement("leveltype", this.LevelType) +
|
||||
LbpSerializer.StringElement("yourRating", yourRatingStats?.RatingLBP1) +
|
||||
LbpSerializer.StringElement("yourDPadRating", yourRatingStats?.Rating) +
|
||||
LbpSerializer.StringElement("yourLBP1PlayCount", yourVisitedStats?.PlaysLBP1) +
|
||||
LbpSerializer.StringElement("yourLBP2PlayCount", yourVisitedStats?.PlaysLBP2) +
|
||||
LbpSerializer.StringElement("yourLBP3PlayCount", yourVisitedStats?.PlaysLBP3) +
|
||||
LbpSerializer.StringElement("yourlbpPlayCount", yourVisitedStats?.PlaysLBP1) +
|
||||
LbpSerializer.StringElement("yourlbp3PlayCount", yourVisitedStats?.PlaysLBP3) +
|
||||
yourReview?.Serialize("yourReview") +
|
||||
LbpSerializer.StringElement("reviewsEnabled", ServerSettings.Instance.LevelReviewsEnabled) +
|
||||
LbpSerializer.StringElement("commentsEnabled", ServerSettings.Instance.LevelCommentsEnabled) +
|
||||
LbpSerializer.StringElement("reviewCount", this.ReviewCount);
|
||||
|
||||
int yourPlays;
|
||||
int plays;
|
||||
int playsComplete;
|
||||
int playsUnique;
|
||||
|
||||
if (gameVersion == GameVersion.LittleBigPlanetVita)
|
||||
{
|
||||
slotData += LbpSerializer.StringElement("yourLBP2PlayCount", yourVisitedStats?.PlaysLBPVita) +
|
||||
LbpSerializer.StringElement("lbp2PlayCount", this.PlaysLBPVita) +
|
||||
LbpSerializer.StringElement("lbp2CompletionCount", this.PlaysLBPVitaComplete) +
|
||||
LbpSerializer.StringElement("lbp2UniquePlayCount", this.PlaysLBPVitaUnique);
|
||||
yourPlays = yourVisitedStats?.PlaysLBPVita ?? 0;
|
||||
plays = this.PlaysLBPVita;
|
||||
playsComplete = this.PlaysLBPVitaComplete;
|
||||
playsUnique = this.PlaysLBPVitaUnique;
|
||||
}
|
||||
else
|
||||
{
|
||||
slotData += LbpSerializer.StringElement("yourLBP2PlayCount", yourVisitedStats?.PlaysLBPVita) +
|
||||
LbpSerializer.StringElement("lbp2PlayCount", this.PlaysLBP2) +
|
||||
LbpSerializer.StringElement("lbp2CompletionCount", this.PlaysLBP2Complete) +
|
||||
LbpSerializer.StringElement("lbp2UniquePlayCount", this.PlaysLBP2Unique); // not actually used ingame, as per above comment
|
||||
yourPlays = yourVisitedStats?.PlaysLBP2 ?? 0;
|
||||
plays = this.PlaysLBP2;
|
||||
playsComplete = this.PlaysLBP2Complete;
|
||||
playsUnique = this.PlaysLBP2Unique;
|
||||
}
|
||||
|
||||
slotData += LbpSerializer.StringElement("yourlbp2PlayCount", yourPlays) +
|
||||
LbpSerializer.StringElement("lbp2PlayCount", plays) +
|
||||
LbpSerializer.StringElement("playCount", plays) +
|
||||
LbpSerializer.StringElement("lbp2CompletionCount", playsComplete) +
|
||||
LbpSerializer.StringElement("completionCount", playsComplete) +
|
||||
LbpSerializer.StringElement("lbp2UniquePlayCount", playsUnique) + // not actually used ingame, as per above comment
|
||||
LbpSerializer.StringElement("uniquePlayCount", playsUnique);
|
||||
|
||||
return LbpSerializer.TaggedStringElement("slot", slotData, "type", "user");
|
||||
}
|
||||
}
|
|
@ -1,23 +1,37 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text.Json.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Match;
|
||||
|
||||
public class Room
|
||||
{
|
||||
public List<User> Players;
|
||||
public int RoomId;
|
||||
[JsonIgnore]
|
||||
public List<User> Players { get; set; }
|
||||
|
||||
public GameVersion RoomVersion;
|
||||
public RoomSlot Slot;
|
||||
public RoomState State;
|
||||
public int RoomId { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public GameVersion RoomVersion { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public Platform RoomPlatform { get; set; }
|
||||
|
||||
public RoomSlot Slot { get; set; }
|
||||
public RoomState State { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsInPod => this.Slot.SlotType == SlotType.Pod;
|
||||
|
||||
[JsonIgnore]
|
||||
public bool IsLookingForPlayers => this.State == RoomState.PlayingLevel || this.State == RoomState.DivingInWaiting;
|
||||
|
||||
[JsonIgnore]
|
||||
public User Host => this.Players[0];
|
||||
|
||||
public int PlayerCount => this.Players.Count;
|
||||
|
||||
#nullable enable
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
|
|
|
@ -4,6 +4,6 @@ namespace LBPUnion.ProjectLighthouse.Types.Match;
|
|||
|
||||
public class RoomSlot
|
||||
{
|
||||
public int SlotId;
|
||||
public SlotType SlotType;
|
||||
public int SlotId { get; set; }
|
||||
public SlotType SlotType { get; set; }
|
||||
}
|
|
@ -10,4 +10,6 @@ public class LastContact
|
|||
public long Timestamp { get; set; }
|
||||
|
||||
public GameVersion GameVersion { get; set; } = GameVersion.Unknown;
|
||||
|
||||
public Platform Platform { get; set; } = Platform.Unknown;
|
||||
}
|
7
ProjectLighthouse/Types/Profiles/StatusType.cs
Normal file
7
ProjectLighthouse/Types/Profiles/StatusType.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||
|
||||
public enum StatusType
|
||||
{
|
||||
Offline = 0,
|
||||
Online = 1,
|
||||
}
|
48
ProjectLighthouse/Types/Profiles/UserStatus.cs
Normal file
48
ProjectLighthouse/Types/Profiles/UserStatus.cs
Normal file
|
@ -0,0 +1,48 @@
|
|||
#nullable enable
|
||||
using System.Linq;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Types.Match;
|
||||
|
||||
namespace LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||
|
||||
public class UserStatus
|
||||
{
|
||||
public StatusType StatusType { get; set; }
|
||||
public GameVersion? CurrentVersion { get; set; }
|
||||
public Platform? CurrentPlatform { get; set; }
|
||||
public Room? CurrentRoom { get; set; }
|
||||
|
||||
public UserStatus()
|
||||
{}
|
||||
|
||||
public UserStatus(Database database, int userId)
|
||||
{
|
||||
LastContact? lastContact = database.LastContacts.Where(l => l.UserId == userId).FirstOrDefault(l => TimestampHelper.Timestamp - l.Timestamp < 300);
|
||||
|
||||
if (lastContact == null)
|
||||
{
|
||||
StatusType = StatusType.Offline;
|
||||
CurrentVersion = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
StatusType = StatusType.Online;
|
||||
CurrentVersion = lastContact.GameVersion;
|
||||
CurrentPlatform = lastContact.Platform;
|
||||
}
|
||||
|
||||
CurrentRoom = RoomHelper.FindRoomByUserId(userId);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
CurrentVersion ??= GameVersion.Unknown;
|
||||
CurrentPlatform ??= Platform.Unknown;
|
||||
return this.StatusType switch
|
||||
{
|
||||
StatusType.Online => $"Currently online on {((GameVersion)this.CurrentVersion).ToPrettyString()} on {((Platform)this.CurrentPlatform)}",
|
||||
StatusType.Offline => "Offline",
|
||||
_ => "Unknown",
|
||||
};
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ using System.ComponentModel.DataAnnotations.Schema;
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Helpers;
|
||||
using LBPUnion.ProjectLighthouse.Serialization;
|
||||
using LBPUnion.ProjectLighthouse.Types.Profiles;
|
||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||
|
@ -153,16 +152,10 @@ public class User
|
|||
#nullable enable
|
||||
[NotMapped]
|
||||
[JsonIgnore]
|
||||
public string Status {
|
||||
public UserStatus Status {
|
||||
get {
|
||||
using Database database = new();
|
||||
LastContact? lastMatch = database.LastContacts.Where
|
||||
(l => l.UserId == this.UserId)
|
||||
.FirstOrDefault(l => TimestampHelper.Timestamp - l.Timestamp < 300);
|
||||
|
||||
if (lastMatch == null) return "Offline";
|
||||
|
||||
return "Currently online on " + lastMatch.GameVersion.ToPrettyString();
|
||||
return new UserStatus(database, this.UserId);
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
|
@ -208,9 +201,9 @@ public class User
|
|||
"planets",
|
||||
gameVersion switch
|
||||
{
|
||||
GameVersion.LittleBigPlanet2 => PlanetHashLBP2,
|
||||
GameVersion.LittleBigPlanet3 => PlanetHashLBP3,
|
||||
GameVersion.LittleBigPlanetVita => PlanetHashLBPVita,
|
||||
GameVersion.LittleBigPlanet2 => this.PlanetHashLBP2,
|
||||
GameVersion.LittleBigPlanet3 => this.PlanetHashLBP3,
|
||||
GameVersion.LittleBigPlanetVita => this.PlanetHashLBPVita,
|
||||
_ => "", // other versions do not have custom planets
|
||||
}
|
||||
);
|
||||
|
@ -230,11 +223,14 @@ public class User
|
|||
}
|
||||
}
|
||||
|
||||
public int GetUsedSlotsForGame(GameVersion version)
|
||||
#nullable enable
|
||||
public int GetUsedSlotsForGame(GameVersion version, Database? database = null)
|
||||
{
|
||||
using Database database = new();
|
||||
database ??= new Database();
|
||||
|
||||
return database.Slots.Count(s => s.CreatorId == this.UserId && s.GameVersion == version);
|
||||
}
|
||||
#nullable disable
|
||||
|
||||
/// <summary>
|
||||
/// The number of slots remaining on the earth
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue