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)
This commit is contained in:
2026-07-02 17:38:50 -04:00
parent e2dc429caa
commit e7299b17e9
3237 changed files with 523530 additions and 18 deletions
+183
View File
@@ -0,0 +1,183 @@
@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("")