From 97caaef0011301014d590c856e236b283454eea5 Mon Sep 17 00:00:00 2001 From: Jage9 Date: Sat, 21 Feb 2026 22:04:17 -0500 Subject: [PATCH] Update item docs for per-item modules and registry --- docs/item-schema.md | 2 +- docs/item-type-template.md | 136 +++++++++++++++++-------------------- docs/item-types.md | 15 ++-- 3 files changed, 74 insertions(+), 79 deletions(-) diff --git a/docs/item-schema.md b/docs/item-schema.md index e604d43..e3730e3 100644 --- a/docs/item-schema.md +++ b/docs/item-schema.md @@ -49,7 +49,7 @@ - Persisted state stores only instance data. - Global/type-level properties are loaded from server registry in `server/app/item_catalog.py`. -- Per-type use/update validation and message behavior are handled in `server/app/item_type_handlers.py`. +- Per-type use/update validation and message behavior are implemented in per-item modules under `server/app/items/` and wired in `server/app/items/registry.py`. - Client-side add/edit metadata is handled in `client/src/items/itemRegistry.ts`. - End-to-end add-item template: `docs/item-type-template.md`. diff --git a/docs/item-type-template.md b/docs/item-type-template.md index cc68f85..21d62db 100644 --- a/docs/item-type-template.md +++ b/docs/item-type-template.md @@ -1,58 +1,70 @@ # Item Type Template -This page is a practical, copy/paste template for adding a new item type with the current registry-based system. - -Use this when you want a new item type without editing one huge `if/elif` chain. +This page is a practical template for adding a new item type with the current per-item module + single registry system. ## Plain-English Flow -When a new item type is added, you wire it in four places: +When a new item type is added, wire it in these places: -1. Server catalog (`item_catalog.py`) -- Defines global defaults shared by all instances of that type: - - default title - - default params - - use sound / emit sound - - cooldown +1. Server item module (`server/app/items/.py`) +- Define item metadata constants: + - label/tooltip + - editable properties + - defaults/capabilities/sounds/cooldown/range/directional + - property metadata +- Implement behavior: + - `validate_update(item, next_params)` + - `use_item(item, nickname, clock_formatter)` -2. Server behavior (`item_type_handlers.py`) -- Defines what happens when users edit params (`validate_update`). -- Defines what happens when users press `use` (`use`). +2. Server registry (`server/app/items/registry.py`) +- Add one module entry in `ITEM_MODULES`. +- Update `ITEM_TYPE_ORDER` if needed. -3. Shared type unions (`models.py`, protocol/state types) -- Adds the new type name to type literals/unions so packets validate. +3. Shared item type unions +- Add the type in: + - `server/app/models.py` + - `client/src/network/protocol.ts` + - `client/src/state/gameState.ts` -4. Client item registry (`itemRegistry.ts`) -- Defines add-menu order, editable properties, and optional property dropdown choices. +4. Client fallback metadata +- Add defaults in `client/src/items/itemRegistry.ts`: + - `DEFAULT_ITEM_TYPE_SEQUENCE` + - `DEFAULT_ITEM_TYPE_EDITABLE_PROPERTIES` + - `DEFAULT_ITEM_TYPE_GLOBAL_PROPERTIES` That is enough for a first working item type. -## Example: `counter` +## Minimal Server Module Example: `counter` -This sample item increments a number each time it is used. - -### 1. Server Catalog (`server/app/item_catalog.py`) +`server/app/items/counter.py`: ```py -ItemType = Literal["radio_station", "dice", "wheel", "clock", "counter"] +from __future__ import annotations -ITEM_DEFINITIONS: dict[ItemType, ItemDefinition] = { - # ...existing... - "counter": ItemDefinition( - default_title="counter", - capabilities=("editable", "carryable", "deletable", "usable"), - use_sound=None, - emit_sound=None, - default_params={"value": 0}, - use_cooldown_ms=1000, - ), +from typing import Callable + +from ..item_types import ItemUseResult +from ..models import WorldItem + +LABEL = "counter" +TOOLTIP = "Counts up each time you use it." +EDITABLE_PROPERTIES: tuple[str, ...] = ("title", "value") +CAPABILITIES: tuple[str, ...] = ("editable", "carryable", "deletable", "usable") +USE_SOUND: str | None = None +EMIT_SOUND: str | None = None +USE_COOLDOWN_MS = 1000 +EMIT_RANGE = 15 +DIRECTIONAL = False +DEFAULT_TITLE = "counter" +DEFAULT_PARAMS: dict = {"value": 0} + +PROPERTY_METADATA: dict[str, dict[str, object]] = { + "title": {"valueType": "text", "tooltip": "Display name spoken and shown for this item."}, + "value": {"valueType": "number", "tooltip": "Current counter value.", "range": {"min": 0, "max": 9999, "step": 1}}, } -``` -### 2. Server Handler (`server/app/item_type_handlers.py`) -```py -def _validate_counter_update(_item: WorldItem, next_params: dict) -> dict: +def validate_update(_item: WorldItem, next_params: dict) -> dict: try: value = int(next_params.get("value", 0)) except (TypeError, ValueError) as exc: @@ -63,53 +75,31 @@ def _validate_counter_update(_item: WorldItem, next_params: dict) -> dict: return next_params -def _use_counter(item: WorldItem, nickname: str, _clock_formatter: Callable[[dict], str]) -> ItemUseResult: - current = int(item.params.get("value", 0)) - next_value = current + 1 +def use_item(item: WorldItem, nickname: str, _clock_formatter: Callable[[dict], str]) -> ItemUseResult: + next_value = int(item.params.get("value", 0)) + 1 return ItemUseResult( self_message=f"{item.title}: {next_value}", others_message=f"{nickname} uses {item.title}: {next_value}", updated_params={**item.params, "value": next_value}, ) +``` +Then register it in `server/app/items/registry.py`: -ITEM_TYPE_HANDLERS: dict[ItemType, ItemTypeHandler] = { - # ...existing... - "counter": ItemTypeHandler( - validate_update=_validate_counter_update, - use=_use_counter, - ), +```py +from . import clock, counter, dice, radio, wheel + +ITEM_TYPE_ORDER: tuple[str, ...] = ("clock", "counter", "dice", "radio_station", "wheel") + +ITEM_MODULES: dict[str, ItemModule] = { + "clock": clock, + "counter": counter, + "dice": dice, + "radio_station": radio, + "wheel": wheel, } ``` -### 3. Type Unions - -Update item-type unions/literals in: - -- `server/app/models.py` -- `client/src/network/protocol.ts` -- `client/src/state/gameState.ts` - -Add `"counter"` anywhere item types are enumerated. - -### 4. Client Registry (`client/src/items/itemRegistry.ts`) - -```ts -export const ITEM_TYPE_SEQUENCE: ItemType[] = ['clock', 'counter', 'dice', 'radio_station', 'wheel']; - -const ITEM_TYPE_EDITABLE_PROPERTIES: Record = { - // ...existing... - counter: ['title', 'value'], -}; - -export const ITEM_TYPE_GLOBAL_PROPERTIES: Record> = { - // ...existing... - counter: { useSound: 'none', emitSound: 'none', useCooldownMs: 1000 }, -}; -``` - -No dropdown options are needed here because `value` is a numeric text field. - ## Checklist Before Commit 1. Add/adjust server tests for `use` and `update` validation. diff --git a/docs/item-types.md b/docs/item-types.md index 298b23d..07b7c51 100644 --- a/docs/item-types.md +++ b/docs/item-types.md @@ -112,15 +112,20 @@ This is behavior-focused documentation for item types and their defaults. ## Adding A New Item Type (Registry V1) -Item types are currently code-registered on both server and client so new types are additive instead of editing one large branch. +Item types are currently code-registered on both server and client. Server item logic is split per item module and wired through one registry. For a full copy/paste example with plain-English explanation, see `docs/item-type-template.md`. -1. Server catalog: add global defaults in `server/app/item_catalog.py` (`ITEM_DEFINITIONS`). -2. Server handlers: add `validate_update` + `use` logic in `server/app/item_type_handlers.py` and register it in `ITEM_TYPE_HANDLERS`. +1. Server item module: add a new file under `server/app/items/` with: + - defaults/capabilities + - property metadata/options + - `validate_update` and `use_item` +2. Server registry: add one entry in `server/app/items/registry.py`: + - `ITEM_MODULES` + - `ITEM_TYPE_ORDER` (if ordering changes) 3. Server models: extend `ItemType` literals in `server/app/models.py` and any packet enums that list item types. -4. Client registry: add type metadata in `client/src/items/itemRegistry.ts` (`ITEM_TYPE_SEQUENCE`, editable properties, and global property hints). -5. Client protocol types: update item-type unions in `client/src/network/protocol.ts` and `client/src/state/gameState.ts`. +4. Client fallback registry: add type defaults in `client/src/items/itemRegistry.ts` (`DEFAULT_ITEM_TYPE_SEQUENCE`, editable/global fallback metadata). +5. Client protocol/state types: update item-type unions in `client/src/network/protocol.ts` and `client/src/state/gameState.ts`. 6. Tests: add or update server tests under `server/tests/` for use/update validation and cooldown behavior. ### Example Shape