logo SERENITY
Game Systems Foundation
Search Results for

    Show / Hide Table of Contents

    Class CompositeAchievementPlatformGateway

    Fans every gateway call out to a set of child gateways so a build that ships to more than one storefront still sees a single IAchievementPlatformGateway.

    Inheritance
    object
    CompositeAchievementPlatformGateway
    Implements
    IAchievementPlatformGateway
    IDisposable
    Inherited Members
    object.ToString()
    object.Equals(object)
    object.Equals(object, object)
    object.ReferenceEquals(object, object)
    object.GetHashCode()
    object.GetType()
    Namespace: Serenity.Achievements.Application.Gateways
    Assembly: Serenity.Achievements.Application.dll
    Syntax
    public sealed class CompositeAchievementPlatformGateway : IAchievementPlatformGateway, IDisposable
    Remarks

    A child that throws is caught, logged and treated as unavailable for that call: one broken SDK must never take down the unlock path or the other platforms. A write succeeds when at least one child accepted it. QueryUnlockedAsync(CancellationToken) is stricter: it answers with the union of what every child reported only when EVERY child answered, and reports the whole query unreachable otherwise — a union built from some of the children is indistinguishable from a smaller account, which is exactly the data loss PlatformUnlockQueryResult exists to prevent.

    The same one-broken-child containment applies to Dispose(): a child gateway that owns a real SDK handle (SteamAchievementGateway releases a Steamworks callback) needs disposing when the composition is torn down, and a child that throws while doing so must not stop its siblings from releasing theirs.

    A public member called after Dispose() returns the same "nobody accepted this" result an unavailable platform already produces — false, or Unreachable() — no child is ever touched. A disposed composite cannot vouch for any account, so it must not answer Answered(IReadOnlyList<AchievementId>) with an empty list either, or reconciliation would read "torn down" as "verified empty" and push out every local unlock. _isDisposed is volatile so a call racing a concurrent Dispose() from another thread still observes it.

    Constructors

    CompositeAchievementPlatformGateway(IReadOnlyList<IAchievementPlatformGateway>, ILogService)

    Initializes a new instance of the CompositeAchievementPlatformGateway class.

    Declaration
    public CompositeAchievementPlatformGateway(IReadOnlyList<IAchievementPlatformGateway> gateways, ILogService logService)
    Parameters
    Type Name Description
    IReadOnlyList<IAchievementPlatformGateway> gateways

    The child gateways to fan out to. Cannot be null; null entries are ignored.

    ILogService logService

    Logging service. May be null.

    Exceptions
    Type Condition
    ArgumentNullException

    Thrown when gateways is null.

    Properties

    IsAvailable

    Whether the platform is reachable right now.

    Declaration
    public bool IsAvailable { get; }
    Property Value
    Type Description
    bool

    PlatformName

    The human-readable name of the platform this gateway talks to.

    Declaration
    public string PlatformName { get; }
    Property Value
    Type Description
    string

    Methods

    ClearAsync(CancellationToken)

    Clears every achievement on the platform account. Intended for debugging and QA.

    Declaration
    public Task<bool> ClearAsync(CancellationToken cancellationToken)
    Parameters
    Type Name Description
    CancellationToken cancellationToken

    Token used to cancel the operation.

    Returns
    Type Description
    Task<bool>

    True when the platform accepted the clear; otherwise false.

    Dispose()

    Disposes every child gateway that owns a disposable resource. Safe to call more than once.

    Declaration
    public void Dispose()
    Remarks

    A child that is not IDisposable (most inert templates, and every gateway with nothing to release) is skipped without comment; a child that throws while disposing is logged the same way a failed call is, and its siblings still get disposed.

    InitializeAsync(CancellationToken)

    Brings the platform session up. Returns whether the gateway is usable afterwards.

    Declaration
    public Task<bool> InitializeAsync(CancellationToken cancellationToken)
    Parameters
    Type Name Description
    CancellationToken cancellationToken

    Token used to cancel the operation.

    Returns
    Type Description
    Task<bool>

    QueryUnlockedAsync(CancellationToken)

    Reads back which achievements the platform account already has.

    Declaration
    public Task<PlatformUnlockQueryResult> QueryUnlockedAsync(CancellationToken cancellationToken)
    Parameters
    Type Name Description
    CancellationToken cancellationToken

    Token used to cancel the operation.

    Returns
    Type Description
    Task<PlatformUnlockQueryResult>
    Remarks

    The result keeps "the account has nothing unlocked" apart from "the platform could not be asked": a gateway that genuinely has no account to be wrong about (no SDK configured, no storefront targeted) answers Answered(IReadOnlyList<AchievementId>) with an empty list, while a gateway that talks to a real storefront answers Unreachable() when the client is down, the call throws, or it cannot otherwise vouch for the account it is reporting. Collapsing the two makes an unreachable storefront indistinguishable from an empty one, which is the exact invariant PlatformUnlockQueryResult exists to protect.

    SetProgressAsync(AchievementDefinition, long, long, CancellationToken)

    Reports progress towards a progressive achievement on the platform account.

    Declaration
    public Task<bool> SetProgressAsync(AchievementDefinition definition, long current, long target, CancellationToken cancellationToken)
    Parameters
    Type Name Description
    AchievementDefinition definition

    The achievement being advanced, carrying its platform identifiers.

    long current

    The current numerator.

    long target

    The numerator that unlocks the achievement.

    CancellationToken cancellationToken

    Token used to cancel the operation.

    Returns
    Type Description
    Task<bool>

    True when the platform accepted the progress; otherwise false.

    UnlockAsync(AchievementDefinition, CancellationToken)

    Marks an achievement as unlocked on the platform account.

    Declaration
    public Task<bool> UnlockAsync(AchievementDefinition definition, CancellationToken cancellationToken)
    Parameters
    Type Name Description
    AchievementDefinition definition

    The achievement to unlock, carrying its platform identifiers.

    CancellationToken cancellationToken

    Token used to cancel the operation.

    Returns
    Type Description
    Task<bool>

    True when the platform accepted the unlock; otherwise false.

    Implements

    IAchievementPlatformGateway
    IDisposable
    In this article
    © 2026 Serenity. All Rights Reserved