NEO-25: queue last-wins interact POST when HTTP client is busy
parent
06d9104157
commit
ba667f1581
|
|
@ -82,7 +82,7 @@ If the server is **down**, boot **`GET`** fails silently (check Output for warni
|
||||||
|
|
||||||
On boot, **`InteractablesCatalogClient`** **`GET`s** **`/game/world/interactables`**; **`interactable_world_builder.gd`** spawns **walkable** prototype props plus **two** small glow markers per row under **`World/InteractionMarkers`**. **`interaction_radius_indicators.gd`** compares the snapped **`CharacterBody3D`** **`global_position`** to each descriptor’s **`anchor`** on **X/Z** with the same **`interactionRadius`** and inclusive **`<=`** rule as the server — **preview only**; **`POST /game/players/{id}/interact`** remains authoritative.
|
On boot, **`InteractablesCatalogClient`** **`GET`s** **`/game/world/interactables`**; **`interactable_world_builder.gd`** spawns **walkable** prototype props plus **two** small glow markers per row under **`World/InteractionMarkers`**. **`interaction_radius_indicators.gd`** compares the snapped **`CharacterBody3D`** **`global_position`** to each descriptor’s **`anchor`** on **X/Z** with the same **`interactionRadius`** and inclusive **`<=`** rule as the server — **preview only**; **`POST /game/players/{id}/interact`** remains authoritative.
|
||||||
|
|
||||||
- **`InteractionRequestClient`**: **`interact`** (**E**) → **`prototype_terminal`**; **`interact_secondary`** (**R**) → **`prototype_resource_node_alpha`** (stable ids; must match `PrototypeInteractableRegistry.cs`). **Output** prints `allowed` / `reasonCode`. In-flight requests are ignored (same busy pattern as **`PositionAuthorityClient`**).
|
- **`InteractionRequestClient`**: **`interact`** (**E**) → **`prototype_terminal`**; **`interact_secondary`** (**R**) → **`prototype_resource_node_alpha`** (stable ids; must match `PrototypeInteractableRegistry.cs`). **Output** prints `allowed` / `reasonCode` per response (lines prefixed with `Interaction [<id>]: …`). Only one HTTP POST runs at a time; if you press **E** then **R** while the first request is still in flight, the **latest** id is remembered and sent **immediately after** the first completes (last-wins coalescing — not a silent drop).
|
||||||
- **Inspector:** match **`base_url`** on **`InteractablesCatalogClient`**, **`InteractionRequestClient`**, and **`PositionAuthorityClient`** to the running server.
|
- **Inspector:** match **`base_url`** on **`InteractablesCatalogClient`**, **`InteractionRequestClient`**, and **`PositionAuthorityClient`** to the running server.
|
||||||
- **No server:** catalog **GET** fails → **Output** errors; props and glow markers do not spawn (expected prototype degradation).
|
- **No server:** catalog **GET** fails → **Output** errors; props and glow markers do not spawn (expected prototype degradation).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,10 @@ const ID_RESOURCE_NODE := "prototype_resource_node_alpha"
|
||||||
|
|
||||||
var _http: Node
|
var _http: Node
|
||||||
var _busy: bool = false
|
var _busy: bool = false
|
||||||
|
## While an HTTP POST is in flight, the latest [code]interactableId[/code] from a new press overwrites
|
||||||
|
## this slot (last wins); [method _try_flush_pending] runs the next POST after [signal HTTPRequest.request_completed].
|
||||||
|
var _pending_interactable_id: String = ""
|
||||||
|
var _current_interactable_id: String = ""
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
|
|
@ -44,7 +48,13 @@ func _base_root() -> String:
|
||||||
|
|
||||||
func _post_interact(interactable_id: String) -> void:
|
func _post_interact(interactable_id: String) -> void:
|
||||||
if _busy:
|
if _busy:
|
||||||
|
_pending_interactable_id = interactable_id
|
||||||
return
|
return
|
||||||
|
_start_post(interactable_id)
|
||||||
|
|
||||||
|
|
||||||
|
func _start_post(interactable_id: String) -> void:
|
||||||
|
_current_interactable_id = interactable_id
|
||||||
_busy = true
|
_busy = true
|
||||||
var url := "%s/game/players/%s/interact" % [_base_root(), dev_player_id.strip_edges()]
|
var url := "%s/game/players/%s/interact" % [_base_root(), dev_player_id.strip_edges()]
|
||||||
var payload := {"schemaVersion": 1, "interactableId": interactable_id}
|
var payload := {"schemaVersion": 1, "interactableId": interactable_id}
|
||||||
|
|
@ -54,6 +64,14 @@ func _post_interact(interactable_id: String) -> void:
|
||||||
if err != OK:
|
if err != OK:
|
||||||
push_warning("InteractionRequestClient: POST failed to start (%s)" % err)
|
push_warning("InteractionRequestClient: POST failed to start (%s)" % err)
|
||||||
_busy = false
|
_busy = false
|
||||||
|
_try_flush_pending()
|
||||||
|
|
||||||
|
|
||||||
|
func _try_flush_pending() -> void:
|
||||||
|
var next: String = _pending_interactable_id
|
||||||
|
_pending_interactable_id = ""
|
||||||
|
if not next.is_empty() and not _busy:
|
||||||
|
_start_post(next)
|
||||||
|
|
||||||
|
|
||||||
func _on_request_completed(
|
func _on_request_completed(
|
||||||
|
|
@ -61,6 +79,7 @@ func _on_request_completed(
|
||||||
) -> void:
|
) -> void:
|
||||||
_busy = false
|
_busy = false
|
||||||
var text := body.get_string_from_utf8()
|
var text := body.get_string_from_utf8()
|
||||||
|
var id_echo: String = _current_interactable_id
|
||||||
if response_code == 200:
|
if response_code == 200:
|
||||||
var parsed: Variant = JSON.parse_string(text)
|
var parsed: Variant = JSON.parse_string(text)
|
||||||
if parsed is Dictionary:
|
if parsed is Dictionary:
|
||||||
|
|
@ -68,8 +87,14 @@ func _on_request_completed(
|
||||||
var allowed: bool = bool(d.get("allowed", false))
|
var allowed: bool = bool(d.get("allowed", false))
|
||||||
var reason: Variant = d.get("reasonCode", null)
|
var reason: Variant = d.get("reasonCode", null)
|
||||||
if allowed:
|
if allowed:
|
||||||
print("Interaction: allowed=true (reasonCode omitted on success)")
|
print(
|
||||||
|
"Interaction [%s]: allowed=true (reasonCode omitted on success)" % id_echo
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
print("Interaction: allowed=false reasonCode=%s" % str(reason))
|
print(
|
||||||
|
"Interaction [%s]: allowed=false reasonCode=%s" % [id_echo, str(reason)]
|
||||||
|
)
|
||||||
|
_try_flush_pending()
|
||||||
return
|
return
|
||||||
print("Interaction: HTTP %s body=%s" % [response_code, text])
|
print("Interaction [%s]: HTTP %s body=%s" % [id_echo, response_code, text])
|
||||||
|
_try_flush_pending()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue