Migrate to Godot 4 #1
Reference in New Issue
Block a user
Delete Branch "feature/godot-migration"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Catch-all commit for everything the --convert-3to4 tool missed during a manual playtest of the game. All errors raised by clicking through Main -> Puzzles -> level were fixed. GDScript: - PackedScene.instance() -> instantiate() (ChooseScene.gd) - String(x) constructor doesn't exist -> str(x) (MBase, MScene, MLevel, Animation, Levels) - 'x as int/String/bool' doesn't parse strings -> explicit int()/str()/bool(int()) (MScene, MLevel, MSetting) - BaseButton.pressed (property) -> button_pressed; set_pressed() -> direct assignment (Settings.gd) - AnimationPlayer.add_animation() removed -> go through AnimationLibrary (Levels.gd) - PhysicsDirectSpaceState3D.intersect_ray(from, to, ...) -> PhysicsRayQueryParameters3D.create() (Levels.gd) - @export with type-hint-in-comment ('# (String, ...)') -> explicit @export_enum (candle.gd) - Get effective material with get_active_material() instead of get_surface_override_material(), with null guard (Levels.gd) - get_node() -> get_node_or_null() so missing items from ahog.json (e.g. sm_super_dager in Home) don't crash (Levels.gd) Scenes/resources: - Remove 14 Tween nodes from WarCraft.tscn — Tween is no longer a Node in Godot 4. Rewrite Animation.start_dissolve to use create_tween().tween_method(). - Rename property material/N -> surface_material_override/N in every .tscn (10 files) — Godot 3 -> 4 rename that --convert-3to4 missed. Without this, MeshInstance3D.get_active_material(0) returned the glTF-imported StandardMaterial3D instead of the project's custom dissolve ShaderMaterial. Shaders: - One-shot scripts/migrate_shaders.gd walks every .material under assets/ and fixes Godot 3 -> 4 shader code in-place. Fixed 17 materials: depth_draw_alpha_prepass -> depth_prepass_alpha, hint_color -> source_color, NORMALMAP -> NORMAL_MAP. Result: Main, Settings, ChooseScene, and the WarCraft level all run without script or shader errors. Remaining noise is non-blocking (visual_shader graph in text_outline.material, baked lightmap binary format from Godot 3, and empty animation tracks). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>- assets/props/dagger/dagger_Dagger_{BC,NM}.png + dagger_dagger_{E,ORM}.png: complete PBR texture set for the dagger prop. - assets/fonts/MKX Title.ttf.import + kirsty/*.otf.import: Godot 4 import metadata sidecars for fonts whose source files were already tracked. - scripts/migrate_shaders.gd.uid: UID sidecar missed in the previous migration commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Two of the five autoloads were stateless helper bundles, not the persistent application-wide systems that the Godot 4 best-practice guide reserves autoload slots for. Convert them to plain classes with all-static methods so they no longer need a Node living under /root. - scripts/Animation.gd -> scripts/game_animation.gd (renamed: conflict with the built-in Animation class; the autoload sidestepped it by being called GlobalAnimation). class_name GameAnimation, every helper static. The dissolve tween now captures its target material in a lambda closure, eliminating the current_material member that the autoload kept as shared mutable state. - scripts/Event.gd -> scripts/event.gd, class_name Event, every handler static. Added Event.level_pressed(name) -> Callable for the one place ChooseScene needed dynamic lookup of a per-level handler (replaces the old _build_method('_on_' + name + '_pressed') + Callable(autoload, string) reflection trick with an explicit match). Updated call sites: - scripts/Global.gd: animation.connect('animation_started', Callable(Event, '...')) -> animation.animation_started.connect( Event._loading_is_started). Same for animation_finished. - scenes/levels/Levels.gd: GlobalAnimation.* -> GameAnimation.*; Quit/TextureButton.connect('pressed', Callable(Event, '...')) -> pressed.connect(Event._on_main_scene_pressed). - scenes/UI/choose_scenes/ChooseScene.gd: per-level button connects go through Event.level_pressed(); reset button's bound callable now reads Event._on_reset_level.bind(...); cleanup no longer relies on is_connected with an unbound Callable (which would never match a bound one anyway) -- iterates reset.pressed.get_connections() instead. Drop the now-dead _build_method helper. Also: organise scripts/ by promoting the one-shot migration helpers (migrate_shaders, migrate_misc, resave_scenes, devisualize_shaders, find_visualshaders) into scripts/migration/. They are not part of the runtime and should not be browsable next to the autoloads. Autoload count goes 5 -> 3 (Loading, Global, Setting remain -- Setting will move to a Resource in a later refactor). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>- scenes/levels/Levels.gd: replace 'var level := Global.database .level_by_index(...)' with explicit 'var level: LevelEntry = ...'. Global.database is typed RefCounted so the parser can't see DB's return types through the walrus operator. Two callsites. - scripts/Database.gd: annotate the two 'range(data.size() / W)' loops with @warning_ignore('integer_division'). The division is intentional (row count = bytes / row width); Godot 4 warns by default in case the slash was a typo. - env: ambient_light_energy 0.4 -> 1.0 in WarCraft.tscn, Home.tscn and env_warcraft.tres. 0.4 left the floor pitch-black; 1.0 is a compromise between the original 1.55 (oversaturated) and this. Re-baking the lightmap in the editor is still the right fix — this commit just keeps the scene playable in the meantime. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>- Global.gd: move @onready var animation below the regular vars (gdlint class-definitions-order expects onready vars after public/private vars). - Database.gd::DB: move the three _*_PROPS constants above the vars (constants come before vars in a class body). - Levels.gd:_search_button_to_use: drop the elif after a branch that returns (no-elif-return). - Levels.gd:_gyroscope_changed_{down,up}: continuation lines of the multi-line return mixed two tabs + three spaces; normalised to pure tabs. No semantic change: @onready is property-level so source ordering doesn't affect init; elif after a return is equivalent to if; the continuation indent is cosmetic. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>The Android export preset relied on Godot's $genname placeholder ("org.godotengine.$genname"). With the project name "Puzzle Quest" containing a space, Godot 4 refuses the headless export with: The project name does not meet the requirement for the package name format and will be updated to "puzzlequest". Please explicitly specify the package name if needed. Pin both Android presets (AndroidTesting, AndroidDebug) to com.devcrea.puzzlequest — clean, follows reverse-DNS, matches the DevCrea organization. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Two fixes that finally land the Android export. Verified locally with godot 4.6.2-arch + downloaded 4.6 templates + Android SDK. - project.godot: add rendering/textures/vram_compression/import_etc2_astc=true. Without it Godot refuses the Android export with "La plateforme cible nécessite une compression de texture « ETC2/ASTC »". In headless mode this surfaces as an *empty* configuration-errors block, which is what kept us stuck in CI. - workflow: write Godot editor settings to editor_settings-${GODOT_VERSION}.tres (i.e. -4.6.tres on 4.6), not -4.tres. Godot 4.5+ uses a minor-version-suffixed settings file; the major-only name is ignored by 4.6, so our injected android_sdk_path / java_sdk_path / debug_keystore never reached the export plugin. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>