Files
JonShard acb96933a7 Docs
2026-08-17 16:09:08 +02:00

5.9 KiB

Stations

Overview

A "station" is any interactable kitchen fixture a player works at: Counter, Hob, Sink, Table, DirtStation, and the item dispensers. They share networking, sound, and snap-zone plumbing through a common script base, and share their node layout through a common base scene.

Two independent inheritance mechanisms combine to build a concrete station, e.g. Table:

  • Scene inheritancetable.tscn is a Godot "inherited scene" of abstract/station.tscn, so it gets the same child nodes (snap zone, synchronizer, audio players, progress bar) for free.
  • Script inheritancetable.gd (attached as a script override on that inherited scene) extends SharedInventoryStation, which extends Station.

These two axes are independent: which base scene a .tscn inherits from is unrelated to which class its attached script extends.

Scene inheritance

abstract/station.tscn is the base scene every station scene inherits from:

Station (Node3D)
├─ StationMovement      (drag-to-move handle, res://stations/StationMovement.tscn)
├─ MultiplayerSynchronizer
├─ AudioStreamPlayer3DNotification
├─ AudioStreamPlayer3DAmbient
├─ ProgressBar3D
└─ SnapZone

Each concrete station scene inherits this scene and overrides the root node's script property to attach its own class:

Scene Script attached
Counter.tscn stations/counter.gd (Counter)
Hob.tscn stations/hob.gd (Hob)
sink.tscn stations/sink.gd (Sink)
table.tscn stations/table.gd (Table)
dirt_station.tscn stations/dirt_station.gd (DirtStation)
BurgerBunsDispenser.tscn, cube_side_dispense.tscn, plate_dispenser.tscn, potato_dispenser.tscn, raw_burger_dispenser.tscn stations/item_dispenser.gd (ItemDispenser)

StationMovement (stations/station_movement.gd) is a sibling node composed into the base scene, not a station subclass — it's what lets players pick the whole station up and move it in build mode.

Script (class) inheritance

classDiagram
    direction TB
    Node3D <|-- Station
    Station <|-- WorkStation
    Station <|-- SharedInventoryStation
    Station <|-- DirtStation
    Station <|-- ItemDispenser
    WorkStation <|-- Hob
    WorkStation <|-- Sink
    WorkStation <|-- Counter
    SharedInventoryStation <|-- Table

    class Station {
        <<abstract>>
        +snap_zone : XRToolsSnapZone
        +synchronizer : MultiplayerSynchronizer
        +enabled : bool
        +on_object_picked_up(item)
        +on_object_dropped(item)
        +refresh_display()
    }
    class WorkStation {
        <<abstract>>
        +current_work : float
        +max_work : float
        +result_id : String
        +add_work(work)
        +convert_item()
    }
    class SharedInventoryStation {
        <<abstract>>
        +probes : Area3D[]
        +neighbors : Dictionary
        +get_connected_group()
        +is_group_leader()
    }
    class Hob {
        +cook_speed : float
    }
    class Sink {
        +wash_speed : float
    }
    class Counter {
        +chop_work_steps : float
    }
    class DirtStation
    class ItemDispenser {
        +item_scene : PackedScene
    }
    class Table {
        +_state : TableState
        +place_order()
    }
Class File Role
Station abstract/station.gd Base for every station. Owns the snap zone, sets up the MultiplayerSynchronizer's replication config, propagates pickup/drop events to clients over RPC, and exposes virtual hooks (on_object_picked_up, on_object_dropped, on_food_item_picked_up, on_food_item_dropped, refresh_display).
WorkStation abstract/work_station.gd Base for stations that convert a held FoodItem over time via a synced work meter (current_work/max_work/result_id). add_work() routes through the server via RPC, and convert_item() swaps the held item for the recipe result on completion.
Hob stations/hob.gd Cooks food using RecipeManager cooking recipes; plays a cook animation while active.
Sink stations/sink.gd Washes a dirty PlateController over time; drives water/bubble effect nodes.
Counter stations/counter.gd Chops food when a knife gesture area detects a fast-enough swipe.
SharedInventoryStation abstract/shared_inventory_station.gd Base for stations that need to know about same-kind neighbors. Resolves probe_paths into neighbor Area3Ds, builds a connected-group graph (cycle-safe, for belt/table loops), and computes a deterministic group leader.
Table stations/table.gd The only concrete SharedInventoryStation. Runs the customer-order finite state machine (EMPTY → THINKING → ORDERING → WAITING_PRIMARY → WAITING_FRIEND → EATING); the connected group's leader orchestrates state, followers mirror it.
DirtStation stations/dirt_station.gd Marks a dropped plate as dirty. Extends Station directly (no work meter).
ItemDispenser stations/item_dispenser.gd Server keeps a fresh instance of item_scene spawned into its snap zone whenever it's empty. Extends Station directly.

Networking pattern

Every station follows the same client/server split, established in Station:

  • The server (NetworkManager.owns_world()) is authoritative for state changes.
  • A client calls a public method (e.g. add_work, place_order); if it isn't the server, that method forwards the call via *_id.rpc_id(1) and returns.
  • The server applies the change locally, then RPCs the result back out to clients (e.g. _clients_on_object_picked_up_handler, _everyone_on_work_complete).
  • Frequently-changing fields (current_work, result_id, table _state, etc.) are also registered on sync_config in _enter_tree() for straight property replication.

Notes

  • stations/station.gd (extends "res://stations/hob.gd", no class_name) is not attached to any scene and isn't part of this hierarchy — it looks like leftover scaffolding.