This guide shows how Calendar Time reports authoring mistakes and how your game can route plugin output into its own logging pipeline.
You can skip this guide at first. The default Godot Errors/Output panel works fine. Use this when you want plugin errors to appear in your game logs, test harnesses, telemetry, or custom debug UI.
Plugin Output Goes Through CalendarTimeLogger
Runtime addon code uses the static CalendarTimeLogger facade for plugin output:
CalendarTimeLogger.error("GameClock","Clock is missing")
CalendarTimeLogger.warn("TimeEventMessenger","Signal is already disconnected")
CalendarTimeLogger.info("TimeHost","Clock advanced")If your game does nothing, Calendar Time preserves Godot-style behavior:
Default Godot output mapping:
error(source, message)→push_error.warn(source, message)→push_warning.info(source, message)→print.
Route Plugin Logs Into Your Game Logger
Create a LogSink and register it once during game boot:
class_name GameCalendarTimeLogSink
extends LogSink
func error(source :String, message :String)-> void:
GameLogger.error("[%s]%s" % [source, message])
func warn(source :String, message :String)-> void:
GameLogger.warn("[%s]%s" % [source, message])
func info(source :String, message :String)-> void:
GameLogger.info("[%s]%s" % [source, message])Register the sink before scenes with Calendar Time nodes or services run:
func _ready()-> void:
CalendarTimeLogger.set_logger(GameCalendarTimeLogSink.new())The logger is a static singleton, so you do not need to wire a logger into each Calendar Time object.
Release the injected sink during shutdown if it references scene nodes, autoloads, or other game-owned objects:
func _exit_tree()-> void:
CalendarTimeLogger.clear_logger()Unbound Clocks Fail Loudly
Calendar Time treats a missing GameClock as an authoring error. Clock-consuming
nodes validate their clock binding during _ready() or validate() and stop
work if the clock is missing.
Examples of clock-consuming surfaces include:
DateTimeDisplayTimeOfDayDisplayCalendarDisplayTimeDialTimeOfDayDirectionalLight2DDayNightCycleServiceTimeEventMessenger- your own scripts that subscribe to
clock.signal_bus
When your game has registered a LogSink, those validation failures reach your
injected logger. This lets automated tests and game log files capture scene
authoring mistakes such as a copied UI template whose clock export was never
assigned.
Integration Checklist
- Create one shared
GameClockresource for each timeline your game needs. - Add each
GameClocktoTimeHost.clocksso the host drives it. - Assign the same
GameClockto UI, lighting, aging components, and gameplay scripts that should follow that timeline. - Register
CalendarTimeLogger.set_logger(...)during game boot if you want plugin output in your own logs. - Call
CalendarTimeLogger.clear_logger()during shutdown if your sink holds references to game objects. - Treat Calendar Time errors as scene authoring problems to fix in the editor, not as warnings to suppress.
- In your own scripts, guard duplicate
clock.signal_busconnections and disconnect in_exit_tree()when the script owns the connection.
Troubleshooting
Common fixes:
- Display shows no time — empty
clockexport. Assign theGameClockfromTimeHost.clocks. - Time does not advance — empty
clocksorMANUALwithout a driver. Add a clock or calldrive_microseconds(). - Game logger misses plugin output —
set_logger()runs too late. Register in an autoload or early bootstrap. - Logger stays alive after shutdown — static logger still holds the sink. Call
clear_logger()on exit. - Duplicate callbacks — your code connected repeatedly. Guard with
is_connected()or disconnect in_exit_tree(). - Disconnect errors after toggling nodes — disconnect without checking state. Guard with
is_connected()first.
Related Guides
README.mdfor setup and the node/resource API surface.examples.mdfor runtime clock examples.template-ui.mdfor shipped UI templates.