Skip to content

Commit

Permalink
Add option to redirect grief reports to photos (#199)
Browse files Browse the repository at this point in the history
This adds photo support to PSP, and allows you to take really quick
photos (with UI) on the mainline games almost anywhere too

Marking as draft as
[this](https://github.com/Beyley/Refresh/blob/59c21971bec14b7f59b85bf4c7a1ece933fe1054/Refresh.GameServer/Endpoints/Game/ReportingEndpoints.cs#L37)
needs to be resolved, so we can remove [this
hack](https://github.com/Beyley/Refresh/blob/98b7e77e1e0341b914746fd22515388370999855/Refresh.GameServer/Types/Photos/SerializedPhotoSubject.cs#L26),
but im not sure what the range of values are supposed to be
  • Loading branch information
jvyden authored Oct 17, 2023
2 parents a1cdb9e + 095c0ae commit 55d2dd1
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 10 deletions.
9 changes: 5 additions & 4 deletions Refresh.GameServer/Database/GameDatabaseContext.Photos.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ public void UploadPhoto(SerializedPhoto photo, GameUser publisher)
PlanHash = photo.PlanHash,

Publisher = publisher,
LevelName = photo.Level.Title,
LevelType = photo.Level.Type,
LevelId = photo.Level.LevelId,
LevelName = photo.Level?.Title ?? "",
LevelType = photo.Level?.Type ?? "",
//If level is null, default to level ID 0
LevelId = photo.Level?.LevelId ?? 0,

TakenAt = DateTimeOffset.FromUnixTimeSeconds(Math.Clamp(photo.Timestamp, this._time.EarliestDate, this._time.TimestampSeconds)),
PublishedAt = this._time.Now,
};

if (photo.Level.Type == "user")
if (photo.Level?.Type == "user")
newPhoto.Level = this.GetLevelById(photo.Level.LevelId);

float[] bounds = new float[SerializedPhotoSubject.FloatCount];
Expand Down
5 changes: 4 additions & 1 deletion Refresh.GameServer/Database/GameDatabaseProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ protected GameDatabaseProvider(IDateTimeProvider time)
this._time = time;
}

protected override ulong SchemaVersion => 93;
protected override ulong SchemaVersion => 95;

protected override string Filename => "refreshGameServer.realm";

Expand Down Expand Up @@ -159,6 +159,9 @@ protected override void Migrate(Migration migration, ulong oldVersion)
{
newUser.VitaPlanetsHash = "0";
}

// In version 94, we added an option to redirect grief reports to photos
if (oldVersion < 94) newUser.RedirectGriefReportsToPhotos = false;
}

IQueryable<dynamic>? oldLevels = migration.OldRealm.DynamicApi.All("GameLevel");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ public class ApiUpdateUserRequest
public bool? PsnAuthenticationAllowed { get; set; }
public bool? RpcnAuthenticationAllowed { get; set; }

public bool? RedirectGriefReportsToPhotos { get; set; }

public string? EmailAddress { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class ApiExtendedGameUserResponse : IApiResponse, IDataConvertableFrom<Ap
public required bool RpcnAuthenticationAllowed { get; set; }
public required bool PsnAuthenticationAllowed { get; set; }

public bool RedirectGriefReportsToPhotos { get; set; }

public required string? EmailAddress { get; set; }
public required bool EmailAddressVerified { get; set; }
public required bool ShouldResetPassword { get; set; }
Expand Down Expand Up @@ -54,6 +56,7 @@ public class ApiExtendedGameUserResponse : IApiResponse, IDataConvertableFrom<Ap
EmailAddress = user.EmailAddress,
EmailAddressVerified = user.EmailAddressVerified,
ShouldResetPassword = user.ShouldResetPassword,
RedirectGriefReportsToPhotos = user.RedirectGriefReportsToPhotos,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Refresh.GameServer.Types.Levels;
using Refresh.GameServer.Types.Levels.SkillRewards;
using Refresh.GameServer.Types.Matching;
using Refresh.GameServer.Types.Relations;
using Refresh.GameServer.Types.Reviews;
using Refresh.GameServer.Types.UserData;

Expand Down Expand Up @@ -80,6 +81,12 @@ public class GameLevelResponse : IDataConvertableFrom<GameLevelResponse, GameLev
{
if (old == null) return null;

int totalPlayCount = 0;
foreach (PlayLevelRelation playLevelRelation in old.AllPlays)
{
totalPlayCount += playLevelRelation.Count;
}

GameLevelResponse response = new()
{
LevelId = old.LevelId,
Expand All @@ -96,7 +103,7 @@ public class GameLevelResponse : IDataConvertableFrom<GameLevelResponse, GameLev
EnforceMinMaxPlayers = old.EnforceMinMaxPlayers,
SameScreenGame = old.SameScreenGame,
HeartCount = old.FavouriteRelations.Count(),
TotalPlayCount = old.AllPlays.Sum(p => p.Count),
TotalPlayCount = totalPlayCount,
UniquePlayCount = old.UniquePlays.Count(),
YayCount = old.Ratings.Count(r => r._RatingType == (int)RatingType.Yay),
BooCount = old.Ratings.Count(r => r._RatingType == (int)RatingType.Boo),
Expand Down
68 changes: 65 additions & 3 deletions Refresh.GameServer/Endpoints/Game/ReportingEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,82 @@
using Bunkum.Core.Responses;
using Bunkum.Listener.Protocol;
using Bunkum.Protocols.Http;
using Refresh.GameServer.Authentication;
using Refresh.GameServer.Database;
using Refresh.GameServer.Extensions;
using Refresh.GameServer.Time;
using Refresh.GameServer.Types.Levels;
using Refresh.GameServer.Types.Photos;
using Refresh.GameServer.Types.Report;
using Refresh.GameServer.Types.UserData;

namespace Refresh.GameServer.Endpoints.Game;

public class ReportingEndpoints : EndpointGroup
{
[GameEndpoint("grief", HttpMethods.Post, ContentType.Xml)]
public Response UploadReport(RequestContext context, GameDatabaseContext database, GameReport body)
public Response UploadReport(RequestContext context, GameDatabaseContext database, GameReport body, GameUser user, IDateTimeProvider time, Token token)
{
if ((body.LevelId != 0 && database.GetLevelById(body.LevelId) == null) || body.Players is { Length: > 4 } || body.ScreenElements is { Player.Length: > 4 })
{
GameLevel? level = database.GetLevelById(body.LevelId);

Size imageSize = token.TokenGame switch {
TokenGame.LittleBigPlanet1 => new Size(640, 360),
TokenGame.LittleBigPlanet2 => new Size(640, 360),
TokenGame.LittleBigPlanet3 => new Size(640, 360),
TokenGame.LittleBigPlanetVita => new Size(512, 290),
TokenGame.LittleBigPlanetPSP => new Size(480, 272),
_ => throw new ArgumentOutOfRangeException(nameof(token), $"Token game {token.TokenGame} is not allowed for grief upload!"),
};

//If the level is specified but its invalid, return BadRequest
if (body.LevelId != 0 && level == null)
return BadRequest;

if (user.RedirectGriefReportsToPhotos)
{
List<SerializedPhotoSubject> subjects = new();
if (body.Players != null)
subjects.AddRange(body.Players.Select(player => new SerializedPhotoSubject
{
Username = player.Username,
DisplayName = player.Username,
// ReSharper disable PossibleLossOfFraction YES I KNOW THESE ARE INTEGERS
BoundsList = $"{(float)(player.Rectangle.Left - imageSize.Width / 2) / (imageSize.Width / 2)}," +
$"{(float)(player.Rectangle.Top - imageSize.Height / 2) / (imageSize.Height / 2)}," +
$"{(float)(player.Rectangle.Right - imageSize.Width / 2) / (imageSize.Width / 2)}," +
$"{(float)(player.Rectangle.Bottom - imageSize.Height / 2) / (imageSize.Height / 2)}",
}));

string hash = context.IsPSP() ? "psp/" + body.JpegHash : body.JpegHash;

database.UploadPhoto(new SerializedPhoto
{
Timestamp = time.TimestampSeconds,
AuthorName = user.Username,
SmallHash = hash,
MediumHash = hash,
LargeHash = hash,
PlanHash = "0",
//If the level id is 0 or we couldn't find the level null, dont fill out the `Level` field
Level = body.LevelId == 0 || level == null ? null : new SerializedPhotoLevel
{
LevelId = level.LevelId,
Title = level.Title,
Type = level.Source switch {
GameLevelSource.User => "user",
GameLevelSource.Story => "developer",
_ => throw new ArgumentOutOfRangeException(),
},
},
PhotoSubjects = subjects,
}, user);

return OK;
}

//Basic validation
if (body.Players is { Length: > 4 } || body.ScreenElements is { Player.Length: > 4 })
return BadRequest;

database.AddGriefReport(body);

Expand Down
10 changes: 10 additions & 0 deletions Refresh.GameServer/Services/CommandService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@ public void HandleCommand(CommandInvocation command, GameDatabaseContext databas

break;
}
case "griefphotoson": {
user.RedirectGriefReportsToPhotos = true;

break;
}
case "griefphotosoff": {
user.RedirectGriefReportsToPhotos = false;

break;
}
#if DEBUG
case "tokengame":
{
Expand Down
5 changes: 4 additions & 1 deletion Refresh.GameServer/Types/Report/GameReport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ public InfoBubble[] InfoBubble

[XmlElement("levelId")]
public int LevelId { get; set; }


[XmlElement("description")]
public string Description { get; set; }

[XmlElement("griefStateHash")]
public string GriefStateHash { get; set; }

Expand Down
5 changes: 5 additions & 0 deletions Refresh.GameServer/Types/UserData/GameUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ public partial class GameUser : IRealmObject, IRateLimitUser
public bool RpcnAuthenticationAllowed { get; set; }
public bool PsnAuthenticationAllowed { get; set; }

/// <summary>
/// If `true`, turn all grief reports into photo uploads
/// </summary>
public bool RedirectGriefReportsToPhotos { get; set; }

[Ignored] public GameUserRole Role
{
get => (GameUserRole)this._Role;
Expand Down

0 comments on commit 55d2dd1

Please sign in to comment.