@tool extends SceneTree # Replace every VisualShader in the project with a plain Shader carrying the # same compiled code. Godot 4 spams "graph_offset deprecated" and "p_from_port # out of bounds" warnings every time it reconstructs a Godot-3 VisualShader # graph; converting to plain Shader bypasses the graph reconstruction entirely. func _init() -> void: var fixed := 0 for path in _walk("res://"): if not (path.ends_with(".material") or path.ends_with(".tres") or path.ends_with(".mesh")): continue var res = ResourceLoader.load(path, "", ResourceLoader.CACHE_MODE_IGNORE) if res == null: continue var dirty := false if res is ShaderMaterial and res.shader is VisualShader: res.shader = _to_plain(res.shader) dirty = true if res is ArrayMesh: for i in range(res.get_surface_count()): var m = res.surface_get_material(i) if m is ShaderMaterial and m.shader is VisualShader: m.shader = _to_plain(m.shader) res.surface_set_material(i, m) dirty = true if dirty: if ResourceSaver.save(res, path) == OK: fixed += 1 print("FIXED ", path) else: push_error("Failed to save " + path) print("Done. fixed=", fixed) quit() func _to_plain(vs: VisualShader) -> Shader: var plain := Shader.new() plain.code = vs.code return plain func _walk(p: String) -> Array: var out := [] var d = DirAccess.open(p) if d == null: return out d.list_dir_begin() var n = d.get_next() while n != "": if n != "." and n != ".." and n != "android" and not n.begins_with("."): var sub = p if p.ends_with("/") else (p + "/") sub += n if d.current_is_dir(): out.append_array(_walk(sub)) else: out.append(sub) n = d.get_next() return out