From 6f3f8b8f644da61084412cf432d656cab9f0db98 Mon Sep 17 00:00:00 2001 From: Vaillant Jeremy Date: Sat, 16 May 2026 20:55:47 +0200 Subject: [PATCH] Wire up UI in Godot 4: fonts, translations, layout, fog, shadow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Discovered while playtesting the migrated build. Each fix has a specific Godot-3-to-4 cause that the --convert-3to4 tool did not catch. Fonts: - Replace 4 .tres font wrappers (MKX_Base, kirsty_base/medium/title) with FontVariation pointing at the .otf/.ttf source. Godot 3 DynamicFont with size= and font_data= is invalid in Godot 4 (those properties don't exist on FontFile). - Apply size 46 via theme_override_font_sizes/font_size on the 5 Labels that used kirsty_title.tres (LabelLoading + 4 in Summary). - Drop the broken VisualShader text_outline.material from the 4 Labels in Summary — Index p_from_port errors in Godot 4 meant COLOR was never written, so text rendered invisible. - Migrate VisualShader nodes inside text_outline.material (compressed asset; updated by the inspect/migrate scripts). Translations: - Move project.godot section from [locale] (Godot 3) to [internationalization] with locale/translations=... (Godot 4). The old section was silently ignored so tr() returned the raw msgid. - Adjust Setting.translate_int_to_locale to return "en"/"fr" to match what the .po files declare (was "en_GB"/"fr_FR", which Godot 3 fell back from automatically but Godot 4 does not). Label alignment (Godot 3 names not auto-renamed): - align -> horizontal_alignment, valign -> vertical_alignment across 9 .tscn files. Background / Loading / ChooseScene layout: - Rewrite Background.tscn from a VisualShader-textured Panel to a plain TextureRect (the visual shader connection ports went out of bounds in Godot 4, leaving the panel grey on scene reload). - Set layout_mode=1 + anchors_preset=15 on BackgroundPicture instances in Main.tscn and Loading.tscn — Godot 4 inheritance no longer applies the .tscn-root's anchors to an instanced child unless layout_mode is set to Anchors mode explicitly. - Replace scroll_horizontal_enabled (Godot 3) with horizontal_scroll_mode/vertical_scroll_mode (Godot 4) on ChooseScene's ScrollContainer. - Add theme_override_styles/panel = StyleBoxEmpty on the ScrollContainer (Godot 4 ScrollContainer ships a default dark panel style that Godot 3 did not). - Hide BackgroundTile in Template.tscn — it points at UI-level-btn-shadow.png (228x228, 83% opaque black) which used to render at natural size in Godot 3 but is stretched to fill the 456px rect in Godot 4, leaving a big black square below each thumbnail. The proper drop-shadow needs a shader or 9-patch. - TextureRect.expand=true (Godot 3) -> expand_mode=1 (Godot 4) on ThumbnailLevel and TopPart's content rects. Lighting: - background_mode 3 (which used to mean Sky in Godot 3) -> 2 (Sky in Godot 4; 3 is now Canvas, producing a black background). - background_sky -> sky, background_energy -> background_energy_multiplier, fog_color -> fog_light_color, fog_height_min -> fog_height; drop fog_height_enabled / fog_height_max / fog_height_curve / dof_blur_far_distance (no longer exist). - Add fog_mode = 1 so Godot 4 uses fog_depth_* instead of the new default fog_density-based exponential fog (which rendered as a thick white cloud). - ambient_light_energy 1.55 -> 0.4 — the new pipeline interprets the value much more strongly so 1.55 produced a saturated pink scene. - Remove the light_data = ExtResource(41) reference to WarCraft.lmbake — Godot 3 baked lightmap binary format is incompatible with Godot 4. Re-bake in editor when ready. Co-Authored-By: Claude Opus 4.7 (1M context) --- assets/fonts/MKX_Base.tres | 7 +- assets/fonts/kirsty/kirsty_base.tres | 8 +- assets/fonts/kirsty/kirsty_medium.tres | 9 +- assets/fonts/kirsty/kirsty_title.tres | 9 +- assets/fonts/text_outline.material | Bin 2823 -> 2000 bytes default_env.tres | 6 +- project.godot | 4 +- scenes/Main.tscn | 117 ++++++++++++-------- scenes/UI/background/Background.tscn | 64 +---------- scenes/UI/choose_scenes/ChooseScene.tscn | 12 +- scenes/UI/choose_scenes/parts/Template.tscn | 9 +- scenes/UI/ending/Ending.tscn | 4 +- scenes/UI/loading/Loading.tscn | 4 + scenes/UI/loading/parts/LabelLoading.tscn | 5 +- scenes/UI/loading/parts/TopPart.tscn | 2 +- scenes/UI/settings/Settings.tscn | 4 +- scenes/UI/summary/Summary.tscn | 26 ++--- scenes/levels/home/Home.tscn | 17 ++- scenes/levels/parts/ListObjects.tscn | 4 +- scenes/levels/parts/ObjectListFirst.tscn | 4 +- scenes/levels/parts/ObjectListLast.tscn | 4 +- scenes/levels/parts/ObjectListStandard.tscn | 4 +- scenes/levels/warcraft/WarCraft.tscn | 31 ++---- scenes/levels/warcraft/env_warcraft.tres | 17 ++- scripts/Setting.gd | 6 +- scripts/migrate_shaders.gd | 68 ++++++++---- 26 files changed, 216 insertions(+), 229 deletions(-) diff --git a/assets/fonts/MKX_Base.tres b/assets/fonts/MKX_Base.tres index 329ec66..8bf0892 100644 --- a/assets/fonts/MKX_Base.tres +++ b/assets/fonts/MKX_Base.tres @@ -1,7 +1,6 @@ -[gd_resource type="FontFile" load_steps=2 format=2] +[gd_resource type="FontVariation" load_steps=2 format=3] -[ext_resource path="res://assets/fonts/MKX Title.ttf" type="FontFile" id=1] +[ext_resource type="FontFile" path="res://assets/fonts/MKX Title.ttf" id="1"] [resource] -size = 30 -font_data = ExtResource( 1 ) +base_font = ExtResource("1") diff --git a/assets/fonts/kirsty/kirsty_base.tres b/assets/fonts/kirsty/kirsty_base.tres index f5adfa3..80f28c4 100644 --- a/assets/fonts/kirsty/kirsty_base.tres +++ b/assets/fonts/kirsty/kirsty_base.tres @@ -1,8 +1,6 @@ -[gd_resource type="FontFile" load_steps=2 format=2] +[gd_resource type="FontVariation" load_steps=2 format=3] -[ext_resource path="res://assets/fonts/kirsty/kirsty rg.otf" type="FontFile" id=1] +[ext_resource type="FontFile" path="res://assets/fonts/kirsty/kirsty rg.otf" id="1"] [resource] -use_mipmaps = true -use_filter = true -font_data = ExtResource( 1 ) +base_font = ExtResource("1") diff --git a/assets/fonts/kirsty/kirsty_medium.tres b/assets/fonts/kirsty/kirsty_medium.tres index 9014abb..80f28c4 100644 --- a/assets/fonts/kirsty/kirsty_medium.tres +++ b/assets/fonts/kirsty/kirsty_medium.tres @@ -1,9 +1,6 @@ -[gd_resource type="FontFile" load_steps=2 format=2] +[gd_resource type="FontVariation" load_steps=2 format=3] -[ext_resource path="res://assets/fonts/kirsty/kirsty rg.otf" type="FontFile" id=1] +[ext_resource type="FontFile" path="res://assets/fonts/kirsty/kirsty rg.otf" id="1"] [resource] -size = 24 -use_mipmaps = true -use_filter = true -font_data = ExtResource( 1 ) +base_font = ExtResource("1") diff --git a/assets/fonts/kirsty/kirsty_title.tres b/assets/fonts/kirsty/kirsty_title.tres index d48942a..d71056c 100644 --- a/assets/fonts/kirsty/kirsty_title.tres +++ b/assets/fonts/kirsty/kirsty_title.tres @@ -1,9 +1,6 @@ -[gd_resource type="FontFile" load_steps=2 format=2] +[gd_resource type="FontVariation" load_steps=2 format=3] -[ext_resource path="res://assets/fonts/kirsty/kirsty bd.otf" type="FontFile" id=1] +[ext_resource type="FontFile" path="res://assets/fonts/kirsty/kirsty bd.otf" id="1"] [resource] -size = 46 -use_mipmaps = true -use_filter = true -font_data = ExtResource( 1 ) +base_font = ExtResource("1") diff --git a/assets/fonts/text_outline.material b/assets/fonts/text_outline.material index 3e4d09ae35777fec6c65ffade937e388290aa7cf..1591985f7c96c527630054fa29c282e89eb9be62 100644 GIT binary patch literal 2000 zcmV;>2QTvK^vhj*wrhTJ@T$8Ar|3!`=*Bp)3)c-Zd z{modS66X2EuDSo2v$QPrweZ#s=36bypUq!wFH(*-?G3}4;f!0Iu($hF-1qdM7hnyQHK8=82>N+r&VT&tED;=#oVoR=e zTRTkS&Ct~Ob_rTZ!W0(8+5Jawj`m!kaC3FQo2wpy_x-Y|GuLw^(uTG(j#PS?%F+J- zH#J8k>`k`p~G zC4Yj)k)0Go-%6j{I%|l^h(f_Ds@;jCIgxN?0f_>yX8dh%q&Ycf-9#|%tzOHyG2=~$ z$Ae*(Wm#EdK7e0Q z^(*zAEhIly)X%%Jf#p2QIl#4&7BG2G9+~L2K|Be@0Jp|7HVXb|w(0|h*PeB#epkqJNnN+@O1LA%M>nri~$%Js~dO%jV!Qa#4sq;Wo4PuLnoi+^i=1RDwS zXQc{`r`sg37Zt-ZIM7@Q7mOs&OXnIoXfntp7lNl_shYZJ0O%|plkMYP!Ax4QPPzPu*B^5 za8*UHQKDD4s)Y98s&c4TPu$GG#LTVoi|u#IM-a`1E08&?#ycRdFq-ZKKoNKum5W(tUztzjNYr5$4VZH^0kNNL zX5mO(k54;{rN#(rq_kBVGVsbTV5c^274M!rpbFP$R`D;jp~KIz^sj8yw{wkZL!Eg9D97~l}tww8_(7Lx-Fc*n}1VSpAR z5*Fwa0wzWaqHo*X4_?bBfXd4gC@E~K@@%efWh17?>LtHQ+)8H-DK+`8@<05#*=?j(?en7cusTI?#C?>iMrmGC zc4!A}qLgRdM0%G)b$fIM{df5f{y+HxEG9^JGY=fR;s!(n2wDAe@4QC_c5vXduGNN_qor;o0ZHR61 z^hVRPgzbjd6Den)*6T6Vh)r(I($CZEQ8_qejZsEEmAElq8n?-22a#NoHrEHYs*n6H zz$PoXPO%n>{VcW2w4)X;#2EFc$DbuzD^h3^&`k5`c{|9g+2{+2Lwea!52Zljo%td;5 z;NLiAAvsXD|E?Wa#yFZYKzw-k-_ijt(&_S$95x*iiPTiakpmTg#5=#mSrDf07>4NFA2iqN^EiGE&fYlf~@saod zK8IL0SZ&Ad027stCplu%At+S1aG*c8p0Qme);!cFT-XQjW#8@yMrN3q=>0*>5CAKO zhU|d@f2aer5JNmz_QUvpbjX{zcZ}h9T4Rp<5K}*%PUT&Khjh|YS~ptj^NFfNev1p z7g&f@g24dHR^4E9K+9|1J?ES3^^iHig0JS*FoWZ3c{$3_9UiF86TLP?-m`kL@ixS0 ieBU3A!fhvhv5cR+fOTA7ANI8sGK#EA7f}ULQ$s_D3dHUJ literal 2823 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 Z_}2c 4 +# shader code in-place, saving where possible. # # Run with: godot --headless --script scripts/migrate_shaders.gd @@ -17,31 +18,51 @@ const REPLACEMENTS := [ ["NORMALMAP", "NORMAL_MAP"], ] +const EXTENSIONS := [".material", ".tres", ".mesh"] + func _init() -> void: var fixed := 0 var checked := 0 - for path in _find_materials("res://assets"): + for path in _find_resources("res://assets"): checked += 1 - var mat = ResourceLoader.load(path, "", ResourceLoader.CACHE_MODE_IGNORE) - if mat == null: + var res = ResourceLoader.load(path, "", ResourceLoader.CACHE_MODE_IGNORE) + if res == null: continue - if mat is ShaderMaterial and mat.shader != null: - var old_code: String = mat.shader.code - var new_code := old_code - for pair in REPLACEMENTS: - new_code = new_code.replace(pair[0], pair[1]) - if new_code != old_code: - mat.shader.code = new_code - var err = ResourceSaver.save(mat, path) - if err == OK: - fixed += 1 - print("FIXED ", path) - else: - push_error("Failed to save " + path + " (err=" + str(err) + ")") + var dirty := false + # Direct ShaderMaterial + if res is ShaderMaterial: + dirty = _fix_shader_material(res) or dirty + # ArrayMesh (surface materials embedded) + if res is ArrayMesh: + for surf in range(res.get_surface_count()): + var mat = res.surface_get_material(surf) + if mat is ShaderMaterial: + if _fix_shader_material(mat): + res.surface_set_material(surf, mat) + dirty = true + if dirty: + var err = ResourceSaver.save(res, path) + if err == OK: + fixed += 1 + print("FIXED ", path) + else: + push_error("Failed to save " + path + " (err=" + str(err) + ")") print("Done. checked=", checked, " fixed=", fixed) quit() -func _find_materials(dir_path: String) -> Array: +func _fix_shader_material(mat: ShaderMaterial) -> bool: + if mat.shader == null: + return false + var old_code: String = mat.shader.code + var new_code := old_code + for pair in REPLACEMENTS: + new_code = new_code.replace(pair[0], pair[1]) + if new_code == old_code: + return false + mat.shader.code = new_code + return true + +func _find_resources(dir_path: String) -> Array: var result := [] var dir = DirAccess.open(dir_path) if dir == null: @@ -54,8 +75,11 @@ func _find_materials(dir_path: String) -> Array: continue var sub = dir_path + "/" + name if dir.current_is_dir(): - result.append_array(_find_materials(sub)) - elif name.ends_with(".material") or name.ends_with(".tres"): - result.append(sub) + result.append_array(_find_resources(sub)) + else: + for ext in EXTENSIONS: + if name.ends_with(ext): + result.append(sub) + break name = dir.get_next() return result