forked from Rockachopa/Timmy-time-dashboard
65 lines
2.1 KiB
Python
65 lines
2.1 KiB
Python
"""Abstract WorldInterface — the contract every game-world adapter must fulfil.
|
|
|
|
Follows a Gymnasium-inspired pattern: observe → act → speak, with each
|
|
method returning strongly-typed data structures.
|
|
|
|
Any future engine (TES3MP, Luanti, Godot, …) plugs in by subclassing
|
|
``WorldInterface`` and implementing the three methods.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from abc import ABC, abstractmethod
|
|
|
|
from infrastructure.world.types import ActionResult, CommandInput, PerceptionOutput
|
|
|
|
|
|
class WorldInterface(ABC):
|
|
"""Engine-agnostic base class for world adapters.
|
|
|
|
Subclasses must implement:
|
|
- ``observe()`` — gather structured perception from the world
|
|
- ``act()`` — dispatch a command and return the outcome
|
|
- ``speak()`` — send a message to an NPC / player / broadcast
|
|
|
|
Lifecycle hooks ``connect()`` and ``disconnect()`` are optional.
|
|
"""
|
|
|
|
# -- lifecycle (optional overrides) ------------------------------------
|
|
|
|
def connect(self) -> None: # noqa: B027
|
|
"""Establish connection to the game world.
|
|
|
|
Default implementation is a no-op. Override to open sockets,
|
|
authenticate, etc.
|
|
"""
|
|
|
|
def disconnect(self) -> None: # noqa: B027
|
|
"""Tear down the connection.
|
|
|
|
Default implementation is a no-op.
|
|
"""
|
|
|
|
@property
|
|
def is_connected(self) -> bool:
|
|
"""Return ``True`` if the adapter has an active connection.
|
|
|
|
Default returns ``True``. Override for adapters that maintain
|
|
persistent connections.
|
|
"""
|
|
return True
|
|
|
|
# -- core contract (must implement) ------------------------------------
|
|
|
|
@abstractmethod
|
|
def observe(self) -> PerceptionOutput:
|
|
"""Return a structured snapshot of the current world state."""
|
|
|
|
@abstractmethod
|
|
def act(self, command: CommandInput) -> ActionResult:
|
|
"""Execute *command* in the world and return the result."""
|
|
|
|
@abstractmethod
|
|
def speak(self, message: str, target: str | None = None) -> None:
|
|
"""Send *message* in the world, optionally directed at *target*."""
|