Progression: Achievements, Stats & Leaderboards

UCrimsonOnlineAchievementService

Wraps IOnlineAchievements. Achievement IDs are FString and must match the IDs registered in the platform backend exactly, including case. Progress runs 0.0 to 100.0; writing 100.0 unlocks.

MemberDescription
WriteProgress(AchievementId, Progress, LocalUserNum = 0)Writes progress 0-100 for one achievement. Completes on OnAchievementWritten
UnlockAchievement(AchievementId, LocalUserNum = 0)Convenience wrapper - calls WriteProgress with 100.0
QueryAchievements(LocalUserNum = 0)Fetches definitions and current progress from the platform. Completes on OnAchievementsQueried
OnAchievementWrittenDelegate: bool bSuccess, const FString& AchievementId, float NewProgress
OnAchievementsQueriedDelegate: bool bSuccess, const TArray<FCrimsonAchievementProgress>& Achievements
The query result is not cached
Achievements arrive as the Achievements argument of OnAchievementsQueried - there is no GetCachedAchievements accessor. Copy the array in your handler if you need it later.
Async node
Write Achievement Progress (UCrimsonAsyncAction_WriteAchievement). Input pins: Achievement Id (FString), Progress (float, 0-100), Local User Num (int32, default 0). Output pins On Success and On Failure, each carrying bSuccess, Achievement Id and New Progress.

UCrimsonOnlineStatsService - global leaderboards

Wraps IOnlineLeaderboards. Writes stat columns to a named leaderboard and reads ranked entries back. Leaderboard names must match the platform backend - the Steamworks board name, or the EOS stat name.

MemberDescription
WriteStats(LeaderboardName, Stats, LocalUserNum = 0)Submits an array of FCrimsonStatWrite column values. Completes on OnStatsWritten
ReadLeaderboard(LeaderboardName, MaxEntries = 100)Reads the global top N entries. Completes on OnLeaderboardRead
ReadLeaderboardAroundPlayer(LeaderboardName, RangeBelow = 10, RangeAbove = 10, LocalUserNum = 0)Reads entries centered on the local player's rank. Completes on OnLeaderboardRead
OnStatsWrittenDelegate: bool bSuccess, const FString& LeaderboardName
OnLeaderboardReadDelegate: bool bSuccess, const FString& LeaderboardName, const TArray<FCrimsonLeaderboardEntry>& Entries

FCrimsonLeaderboardEntry

FieldTypeDescription
PlayerNameFStringDisplay name reported by the platform for the ranked player
Rankint32Rank as reported by the platform
Scoreint64Raw score value
Read results are delivered, not cached
Entries arrive as the Entries argument of OnLeaderboardRead; there is no cached-leaderboard accessor, and no friends-only read. FCrimsonLeaderboardEntry carries a display name only - no unique net ID - so pair it with UCrimsonOnlineUserService when you need to act on a listed player.

UCrimsonOnlineRawStatsService - per-player stat values

Wraps IOnlineStats - a different interface from the leaderboards one above. Stores arbitrary named int64 stats per player, with a per-write combine mode, and can read them back for the local player or for a list of remote players. Use it for kills, play time, best times: values you own, rather than a ranked board.

MemberDescription
UpdateStats(Updates, LocalUserNum = 0)Submits a batch of FCrimsonRawStatUpdate values. Completes on OnRawStatsUpdated
QueryStats(StatNames, LocalUserNum = 0)Queries the named stats for the local player; an empty array queries all. Completes on OnRawStatsQueried
QueryStatsForUsers(PlatformUserIds, StatNames, LocalUserNum = 0)Queries stats for a list of remote players. Completes on OnRawStatsQueried
GetCachedStats(PlatformUserId)BlueprintPure. Returns TArray<FCrimsonRawStatValue> for one player from the last query
OnRawStatsUpdatedDelegate: bool bSuccess
OnRawStatsQueriedDelegate: bool bSuccess, const TArray<FCrimsonRawStatValue>& Stats

ECrimsonStatModification - set per update in FCrimsonRawStatUpdate::ModificationType (default Set).

ValueBehavior
SumAdd the new value to the existing value
SetOverwrite the existing value with the new value
LargestOnly update if the new value is larger
SmallestOnly update if the new value is smaller
cpp
#include "CrimsonOnlineSubsystemGI.h"
#include "Services/CrimsonOnlineRawStatsService.h"
UCrimsonOnlineRawStatsService* RawStats =
UCrimsonOnlineSubsystemGI::Get(this)->GetRawStatsService();
// Handler must be a UFUNCTION - OnRawStatsUpdated is a dynamic multicast delegate.
RawStats->OnRawStatsUpdated.AddDynamic(this, &UMyStatsComponent::HandleStatsUpdated);
FCrimsonRawStatUpdate Kills;
Kills.StatName = TEXT("Kills");
Kills.Value = 150;
Kills.ModificationType = ECrimsonStatModification::Sum;
FCrimsonRawStatUpdate BestTime;
BestTime.StatName = TEXT("BestTime");
BestTime.Value = 312;
BestTime.ModificationType = ECrimsonStatModification::Smallest;
RawStats->UpdateStats({ Kills, BestTime });
Write stats on the server
Stat and achievement writes are player-authoritative calls into the platform backend, so run them where the outcome of the match is authoritative - the server - and let the owning client's copy of the subsystem only read. A client that writes its own scores is a client that can write any score.