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:
@@ -0,0 +1,157 @@
|
||||
@tool
|
||||
extends RefCounted
|
||||
|
||||
# Validator: Texture Size
|
||||
#
|
||||
# Checks:
|
||||
# - All textures referenced by materials in the scene are ≤ 1024×1024
|
||||
# - Checks StandardMaterial3D, ORMMaterial3D, and ShaderMaterial textures
|
||||
# - Warns on textures > 512×512 (suggested for secondary surfaces)
|
||||
# - Skips LightmapGI textures (baked lightmaps are handled separately)
|
||||
|
||||
const MAX_TEXTURE_SIZE := 1024
|
||||
const WARN_TEXTURE_SIZE := 512
|
||||
|
||||
|
||||
func validate(scene_root: Node, scene_path: String) -> Dictionary:
|
||||
var errors: Array[String] = []
|
||||
var warnings: Array[String] = []
|
||||
|
||||
var inspected := 0
|
||||
var oversized: Array[String] = []
|
||||
|
||||
# Collect all MeshInstance3D nodes and their materials
|
||||
var mesh_instances: Array[MeshInstance3D] = []
|
||||
_collect_mesh_instances(scene_root, mesh_instances)
|
||||
|
||||
# Track visited textures to avoid duplicate reports
|
||||
var visited_textures: Dictionary = {}
|
||||
|
||||
for mi in mesh_instances:
|
||||
var mesh: Mesh = mi.mesh
|
||||
if mesh == null:
|
||||
continue
|
||||
|
||||
for surf_idx in mesh.get_surface_count():
|
||||
var mat := mesh.surface_get_material(surf_idx)
|
||||
if mat == null:
|
||||
# Check override material on MeshInstance3D
|
||||
mat = mi.get_surface_override_material(surf_idx)
|
||||
if mat == null:
|
||||
# Check material_override on MeshInstance3D
|
||||
mat = mi.material_override
|
||||
if mat == null:
|
||||
continue
|
||||
|
||||
_check_material_textures(mat, visited_textures, errors, warnings, inspected)
|
||||
|
||||
# Check material_override if no per-surface materials
|
||||
if mesh_instances.is_empty():
|
||||
_find_materials_on_node(scene_root, visited_textures, errors, warnings, inspected)
|
||||
|
||||
# Check LightmapGI light_data texture sizes separately
|
||||
var lightmaps: Array[LightmapGI] = []
|
||||
_find_nodes_by_type(scene_root, "LightmapGI", lightmaps)
|
||||
for lm in lightmaps:
|
||||
if lm.light_data != null:
|
||||
var lightmap_tex = lm.light_data.get_texture()
|
||||
if lightmap_tex != null and not visited_textures.has(lightmap_tex.resource_path):
|
||||
visited_textures[lightmap_tex.resource_path] = true
|
||||
var size := _get_texture_size(lightmap_tex)
|
||||
if size > 0:
|
||||
print(" Lightmap texture: ", lightmap_tex.resource_path, " — ", size, "×")
|
||||
if size > MAX_TEXTURE_SIZE:
|
||||
warnings.append("Lightmap texture exceeds %d: %s (%d×)" % [MAX_TEXTURE_SIZE, lightmap_tex.resource_path, size])
|
||||
|
||||
print("")
|
||||
print(" Textures inspected: ", inspected)
|
||||
if oversized.is_empty():
|
||||
print(" ✓ All textures within ", MAX_TEXTURE_SIZE, "×", MAX_TEXTURE_SIZE, " limit")
|
||||
else:
|
||||
for o in oversized:
|
||||
print(" ✖ ", o)
|
||||
|
||||
return {
|
||||
"pass": errors.is_empty(),
|
||||
"errors": errors,
|
||||
"warnings": warnings,
|
||||
}
|
||||
|
||||
|
||||
func _check_material_textures(mat: Material, visited: Dictionary, errors: Array, warnings: Array, inspected: int) -> void:
|
||||
if mat is StandardMaterial3D:
|
||||
var smat := mat as StandardMaterial3D
|
||||
_check_single_texture(smat.albedo_texture, "albedo", smat.resource_path, visited, errors, warnings, inspected)
|
||||
_check_single_texture(smat.normal_texture, "normal", smat.resource_path, visited, errors, warnings, inspected)
|
||||
_check_single_texture(smat.roughness_texture, "roughness", smat.resource_path, visited, errors, warnings, inspected)
|
||||
_check_single_texture(smat.metallic_texture, "metallic", smat.resource_path, visited, errors, warnings, inspected)
|
||||
_check_single_texture(smat.emission_texture, "emission", smat.resource_path, visited, errors, warnings, inspected)
|
||||
_check_single_texture(smat.ao_texture, "ambient_occlusion", smat.resource_path, visited, errors, warnings, inspected)
|
||||
|
||||
elif mat is ORMMaterial3D:
|
||||
var orm := mat as ORMMaterial3D
|
||||
_check_single_texture(orm.albedo_texture, "albedo", orm.resource_path, visited, errors, warnings, inspected)
|
||||
_check_single_texture(orm.normal_texture, "normal", orm.resource_path, visited, errors, warnings, inspected)
|
||||
_check_single_texture(orm.orm_texture, "ORM", orm.resource_path, visited, errors, warnings, inspected)
|
||||
_check_single_texture(orm.emission_texture, "emission", orm.resource_path, visited, errors, warnings, inspected)
|
||||
|
||||
elif mat is ShaderMaterial:
|
||||
var sm := mat as ShaderMaterial
|
||||
# ShaderMaterial textures are set via shader params — check all Texture2D params
|
||||
var param_list = sm.get_shader_parameter_list() if sm.shader else []
|
||||
for param in param_list:
|
||||
var val = sm.get_shader_parameter(param)
|
||||
if val is Texture2D:
|
||||
_check_single_texture(val as Texture2D, param, sm.resource_path, visited, errors, warnings, inspected)
|
||||
|
||||
|
||||
func _check_single_texture(tex: Texture2D, slot_name: String, material_path: String, visited: Dictionary, errors: Array, warnings: Array, inspected: int) -> void:
|
||||
if tex == null:
|
||||
return
|
||||
var path := tex.resource_path
|
||||
if path.is_empty():
|
||||
path = tex.name # built-in/placeholder texture
|
||||
if visited.has(path):
|
||||
return
|
||||
visited[path] = true
|
||||
inspected += 1
|
||||
|
||||
var size := _get_texture_size(tex)
|
||||
if size <= 0:
|
||||
return
|
||||
|
||||
var label := "%s/%s" % [material_path.get_file(), slot_name]
|
||||
|
||||
if size > MAX_TEXTURE_SIZE:
|
||||
errors.append("Texture exceeds %d×%d: %s (%s) — %d× (path: %s)" % [MAX_TEXTURE_SIZE, MAX_TEXTURE_SIZE, label, path, size, path])
|
||||
elif size > WARN_TEXTURE_SIZE:
|
||||
warnings.append("Texture > %d×%d: %s (%s) — %d× (consider downscaling)" % [WARN_TEXTURE_SIZE, WARN_TEXTURE_SIZE, label, path, size])
|
||||
|
||||
|
||||
func _get_texture_size(tex: Texture2D) -> int:
|
||||
# Return the larger dimension
|
||||
return max(tex.get_width(), tex.get_height())
|
||||
|
||||
|
||||
func _collect_mesh_instances(node: Node, result: Array) -> void:
|
||||
if node is MeshInstance3D:
|
||||
result.append(node)
|
||||
for child in node.get_children():
|
||||
_collect_mesh_instances(child, result)
|
||||
|
||||
|
||||
func _find_nodes_by_type(root: Node, expected_type: String, output) -> void:
|
||||
if root.get_class() == expected_type:
|
||||
output.append(root)
|
||||
for child in root.get_children():
|
||||
_find_nodes_by_type(child, expected_type, output)
|
||||
|
||||
|
||||
func _find_materials_on_node(node: Node, visited: Dictionary, errors: Array, warnings: Array, inspected: int) -> void:
|
||||
# Fallback: walk all nodes and check their material_override
|
||||
for child in node.get_children():
|
||||
if child.has_method("get_material_override"):
|
||||
var mat = child.get("material_override")
|
||||
if mat != null and mat is Material:
|
||||
_check_material_textures(mat, visited, errors, warnings, inspected)
|
||||
_find_materials_on_node(child, visited, errors, warnings, inspected)
|
||||
Reference in New Issue
Block a user