Implement playable Mac client and rendering validation

This commit is contained in:
shen
2026-09-11 14:58:22 +08:00
parent 1ab68bd06e
commit 374d4165d8
233 changed files with 6546 additions and 284 deletions
+50 -1
View File
@@ -9,6 +9,13 @@
#include <godot_cpp/classes/image.hpp>
#include <godot_cpp/classes/image_texture.hpp>
#include <godot_cpp/classes/file_access.hpp>
#include <godot_cpp/classes/json.hpp>
#include <godot_cpp/classes/gltf_document.hpp>
#include <godot_cpp/classes/gltf_state.hpp>
#include <godot_cpp/classes/gltf_mesh.hpp>
#include <godot_cpp/classes/importer_mesh.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
#include <godot_cpp/classes/shader.hpp>
#include <godot_cpp/classes/shader_material.hpp>
#include <godot_cpp/classes/standard_material3d.hpp>
@@ -477,15 +484,57 @@ Ref<ArrayMesh> build_placeholder_tree(const String &species_hint, float height_m
return build_proxy_impl(std::string(species_hint.utf8().get_data()), height_m, empty);
}
Ref<ArrayMesh> get_tree_proxy_mesh(const std::string &treefile,
static Ref<ArrayMesh> load_native_tree(const std::string &treefile, const fmt::AssetResolver &resolver) {
const String source(resolver.resolve(treefile, nullptr).c_str());
if (source.is_empty()) return {};
const String directory = String(resolver.assets_root.c_str()).path_join("TreeGeometry");
const String manifest_path = directory.path_join("manifest.json");
if (!FileAccess::file_exists(manifest_path)) return {};
const Variant parsed = JSON::parse_string(FileAccess::get_file_as_string(manifest_path));
if (parsed.get_type() != Variant::DICTIONARY) return {};
const Dictionary manifest = parsed;
if (int(manifest.get("schema_version", 0)) != 1 || String(manifest.get("coordinates", "")) != "godot_y_up_meters") return {};
const Dictionary trees = manifest.get("trees", Dictionary());
const String source_hash = FileAccess::get_sha256(source);
if (!trees.has(source_hash)) return {};
const Dictionary record = trees[source_hash];
const String filename = record.get("glb", "");
if (filename != source_hash + String(".glb")) return {};
const String path = directory.path_join(filename);
if (!FileAccess::file_exists(path) || FileAccess::get_sha256(path) != String(record.get("glb_sha256", ""))) return {};
Ref<GLTFDocument> document;
document.instantiate();
Ref<GLTFState> state;
state.instantiate();
if (document->append_from_file(path, state) != OK || state->get_meshes().size() != 1) return {};
Ref<GLTFMesh> gltf_mesh = state->get_meshes()[0];
if (gltf_mesh.is_null() || gltf_mesh->get_mesh().is_null()) return {};
Ref<ArrayMesh> mesh = gltf_mesh->get_mesh()->get_mesh();
if (mesh.is_null() || mesh->get_surface_count() == 0) return {};
mesh->set_meta("tree_geometry", "native_spt");
mesh->set_meta("source_sha256", source_hash);
mesh->set_meta("glb_sha256", record.get("glb_sha256", ""));
mesh->set_meta("leaf_mode", "static_extracted_cards");
// GLB vertices already use Godot metres. Never impose the proxy's 12m height.
return mesh;
}
Ref<ArrayMesh> get_tree_mesh(const std::string &treefile,
const fmt::AssetResolver &resolver, float height_m) {
const std::string key = resolver.assets_root + "|" + fmt::AssetResolver::normalize(treefile) +
"#" + std::to_string(height_m);
auto found = g_tree_mesh_cache.find(key);
if (found != g_tree_mesh_cache.end())
return found->second;
Ref<ArrayMesh> native = load_native_tree(treefile, resolver);
if (native.is_valid()) {
g_tree_mesh_cache.emplace(key, native);
return native;
}
UtilityFunctions::push_warning(String("Tree native geometry unavailable or hash mismatch; proxy: ") + String(treefile.c_str()));
const TreeTextures textures = resolve_tree_textures(treefile, resolver);
Ref<ArrayMesh> mesh = build_proxy_impl(treefile, height_m, textures);
mesh->set_meta("tree_geometry", "proxy");
g_tree_mesh_cache.emplace(key, mesh);
return mesh;
}