What we've learned about mpf-gmc (the Godot display/audio addon in
machinefolder/addons/mpf-gmc/), now version 1.0.0 on Godot 4.3 (upgraded 2026-10-09 from
0.1.0.dev2, CHANGES #75). The addon is kept stock; each entry says how the project lives
with it.
After the upgrade every earlier finding was retested (2026-10-09) and sorted by what it really
is. Only one is a real bug worth reporting - it has a minimal repro in
gmc-repros/. The rest are kept here because they're easy to trip over.
MPFConditional.evaluate() converts the condition value to the type of the variable's value; for
a variable that doesn't exist that's null, and null == null is true. So == 1 (any ==)
shows for a variable that was never set. The code's own comment says a missing target should
evaluate false.
initial_value: 0config/story-player-vars.yaml; tests/test_chamber_signs.py keeps it complete). Machineconfig/machine-stats.yaml).update actionMPFConditional doesn't listen to player-variable changes (only MPFVariable does; since 0.1.4
only the ACTIVE_SLIDE type re-evaluates by itself, per GMC's changelog). A widget left on screen
keeps the state it had when it appeared.
widget_player entry player_<var>: {<widget>: {action: update, slide: base}}tests/test_chamber_signs.py).slide: goes on the slide that's current at that momentDocumented in MPF: "If this is not specified, then the widget will be added to whichever slide is
currently active on the default display" (widget_player docs,
archived as mpf-docs-widget-player). If that's a short-lived card, the widget goes with it.
{slide: base} on every widget that should stay up.When MPF stops, GMC shuts its BCP server down and exits (get_tree().quit(6) - "so we know MPF is
the cause of the exit"; a TODO in bcp_server.gd mentions a future option to stay open). So a
restarted MPF has nothing to connect to.
mpf together (docs/testing-strategy.md, Tier 2.5).<setting>.valueMPF.game.settings holds a setting object per name; a SETTING conditional on demo compares
that object (== 1 never matches, != 1 always does), while demo.value works through the
nested-name lookup. Undocumented, but it works.
A conditional decides its visibility when its slide gets an update - MPF's slide player does
that (MPFSceneBase.initialize() → action_update()); just instancing a scene in a Godot script
doesn't, so every layer shows.
action_update({}, {}) on each slide, as adocs/testing-strategy.md, Tier 2.5). The attract copies of the chamber signstools/display/attract_slides.py, sign_page).loops: -1 uses the file's native, gapless loop; any other count restarts the file when it
finishes, which can leave a small gap (design/research/story-brainstorm/music-map.md).
A headless import logs an invalid UID for mpf_panel.tscn; the first import after replacing the
addon logs "Preload file ... has no resource loaders" for its icons (gone on the second pass).
Found on 0.1.0.dev2 and reproduced there (2026-10-08); fixed in 1.0.0 (code read and retested):
MPF.game.machine instead ofmachine_vars). Our workaround subclass scripts/machine_var_conditional.gd is deleted.loops: -1 on a WAV threw a script error and played once (GMCChannel.gd).GMCChannel.clear()): in a minimal setup the queue kept working, on both versions. TheTODO.md is closed.GMCMedia methods hanging outside the scene tree (2026-08-27): seen once, never pinned down;