Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 40 additions & 40 deletions Refresh.Database/GameDatabaseContext.Pins.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ namespace Refresh.Database;

public partial class GameDatabaseContext // Pins
{
public void UpdateUserPinProgress(Dictionary<long, int> pinProgressUpdates, GameUser user, TokenGame game)
public void UpdateUserPinProgress(Dictionary<long, int> pinProgressUpdates, GameUser user, bool isBeta, TokenPlatform platform)
{
DateTimeOffset now = this._time.Now;
bool isBeta = game == TokenGame.BetaBuild;
IEnumerable<PinProgressRelation> existingProgresses = this.GetPinProgressesByUser(user, isBeta);
IEnumerable<PinProgressRelation> existingProgresses = this.GetPinProgressesByUser(user, isBeta, platform);
List<long> descendingProgressPins =
[
(long)ServerPins.TopXOfAnyStoryLevelWithOver50Scores,
Expand All @@ -34,6 +33,7 @@ public void UpdateUserPinProgress(Dictionary<long, int> pinProgressUpdates, Game
FirstPublished = now,
LastUpdated = now,
IsBeta = isBeta,
Platform = platform,
};
this.PinProgressRelations.Add(newRelation);
continue;
Expand All @@ -53,10 +53,12 @@ public void UpdateUserPinProgress(Dictionary<long, int> pinProgressUpdates, Game
this.SaveChanges();
}

public void UpdateUserProfilePins(List<long> pinUpdates, GameUser user, TokenGame game)
public void UpdateUserProfilePins(List<long> pinUpdates, GameUser user, TokenGame game, TokenPlatform platform)
{
IEnumerable<long> existingProgressIds = this.GetPinProgressesByUser(user, game == TokenGame.BetaBuild).Select(p => p.PinId);
IEnumerable<ProfilePinRelation> existingProfilePins = this.GetProfilePinsByUser(user, game);
IEnumerable<long> existingProgressIds = this
.GetPinProgressesByUser(user, game == TokenGame.BetaBuild, platform)
.Select(p => p.PinId);
IEnumerable<ProfilePinRelation> existingProfilePins = this.GetProfilePinsByUser(user, game, platform);
DateTimeOffset now = this._time.Now;

for (int i = 0; i < pinUpdates.Count; i++)
Expand All @@ -80,6 +82,7 @@ public void UpdateUserProfilePins(List<long> pinUpdates, GameUser user, TokenGam
PublisherId = user.UserId,
Index = i,
Game = game,
Platform = platform,
Timestamp = now,
});
}
Expand All @@ -93,10 +96,10 @@ public void UpdateUserProfilePins(List<long> pinUpdates, GameUser user, TokenGam
this.SaveChanges();
}

public PinProgressRelation UpdateUserPinProgressToLowest(long pinId, int newProgressValue, GameUser user, bool isBeta)
public PinProgressRelation UpdateUserPinProgressToLowest(long pinId, int newProgressValue, GameUser user, bool isBeta, TokenPlatform platform)
{
// Get pin progress if it exists already
PinProgressRelation? progressToUpdate = this.GetUserPinProgress(pinId, user, isBeta);
PinProgressRelation? progressToUpdate = this.GetUserPinProgress(pinId, user, isBeta, platform);
DateTimeOffset now = this._time.Now;

if (progressToUpdate == null)
Expand Down Expand Up @@ -126,31 +129,15 @@ public PinProgressRelation UpdateUserPinProgressToLowest(long pinId, int newProg
return progressToUpdate!;
}

public void IncrementUserPinProgress(long pinId, int progressToAdd, GameUser user)
{
this.IncrementUserPinProgressInternal(pinId, progressToAdd, user, true);
this.IncrementUserPinProgressInternal(pinId, progressToAdd, user, false);

this.SaveChanges();
}

public PinProgressRelation IncrementUserPinProgress(long pinId, int progressToAdd, GameUser user, bool isBeta)
{
PinProgressRelation relation = this.IncrementUserPinProgressInternal(pinId, progressToAdd, user, isBeta);
this.SaveChanges();

return relation;
}

private PinProgressRelation IncrementUserPinProgressInternal(long pinId, int progressToAdd, GameUser user, bool isBeta)
public PinProgressRelation IncrementUserPinProgress(long pinId, int progressToAdd, GameUser user, bool isBeta, TokenPlatform platform)
{
// Get pin progress if it exists already
PinProgressRelation? progressToUpdate = this.GetUserPinProgress(pinId, user, isBeta);
PinProgressRelation? progressToUpdate = this.GetUserPinProgress(pinId, user, isBeta, platform);
DateTimeOffset now = this._time.Now;

if (progressToUpdate == null)
{
PinProgressRelation newRelation = new()
progressToUpdate = new()
{
PinId = pinId,
Progress = progressToAdd,
Expand All @@ -159,36 +146,49 @@ private PinProgressRelation IncrementUserPinProgressInternal(long pinId, int pro
FirstPublished = now,
LastUpdated = now,
IsBeta = isBeta,
Platform = platform,
};

this.PinProgressRelations.Add(newRelation);
return newRelation;
this.PinProgressRelations.Add(progressToUpdate);
}
else
{
progressToUpdate.Progress += progressToAdd;
progressToUpdate.LastUpdated = now;
}

this.SaveChanges();
return progressToUpdate;
}

private IEnumerable<PinProgressRelation> GetPinProgressesByUser(GameUser user, bool isBeta)
private IEnumerable<PinProgressRelation> GetPinProgressesByUser(GameUser user, bool isBeta, TokenPlatform platform)
=> this.PinProgressRelations
.Where(p => p.PublisherId == user.UserId && p.IsBeta == isBeta)
.Where(p => p.PublisherId == user.UserId && (p.IsBeta == isBeta && p.Platform == platform || p.Platform == TokenPlatform.Website))
.OrderByDescending(p => p.LastUpdated);

public DatabaseList<PinProgressRelation> GetPinProgressesByUser(GameUser user, TokenGame game, int skip, int count)
=> new(this.GetPinProgressesByUser(user, game == TokenGame.BetaBuild), skip, count);
public DatabaseList<PinProgressRelation> GetPinProgressesByUser(GameUser user, bool isBeta, TokenPlatform platform, int skip, int count)
=> new(this.GetPinProgressesByUser(user, isBeta, platform), skip, count);

public PinProgressRelation? GetUserPinProgress(long pinId, GameUser user, bool isBeta)
=> this.PinProgressRelations.FirstOrDefault(p => p.PinId == pinId && p.PublisherId == user.UserId && p.IsBeta == isBeta);
public PinProgressRelation? GetUserPinProgress(long pinId, GameUser user, bool isBeta, TokenPlatform platform)
=> this.PinProgressRelations.FirstOrDefault(p => p.PinId == pinId && p.PublisherId == user.UserId
&& (p.IsBeta == isBeta && p.Platform == platform || p.Platform == TokenPlatform.Website));

private IEnumerable<ProfilePinRelation> GetProfilePinsByUser(GameUser user, TokenGame game)
private IEnumerable<ProfilePinRelation> GetProfilePinsByUser(GameUser user, TokenGame game, TokenPlatform platform)
=> this.ProfilePinRelations
.Where(p => p.PublisherId == user.UserId && p.Game == game)
.Where(p => p.PublisherId == user.UserId && p.Game == game && p.Platform == platform)
.OrderBy(p => p.Index);

public DatabaseList<ProfilePinRelation> GetProfilePinsByUser(GameUser user, TokenGame game, int skip, int count)
=> new(this.GetProfilePinsByUser(user, game), skip, count);
public DatabaseList<ProfilePinRelation> GetProfilePinsByUser(GameUser user, TokenGame game, TokenPlatform platform, int skip, int count)
=> new(this.GetProfilePinsByUser(user, game, platform), skip, count);

public void AddPinProgress(PinProgressRelation relation, bool save)
{
this.PinProgressRelations.Add(relation);
if (save) this.SaveChanges();
}

public void RemovePinProgresses(IEnumerable<PinProgressRelation> relations, bool save)
{
this.PinProgressRelations.RemoveRange(relations);
if (save) this.SaveChanges();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Refresh.Database.Models.Authentication;
using Refresh.Database.Models.Pins;

#nullable disable

namespace Refresh.Database.Migrations
{
/// <inheritdoc />
[DbContext(typeof(GameDatabaseContext))]
[Migration("20251029184346_SeperatePinProgressByPlatform")]
public partial class SeperatePinProgressByPlatform : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
// RPCS3 is the safest default value here, as game achievements on RPCS3 are considered the least valuable.
// Also, the game will sync progress and profile pins after login anyway, so practically no information is lost here.
migrationBuilder.AddColumn<int>(
name: "Platform",
table: "ProfilePinRelations",
type: "integer",
nullable: false,
defaultValue: TokenPlatform.RPCS3);

migrationBuilder.AddColumn<int>(
name: "Platform",
table: "PinProgressRelations",
type: "integer",
nullable: false,
defaultValue: TokenPlatform.RPCS3);

migrationBuilder.DropPrimaryKey(
name: "PK_ProfilePinRelations",
table: "ProfilePinRelations");

migrationBuilder.DropPrimaryKey(
name: "PK_PinProgressRelations",
table: "PinProgressRelations");

migrationBuilder.AddPrimaryKey(
name: "PK_ProfilePinRelations",
table: "ProfilePinRelations",
columns: ["Index", "PublisherId", "Game", "Platform"]);

migrationBuilder.AddPrimaryKey(
name: "PK_PinProgressRelations",
table: "PinProgressRelations",
columns: ["PinId", "PublisherId", "IsBeta", "Platform"]);
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Platform",
table: "ProfilePinRelations");

migrationBuilder.DropColumn(
name: "Platform",
table: "PinProgressRelations");

migrationBuilder.DropPrimaryKey(
name: "PK_ProfilePinRelations",
table: "ProfilePinRelations");

migrationBuilder.DropPrimaryKey(
name: "PK_PinProgressRelations",
table: "PinProgressRelations");

migrationBuilder.AddPrimaryKey(
name: "PK_ProfilePinRelations",
table: "ProfilePinRelations",
columns: ["Index", "PublisherId", "Game"]);

migrationBuilder.AddPrimaryKey(
name: "PK_PinProgressRelations",
table: "PinProgressRelations",
columns: ["PinId", "PublisherId", "IsBeta"]);
}
}
}
10 changes: 8 additions & 2 deletions Refresh.Database/Migrations/GameDatabaseContextModelSnapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<bool>("IsBeta")
.HasColumnType("boolean");

b.Property<int>("Platform")
.HasColumnType("integer");

b.Property<DateTimeOffset>("FirstPublished")
.HasColumnType("timestamp with time zone");

Expand All @@ -952,7 +955,7 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<int>("Progress")
.HasColumnType("integer");

b.HasKey("PinId", "PublisherId", "IsBeta");
b.HasKey("PinId", "PublisherId", "IsBeta", "Platform");

b.HasIndex("PublisherId");

Expand Down Expand Up @@ -1024,13 +1027,16 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<int>("Game")
.HasColumnType("integer");

b.Property<int>("Platform")
.HasColumnType("integer");

b.Property<long>("PinId")
.HasColumnType("bigint");

b.Property<DateTimeOffset>("Timestamp")
.HasColumnType("timestamp with time zone");

b.HasKey("Index", "PublisherId", "Game");
b.HasKey("Index", "PublisherId", "Game", "Platform");

b.HasIndex("PublisherId");

Expand Down
12 changes: 11 additions & 1 deletion Refresh.Database/Models/Relations/PinProgressRelation.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
using MongoDB.Bson;
using Refresh.Database.Models.Authentication;
using Refresh.Database.Models.Users;

namespace Refresh.Database.Models.Relations;

#nullable disable

[PrimaryKey(nameof(PinId), nameof(PublisherId), nameof(IsBeta))]
[PrimaryKey(nameof(PinId), nameof(PublisherId), nameof(IsBeta), nameof(Platform))]
public partial class PinProgressRelation
{
/// <summary>
Expand All @@ -26,4 +27,13 @@ public partial class PinProgressRelation
/// for these game groups seperately.
/// </summary>
public bool IsBeta { get; set; }

/// <summary>
/// Seperates pin progresses per platform, to not let progress transfer inbetween PS3, RPCS3 and especially Vita,
/// as that's commonly unwanted behaviour. Maybe figure out how to make this be opt-out in the future?
///
/// Website = this pin is "universal" across platforms and games (e.g. LBP.me pin).
/// In that case ignore both IsBeta and Platform, and show this progress on all games.
/// </summary>
public TokenPlatform Platform { get; set; }
}
7 changes: 6 additions & 1 deletion Refresh.Database/Models/Relations/ProfilePinRelation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace Refresh.Database.Models.Relations;

#nullable disable

[PrimaryKey(nameof(Index), nameof(PublisherId), nameof(Game))]
[PrimaryKey(nameof(Index), nameof(PublisherId), nameof(Game), nameof(Platform))]
public partial class ProfilePinRelation
{
public long PinId { get; set; }
Expand All @@ -26,5 +26,10 @@ public partial class ProfilePinRelation
/// </summary>
public TokenGame Game { get; set; }

/// <summary>
/// Since pin progresses are split per platforms now, we also have to split profile pins aswell
/// </summary>
public TokenPlatform Platform { get; set; }

public DateTimeOffset Timestamp { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public ApiResponse<IApiAuthenticationResponse> Authenticate(RequestContext conte
context.Logger.LogInfo(BunkumCategory.Authentication, $"{user} successfully logged in through the API");

// Update pin progress for signing into the API
database.IncrementUserPinProgress((long)ServerPins.SignIntoWebsite, 1, user);
database.IncrementUserPinProgress((long)ServerPins.SignIntoWebsite, 1, user, false, TokenPlatform.Website);

return new ApiAuthenticationResponse
{
Expand Down
3 changes: 2 additions & 1 deletion Refresh.Interfaces.APIv3/Endpoints/LevelApiEndpoints.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using Refresh.Core.Services;
using Refresh.Core.Types.Data;
using Refresh.Database;
using Refresh.Database.Models.Authentication;
using Refresh.Database.Models.Levels;
using Refresh.Database.Models.Pins;
using Refresh.Database.Models.Users;
Expand Down Expand Up @@ -183,7 +184,7 @@ public ApiOkResponse QueueLevel(RequestContext context, GameDatabaseContext data
database.QueueLevel(level, user);

// Update pin progress for queueing a level through the API
database.IncrementUserPinProgress((long)ServerPins.QueueLevelOnWebsite, 1, user);
database.IncrementUserPinProgress((long)ServerPins.QueueLevelOnWebsite, 1, user, false, TokenPlatform.Website);

return new ApiOkResponse();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public class GameUserResponse : IDataConvertableFrom<GameUserResponse, GameUser>
}
if (game is not TokenGame.LittleBigPlanet1 or TokenGame.LittleBigPlanetPSP)
{
response.ProfilePins = dataContext.Database.GetProfilePinsByUser(old, dataContext.Game, 0, 3)
response.ProfilePins = dataContext.Database.GetProfilePinsByUser(old, dataContext.Game, dataContext.Platform, 0, 3)
.Items.Select(p => p.PinId).ToList();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,12 +211,12 @@ private void AwardScoreboardPins(DatabaseList<ScoreWithRank> scores, DataContext
if (isStoryLevel)
{
dataContext.Database.UpdateUserPinProgressToLowest((long)ServerPins.TopXOfAnyStoryLevelWithOver50Scores,
rankingInPercent, user, isGameBetaBuild);
rankingInPercent, user, isGameBetaBuild, dataContext.Platform);
}
else
{
dataContext.Database.UpdateUserPinProgressToLowest((long)ServerPins.TopXOfAnyCommunityLevelWithOver50Scores,
rankingInPercent, user, isGameBetaBuild);
rankingInPercent, user, isGameBetaBuild, dataContext.Platform);
}

// Update on how many story/user levels the user's ranking is in the top 25% (top 1/4th) of the leaderboard or below
Expand All @@ -225,12 +225,12 @@ private void AwardScoreboardPins(DatabaseList<ScoreWithRank> scores, DataContext
if (isStoryLevel)
{
dataContext.Database.IncrementUserPinProgress((long)ServerPins.TopFourthOfXStoryLevelsWithOver50Scores,
1, user, isGameBetaBuild);
1, user, isGameBetaBuild, dataContext.Platform);
}
else
{
dataContext.Database.IncrementUserPinProgress((long)ServerPins.TopFourthOfXCommunityLevelsWithOver50Scores,
1, user, isGameBetaBuild);
1, user, isGameBetaBuild, dataContext.Platform);
}
}

Expand Down
Loading