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.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, 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, 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; } }