Files
tactical-shooter/client/tools/validate_map.gd
T
shawn e7299b17e9 Phase 7: netfox + godot-jolt stack upgrade
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)
2026-07-02 17:39:22 -04:00

184 lines
5.8 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
@tool
extends Node
# Map Validator — Command-line entry point.
#
# Usage:
# godot --path client --script tools/validate_map.gd -- res://maps/mymap.tscn
#
# The scene path must come after `--` so Godot passes it as a user argument.
#
# Exit codes:
# 0 — All checks passed
# 1 — Warnings only (light suggestions, no blocked items)
# 2 — Errors found (must-fix items)
#
# Runs four validation modules in order:
# 1. Scene structure — node hierarchy, required groups, LightmapGI, WorldEnvironment
# 2. Polygon count — total mesh triangles ≤ 50K
# 3. Texture size — all material textures ≤ 1024×1024
# 4. Light count — dynamic (non-baked) lights ≤ 4, lightmap bake status
#
# Each module returns a dictionary {pass: bool, errors: [str], warnings: [str]}.
const VALIDATOR_DIR := "res://tools/validate_map/"
enum ExitCode {
PASS = 0,
WARNINGS = 1,
ERRORS = 2,
}
func _ready() -> void:
var args := OS.get_cmdline_user_args()
if args.is_empty():
_print_usage()
get_tree().quit(ExitCode.ERRORS)
return
var scene_path := args[0]
# Validate path prefix
if not scene_path.begins_with("res://"):
push_error("Scene path must be a Godot resource path (res://) — got: ", scene_path)
get_tree().quit(ExitCode.ERRORS)
return
# Load the scene
var scene := ResourceLoader.load(scene_path, "PackedScene", ResourceLoader.CACHE_MODE_IGNORE)
if scene == null:
push_error("Failed to load scene: ", scene_path)
get_tree().quit(ExitCode.ERRORS)
return
print("═══════════════════════════════════════════")
print(" MAP VALIDATOR")
print(" Scene: ", scene_path)
print("═══════════════════════════════════════════")
print("")
# Instantiate the scene (in @tool mode this runs in editor)
var instance_data: Array = _try_instantiate(scene, scene_path)
var instance: Node = instance_data[0] as Node
var instantiate_error: String = instance_data[1] as String
if instance == null:
push_error(instantiate_error)
get_tree().quit(ExitCode.ERRORS)
return
add_child(instance)
# Run all validators
var results: Array[Dictionary] = []
results.append(_run_module("validate_scene", instance, scene_path))
results.append(_run_module("validate_polycount", instance, scene_path))
results.append(_run_module("validate_textures", instance, scene_path))
results.append(_run_module("validate_lights", instance, scene_path))
# Summary
print("")
print("═══════════════════════════════════════════")
print(" SUMMARY")
print("═══════════════════════════════════════════")
var total_errors := 0
var total_warnings := 0
for result in results:
var label: String = "PASS" if result["pass"] else result["status"]
print(" [", label, "] ", result["name"])
total_errors += result["errors"].size()
total_warnings += result["warnings"].size()
print("")
print(" Errors: ", total_errors)
print(" Warnings: ", total_warnings)
if total_errors > 0:
print(" Result: FAIL")
print("")
get_tree().quit(ExitCode.ERRORS)
elif total_warnings > 0:
print(" Result: PASS (with warnings)")
print("")
get_tree().quit(ExitCode.WARNINGS)
else:
print(" Result: PASS")
print("")
get_tree().quit(ExitCode.PASS)
# Attempts to instantiate a PackedScene, catching errors gracefully.
func _try_instantiate(scene: PackedScene, path: String) -> Array:
var err_test := scene.can_instantiate()
if not err_test:
return [null, "Scene cannot be instantiated (may depend on other resources): " + path]
var inst := scene.instantiate(PackedScene.GEN_EDIT_STATE_INSTANCE)
if inst == null:
return [null, "Scene instantiate returned null: " + path]
return [inst, ""]
# Loads a validator script from VALIDATOR_DIR and runs its checks.
func _run_module(name: String, scene_root: Node, scene_path: String) -> Dictionary:
var script_path := VALIDATOR_DIR.path_join(name + ".gd")
var script := ResourceLoader.load(script_path, "Script", ResourceLoader.CACHE_MODE_IGNORE)
if script == null:
push_error("Failed to load validator module: ", script_path)
return {
"name": name,
"pass": false,
"status": "ERROR",
"errors": ["Validator script not found: " + script_path],
"warnings": [],
}
# Instantiate the validator module directly (scripts extend RefCounted)
if not script.has_method("validate"):
push_error("Validator module missing validate() method: ", script_path)
return {
"name": name,
"pass": false,
"status": "ERROR",
"errors": ["Missing validate() method in " + script_path],
"warnings": [],
}
print("── [", name, "] ────────────────────────────")
var validator = script.new()
var result: Dictionary = validator.validate(scene_root, scene_path)
# Print inline results
for w in result.get("warnings", []):
print("", w)
for e in result.get("errors", []):
print("", e)
var ok: bool = result.get("pass", false)
if ok:
print(" ✓ pass")
else:
print(" ✖ FAIL")
print("")
return result
func _print_usage() -> void:
print("Map Validator — usage:")
print("")
print(" godot --path <project> --script tools/validate_map.gd -- <scene_path>")
print("")
print("Examples:")
print(" godot --path client --script tools/validate_map.gd -- res://maps/de_dust2.tscn")
print(" godot --path client --script tools/validate_map.gd -- res://maps/my_map.tscn")
print("")
print("Exit codes:")
print(" 0 — All checks passed")
print(" 1 — Warnings (non-blocking suggestions)")
print(" 2 — Errors (must-fix items)")
print("")