namespace NeonSprawl.Server.Game.Gathering; /// Registry-backed lazy init and atomic depletion commits for world node instances (NEO-61). public static class ResourceNodeInstanceOperations { /// /// Decrements remaining gathers by one after lazy-init from catalog maxGathers. Interact wiring (NEO-63) /// maps to denied interact responses. /// public static ResourceNodeInstanceMutationOutcome TryCommitSuccessfulGatherDecrement( string interactableId, IResourceNodeDefinitionRegistry registry, IResourceNodeInstanceStore store) { var key = ResourceNodeInstanceIds.Normalize(interactableId); if (key.Length == 0 || !registry.TryGetDefinition(key, out var definition)) { return new ResourceNodeInstanceMutationOutcome( ResourceNodeInstanceMutationKind.Denied, ResourceNodeInstanceReasonCodes.UnknownNode, null); } if (!store.TryGetRemainingGathers(key, out _)) { if (!store.TryEnsureInitialized(key, definition.MaxGathers)) { throw new InvalidOperationException( $"Failed to initialize resource node instance '{key}' with maxGathers {definition.MaxGathers}."); } } if (store.TryDecrementRemainingGathers(key, out _, out var remaining)) { return new ResourceNodeInstanceMutationOutcome( ResourceNodeInstanceMutationKind.Applied, null, new ResourceNodeInstanceSnapshot(key, remaining)); } if (!store.TryGetRemainingGathers(key, out var current)) { current = new ResourceNodeInstanceSnapshot(key, 0); } return new ResourceNodeInstanceMutationOutcome( ResourceNodeInstanceMutationKind.Denied, ResourceNodeInstanceReasonCodes.NodeDepleted, current); } }