diff --git a/ProjectLighthouse.sln.DotSettings b/ProjectLighthouse.sln.DotSettings
index 698d69e9..ab04bcc9 100644
--- a/ProjectLighthouse.sln.DotSettings
+++ b/ProjectLighthouse.sln.DotSettings
@@ -71,7 +71,9 @@
UseExplicitType
UseExplicitType
UseExplicitType
+ LBP
MM
+ NP
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"><ExtraRule Prefix="" Suffix="" Style="aaBb" /></Policy>
<Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
@@ -93,10 +95,12 @@
True
True
True
+ True
True
True
True
True
+ True
True
True
True
diff --git a/ProjectLighthouse/Controllers/FriendsController.cs b/ProjectLighthouse/Controllers/FriendsController.cs
new file mode 100644
index 00000000..6cd14fce
--- /dev/null
+++ b/ProjectLighthouse/Controllers/FriendsController.cs
@@ -0,0 +1,92 @@
+#nullable enable
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using System.Xml.Serialization;
+using LBPUnion.ProjectLighthouse.Helpers;
+using LBPUnion.ProjectLighthouse.Serialization;
+using LBPUnion.ProjectLighthouse.Types;
+using LBPUnion.ProjectLighthouse.Types.Profiles;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+
+namespace LBPUnion.ProjectLighthouse.Controllers
+{
+ [ApiController]
+ [Route("LITTLEBIGPLANETPS3_XML/")]
+ public class FriendsController : ControllerBase
+ {
+ private readonly Database database;
+
+ public FriendsController(Database database)
+ {
+ this.database = database;
+ }
+
+ [HttpPost("npdata")]
+ public async Task NPData()
+ {
+ User? user = await this.database.UserFromRequest(this.Request);
+ if (user == null) return this.StatusCode(403, "");
+
+ this.Request.Body.Position = 0;
+ string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
+
+ XmlSerializer serializer = new(typeof(NPData));
+ NPData? npData = (NPData?)serializer.Deserialize(new StringReader(bodyString));
+ if (npData == null) return this.BadRequest();
+
+ List friends = new();
+ foreach (string friendName in npData.Friends)
+ {
+ User? friend = await this.database.Users.FirstOrDefaultAsync(u => u.Username == friendName);
+ if (friend == null) continue;
+
+ friends.Add(friend.UserId);
+ }
+
+ List blockedUsers = new();
+ foreach (string blockedUserName in npData.BlockedUsers)
+ {
+ User? blockedUser = await this.database.Users.FirstOrDefaultAsync(u => u.Username == blockedUserName);
+ if (blockedUser == null) continue;
+
+ blockedUsers.Add(blockedUser.UserId);
+ }
+
+ if (FriendHelper.FriendIdsByUserId.ContainsKey(user.UserId))
+ {
+ FriendHelper.FriendIdsByUserId.Remove(user.UserId);
+ FriendHelper.BlockedIdsByUserId.Remove(user.UserId);
+ }
+
+ FriendHelper.FriendIdsByUserId.Add(user.UserId, friends.ToArray());
+ FriendHelper.BlockedIdsByUserId.Add(user.UserId, blockedUsers.ToArray());
+
+ return this.Ok();
+ }
+
+ [HttpGet("myFriends")]
+ public async Task MyFriends()
+ {
+ User? user = await this.database.UserFromRequest(this.Request);
+ if (user == null) return this.StatusCode(403, "");
+
+ if (!FriendHelper.FriendIdsByUserId.TryGetValue(user.UserId, out int[]? friendIds) || friendIds == null)
+ {
+ return this.NotFound();
+ }
+
+ string friends = "";
+ foreach (int friendId in friendIds)
+ {
+ User? friend = await this.database.Users.Include(u => u.Location).FirstOrDefaultAsync(u => u.UserId == friendId);
+ if (friend == null) continue;
+
+ friends += friend.Serialize();
+ }
+
+ return this.Ok(LbpSerializer.StringElement("myFriends", friends));
+ }
+ }
+}
\ No newline at end of file
diff --git a/ProjectLighthouse/Controllers/ReviewController.cs b/ProjectLighthouse/Controllers/ReviewController.cs
new file mode 100644
index 00000000..cece8a3e
--- /dev/null
+++ b/ProjectLighthouse/Controllers/ReviewController.cs
@@ -0,0 +1,78 @@
+#nullable enable
+using System;
+using System.Threading.Tasks;
+using LBPUnion.ProjectLighthouse.Types;
+using LBPUnion.ProjectLighthouse.Types.Levels;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.EntityFrameworkCore;
+
+namespace LBPUnion.ProjectLighthouse.Controllers
+{
+ [ApiController]
+ [Route("LITTLEBIGPLANETPS3_XML/")]
+ [Produces("text/plain")]
+ public class ReviewController : ControllerBase
+ {
+ private readonly Database database;
+
+ public ReviewController(Database database)
+ {
+ this.database = database;
+ }
+
+ // LBP1 rating
+ [HttpPost("rate/user/{slotId}")]
+ public async Task Rate(int slotId, [FromQuery] int rating)
+ {
+ User? user = await this.database.UserFromRequest(this.Request);
+ if (user == null) return this.StatusCode(403, "");
+
+ Slot? slot = await this.database.Slots.Include(s => s.Creator).Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == slotId);
+ if (slot == null) return this.StatusCode(403, "");
+
+ RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == user.UserId);
+ if (ratedLevel == null)
+ {
+ ratedLevel = new();
+ ratedLevel.SlotId = slotId;
+ ratedLevel.UserId = user.UserId;
+ ratedLevel.Rating = 0;
+ this.database.RatedLevels.Add(ratedLevel);
+ }
+
+ ratedLevel.RatingLBP1 = Math.Max(Math.Min(5, rating), 0);
+
+ await this.database.SaveChangesAsync();
+
+ return this.Ok();
+ }
+
+ // LBP2 and beyond rating
+ [HttpPost("dpadrate/user/{slotId}")]
+ public async Task DPadRate(int slotId, [FromQuery] int rating)
+ {
+ User? user = await this.database.UserFromRequest(this.Request);
+ if (user == null) return this.StatusCode(403, "");
+
+ Slot? slot = await this.database.Slots.Include(s => s.Creator).Include(s => s.Location).FirstOrDefaultAsync(s => s.SlotId == slotId);
+ if (slot == null) return this.StatusCode(403, "");
+
+ RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == slotId && r.UserId == user.UserId);
+ if (ratedLevel == null)
+ {
+ ratedLevel = new();
+ ratedLevel.SlotId = slotId;
+ ratedLevel.UserId = user.UserId;
+ ratedLevel.RatingLBP1 = 0;
+ this.database.RatedLevels.Add(ratedLevel);
+ }
+
+ ratedLevel.Rating = Math.Max(Math.Min(1, rating), -1);
+
+ await this.database.SaveChangesAsync();
+
+ return this.Ok();
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/ProjectLighthouse/Controllers/SlotsController.cs b/ProjectLighthouse/Controllers/SlotsController.cs
index 953ea027..2a01f5fc 100644
--- a/ProjectLighthouse/Controllers/SlotsController.cs
+++ b/ProjectLighthouse/Controllers/SlotsController.cs
@@ -1,5 +1,6 @@
#nullable enable
using System;
+using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using LBPUnion.ProjectLighthouse.Serialization;
@@ -45,19 +46,24 @@ namespace LBPUnion.ProjectLighthouse.Controllers
[HttpGet("s/user/{id:int}")]
public async Task SUser(int id)
{
+ User? user = await this.database.UserFromRequest(this.Request);
+ if (user == null) return this.StatusCode(403, "");
+
Token? token = await this.database.TokenFromRequest(this.Request);
if (token == null) return this.BadRequest();
GameVersion gameVersion = token.GameVersion;
- Slot slot = await this.database.Slots.Where(s => s.GameVersion <= gameVersion)
+ Slot? slot = await this.database.Slots.Where(s => s.GameVersion <= gameVersion)
.Include(s => s.Creator)
.Include(s => s.Location)
.FirstOrDefaultAsync(s => s.SlotId == id);
if (slot == null) return this.NotFound();
- return this.Ok(slot.Serialize());
+ RatedLevel? ratedLevel = await this.database.RatedLevels.FirstOrDefaultAsync(r => r.SlotId == id && r.UserId == user.UserId);
+ string res = ratedLevel != null ? slot.Serialize(ratedLevel.RatingLBP1, ratedLevel.Rating) : slot.Serialize();
+ return this.Ok(res);
}
[HttpGet("slots/lbp2cool")]
@@ -110,15 +116,20 @@ namespace LBPUnion.ProjectLighthouse.Controllers
if (token == null) return this.BadRequest();
GameVersion gameVersion = token.GameVersion;
+ int slotCount = await this.database.Slots.Where(s => s.GameVersion <= gameVersion).CountAsync();
+ pageSize = Math.Min(pageSize, 30);
+
+ int skipCount = new Random().Next(seed, slotCount) + pageStart - 1;
// TODO: Incorporate seed?
- IQueryable slots = this.database.Slots.Where(s => s.GameVersion <= gameVersion)
- .OrderBy(_ => Guid.NewGuid())
+ IEnumerable slots = this.database.Slots.Where(s => s.GameVersion <= gameVersion)
.Include(s => s.Creator)
.Include(s => s.Location)
- .Skip(pageStart - 1)
- .Take(Math.Min(pageSize, 30));
- string response = Enumerable.Aggregate(slots, string.Empty, (current, slot) => current + slot.Serialize());
+ .Skip(skipCount)
+ .Take(pageSize)
+ .AsEnumerable();
+
+ string response = slots.Aggregate(string.Empty, (current, slot) => current + slot.Serialize());
return this.Ok(LbpSerializer.TaggedStringElement("slots", response, "hint_start", pageStart + Math.Min(pageSize, 30)));
}
diff --git a/ProjectLighthouse/Controllers/StatisticsController.cs b/ProjectLighthouse/Controllers/StatisticsController.cs
index e27e52ea..9deb12c4 100644
--- a/ProjectLighthouse/Controllers/StatisticsController.cs
+++ b/ProjectLighthouse/Controllers/StatisticsController.cs
@@ -39,5 +39,8 @@ namespace LBPUnion.ProjectLighthouse.Controllers
("planetStats", LbpSerializer.StringElement("totalSlotCount", totalSlotCount) + LbpSerializer.StringElement("mmPicksCount", mmPicksCount))
);
}
+
+ [HttpGet("planetStats/totalLevelCount")]
+ public async Task TotalLevelCount() => this.Ok((await this.database.Slots.CountAsync()).ToString());
}
}
\ No newline at end of file
diff --git a/ProjectLighthouse/Database.cs b/ProjectLighthouse/Database.cs
index 57b18abb..fce30fd4 100644
--- a/ProjectLighthouse/Database.cs
+++ b/ProjectLighthouse/Database.cs
@@ -27,6 +27,7 @@ namespace LBPUnion.ProjectLighthouse
public DbSet Photos { get; set; }
public DbSet LastMatches { get; set; }
public DbSet VisitedLevels { get; set; }
+ public DbSet RatedLevels { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseMySql(ServerSettings.DbConnectionString, MySqlServerVersion.LatestSupportedServerVersion);
diff --git a/ProjectLighthouse/Helpers/FriendHelper.cs b/ProjectLighthouse/Helpers/FriendHelper.cs
new file mode 100644
index 00000000..9475e582
--- /dev/null
+++ b/ProjectLighthouse/Helpers/FriendHelper.cs
@@ -0,0 +1,12 @@
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace LBPUnion.ProjectLighthouse.Helpers
+{
+ [NotMapped]
+ public static class FriendHelper
+ {
+ public static Dictionary FriendIdsByUserId = new();
+ public static Dictionary BlockedIdsByUserId = new();
+ }
+}
\ No newline at end of file
diff --git a/ProjectLighthouse/Migrations/20211108212022_BooYayRateLevels.Designer.cs b/ProjectLighthouse/Migrations/20211108212022_BooYayRateLevels.Designer.cs
new file mode 100644
index 00000000..4d1d9dbf
--- /dev/null
+++ b/ProjectLighthouse/Migrations/20211108212022_BooYayRateLevels.Designer.cs
@@ -0,0 +1,632 @@
+//
+using LBPUnion.ProjectLighthouse;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace ProjectLighthouse.Migrations
+{
+ [DbContext(typeof(Database))]
+ [Migration("20211108212022_BooYayRateLevels")]
+ partial class BooYayRateLevels
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("Relational:MaxIdentifierLength", 64)
+ .HasAnnotation("ProductVersion", "5.0.12");
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b =>
+ {
+ b.Property("HeartedProfileId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("HeartedUserId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("HeartedProfileId");
+
+ b.HasIndex("HeartedUserId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("HeartedProfiles");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b =>
+ {
+ b.Property("HeartedLevelId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("SlotId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("HeartedLevelId");
+
+ b.HasIndex("SlotId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("HeartedLevels");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b =>
+ {
+ b.Property("QueuedLevelId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("SlotId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("QueuedLevelId");
+
+ b.HasIndex("SlotId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("QueuedLevels");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b =>
+ {
+ b.Property("RatedLevelId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Rating")
+ .HasColumnType("int");
+
+ b.Property("RatingLBP1")
+ .HasColumnType("double");
+
+ b.Property("SlotId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("RatedLevelId");
+
+ b.HasIndex("SlotId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("RatedLevels");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
+ {
+ b.Property("SlotId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("AuthorLabels")
+ .HasColumnType("longtext");
+
+ b.Property("BackgroundHash")
+ .HasColumnType("longtext");
+
+ b.Property("CreatorId")
+ .HasColumnType("int");
+
+ b.Property("Description")
+ .HasColumnType("longtext");
+
+ b.Property("FirstUploaded")
+ .HasColumnType("bigint");
+
+ b.Property("GameVersion")
+ .HasColumnType("int");
+
+ b.Property("IconHash")
+ .HasColumnType("longtext");
+
+ b.Property("InitiallyLocked")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LastUpdated")
+ .HasColumnType("bigint");
+
+ b.Property("Lbp1Only")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LocationId")
+ .HasColumnType("int");
+
+ b.Property("MaximumPlayers")
+ .HasColumnType("int");
+
+ b.Property("MinimumPlayers")
+ .HasColumnType("int");
+
+ b.Property("MoveRequired")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Name")
+ .HasColumnType("longtext");
+
+ b.Property("PlaysLBP1")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP1Complete")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP1Unique")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP2")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP2Complete")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP2Unique")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP3")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP3Complete")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP3Unique")
+ .HasColumnType("int");
+
+ b.Property("ResourceCollection")
+ .HasColumnType("longtext");
+
+ b.Property("RootLevel")
+ .HasColumnType("longtext");
+
+ b.Property("Shareable")
+ .HasColumnType("int");
+
+ b.Property("SubLevel")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("TeamPick")
+ .HasColumnType("tinyint(1)");
+
+ b.HasKey("SlotId");
+
+ b.HasIndex("CreatorId");
+
+ b.HasIndex("LocationId");
+
+ b.ToTable("Slots");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b =>
+ {
+ b.Property("VisitedLevelId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("GameVersion")
+ .HasColumnType("int");
+
+ b.Property("SlotId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("VisitedLevelId");
+
+ b.HasIndex("SlotId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("VisitedLevels");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b =>
+ {
+ b.Property("PhotoId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("CreatorId")
+ .HasColumnType("int");
+
+ b.Property("LargeHash")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("MediumHash")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("PhotoSubjectCollection")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("PlanHash")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("SmallHash")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("Timestamp")
+ .HasColumnType("bigint");
+
+ b.HasKey("PhotoId");
+
+ b.HasIndex("CreatorId");
+
+ b.ToTable("Photos");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b =>
+ {
+ b.Property("PhotoSubjectId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Bounds")
+ .HasColumnType("longtext");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("PhotoSubjectId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("PhotoSubjects");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b =>
+ {
+ b.Property("CommentId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Message")
+ .HasColumnType("longtext");
+
+ b.Property("PosterUserId")
+ .HasColumnType("int");
+
+ b.Property("TargetUserId")
+ .HasColumnType("int");
+
+ b.Property("ThumbsDown")
+ .HasColumnType("int");
+
+ b.Property("ThumbsUp")
+ .HasColumnType("int");
+
+ b.Property("Timestamp")
+ .HasColumnType("bigint");
+
+ b.HasKey("CommentId");
+
+ b.HasIndex("PosterUserId");
+
+ b.HasIndex("TargetUserId");
+
+ b.ToTable("Comments");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.LastMatch", b =>
+ {
+ b.Property("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Timestamp")
+ .HasColumnType("bigint");
+
+ b.HasKey("UserId");
+
+ b.ToTable("LastMatches");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Location", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("X")
+ .HasColumnType("int");
+
+ b.Property("Y")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.ToTable("Locations");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b =>
+ {
+ b.Property("ScoreId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("PlayerIdCollection")
+ .HasColumnType("longtext");
+
+ b.Property("Points")
+ .HasColumnType("int");
+
+ b.Property("SlotId")
+ .HasColumnType("int");
+
+ b.Property("Type")
+ .HasColumnType("int");
+
+ b.HasKey("ScoreId");
+
+ b.HasIndex("SlotId");
+
+ b.ToTable("Scores");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b =>
+ {
+ b.Property("TokenId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("GameVersion")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("UserToken")
+ .HasColumnType("longtext");
+
+ b.HasKey("TokenId");
+
+ b.ToTable("Tokens");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b =>
+ {
+ b.Property("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Biography")
+ .HasColumnType("longtext");
+
+ b.Property("BooHash")
+ .HasColumnType("longtext");
+
+ b.Property("Game")
+ .HasColumnType("int");
+
+ b.Property("IconHash")
+ .HasColumnType("longtext");
+
+ b.Property("LocationId")
+ .HasColumnType("int");
+
+ b.Property("Pins")
+ .HasColumnType("longtext");
+
+ b.Property("PlanetHash")
+ .HasColumnType("longtext");
+
+ b.Property("StaffChallengeBronzeCount")
+ .HasColumnType("int");
+
+ b.Property("StaffChallengeGoldCount")
+ .HasColumnType("int");
+
+ b.Property("StaffChallengeSilverCount")
+ .HasColumnType("int");
+
+ b.Property("Username")
+ .HasColumnType("longtext");
+
+ b.Property("YayHash")
+ .HasColumnType("longtext");
+
+ b.HasKey("UserId");
+
+ b.HasIndex("LocationId");
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "HeartedUser")
+ .WithMany()
+ .HasForeignKey("HeartedUserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("HeartedUser");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
+ .WithMany()
+ .HasForeignKey("SlotId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Slot");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
+ .WithMany()
+ .HasForeignKey("SlotId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Slot");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
+ .WithMany()
+ .HasForeignKey("SlotId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Slot");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator")
+ .WithMany()
+ .HasForeignKey("CreatorId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location")
+ .WithMany()
+ .HasForeignKey("LocationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Creator");
+
+ b.Navigation("Location");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
+ .WithMany()
+ .HasForeignKey("SlotId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Slot");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator")
+ .WithMany()
+ .HasForeignKey("CreatorId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Creator");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Poster")
+ .WithMany()
+ .HasForeignKey("PosterUserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Target")
+ .WithMany()
+ .HasForeignKey("TargetUserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Poster");
+
+ b.Navigation("Target");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
+ .WithMany()
+ .HasForeignKey("SlotId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Slot");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location")
+ .WithMany()
+ .HasForeignKey("LocationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Location");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/ProjectLighthouse/Migrations/20211108212022_BooYayRateLevels.cs b/ProjectLighthouse/Migrations/20211108212022_BooYayRateLevels.cs
new file mode 100644
index 00000000..0bb803a3
--- /dev/null
+++ b/ProjectLighthouse/Migrations/20211108212022_BooYayRateLevels.cs
@@ -0,0 +1,56 @@
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace ProjectLighthouse.Migrations
+{
+ public partial class BooYayRateLevels : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.CreateTable(
+ name: "RatedLevels",
+ columns: table => new
+ {
+ RatedLevelId = table.Column(type: "int", nullable: false)
+ .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+ UserId = table.Column(type: "int", nullable: false),
+ SlotId = table.Column(type: "int", nullable: false),
+ Rating = table.Column(type: "int", nullable: false),
+ RatingLBP1 = table.Column(type: "double", nullable: false)
+ },
+ constraints: table =>
+ {
+ table.PrimaryKey("PK_RatedLevels", x => x.RatedLevelId);
+ table.ForeignKey(
+ name: "FK_RatedLevels_Slots_SlotId",
+ column: x => x.SlotId,
+ principalTable: "Slots",
+ principalColumn: "SlotId",
+ onDelete: ReferentialAction.Cascade);
+ table.ForeignKey(
+ name: "FK_RatedLevels_Users_UserId",
+ column: x => x.UserId,
+ principalTable: "Users",
+ principalColumn: "UserId",
+ onDelete: ReferentialAction.Cascade);
+ })
+ .Annotation("MySql:CharSet", "utf8mb4");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_RatedLevels_SlotId",
+ table: "RatedLevels",
+ column: "SlotId");
+
+ migrationBuilder.CreateIndex(
+ name: "IX_RatedLevels_UserId",
+ table: "RatedLevels",
+ column: "UserId");
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropTable(
+ name: "RatedLevels");
+ }
+ }
+}
diff --git a/ProjectLighthouse/Migrations/20211109225543_AddLevelTypeToSlot.Designer.cs b/ProjectLighthouse/Migrations/20211109225543_AddLevelTypeToSlot.Designer.cs
new file mode 100644
index 00000000..cc243392
--- /dev/null
+++ b/ProjectLighthouse/Migrations/20211109225543_AddLevelTypeToSlot.Designer.cs
@@ -0,0 +1,635 @@
+//
+using LBPUnion.ProjectLighthouse;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace ProjectLighthouse.Migrations
+{
+ [DbContext(typeof(Database))]
+ [Migration("20211109225543_AddLevelTypeToSlot")]
+ partial class AddLevelTypeToSlot
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("Relational:MaxIdentifierLength", 64)
+ .HasAnnotation("ProductVersion", "5.0.12");
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b =>
+ {
+ b.Property("HeartedProfileId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("HeartedUserId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("HeartedProfileId");
+
+ b.HasIndex("HeartedUserId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("HeartedProfiles");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b =>
+ {
+ b.Property("HeartedLevelId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("SlotId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("HeartedLevelId");
+
+ b.HasIndex("SlotId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("HeartedLevels");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b =>
+ {
+ b.Property("QueuedLevelId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("SlotId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("QueuedLevelId");
+
+ b.HasIndex("SlotId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("QueuedLevels");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b =>
+ {
+ b.Property("RatedLevelId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Rating")
+ .HasColumnType("int");
+
+ b.Property("RatingLBP1")
+ .HasColumnType("double");
+
+ b.Property("SlotId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("RatedLevelId");
+
+ b.HasIndex("SlotId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("RatedLevels");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
+ {
+ b.Property("SlotId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("AuthorLabels")
+ .HasColumnType("longtext");
+
+ b.Property("BackgroundHash")
+ .HasColumnType("longtext");
+
+ b.Property("CreatorId")
+ .HasColumnType("int");
+
+ b.Property("Description")
+ .HasColumnType("longtext");
+
+ b.Property("FirstUploaded")
+ .HasColumnType("bigint");
+
+ b.Property("GameVersion")
+ .HasColumnType("int");
+
+ b.Property("IconHash")
+ .HasColumnType("longtext");
+
+ b.Property("InitiallyLocked")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LastUpdated")
+ .HasColumnType("bigint");
+
+ b.Property("Lbp1Only")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LevelType")
+ .HasColumnType("longtext");
+
+ b.Property("LocationId")
+ .HasColumnType("int");
+
+ b.Property("MaximumPlayers")
+ .HasColumnType("int");
+
+ b.Property("MinimumPlayers")
+ .HasColumnType("int");
+
+ b.Property("MoveRequired")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Name")
+ .HasColumnType("longtext");
+
+ b.Property("PlaysLBP1")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP1Complete")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP1Unique")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP2")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP2Complete")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP2Unique")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP3")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP3Complete")
+ .HasColumnType("int");
+
+ b.Property("PlaysLBP3Unique")
+ .HasColumnType("int");
+
+ b.Property("ResourceCollection")
+ .HasColumnType("longtext");
+
+ b.Property("RootLevel")
+ .HasColumnType("longtext");
+
+ b.Property("Shareable")
+ .HasColumnType("int");
+
+ b.Property("SubLevel")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("TeamPick")
+ .HasColumnType("tinyint(1)");
+
+ b.HasKey("SlotId");
+
+ b.HasIndex("CreatorId");
+
+ b.HasIndex("LocationId");
+
+ b.ToTable("Slots");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b =>
+ {
+ b.Property("VisitedLevelId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("GameVersion")
+ .HasColumnType("int");
+
+ b.Property("SlotId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("VisitedLevelId");
+
+ b.HasIndex("SlotId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("VisitedLevels");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b =>
+ {
+ b.Property("PhotoId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("CreatorId")
+ .HasColumnType("int");
+
+ b.Property("LargeHash")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("MediumHash")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("PhotoSubjectCollection")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("PlanHash")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("SmallHash")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("Timestamp")
+ .HasColumnType("bigint");
+
+ b.HasKey("PhotoId");
+
+ b.HasIndex("CreatorId");
+
+ b.ToTable("Photos");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b =>
+ {
+ b.Property("PhotoSubjectId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Bounds")
+ .HasColumnType("longtext");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("PhotoSubjectId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("PhotoSubjects");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b =>
+ {
+ b.Property("CommentId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Message")
+ .HasColumnType("longtext");
+
+ b.Property("PosterUserId")
+ .HasColumnType("int");
+
+ b.Property("TargetUserId")
+ .HasColumnType("int");
+
+ b.Property("ThumbsDown")
+ .HasColumnType("int");
+
+ b.Property("ThumbsUp")
+ .HasColumnType("int");
+
+ b.Property("Timestamp")
+ .HasColumnType("bigint");
+
+ b.HasKey("CommentId");
+
+ b.HasIndex("PosterUserId");
+
+ b.HasIndex("TargetUserId");
+
+ b.ToTable("Comments");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.LastMatch", b =>
+ {
+ b.Property("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Timestamp")
+ .HasColumnType("bigint");
+
+ b.HasKey("UserId");
+
+ b.ToTable("LastMatches");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Location", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("X")
+ .HasColumnType("int");
+
+ b.Property("Y")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.ToTable("Locations");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b =>
+ {
+ b.Property("ScoreId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("PlayerIdCollection")
+ .HasColumnType("longtext");
+
+ b.Property("Points")
+ .HasColumnType("int");
+
+ b.Property("SlotId")
+ .HasColumnType("int");
+
+ b.Property("Type")
+ .HasColumnType("int");
+
+ b.HasKey("ScoreId");
+
+ b.HasIndex("SlotId");
+
+ b.ToTable("Scores");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Token", b =>
+ {
+ b.Property("TokenId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("GameVersion")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.Property("UserToken")
+ .HasColumnType("longtext");
+
+ b.HasKey("TokenId");
+
+ b.ToTable("Tokens");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b =>
+ {
+ b.Property("UserId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Biography")
+ .HasColumnType("longtext");
+
+ b.Property("BooHash")
+ .HasColumnType("longtext");
+
+ b.Property("Game")
+ .HasColumnType("int");
+
+ b.Property("IconHash")
+ .HasColumnType("longtext");
+
+ b.Property("LocationId")
+ .HasColumnType("int");
+
+ b.Property("Pins")
+ .HasColumnType("longtext");
+
+ b.Property("PlanetHash")
+ .HasColumnType("longtext");
+
+ b.Property("StaffChallengeBronzeCount")
+ .HasColumnType("int");
+
+ b.Property("StaffChallengeGoldCount")
+ .HasColumnType("int");
+
+ b.Property("StaffChallengeSilverCount")
+ .HasColumnType("int");
+
+ b.Property("Username")
+ .HasColumnType("longtext");
+
+ b.Property("YayHash")
+ .HasColumnType("longtext");
+
+ b.HasKey("UserId");
+
+ b.HasIndex("LocationId");
+
+ b.ToTable("Users");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.HeartedProfile", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "HeartedUser")
+ .WithMany()
+ .HasForeignKey("HeartedUserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("HeartedUser");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.HeartedLevel", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
+ .WithMany()
+ .HasForeignKey("SlotId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Slot");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.QueuedLevel", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
+ .WithMany()
+ .HasForeignKey("SlotId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Slot");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
+ .WithMany()
+ .HasForeignKey("SlotId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Slot");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator")
+ .WithMany()
+ .HasForeignKey("CreatorId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location")
+ .WithMany()
+ .HasForeignKey("LocationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Creator");
+
+ b.Navigation("Location");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.VisitedLevel", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
+ .WithMany()
+ .HasForeignKey("SlotId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Slot");
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Photo", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator")
+ .WithMany()
+ .HasForeignKey("CreatorId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Creator");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.PhotoSubject", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("User");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Profiles.Comment", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Poster")
+ .WithMany()
+ .HasForeignKey("PosterUserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Target")
+ .WithMany()
+ .HasForeignKey("TargetUserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Poster");
+
+ b.Navigation("Target");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Score", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
+ .WithMany()
+ .HasForeignKey("SlotId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Slot");
+ });
+
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.User", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Profiles.Location", "Location")
+ .WithMany()
+ .HasForeignKey("LocationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Location");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/ProjectLighthouse/Migrations/20211109225543_AddLevelTypeToSlot.cs b/ProjectLighthouse/Migrations/20211109225543_AddLevelTypeToSlot.cs
new file mode 100644
index 00000000..791151c5
--- /dev/null
+++ b/ProjectLighthouse/Migrations/20211109225543_AddLevelTypeToSlot.cs
@@ -0,0 +1,24 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace ProjectLighthouse.Migrations
+{
+ public partial class AddLevelTypeToSlot : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "LevelType",
+ table: "Slots",
+ type: "longtext",
+ nullable: true)
+ .Annotation("MySql:CharSet", "utf8mb4");
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "LevelType",
+ table: "Slots");
+ }
+ }
+}
diff --git a/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs b/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs
index 96f61582..80cbef7e 100644
--- a/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs
+++ b/ProjectLighthouse/Migrations/DatabaseModelSnapshot.cs
@@ -79,6 +79,33 @@ namespace ProjectLighthouse.Migrations
b.ToTable("QueuedLevels");
});
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b =>
+ {
+ b.Property("RatedLevelId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Rating")
+ .HasColumnType("int");
+
+ b.Property("RatingLBP1")
+ .HasColumnType("double");
+
+ b.Property("SlotId")
+ .HasColumnType("int");
+
+ b.Property("UserId")
+ .HasColumnType("int");
+
+ b.HasKey("RatedLevelId");
+
+ b.HasIndex("SlotId");
+
+ b.HasIndex("UserId");
+
+ b.ToTable("RatedLevels");
+ });
+
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
{
b.Property("SlotId")
@@ -115,6 +142,9 @@ namespace ProjectLighthouse.Migrations
b.Property("Lbp1Only")
.HasColumnType("tinyint(1)");
+ b.Property("LevelType")
+ .HasColumnType("longtext");
+
b.Property("LocationId")
.HasColumnType("int");
@@ -478,6 +508,25 @@ namespace ProjectLighthouse.Migrations
b.Navigation("User");
});
+ modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.RatedLevel", b =>
+ {
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.Levels.Slot", "Slot")
+ .WithMany()
+ .HasForeignKey("SlotId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "User")
+ .WithMany()
+ .HasForeignKey("UserId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Slot");
+
+ b.Navigation("User");
+ });
+
modelBuilder.Entity("LBPUnion.ProjectLighthouse.Types.Levels.Slot", b =>
{
b.HasOne("LBPUnion.ProjectLighthouse.Types.User", "Creator")
diff --git a/ProjectLighthouse/Types/Levels/RatedLevel.cs b/ProjectLighthouse/Types/Levels/RatedLevel.cs
new file mode 100644
index 00000000..8b2228a0
--- /dev/null
+++ b/ProjectLighthouse/Types/Levels/RatedLevel.cs
@@ -0,0 +1,26 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace LBPUnion.ProjectLighthouse.Types.Levels
+{
+ public class RatedLevel
+ {
+ // ReSharper disable once UnusedMember.Global
+ [Key]
+ public int RatedLevelId { get; set; }
+
+ public int UserId { get; set; }
+
+ [ForeignKey(nameof(UserId))]
+ public User User { get; set; }
+
+ public int SlotId { get; set; }
+
+ [ForeignKey(nameof(SlotId))]
+ public Slot Slot { get; set; }
+
+ public int Rating { get; set; }
+
+ public double RatingLBP1 { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/ProjectLighthouse/Types/Levels/Slot.cs b/ProjectLighthouse/Types/Levels/Slot.cs
index 90bc82e0..95e8bdd7 100644
--- a/ProjectLighthouse/Types/Levels/Slot.cs
+++ b/ProjectLighthouse/Types/Levels/Slot.cs
@@ -110,42 +110,93 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels
[XmlIgnore]
[NotMapped]
- public int Plays { get => this.PlaysLBP1 + this.PlaysLBP2 + this.PlaysLBP3; }
+ public int Plays {
+ get => this.PlaysLBP1 + this.PlaysLBP2 + this.PlaysLBP3;
+ }
+
[XmlIgnore]
[NotMapped]
- public int PlaysUnique { get => this.PlaysLBP1Unique + this.PlaysLBP2Unique + this.PlaysLBP3Unique; }
+ public int PlaysUnique {
+ get => this.PlaysLBP1Unique + this.PlaysLBP2Unique + this.PlaysLBP3Unique;
+ }
+
[XmlIgnore]
[NotMapped]
- public int PlaysComplete { get => this.PlaysLBP1Complete + this.PlaysLBP2Complete + this.PlaysLBP3Complete; }
+ public int PlaysComplete {
+ get => this.PlaysLBP1Complete + this.PlaysLBP2Complete + this.PlaysLBP3Complete;
+ }
[XmlIgnore]
public int PlaysLBP1 { get; set; }
+
[XmlIgnore]
public int PlaysLBP1Complete { get; set; }
+
[XmlIgnore]
public int PlaysLBP1Unique { get; set; }
[XmlIgnore]
public int PlaysLBP2 { get; set; }
+
[XmlIgnore]
public int PlaysLBP2Complete { get; set; }
+
[XmlIgnore]
public int PlaysLBP2Unique { get; set; }
[XmlIgnore]
public int PlaysLBP3 { get; set; }
+
[XmlIgnore]
public int PlaysLBP3Complete { get; set; }
+
[XmlIgnore]
public int PlaysLBP3Unique { get; set; }
-
+ [NotMapped]
+ [XmlElement("thumbsup")]
+ public int Thumbsup {
+ get {
+ using Database database = new();
+
+ return database.RatedLevels.Count(r => r.SlotId == this.SlotId && r.Rating == 1);
+ }
+ }
+
+ [NotMapped]
+ [XmlElement("thumbsdown")]
+ public int Thumbsdown {
+ get {
+ using Database database = new();
+
+ return database.RatedLevels.Count(r => r.SlotId == this.SlotId && r.Rating == -1);
+ }
+ }
+
+ [NotMapped]
+ [XmlElement("averageRating")]
+ public double RatingLBP1 {
+ get {
+ using Database database = new();
+
+ IQueryable ratedLevels = database.RatedLevels.Where(r => r.SlotId == this.SlotId && r.RatingLBP1 > 0);
+ if (!ratedLevels.Any()) return 3.0;
+
+ return Enumerable.Average(ratedLevels, r => r.RatingLBP1);
+
+ ;
+ }
+ }
+
+ [XmlElement("leveltype")]
+ public string LevelType { get; set; }
+
public string SerializeResources()
{
return this.Resources.Aggregate("", (current, resource) => current + LbpSerializer.StringElement("resource", resource));
}
- public string Serialize()
+ public string Serialize(double? yourRating = null, int? yourDPadRating = null, int? yourLBP1PlayCount = null, int? yourLBP2PlayCount = null)
{
string slotData = LbpSerializer.StringElement("name", this.Name) +
LbpSerializer.StringElement("id", this.SlotId) +
@@ -179,7 +230,15 @@ namespace LBPUnion.ProjectLighthouse.Types.Levels
LbpSerializer.StringElement("lbp2UniquePlayCount", this.PlaysLBP2Unique) + // not actually used ingame, as per above comment
LbpSerializer.StringElement("lbp3PlayCount", this.PlaysLBP3) +
LbpSerializer.StringElement("lbp3CompletionCount", this.PlaysLBP3Complete) +
- LbpSerializer.StringElement("lbp3UniquePlayCount", this.PlaysLBP3Unique);
+ LbpSerializer.StringElement("lbp3UniquePlayCount", this.PlaysLBP3Unique) +
+ LbpSerializer.StringElement("thumbsup", this.Thumbsup) +
+ LbpSerializer.StringElement("thumbsdown", this.Thumbsdown) +
+ LbpSerializer.StringElement("averageRating", this.RatingLBP1) +
+ (yourRating != null ? LbpSerializer.StringElement("yourRating", yourRating) : "") +
+ (yourDPadRating != null ? LbpSerializer.StringElement("yourDPadRating", yourDPadRating) : "") +
+ (yourLBP1PlayCount != null ? LbpSerializer.StringElement("yourLBP1PlayCount", yourLBP1PlayCount) : "") +
+ (yourLBP2PlayCount != null ? LbpSerializer.StringElement("yourLBP2PlayCount", yourLBP2PlayCount) : "") +
+ LbpSerializer.StringElement("leveltype", this.LevelType);
return LbpSerializer.TaggedStringElement("slot", slotData, "type", "user");
}
diff --git a/ProjectLighthouse/Types/Profiles/NPData.cs b/ProjectLighthouse/Types/Profiles/NPData.cs
new file mode 100644
index 00000000..a117d6bf
--- /dev/null
+++ b/ProjectLighthouse/Types/Profiles/NPData.cs
@@ -0,0 +1,18 @@
+using System.Collections.Generic;
+using System.Xml.Serialization;
+
+namespace LBPUnion.ProjectLighthouse.Types.Profiles
+{
+ [XmlRoot("npdata")]
+ [XmlType("npdata")]
+ public class NPData
+ {
+ [XmlArray("friends")]
+ [XmlArrayItem("npHandle")]
+ public List Friends { get; set; }
+
+ [XmlArray("blocked")]
+ [XmlArrayItem("npHandle")]
+ public List BlockedUsers { get; set; }
+ }
+}
\ No newline at end of file