using NeonSprawl.Server.Game.Factions; using NeonSprawl.Server.Game.Gathering; using NeonSprawl.Server.Game.Items; using NeonSprawl.Server.Game.Mastery; using NeonSprawl.Server.Game.PositionState; using NeonSprawl.Server.Game.Quests; using NeonSprawl.Server.Game.Rewards; using NeonSprawl.Server.Game.Skills; using NeonSprawl.Server.Game.World; namespace NeonSprawl.Server.Game.Interaction; /// Maps POST /game/players/{{id}}/interact (NS-18). public static class InteractionApi { public const string ReasonOutOfRange = "out_of_range"; public const string ReasonUnknownInteractable = "unknown_interactable"; public static WebApplication MapInteractionApi(this WebApplication app) { app.MapPost( "/game/players/{id}/interact", (string id, InteractionRequest? body, IPositionStateStore store, IResourceNodeDefinitionRegistry nodeRegistry, IItemDefinitionRegistry itemRegistry, IPlayerInventoryStore inventoryStore, ISkillDefinitionRegistry skillRegistry, IPlayerSkillProgressionStore xpStore, ISkillLevelCurve levelCurve, PerkUnlockEngine perkUnlockEngine, IResourceNodeInstanceStore nodeInstanceStore, IQuestDefinitionRegistry questRegistry, IPlayerQuestStateStore progressStore, IPlayerPerkStateStore perkStore, IRewardDeliveryStore deliveryStore, IFactionStandingStore standingStore, IReputationDeltaStore auditStore, TimeProvider timeProvider) => { if (body is null || body.SchemaVersion != InteractionRequest.CurrentSchemaVersion) { return Results.BadRequest(); } var rawId = body.InteractableId; if (rawId is null) { return Results.BadRequest(); } var interactableKey = rawId.Trim(); if (interactableKey.Length == 0) { return Results.BadRequest(); } var lookupKey = interactableKey.ToLowerInvariant(); var playerKey = id.Trim(); if (!store.TryGetPosition(playerKey, out var snap)) { return Results.NotFound(); } if (!PrototypeInteractableRegistry.TryGet(lookupKey, out var entry)) { return Results.Json( new InteractionResponse { SchemaVersion = InteractionResponse.CurrentSchemaVersion, Allowed = false, ReasonCode = ReasonUnknownInteractable, }); } if (!HorizontalReach.IsWithinHorizontalRadius( snap.X, snap.Z, entry.X, entry.Z, entry.InteractionRadius)) { return Results.Json( new InteractionResponse { SchemaVersion = InteractionResponse.CurrentSchemaVersion, Allowed = false, ReasonCode = ReasonOutOfRange, }); } if (string.Equals(entry.Kind, PrototypeInteractableRegistry.ResourceNodeKind, StringComparison.Ordinal)) { var gather = GatherOperations.TryGather( playerKey, lookupKey, nodeRegistry, itemRegistry, inventoryStore, skillRegistry, xpStore, levelCurve, perkUnlockEngine, nodeInstanceStore, questRegistry, progressStore, perkStore, deliveryStore, standingStore, auditStore, timeProvider); if (!gather.Success) { return Results.Json( new InteractionResponse { SchemaVersion = InteractionResponse.CurrentSchemaVersion, Allowed = false, ReasonCode = gather.ReasonCode, }); } return Results.Json( new InteractionResponse { SchemaVersion = InteractionResponse.CurrentSchemaVersion, Allowed = true, InteractableId = lookupKey, Payload = new InteractionPlaceholderPayload(), }); } return Results.Json( new InteractionResponse { SchemaVersion = InteractionResponse.CurrentSchemaVersion, Allowed = true, InteractableId = lookupKey, Payload = new InteractionPlaceholderPayload(), }); }); return app; } }