Table of Contents

Class CharacterPartyService

Namespace
FishMMO.Database.Npgsql.Services
Assembly
FishMMO-DB.dll

Service for managing character party membership in the database. Provides async operations for CRUD operations on character party data. Implements execution strategies for automatic retry on transient database failures. Returns DatabaseResult for consistent, safe error handling.

public sealed class CharacterPartyService : BaseService<CharacterPartyEntity>, ICharacterPartyService, ICountByKeyAction<long>, IDeleteByKeyVersionedAction<long>, IFetchByKeyAction<long, CharacterPartyData?>, IFetchManyByKeyAction<long, CharacterPartyData>
Inheritance
CharacterPartyService
Implements
Inherited Members

Remarks

This service manages character party memberships including:

  • Party membership save/update with atomic UPSERT operations
  • Rank updates
  • Party membership deletion
  • Party membership and member retrieval

Database operations are executed via the BaseService execution wrappers for:

  • Automatic transient failure retry
  • Centralized exception handling and mapping
  • Consistent DatabaseResult pattern

When a write requires multiple database statements, it should be wrapped in ExecuteTransactionAsync(Func<NpgsqlDbContext, Task>, bool, string?, CancellationToken). Single-statement SQL operations (including CTE-based UPSERT/DELETE/UPDATE) are executed atomically without requiring an explicit transaction wrapper.

Constructors

CharacterPartyService(INpgsqlDbContextFactory)

Initializes a new instance of the CharacterPartyService class.

public CharacterPartyService(INpgsqlDbContextFactory dbContextFactory)

Parameters

dbContextFactory INpgsqlDbContextFactory

Factory for creating database contexts.

Exceptions

ArgumentNullException

Thrown when dbContextFactory is null.

Methods

CountAsync(long, CancellationToken)

Counts items for the given key.

public Task<DatabaseResult<int>> CountAsync(long partyId, CancellationToken cancellationToken = default)

Parameters

partyId long
cancellationToken CancellationToken

Token to cancel the operation.

Returns

Task<DatabaseResult<int>>

DeleteAsync(long, long, CancellationToken)

Deletes the entity identified by the given key if incomingVersion is newer.

public Task<DatabaseResult> DeleteAsync(long characterId, long incomingVersion, CancellationToken cancellationToken = default)

Parameters

characterId long
incomingVersion long

The authoritative, monotonic version for this delete operation.

cancellationToken CancellationToken

Token to cancel the operation.

Returns

Task<DatabaseResult>

FetchAsync(long, CancellationToken)

Fetches an entity for the given key.

public Task<DatabaseResult<CharacterPartyData?>> FetchAsync(long characterId, CancellationToken cancellationToken = default)

Parameters

characterId long
cancellationToken CancellationToken

Token to cancel the operation.

Returns

Task<DatabaseResult<CharacterPartyData?>>

FetchManyAsync(long, CancellationToken)

Fetches many items for the given key.

public Task<DatabaseResult<IReadOnlyList<CharacterPartyData>>> FetchManyAsync(long partyId, CancellationToken cancellationToken = default)

Parameters

partyId long
cancellationToken CancellationToken

Token to cancel the operation.

Returns

Task<DatabaseResult<IReadOnlyList<CharacterPartyData>>>

FetchOnlineMemberIdsAsync(long, CancellationToken)

Returns the party's members who currently hold a live session.

public Task<DatabaseResult<IReadOnlyList<long>>> FetchOnlineMemberIdsAsync(long partyId, CancellationToken cancellationToken = default)

Parameters

partyId long

The party to inspect.

cancellationToken CancellationToken

Token to cancel the operation.

Returns

Task<DatabaseResult<IReadOnlyList<long>>>

The character IDs of members with a live session; empty when none are online.

Remarks

Exists so party leadership can be repaired convergently rather than only on the events that break it. A scene server knows which characters IT hosts and nothing about the rest of the shard, so an absent leader — one who disconnected, or crashed, or whose server died — is invisible to every server that could do something about it. Without this the party is stuck: it HAS a leader, so nothing that merely counts leaders sees a problem, and that leader is not there to invite, kick, promote, or close the instance the party is holding open.

"Online" is the same definition the account session checks use, and it is the strict one on purpose. A lapsed lease does not count, which is what lets a party recover from a scene server dying rather than waiting for it to come back. A character running out a combat-logout timer does not count either: its session is still claimed so its body stays authoritative, but the player is gone, and leadership must follow the player.

PersistAsync(CharacterPartyData, int, CancellationToken)

Persists the provided party membership data, enforcing capacity limits.

public Task<DatabaseResult> PersistAsync(CharacterPartyData partyData, int maxCapacity, CancellationToken cancellationToken = default)

Parameters

partyData CharacterPartyData

The party membership data to persist.

maxCapacity int

The maximum number of members allowed in the party.

cancellationToken CancellationToken

Token to cancel the operation.

Returns

Task<DatabaseResult>

A DatabaseResult indicating success or failure.

UpdateRankAsync(long, long, byte, long, CancellationToken)

Updates a character's party rank if incomingVersion is newer.

public Task<DatabaseResult> UpdateRankAsync(long characterId, long partyId, byte rank, long incomingVersion, CancellationToken cancellationToken = default)

Parameters

characterId long

The character ID.

partyId long

The party ID.

rank byte

The new rank.

incomingVersion long

The authoritative, monotonic version for this update operation.

cancellationToken CancellationToken

Token to cancel the operation.

Returns

Task<DatabaseResult>

A DatabaseResult indicating success or failure.