#include "agent_fbx_importer.h" #include "core/io/file_access.h" #include "core/io/json.h" #include "core/string/print_string.h" AgentFBXImporter *AgentFBXImporter::singleton = nullptr; AgentFBXImporter::AgentFBXImporter() { singleton = this; _load_bone_map(); } AgentFBXImporter::~AgentFBXImporter() { singleton = nullptr; } void AgentFBXImporter::_bind_methods() { ClassDB::bind_method(D_METHOD("load_bone_map", "path"), &AgentFBXImporter::load_bone_map, DEFVAL("res://bone_map.json")); ClassDB::bind_method(D_METHOD("remap_bone", "original_name"), &AgentFBXImporter::remap_bone); ClassDB::bind_method(D_METHOD("get_bone_map"), &AgentFBXImporter::get_bone_map); ClassDB::bind_method(D_METHOD("has_mapping", "bone_name"), &AgentFBXImporter::has_mapping); ClassDB::bind_method(D_METHOD("set_mapping", "from", "to"), &AgentFBXImporter::set_mapping); ClassDB::bind_method(D_METHOD("remove_mapping", "from"), &AgentFBXImporter::remove_mapping); ClassDB::bind_method(D_METHOD("save_bone_map", "path"), &AgentFBXImporter::save_bone_map, DEFVAL("res://bone_map.json")); ClassDB::bind_method(D_METHOD("is_loaded"), &AgentFBXImporter::is_loaded); } void AgentFBXImporter::_load_bone_map() { load_bone_map("res://bone_map.json"); } bool AgentFBXImporter::load_bone_map(const String &p_path) { if (!FileAccess::exists(p_path)) { // No bone map file — not an error, just means no remapping. bone_map_loaded = false; return false; } Ref file = FileAccess::open(p_path, FileAccess::READ); if (file.is_null()) { ERR_PRINT(vformat("AgentFBXImporter: Failed to open '%s'", p_path)); return false; } String content = file->get_as_text(); Variant parsed = JSON::parse_string(content); if (parsed.get_type() != Variant::DICTIONARY) { ERR_PRINT(vformat("AgentFBXImporter: Failed to parse '%s' as JSON dictionary", p_path)); return false; } bone_map = parsed; bone_map_loaded = true; print_line(vformat("AgentFBXImporter: Loaded %d bone mappings from '%s'", bone_map.size(), p_path)); return true; } String AgentFBXImporter::remap_bone(const String &p_original_name) const { if (!bone_map_loaded) { return p_original_name; } if (bone_map.has(p_original_name)) { return bone_map[p_original_name]; } // Case-insensitive fallback. for (const Variant &key : bone_map.keys()) { if (String(key).to_lower() == p_original_name.to_lower()) { return bone_map[key]; } } return p_original_name; } bool AgentFBXImporter::has_mapping(const String &p_bone_name) const { if (bone_map.has(p_bone_name)) { return true; } // Case-insensitive check. for (const Variant &key : bone_map.keys()) { if (String(key).to_lower() == p_bone_name.to_lower()) { return true; } } return false; } void AgentFBXImporter::set_mapping(const String &p_from, const String &p_to) { bone_map[p_from] = p_to; bone_map_loaded = true; } void AgentFBXImporter::remove_mapping(const String &p_from) { bone_map.erase(p_from); } bool AgentFBXImporter::save_bone_map(const String &p_path) { Ref file = FileAccess::open(p_path, FileAccess::WRITE); if (file.is_null()) { ERR_PRINT(vformat("AgentFBXImporter: Failed to write '%s'", p_path)); return false; } file->store_string(JSON::stringify(bone_map, "\t")); print_line(vformat("AgentFBXImporter: Saved %d bone mappings to '%s'", bone_map.size(), p_path)); return true; }