e7299b17e9
Stack installed: - netfox v1.35.3 (core + extras + noray + internals) - godot-jolt v0.16.0-stable Architecture: - Server: ENet transport (works headless, no netfox deps) - Client/Editor: netfox rollback (RollbackSynchronizer, TickInterpolator) New/modified: - docs/migration-netfox-plan.md — migration architecture - scripts/network/network_manager.gd — netfox-aware ENet fallback - scripts/network/player.gd — clean base player - client/characters/player_netfox.gd — rollback player w/ WeaponManager - client/characters/input/player_net_input.gd — BaseNetInput subclass - client/characters/character/fps_character_controller.gd — netfox input feed - client/weapons/ — weapon data, registry, TacticalWeaponHitscan, WeaponManager - client/scripts/round_replicator.gd — client-side round state bridge - server/scripts/round_manager.gd — improved state machine - server/scripts/plugin_api/plugin_manager.gd — refined plugin system - config: enemy_tag, ally_tag for meatball targeting Removed: old C++ SimulationServer GDExtension (replaced by netfox rollback)
211 lines
5.9 KiB
GDScript
211 lines
5.9 KiB
GDScript
extends SceneTree
|
|
|
|
# Generalised Lightmap Baking Config Checker
|
|
# ==========================================
|
|
# Validates that a map scene's LightmapGI is configured correctly for baking.
|
|
# Generalised replacement for scripts/bake_lighting.gd — works on ANY map scene.
|
|
#
|
|
# Note: Godot 4.7 LightmapGI baking is editor-only. This script validates
|
|
# configuration only; actual baking must be done from the Godot editor.
|
|
#
|
|
# Usage:
|
|
# godot --headless --script bake_lightmaps.gd -- res://maps/my_map.tscn
|
|
#
|
|
# Exit codes:
|
|
# 0 — All checks passed (or warnings only)
|
|
# 1 — One or more checks failed (fatal)
|
|
# 2 — Scene file could not be loaded
|
|
|
|
var _scene_path: String = ""
|
|
var _checks: Array = [] # [label, passed, is_warning]
|
|
|
|
|
|
func _init() -> void:
|
|
_parse_args()
|
|
if _scene_path.is_empty():
|
|
printerr("ERROR: No scene path provided.")
|
|
print("Usage: godot --headless --script bake_lightmaps.gd -- res://maps/my_map.tscn")
|
|
quit(2)
|
|
return
|
|
|
|
print("")
|
|
print("=== Lightmap Baking Config Checker: %s ===" % _scene_path)
|
|
print("")
|
|
|
|
var scene = ResourceLoader.load(_scene_path)
|
|
if not scene:
|
|
printerr("ERROR: Could not load scene: %s" % _scene_path)
|
|
quit(2)
|
|
return
|
|
|
|
var instance = scene.instantiate()
|
|
if not instance:
|
|
printerr("ERROR: Could not instantiate scene!")
|
|
quit(2)
|
|
return
|
|
|
|
root.add_child(instance)
|
|
print("Scene loaded and instantiated successfully.")
|
|
print("")
|
|
print("Note: Godot 4.x LightmapGI baking is editor-only.")
|
|
print("This script validates configuration only.")
|
|
print("To bake: Open scene in editor > Select LightmapGI > 'Bake Lightmap'")
|
|
print("")
|
|
|
|
var lightmap: LightmapGI = _find_node_of_type(instance, LightmapGI)
|
|
if not lightmap:
|
|
printerr("ERROR: No LightmapGI node found in scene!")
|
|
quit(1)
|
|
return
|
|
|
|
_print_config(lightmap)
|
|
_run_checks(lightmap, instance)
|
|
_print_results()
|
|
|
|
|
|
func _parse_args() -> void:
|
|
var args := OS.get_cmdline_args()
|
|
var found_sep := false
|
|
for a in args:
|
|
if a == "--":
|
|
found_sep = true
|
|
continue
|
|
if found_sep and not a.begins_with("-"):
|
|
_scene_path = a
|
|
return
|
|
for a in args:
|
|
if a.contains("res://") or a.ends_with(".tscn"):
|
|
_scene_path = a
|
|
return
|
|
|
|
|
|
func _check(label: String, passed: bool, is_warning: bool = false) -> void:
|
|
_checks.append([label, passed, is_warning])
|
|
|
|
|
|
func _print_config(lightmap: LightmapGI) -> void:
|
|
print(" LightmapGI configuration:")
|
|
print(" Quality: ", _quality_name(lightmap.quality), " (", lightmap.quality, ")")
|
|
print(" Bounces: ", lightmap.bounces)
|
|
print(" Texel Scale: ", lightmap.texel_scale)
|
|
print(" Max Tex Size: ", lightmap.max_texture_size)
|
|
print(" Interior: ", lightmap.interior)
|
|
print(" Denoiser: ", lightmap.is_using_denoiser())
|
|
print(" Energy: ", lightmap.lightmap_energy)
|
|
print(" Bias: ", lightmap.lightmap_probe_bias)
|
|
|
|
if lightmap.light_data != null:
|
|
print(" Baked data: PRESENT ✓")
|
|
else:
|
|
print(" Baked data: NOT YET BAKED")
|
|
|
|
print("")
|
|
|
|
|
|
func _run_checks(lightmap: LightmapGI, instance: Node) -> void:
|
|
# Configuration checks
|
|
_check("Quality ≥ Medium (1)", lightmap.quality >= 1)
|
|
_check("Bounces ≥ 2", lightmap.bounces >= 2)
|
|
_check("Texel Scale ≤ 2.0", lightmap.texel_scale <= 2.0)
|
|
_check("Interior = true", lightmap.interior == true)
|
|
|
|
# Denoiser recommended
|
|
_check("Use denoiser enabled", lightmap.is_using_denoiser(), true)
|
|
|
|
# Max texture size ≤ 4096 (sanity)
|
|
_check("Max texture size ≤ 4096", lightmap.max_texture_size <= 4096)
|
|
|
|
# Energy shouldn't be zero
|
|
_check("Lightmap energy > 0", lightmap.lightmap_energy > 0)
|
|
|
|
# Check for lightmap-enabled meshes
|
|
var meshes: Array = _find_nodes_of_type(instance, MeshInstance3D)
|
|
var static_meshes := 0
|
|
var dynamic_meshes := 0
|
|
for mi in meshes:
|
|
if mi.gi_mode == GeometryInstance3D.GI_MODE_STATIC:
|
|
static_meshes += 1
|
|
elif mi.gi_mode == GeometryInstance3D.GI_MODE_DYNAMIC:
|
|
dynamic_meshes += 1
|
|
|
|
_check("Static geometry meshes found for lightmapping", static_meshes > 0)
|
|
|
|
# Baked data status (informational)
|
|
if lightmap.light_data != null:
|
|
print(" ✓ Lightmap has baked data.")
|
|
# Check bake timestamp if available
|
|
var ld = lightmap.light_data
|
|
if ld is LightmapGIData and ld.has_method("get_user_data"):
|
|
print(" Bake data size: %d bytes" % ld.get_user_data().size())
|
|
else:
|
|
print(" ⚠ Lightmap NOT YET BAKED. Open in Godot editor and bake.")
|
|
|
|
# Summary
|
|
print("")
|
|
print(" Geometry summary:")
|
|
print(" MeshInstance3D nodes: %d" % meshes.size())
|
|
print(" GI_MODE_STATIC: %d" % static_meshes)
|
|
print(" GI_MODE_DYNAMIC: %d" % dynamic_meshes)
|
|
|
|
|
|
func _print_results() -> void:
|
|
print("")
|
|
print(" ─── Validation Results ───")
|
|
var passed := 0
|
|
var failed := 0
|
|
var warnings := 0
|
|
for c in _checks:
|
|
if c[1]:
|
|
passed += 1
|
|
print(" ✓ %s" % c[0])
|
|
else:
|
|
if c[2]:
|
|
warnings += 1
|
|
print(" ⚠ %s" % c[0])
|
|
else:
|
|
failed += 1
|
|
print(" ✗ %s" % c[0])
|
|
|
|
print("")
|
|
print(" Passed: %d Warnings: %d Failed: %d" % [passed, warnings, failed])
|
|
print("")
|
|
|
|
if failed > 0:
|
|
printerr("Validation FAILED — %d check(s) failed." % failed)
|
|
quit(1)
|
|
else:
|
|
print("=== Config check complete ===")
|
|
quit(0)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
func _quality_name(q: int) -> String:
|
|
match q:
|
|
0: return "Low"
|
|
1: return "Medium"
|
|
2: return "High"
|
|
3: return "Ultra"
|
|
return "Unknown"
|
|
|
|
|
|
func _find_node_of_type(parent: Node, type: Script) -> Node:
|
|
for child in parent.get_children():
|
|
if is_instance_of(child, type):
|
|
return child
|
|
var found = _find_node_of_type(child, type)
|
|
if found:
|
|
return found
|
|
return null
|
|
|
|
|
|
func _find_nodes_of_type(parent: Node, type: Script) -> Array:
|
|
var results: Array = []
|
|
for child in parent.get_children():
|
|
if is_instance_of(child, type):
|
|
results.append(child)
|
|
results.append_array(_find_nodes_of_type(child, type))
|
|
return results
|