neon-sprawl/docs/decomposition/modules/E1_M3_InteractionAndTargeti...

11 KiB

E1.M3 — InteractionAndTargetingLayer

Summary

Field Value
Module ID E1.M3
Epic Epic 1 — Core Player Runtime
Stage target Prototype
Status In Progress (see dependency register)
Linear NEO-23 through NEO-27 (backlog); label E1.M3 per decomposition README — Linear alignment

Purpose

Authority: Client vs server — E1.M3 — the server decides valid targets and interactable eligibility (range, faction, phase, alive/dead, etc.); the client sends selection or use intent and may show hover/soft focus until the server confirms.

Bridges authoritative position and reach policy from E1.M1 — InputAndMovementRuntime into combat, gathering, abilities, and social flows: who is locked for gameplay, what in the world is selectable, and when selection changes—without treating camera pose as gameplay truth (see E1.M2 — world-anchored semantics).

Boundary: E1.M1 vs E1.M3

Topic E1.M1 (today) E1.M3 (this module)
Primary job Locomotion + authoritative “use interactable now attempt via InteractionRequest Selection model: lock, swap rules, descriptors, and change events for UI and downstream systems
Wire / HTTP POST …/interact + InteractionResponse with reasonCode (NEO-9) Future selection/target intents and authoritative TargetState sync (wire shape TBD; see contracts.md)
Registry / catalog Static prototype interactable table for range checks InteractableDescriptor (and combat target projection) as the stable description surface for clients and validators
Client UX Minimal E key + proximity preview glow (authoritative outcome still from server) Tab-target, focus cycling, sticky lock, rich hover, prompts—prototype scope grows here

Shared policy (not owned exclusively by either module): horizontal reach on X/Z only, Y ignored for threshold distance, inclusive radius boundary—same rule as NEO-9. Both E1.M1 interact validation and E1.M3 eligibility checks reuse the same math and content anchors so client preview and server denial stay aligned.

Responsibilities

  • Combat target lock: maintain and expose TargetState for tab-target flow; integrate with E1.M4 — AbilityInputScaffold and E5.M1 — CombatRulesEngine for cast validity (server re-validates; client is a view + intent).
  • World interactables: discovery, selection, and use flow beyond the NEO-9 smoke path—multiple kinds, prompts, and data-driven defs when scoped; still grounded in InteractableDescriptor projections.
  • Focus swap rules: Prototype: explicit input to cycle targets / interactables in a deterministic order (e.g. tab through eligible list); Deferred: nearest-in-cone heuristics, soft-target stickiness under latency—decide with first multiplayer combat vertical slice (authority doc — lag compensation).
  • Presentation: highlights, outlines, and optional wrong local preview until server ack; reconcile on snapshot or denial (authority).
  • E1.M2 adjacency: targeting and line-of-interest for gameplay use world geometry + server-known positions, not CameraState or client-only aim (E1.M2).

Key contracts

Contract Role
TargetState Authoritative (server) view: locked combat/interaction target, validity, swap/clear reasons.
InteractableDescriptor Stable description of a selectable world entity (id, kind, anchor, radius / flags).
SelectionEvent Selection changes for UI and consumers (who/when/cause).

Contract notes (contracts.md)

  • Kind: these are wire contracts once the game channel exists (Protobuf preferred per tech stack); until then, versioned JSON spikes must be explicitly throwaway and tracked for migration—same discipline as early MoveCommand / InteractionRequest.
  • Denials: reuse the stable reasonCode string pattern from InteractionResponse (NEO-9): whenever the server rejects a selection or use intent, return a non-empty machine-oriented code; document new codes alongside E5.M1 / E3.M1 consumers.

Logical fields (illustrative, not a frozen schema):

Contract Illustrative fields
TargetState Target entity id (or empty); validity (ok / out_of_range / invalid_target / …); optional server tick or sequence for reconciliation
InteractableDescriptor interactableId; category/kind; world position or entity ref; interactionRadius; flags (e.g. usable-in-combat)
SelectionEvent Previous id, new id, cause (tab, clear, target_died, zone_change, server_correction, …)

Intent vs state (reference)

flowchart LR
  subgraph clientLayer [Client]
    Hover[HoverHighlight]
    Intent[SelectionIntent]
  end
  subgraph serverLayer [Server]
    Pos[PositionState_E1M1]
    Val[EligibilityValidation]
    TS[TargetState_truth]
  end
  Pos --> Val
  Intent --> Val
  Val --> TS
  TS --> clientLayer
  Hover -.->|"preview_only"| clientLayer

Module dependencies

  • E1.M1 — InputAndMovementRuntime: authoritative PositionState and horizontal reach policy; existing InteractionRequest path for “use now” attempts.

Logical (not in register “Depends On” column): E5.M1 resolves hostile actions and may deny casts for reasons beyond selection; E6.M1 gates player targets (pvp_combat_integration.md). E1.M3 does not list E5.M1 as a hard module dependency in the register so that targeting can ship and test against stubs per Epic 1 Slice 3.

Dependents (by design)

  • E1.M4 — AbilityInputScaffold: reads TargetState (and related validity) to build AbilityCastRequest.
  • E3.M1 — ResourceNodeAndGatherLoop: gather interact flows use range + selection aligned with InteractableDescriptor.
  • E5.M1 — CombatRulesEngine: tab-target resolution, valid actions against locked target; re-validates client intent.
  • E8.M1 — PartyAndMatchAssembly: party-scoped selection / invite context hooks anchored on player identity from targeting layer.

Epic 1 — Slice 3: Interaction, targeting, and ability input wiring

  • Scope: E1.M3 + E1.M4 with stub or live combat consumer for AbilityCastRequest.
  • Dependencies: E1.M2, E5.M1 (minimum combat hook).
  • Acceptance criteria: Players can select targets/interactables and fire hotbar-bound abilities when the combat module accepts casts.
  • Telemetry hooks: target_changed, ability_cast_requested, ability_cast_denied with reason codes (align with E9.M1 when catalog exists).

Implementation snapshot

  • TargetState (prototype JSON v1 — NEO-23): server GET /game/players/{id}/target and POST /game/players/{id}/target/select with versioned PlayerTargetStateResponse / TargetSelectRequest / TargetSelectResponse; stub registry + in-memory lock under server/NeonSprawl.Server/Game/Targeting/; horizontal reach + soft lock semantics — NEO-23, server README — Targeting. Still open on later issues: InteractableDescriptor, SelectionEvent, Godot tab-target (NEO-24). Story backlog: E1M3 prototype backlog.
  • Precursor under E1.M1 (NEO-9): server POST /game/players/{id}/interact with InteractionRequest / InteractionResponse; HorizontalReach (server/NeonSprawl.Server/Game/World/HorizontalReach.cs); prototype registry and API under server/NeonSprawl.Server/Game/Interaction/; client interaction_request_client.gd, interaction_radius_indicators.gd, prototype_interaction_constants.gd — see NEO-9 and server README — Interaction.
  • Alignment: Documentation and implementation alignment.

Risks and telemetry

  • Soft vs authoritative target: client may highlight a target the server will deny; mitigate with visible deny reasons, fast reconciliation, and logging material mismatch (authority — debugging).
  • Occluders vs truth: camera occlusion and pick-through (NEO-20) affect presentation and click-to-move; server eligibility must not depend on “what the camera showed.”
  • Lag compensation for tab-target: deferred per client vs server authority; decide with combat design when E5.M1 networking MVP is scoped.

Telemetry (Slice 3): target_changed, ability_cast_requested, ability_cast_deniedTODO(E9.M1) until event schema exists.

Linear backlog

Parent epic: Epic 1 — Core Player Runtime.

Stories: full acceptance checklists in docs/plans/E1M3-prototype-backlog.md.

Slug Linear
E1M3-01 NEO-23 — TargetState v1 + server selection intent
E1M3-02 NEO-24 — Client tab-target + lock UI synced to server
E1M3-03 NEO-25 — InteractableDescriptor list / projection
E1M3-04 NEO-26 — SelectionEvent surface + consumer
E1M3-05 NEO-27 — Slice 3 telemetry hook sites

Issues should carry label E1.M3 per Linear alignment.

Source anchors