Address every warning that surfaced in the running game's debugger: - Drop deprecated 'graph_offset = Vector2(...)' lines from the three in-tree VisualShader resources (red.tres, green.tres, Summary.tscn). The property is editor-only graph pan, ignored at runtime but warns at load. - Add android/.gdignore so Godot stops scanning the build template copies of red.tres/green.tres (which still had graph_offset). Tighten .gitignore to keep tracking the .gdignore marker only. - Drop the broken 'nodes/fragment/connections = ...' line from the inline VisualShader in Summary.tscn — connections referenced out-of-bounds ports (e.g. port 1 on a 1-output node). The pre-compiled 'code = ...' string is kept so rendering is unaffected. - Drop the orphaned 'ext_resource WarCraft.lmbake' from WarCraft.tscn: the LightmapGI node no longer references it but Godot still loaded the (Godot-3-format) blob from the ext_resource declaration alone, triggering '(p_data.size() % 4) != 0'. - Animation tracks: SlideReset (Template.tscn), BorderAnim (Loading.tscn), and ObjectFindAll (ListObjects.tscn) each had a bezier track with empty PackedFloat32Array keys, which AnimationMixer rejects in Godot 4. Drop the empty x track in each (the y track held the actual motion). - Re-save 57 .mesh files via scripts/migrate_misc.gd so the surface format is the current Godot 4 variant. sm_stackgold.mesh in particular triggered the deprecation warning every load. GDScript: rename function parameters and locals that shadowed Node.name / Node.value in: - db/MScene.gd (set_lock, set_mesh, set_tick_reference, set_value) - scripts/Setting.gd untouched (no shadow, false positive earlier) - scenes/UI/choose_scenes/ChooseScene.gd (_load_scene, _build_path, _build_method) - scenes/levels/Levels.gd (_create_animation_slide, _create_animation_warning, _add_animation_to_player, _create_button_info, _node_object_list) lod plugin: Godot 4 added 'lod_bias' as a native property on VisualInstance3D, which collided with the plugin's 'lod_bias' member across all five lod_*.gd files. Rename to 'lod_distance_bias' so the scripts parse again. Also drop Light3D.shadow_color writes in lod_omni_light.gd and lod_spot_light.gd — that property was removed in Godot 4, so the related shadow_value computation became dead code. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9.0 KiB
Puzzle Quest
Hidden-object game built with Godot 4.6 (single renderer: Forward+). Branched from a Godot 3.3 codebase — migration is recent, expect leftover Godot-3-isms to occasionally surface.
Run
godot --editor # open project in the editor
godot # run the main scene (scenes/Main.tscn)
The system package godot (Arch extra/godot) is the project's Godot. There
is no in-repo Godot binary.
Architecture
Autoloads (declared in project.godot [autoload], loaded in this order):
| Name | Source | Role |
|---|---|---|
Loading |
scenes/UI/loading/Loading.tscn |
Full-screen transition overlay (BG + animated border + progress) |
Global |
scripts/Global.gd |
Async scene loader (goto_scene(path)) + database reference |
Setting |
scripts/Setting.gd |
Reads/writes the settings table; applies locale/resolution/fullscreen |
Event |
scripts/Event.gd |
Static handlers connected to scene buttons (Warcraft / Home / reset / back) |
GlobalAnimation |
scripts/Animation.gd |
Tween-based dissolve + HUD slide/warning animations |
Database (scripts/Database.gd)
- Plain JSON at
db/ahog.json. Three tables:settings,levels,scenes. - On Android the file is copied once to
user://database.jsonand written there (game saves modify lock state per item). Global.databaseis aDatabase.DBinstance exposingget_table_by_name(name)andsave_db(). EachTableexposesget_data_at_row_idx(row_id),edit_data(prop_id, row_id, value),m_rows_count,get_data_by_prop_name_and_data(prop_name, value),get_dictionary_by_prop_name_and_data(prop_name, value).db/M*.gdare typed accessors (MBase / MScene / MLevel / MSetting) that read rows via the API above — extend these, not the JSON shape directly.
Scene transitions (Global.goto_scene(path))
Uses ResourceLoader.load_threaded_request + load_threaded_get_status +
load_threaded_get (Godot 4 API; the original load_interactive/poll()
was removed). The Loading overlay (autoload) plays BorderAnim while the
new scene loads in a background thread; Event._loading_is_started/finished
flip Global.loaded so the poll only runs once the entry animation has set
the boolean. Don't call current_scene.queue_free() outside this function
— it will leak the resource and break the loader state.
Levels.tscn / level scenes
scenes/levels/Levels.tscn is the shared shell; concrete levels
(warcraft/WarCraft.tscn, home/Home.tscn) inherit from it. Each scene
has a HiddenObjectsItems/<Item> MeshInstance3D with an Area3D
collision shape; clicking it triggers Levels._check_collider →
_start_dissolve(name) → GlobalAnimation.start_dissolve(mesh, material)
which runs the dissolve shader on material.dissolve_amount.
The runtime hidden-object list lives under
scenes/levels/parts/ListObjects.tscn and is populated dynamically from
the scenes table for the current Global.current_scene_int.
Migration notes (Godot 3 → 4)
The conversion is mostly done but a few classes of mistake keep surfacing
because godot --convert-3to4 does not handle them:
- Label:
align/valign→horizontal_alignment/vertical_alignment. - Button:
pressed(property) →button_pressed;set_pressed()→ assignment tobutton_pressed. Thepressedsignal still exists. - ScrollContainer:
scroll_horizontal_enabled = false→horizontal_scroll_mode = 0(and same for vertical). ScrollContainer also ships a non-empty default panel style in Godot 4 — settheme_override_styles/panel = StyleBoxEmptyif you need transparency. - TextureRect / TextureButton:
expand = true→expand_mode = 1.stretch_modeenum values shifted down by 1 between 3 and 4 (the deprecated "Scale on Expand" at index 0 was removed): G3's Tile (2) is G4's Tile (1), G3's Keep (3) is G4's Keep (2), etc. - Environment:
background_modeenum changed (G3 3=Sky → G4 2=Sky; G4 3 is Canvas which renders black).background_sky→sky;background_energy→background_energy_multiplier;fog_color→fog_light_color;fog_height_min→fog_height;fog_mode = 1(Depth) needed to keepfog_depth_*semantics, otherwise Godot 4 falls back to densefog_densityexponential fog. - AnimationPlayer:
add_animation(name, anim)removed — go throughget_animation_library("")(create one withadd_animation_library("")if it returns null) and calllib.add_animation(name, anim). - Tween: no longer a Node — call
create_tween()from any Node and usetween.tween_method(...). Delete any[node type="Tween"]from older.tscnfiles (the loader will crash otherwise). - PhysicsRayQuery:
space_state.intersect_ray(from, to, ...)→PhysicsRayQueryParameters3D.create(from, to), set fields, thenspace_state.intersect_ray(query). - PackedScene.instance() →
instantiate(). - String / cast operators:
String(x)constructor doesn't exist — usestr(x).x as int/String/booldoes not parse strings — useint(s),str(x),bool(int(s)). - Internationalization: project setting is
[internationalization] locale/translations=..., not[locale] translations=.... Locale codes must match.pofilenames exactly (fr.po→"fr"; G3-stylefr_FRno longer auto-falls-back). - Inherited scenes: nodes from an instanced child scene need
layout_mode = 1+anchors_preset = 15explicitly set in the parent scene file, otherwise Godot 4 treats them as Position-mode and zeroes the anchors. Watch for stale per-Labellayout_mode = 0/anchor_right = 0overrides in Main.tscn-style parent scenes.
Plugins
addons/lod/— Calinou's Level-of-Detail plugin (Spatial / OmniLight / SpotLight / Particles → 3D variants). Class declarations use the Godot 4 form (@icon("...") class_name X+extends Node3Dseparately).addons/godot_db_manager/— removed during migration. Don't restore it; it relies onWindowDialog/Tabs/PopupPanelwhich were dropped in Godot 4. The replacement isscripts/Database.gd(see above).
Custom shaders / materials
Drop-in shaders live in .material resources (binary RSCC format) next
to each prop. scripts/migrate_shaders.gd is a one-shot tool that walks
assets/ and rewrites the embedded shader code (Godot 3 → 4 keyword
renames: depth_draw_alpha_prepass, hint_color, NORMALMAP). Re-run it
with godot --headless --script scripts/migrate_shaders.gd after adding
new materials authored in Godot 3.
assets/fonts/text_outline.material is a VisualShader graph from Godot 3
that doesn't connect cleanly in 4 (out-of-bounds p_from_port errors,
COLOR never written). It has been detached from the Summary menu labels;
re-author it with Godot 4's built-in theme_override_constants/outline_size
theme_override_colors/font_outline_colorinstead.
Known visual issues to revisit
- Baked lightmap is gone.
scenes/levels/warcraft/WarCraft.lmbakeis in Godot 3's binary format (incompatible). TheLightmapGInode still exists inWarCraft.tscnbut itslight_datareference is cleared. Open the scene in the editor and re-bake (Scene → Bake Lightmaps). assets/ui/themes/tab_select/UI-level-btn-shadow.pngis 83% opaque black with feathered edges (a drop-shadow texture). In Godot 4 it renders stretched and opaque, which looked like a black square below each level tile, so itsBackgroundTileTextureRect is currentlyvisible = false. Replace with a proper 9-patch / shader if the shadow effect is wanted.developers/aurelien/is a sandbox — files there (ui_scrolls.tscn,ui_tile.tscn,CheckLightmap.tscn) still use Godot-3 property names in places. Not on the main flow, low priority.
CI
Build pipeline is in releases/.drone.yml. The Docker images still pin
barichello/godot-ci:3.3.2 and a custom devcrea/godot-ci:3.3.2-android
— bump these to a 4.x image before relying on CI builds again. Butler
push targets dev-crea/ahog:windows|android|linux|mac on itch.io.
Branches: default dev, releases from main. Long-running migration work
on feature/godot-migration.
Conventions
- Don't commit
db/ahog.jsonruntime mutations (lock progress saved during play). The README documents usinggit update-index --skip-worktreebut the cleaner alternative is just togit checkout db/ahog.jsonbefore staging. android/,.godot/, andreleases/are in.gitignore. The.importsidecars next to assets are committed (they carry the stable UIDs Godot 4 generates).- Commit messages: imperative, English, explain the why (especially for migration commits — the next person reading the diff won't have the Godot 3 context).