Two new sibling Runtime owners under GameRuntime per the Slice-J pattern (D2): RuntimeFellowshipState is session-scoped (a new RuntimeGenerationResetStage.Fellowship clears it at every generation reset, matching the ExternalContainer precedent); RuntimeAllegianceState survives reconnect behind a HasServerSeed-style one-way latch and participates in NO reset stage (its data persists like a real disconnect does not sever allegiance membership). Fellowship: full-update REPLACE, incremental-fellow UPSERT, self-vs- other quit/dismiss removal (self clears the whole snapshot), disband clear, and retail's leader hand-off rule for the Quit button (RequiresLeaderHandoffBeforeQuit -- the current leader quitting WITHOUT disbanding must send 0x0290 AssignNewLeader before 0x00A3, lane B §2.5/§3.6). Allegiance: seeded by AllegianceUpdate (0x0020, always self) and, self-gated on TargetGuid == playerGuid(), by AllegianceInfoResponse (0x027C); wraps the FA1-assembled flat AllegianceMemberRecord list directly (AllegianceTree was deleted at FA1 -- nothing left to wrap). Both apply the full 8-edit J-owner template: construction + fault points + Owner/View properties + CaptureOwnership + a new GameRuntimeTeardownStage pair (FellowshipDisposed/AllegianceDisposed, stage count 11->13) + RuntimeGameplayOwnershipSnapshot inclusion + RuntimeStateCheckpoint/trace fields. IRuntimeFellowshipCommands/ IRuntimeAllegianceCommands added to IGameRuntimeCommands and implemented on DirectGameRuntimeCommandAdapter. No IRuntimeEventObserver member added (D2) -- consumers poll Snapshot.Revision. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
399 lines
10 KiB
C#
399 lines
10 KiB
C#
namespace AcDream.Runtime;
|
|
|
|
public enum RuntimeCommandStatus
|
|
{
|
|
Accepted,
|
|
Inactive,
|
|
StaleGeneration,
|
|
Unsupported,
|
|
Rejected,
|
|
}
|
|
|
|
public readonly record struct RuntimeCommandResult(
|
|
RuntimeCommandStatus Status,
|
|
RuntimeGenerationToken Generation,
|
|
uint ResultObjectId = 0u)
|
|
{
|
|
public bool Accepted => Status == RuntimeCommandStatus.Accepted;
|
|
}
|
|
|
|
public enum RuntimeSessionStartStatus
|
|
{
|
|
Disabled,
|
|
MissingCredentials,
|
|
NoCharacters,
|
|
Connected,
|
|
Deferred,
|
|
Failed,
|
|
Inactive,
|
|
StaleGeneration,
|
|
}
|
|
|
|
public readonly record struct RuntimeSessionStartResult(
|
|
RuntimeSessionStartStatus Status,
|
|
RuntimeGenerationToken Generation,
|
|
uint CharacterId = 0u,
|
|
string CharacterName = "",
|
|
Exception? Error = null);
|
|
|
|
public enum RuntimeSelectionCommand
|
|
{
|
|
SelectClosestHostile,
|
|
SelectPrevious,
|
|
ExamineSelected,
|
|
UseSelected,
|
|
PickUpSelected,
|
|
}
|
|
|
|
public enum RuntimeCombatCommand
|
|
{
|
|
ToggleMode,
|
|
}
|
|
|
|
public enum RuntimeMovementCommand
|
|
{
|
|
ToggleRunLock,
|
|
Stop,
|
|
Ready,
|
|
Sit,
|
|
Crouch,
|
|
Sleep,
|
|
}
|
|
|
|
public enum RuntimeChatChannel
|
|
{
|
|
Say,
|
|
Tell,
|
|
Fellowship,
|
|
Allegiance,
|
|
Vassals,
|
|
Patron,
|
|
Monarch,
|
|
CoVassals,
|
|
General,
|
|
Trade,
|
|
LookingForGroup,
|
|
Roleplay,
|
|
Society,
|
|
Olthoi,
|
|
|
|
/// <summary>
|
|
/// Campaign CH slice CH3 (2026-08-09): the legacy
|
|
/// <c>ChatChannel.AllegianceBroadcast (0x02000000)</c> — the monarch/
|
|
/// speaker-permission broadcast bound to retail's <c>@ab</c> verb.
|
|
/// Distinct from <see cref="Allegiance"/>, which is ALWAYS the Turbine
|
|
/// room now (retail's <c>@a</c> binds unconditionally to
|
|
/// <c>DoTurbineChat_Allegiance</c> once Turbine chat starts — see the
|
|
/// research doc §4.3/§6.7).
|
|
/// </summary>
|
|
AllegianceBroadcast,
|
|
}
|
|
|
|
public readonly record struct RuntimeChatCommand(
|
|
RuntimeChatChannel Channel,
|
|
string Text,
|
|
string? TargetName = null);
|
|
|
|
public enum RuntimePortalCommand
|
|
{
|
|
RecallLifestone,
|
|
RecallMarketplace,
|
|
RecallHouse,
|
|
RecallMansion,
|
|
}
|
|
|
|
public interface IRuntimeSessionCommands
|
|
{
|
|
RuntimeSessionStartResult Start(RuntimeGenerationToken expectedGeneration);
|
|
|
|
RuntimeSessionStartResult Reconnect(RuntimeGenerationToken expectedGeneration);
|
|
|
|
RuntimeTeardownAcknowledgement Stop(RuntimeGenerationToken expectedGeneration);
|
|
}
|
|
|
|
public interface IRuntimeSelectionCommands
|
|
{
|
|
RuntimeCommandResult Execute(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
RuntimeSelectionCommand command);
|
|
|
|
RuntimeCommandResult SelectObject(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
uint objectId);
|
|
|
|
RuntimeCommandResult Clear(
|
|
RuntimeGenerationToken expectedGeneration);
|
|
}
|
|
|
|
public interface IRuntimeCombatCommands
|
|
{
|
|
RuntimeCommandResult Execute(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
RuntimeCombatCommand command);
|
|
|
|
RuntimeCommandResult ExecuteAttack(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
in Gameplay.RuntimeCombatAttackInput command);
|
|
}
|
|
|
|
public readonly record struct RuntimeMagicCommand(uint SpellId);
|
|
|
|
public interface IRuntimeMagicCommands
|
|
{
|
|
RuntimeCommandResult Execute(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
in RuntimeMagicCommand command);
|
|
}
|
|
|
|
public interface IRuntimeMovementCommands
|
|
{
|
|
RuntimeCommandResult Execute(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
RuntimeMovementCommand command);
|
|
|
|
RuntimeCommandResult SetIntent(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
in Gameplay.MovementInput input);
|
|
|
|
RuntimeCommandResult ClearIntent(
|
|
RuntimeGenerationToken expectedGeneration);
|
|
}
|
|
|
|
public interface IRuntimeChatCommands
|
|
{
|
|
RuntimeCommandResult Execute(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
in RuntimeChatCommand command);
|
|
}
|
|
|
|
public interface IRuntimePortalCommands
|
|
{
|
|
RuntimeCommandResult Execute(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
RuntimePortalCommand command);
|
|
}
|
|
|
|
public readonly record struct RuntimeShortcutCommand(
|
|
int Index,
|
|
uint ObjectId,
|
|
uint SpellId);
|
|
|
|
public interface IRuntimeInventoryStateCommands
|
|
{
|
|
RuntimeCommandResult AddShortcut(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
in RuntimeShortcutCommand command);
|
|
|
|
RuntimeCommandResult RemoveShortcut(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
int index);
|
|
}
|
|
|
|
public interface IRuntimeSpellbookCommands
|
|
{
|
|
RuntimeCommandResult AddFavorite(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
int tabIndex,
|
|
int position,
|
|
uint spellId);
|
|
|
|
RuntimeCommandResult RemoveFavorite(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
int tabIndex,
|
|
uint spellId);
|
|
|
|
RuntimeCommandResult SetFilter(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
uint filters);
|
|
|
|
RuntimeCommandResult ForgetSpell(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
uint spellId);
|
|
|
|
RuntimeCommandResult SetDesiredComponent(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
uint componentId,
|
|
uint amount);
|
|
|
|
RuntimeCommandResult ClearDesiredComponents(
|
|
RuntimeGenerationToken expectedGeneration);
|
|
}
|
|
|
|
public enum RuntimeAdvancementKind
|
|
{
|
|
Attribute,
|
|
Vital,
|
|
Skill,
|
|
TrainSkill,
|
|
}
|
|
|
|
public readonly record struct RuntimeAdvancementCommand(
|
|
RuntimeAdvancementKind Kind,
|
|
uint StatId,
|
|
ulong Cost);
|
|
|
|
public interface IRuntimeCharacterCommands
|
|
{
|
|
RuntimeCommandResult Advance(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
in RuntimeAdvancementCommand command);
|
|
|
|
/// <summary>
|
|
/// Retail <c>SetSingleCharacterOption (GameActionType 0x0005)</c> —
|
|
/// toggles one character option. Campaign CH slice CH3 (2026-08-09)
|
|
/// replaced the former <c>SetOptions1</c> (the malformed, callerless
|
|
/// full-Options1-blob 0x01A1 builder) with this: the only wire message
|
|
/// that actually changes Turbine room membership for the six
|
|
/// <c>ListenTo*Chat</c> ids.
|
|
/// </summary>
|
|
RuntimeCommandResult SetSingleOption(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
uint optionId,
|
|
bool value);
|
|
|
|
/// <summary>
|
|
/// Retail <c>CPlayerModule::SaveToServer(force: 0)</c> — the batched-
|
|
/// option blob-flush verb (Campaign OP slice OP1, 2026-08-10). Flushes
|
|
/// <c>SetCharacterOptions (0x01A1)</c> iff the module is dirty; a clean
|
|
/// module sends nothing, matching retail exactly (both its own
|
|
/// production call sites — Apply, logout — pass <c>force = 0</c>).
|
|
/// </summary>
|
|
RuntimeCommandResult SaveOptions(RuntimeGenerationToken expectedGeneration);
|
|
}
|
|
|
|
public enum RuntimeFriendCommandKind
|
|
{
|
|
Add,
|
|
Remove,
|
|
Clear,
|
|
RequestLegacyList,
|
|
}
|
|
|
|
public readonly record struct RuntimeFriendCommand(
|
|
RuntimeFriendCommandKind Kind,
|
|
uint CharacterId = 0u,
|
|
string? Name = null);
|
|
|
|
public enum RuntimeSquelchScope
|
|
{
|
|
Character,
|
|
Account,
|
|
Global,
|
|
}
|
|
|
|
public readonly record struct RuntimeSquelchCommand(
|
|
RuntimeSquelchScope Scope,
|
|
bool Add,
|
|
uint CharacterId = 0u,
|
|
string? Name = null,
|
|
uint MessageType = 0u);
|
|
|
|
public interface IRuntimeSocialCommands
|
|
{
|
|
RuntimeCommandResult Execute(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
in RuntimeFriendCommand command);
|
|
|
|
RuntimeCommandResult Execute(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
in RuntimeSquelchCommand command);
|
|
}
|
|
|
|
// ── Fellowship / Allegiance (Campaign FA slice FA2, 2026-08-12) ────────────
|
|
|
|
/// <summary>
|
|
/// Generation-gated fellowship outbound actions. <see cref="Quit"/>
|
|
/// implements retail's leader hand-off rule itself (lane B §2.5/§3.6): the
|
|
/// current leader quitting WITHOUT disbanding sends <c>0x0290</c> (assign
|
|
/// a non-leader fellow) BEFORE <c>0x00A3</c> — see
|
|
/// <c>RuntimeFellowshipState.RequiresLeaderHandoffBeforeQuit</c>.
|
|
/// <see cref="SetPanelOpen"/> is D4's <c>0x00A6</c> panel-visibility
|
|
/// declaration, the command the fellowship page's show/hide seam calls
|
|
/// (FA3+); without it ACE freezes the roster's vitals stream at join.
|
|
/// </summary>
|
|
public interface IRuntimeFellowshipCommands
|
|
{
|
|
RuntimeCommandResult Create(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
string fellowshipName,
|
|
bool shareXp);
|
|
|
|
RuntimeCommandResult Recruit(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
uint targetGuid);
|
|
|
|
RuntimeCommandResult Dismiss(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
uint targetGuid);
|
|
|
|
RuntimeCommandResult Quit(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
bool disband);
|
|
|
|
RuntimeCommandResult AssignLeader(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
uint newLeaderGuid);
|
|
|
|
RuntimeCommandResult SetOpen(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
bool isOpen);
|
|
|
|
RuntimeCommandResult SetPanelOpen(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
bool panelOpen);
|
|
}
|
|
|
|
/// <summary>Generation-gated allegiance outbound actions.</summary>
|
|
public interface IRuntimeAllegianceCommands
|
|
{
|
|
RuntimeCommandResult Swear(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
uint patronGuid);
|
|
|
|
RuntimeCommandResult Break(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
uint targetGuid);
|
|
|
|
RuntimeCommandResult Kick(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
uint vassalGuid);
|
|
|
|
/// <summary><c>0x027B</c> — empty name queries self.</summary>
|
|
RuntimeCommandResult RequestInfo(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
string playerName);
|
|
|
|
/// <summary><c>0x001F</c> — the allegiance panel's subscribe/unsubscribe toggle.</summary>
|
|
RuntimeCommandResult SetUpdateSubscription(
|
|
RuntimeGenerationToken expectedGeneration,
|
|
bool on);
|
|
}
|
|
|
|
public interface IGameRuntimeCommands
|
|
{
|
|
IRuntimeSessionCommands Session { get; }
|
|
|
|
IRuntimeSelectionCommands Selection { get; }
|
|
|
|
IRuntimeCombatCommands Combat { get; }
|
|
|
|
IRuntimeMagicCommands Magic { get; }
|
|
|
|
IRuntimeMovementCommands Movement { get; }
|
|
|
|
IRuntimeChatCommands Chat { get; }
|
|
|
|
IRuntimePortalCommands Portal { get; }
|
|
|
|
IRuntimeInventoryStateCommands InventoryState { get; }
|
|
|
|
IRuntimeSpellbookCommands Spellbook { get; }
|
|
|
|
IRuntimeCharacterCommands Character { get; }
|
|
|
|
IRuntimeSocialCommands Social { get; }
|
|
|
|
IRuntimeFellowshipCommands Fellowship { get; }
|
|
|
|
IRuntimeAllegianceCommands Allegiance { get; }
|
|
}
|