diff --git a/ProjectLighthouse/Controllers/GameApi/Resources/ResourcesController.cs b/ProjectLighthouse/Controllers/GameApi/Resources/ResourcesController.cs
index 63d30d9e..0e2d5ae1 100644
--- a/ProjectLighthouse/Controllers/GameApi/Resources/ResourcesController.cs
+++ b/ProjectLighthouse/Controllers/GameApi/Resources/ResourcesController.cs
@@ -82,7 +82,8 @@ public class ResourcesController : ControllerBase
string path = FileHelper.GetResourcePath(hash);
FileHelper.EnsureDirectoryCreated(assetsDirectory);
- if (FileHelper.ResourceExists(hash)) this.Ok(); // no reason to fail if it's already uploaded
+ // lbp treats code 409 as success and as an indicator that the file is already present
+ if (FileHelper.ResourceExists(hash)) this.Conflict();
Logger.Log($"Processing resource upload (hash: {hash})", LoggerLevelResources.Instance);
LbpFile file = new(await BinaryHelper.ReadFromPipeReader(this.Request.BodyReader));
@@ -90,7 +91,7 @@ public class ResourcesController : ControllerBase
if (!FileHelper.IsFileSafe(file))
{
Logger.Log($"File is unsafe (hash: {hash}, type: {file.FileType})", LoggerLevelResources.Instance);
- return this.UnprocessableEntity();
+ return this.Conflict();
}
string calculatedHash = file.Hash;
diff --git a/ProjectLighthouse/Controllers/GameApi/UserController.cs b/ProjectLighthouse/Controllers/GameApi/UserController.cs
index 62c99565..1a8f05b0 100644
--- a/ProjectLighthouse/Controllers/GameApi/UserController.cs
+++ b/ProjectLighthouse/Controllers/GameApi/UserController.cs
@@ -5,7 +5,7 @@ using System.IO;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
-using System.Xml;
+using System.Xml.Serialization;
using LBPUnion.ProjectLighthouse.Serialization;
using LBPUnion.ProjectLighthouse.Types;
using LBPUnion.ProjectLighthouse.Types.Profiles;
@@ -69,130 +69,66 @@ public class UserController : ControllerBase
User user = userAndToken.Value.Item1;
GameToken gameToken = userAndToken.Value.Item2;
- XmlReaderSettings settings = new()
- {
- Async = true, // this is apparently not default
- };
- bool locationChanged = false;
+ this.Request.Body.Position = 0;
+ string bodyString = await new StreamReader(this.Request.Body).ReadToEndAsync();
+ // xml hack so we can use one class to deserialize different root names
+ string rootElement = bodyString.Contains("updateUser") ? "updateUser" : "user";
+ XmlSerializer serializer = new(typeof(UserUpdate), new XmlRootAttribute(rootElement));
+ UserUpdate? update = (UserUpdate?) serializer.Deserialize(new StringReader(bodyString));
- // this is an absolute mess, but necessary because LBP only sends what changed
- //
- // example for changing profile card location:
- //
- //
- // 1234
- // 1234
- //
- //
- //
- // example for changing biography:
- //
- // biography stuff
- //
- //
- // if you find a way to make it not stupid feel free to replace this
- using (XmlReader reader = XmlReader.Create(this.Request.Body, settings))
+ if (update == null) return this.BadRequest();
+
+ if (update.Biography != null) user.Biography = update.Biography;
+
+ if (update.IconHash != null) user.IconHash = update.IconHash;
+
+ if (update.YayHash != null) user.YayHash = update.YayHash;
+
+ if (update.MehHash != null) user.MehHash = update.MehHash;
+
+ if (update.BooHash != null) user.BooHash = update.BooHash;
+
+ if (update.PlanetHash != null)
{
- List path = new(); // you can think of this as a file path in the XML, like -> ->
- while (await reader.ReadAsync()) // ReSharper disable once SwitchStatementMissingSomeEnumCasesNoDefault
- switch (reader.NodeType)
+ switch (gameToken.GameVersion)
+ {
+ case GameVersion.LittleBigPlanet2: // LBP2 planets will apply to LBP3
{
- case XmlNodeType.Element:
- path.Add(reader.Name);
- break;
- case XmlNodeType.Text:
- switch (path[1])
- {
- case "biography":
- {
- user.Biography = await reader.GetValueAsync();
- break;
- }
- case "location":
- {
- locationChanged = true; // if we're here then we're probably about to change the location.
- // ReSharper disable once ConvertIfStatementToSwitchStatement
- if (path[2] == "x")
- user.Location.X = Convert.ToInt32
- (await reader.GetValueAsync()); // GetValue only returns a string, i guess we just hope its a number lol
- else if (path[2] == "y") user.Location.Y = Convert.ToInt32(await reader.GetValueAsync());
- break;
- }
- case "icon":
- {
- user.IconHash = await reader.GetValueAsync();
- break;
- }
- case "planets":
- {
- switch (gameToken.GameVersion)
- {
- case GameVersion.LittleBigPlanet2: // LBP2 planets will apply to LBP3
- {
- user.PlanetHashLBP2 = await reader.GetValueAsync();
- user.PlanetHashLBP3 = await reader.GetValueAsync();
- break;
- }
- case GameVersion.LittleBigPlanet3: // LBP3 and vita can only apply to their own games, only set 1 here
- {
- user.PlanetHashLBP3 = await reader.GetValueAsync();
- break;
- }
- case GameVersion.LittleBigPlanetVita:
- {
- user.PlanetHashLBPVita = await reader.GetValueAsync();
- break;
- }
- case GameVersion.LittleBigPlanet1:
- case GameVersion.LittleBigPlanetPSP:
- case GameVersion.Unknown:
- default: // The rest do not support custom earths.
- {
- throw new ArgumentException($"invalid gameVersion {gameToken.GameVersion} for setting earth");
- }
- }
- break;
- }
- case "yay2":
- {
- user.YayHash = await reader.GetValueAsync();
- break;
- }
- case "meh2":
- {
- user.MehHash = await reader.GetValueAsync();
- break;
- }
- case "boo2":
- {
- user.BooHash = await reader.GetValueAsync();
- break;
- }
- }
-
- break;
- case XmlNodeType.EndElement:
- path.RemoveAt(path.Count - 1);
- break;
+ user.PlanetHashLBP2 = update.PlanetHash;
+ user.PlanetHashLBP3 = update.PlanetHash;
+ break;
}
+ case GameVersion.LittleBigPlanet3: // LBP3 and vita can only apply to their own games, only set 1 here
+ {
+ user.PlanetHashLBP3 = update.PlanetHash;
+ break;
+ }
+ case GameVersion.LittleBigPlanetVita:
+ {
+ user.PlanetHashLBPVita = update.PlanetHash;
+ break;
+ }
+ case GameVersion.LittleBigPlanet1:
+ case GameVersion.LittleBigPlanetPSP:
+ case GameVersion.Unknown:
+ default: // The rest do not support custom earths.
+ {
+ throw new ArgumentException($"invalid gameVersion {gameToken.GameVersion} for setting earth");
+ }
+ }
}
- // the way location on a user card works is stupid and will not save with the way below as-is, so we do the following:
- if (locationChanged) // only modify the database if we modify here
+ if (update.Location != null)
{
- Location? l = await this.database.Locations.FirstOrDefaultAsync(l => l.Id == user.LocationId); // find the location in the database again
+ Location? loc = await this.database.Locations.FirstOrDefaultAsync(l => l.Id == user.LocationId);
+ if (loc == null) throw new Exception("User loc is null, this should never happen.");
- if (l == null) throw new Exception("this shouldn't happen ever but we handle this");
-
- // set the location in the database to the one we modified above
- l.X = user.Location.X;
- l.Y = user.Location.Y;
-
- // now both are in sync, and will update in the database.
+ loc.X = update.Location.X;
+ loc.Y = update.Location.Y;
}
- if (this.database.ChangeTracker.HasChanges()) await this.database.SaveChangesAsync(); // save the user to the database if we changed anything
+ if (this.database.ChangeTracker.HasChanges()) await this.database.SaveChangesAsync();
return this.Ok();
}
diff --git a/ProjectLighthouse/Database.cs b/ProjectLighthouse/Database.cs
index d21ccc57..9c38ff41 100644
--- a/ProjectLighthouse/Database.cs
+++ b/ProjectLighthouse/Database.cs
@@ -75,7 +75,7 @@ public class Database : DbContext
Username = username,
Password = password,
LocationId = l.Id,
- Biography = username + " hasn't introduced themselves yet.",
+ Biography = "",
EmailAddress = emailAddress,
};
this.Users.Add(user);
diff --git a/ProjectLighthouse/Pages/UserPage.cshtml b/ProjectLighthouse/Pages/UserPage.cshtml
index 61200e7f..3e6953e1 100644
--- a/ProjectLighthouse/Pages/UserPage.cshtml
+++ b/ProjectLighthouse/Pages/UserPage.cshtml
@@ -83,7 +83,14 @@