using System; using System.IO; using System.Reflection; using Cysharp.Threading.Tasks; using Duckov.Utilities; using ItemStatsSystem; using Saves; using UnityEngine; using UnityEngine.SceneManagement; using Object = UnityEngine.Object; namespace CharacterPreview { public class ModBehaviour : Duckov.Modding.ModBehaviour { private static CharacterMainControl characterControl; public static ModelMove modelMove; private const string characterFaceSaveKey = "CustomFace_MainCharacter"; private const string characterItemSaveKey = "MainCharacterItemData"; private const string ModelName = "CharacterPreviewModel"; public static Config config; private static GameObject cameraModelObject; private void OnDestroy() { config.Save(); } protected override void OnAfterSetup() { var path=Path.Combine(info.path,"config.json"); config = Config.Load(path); SceneManager.sceneLoaded+=OnSceneLoaded; AddListen(); } protected override void OnBeforeDeactivate() { SceneManager.sceneLoaded -= OnSceneLoaded; RemoveModel(); } private void OnSceneLoaded(Scene scene, LoadSceneMode mode) { if (scene.name == "MainMenu") { AddListen(); // _ = CreateCharacterModel(); } } private void AddListen() { var canvasObj = GameObject.Find("Canvas"); if (canvasObj == null) { Debug.LogWarning("Canvas not found"); return; } var mainMenu=GameObjectUtils.FindObjectByPath(canvasObj, "MainMenuContainer"); if (!mainMenu) { Debug.LogWarning("MainMenuContainer not found"); return; } var listen = mainMenu.GetComponent(); if (!listen) { mainMenu.AddComponent(); } } public static void RemoveModel() { if (characterControl) { Destroy(characterControl.gameObject); characterControl = null; modelMove = null; } } public static async UniTask CreateCharacterModel() { if (characterControl) { Debug.LogWarning("[CreateCharacterModel] CharacterModel 已经被创建,跳过重复创建。"); return; } if (SceneManager.GetActiveScene().name != "MainMenu") { Debug.LogWarning( $"[CreateCharacterModel] 当前场景为 \"{SceneManager.GetActiveScene().name}\",非主菜单界面 \"MainMenu\",无法创建角色模型。"); return; } Item? item = null; if (config.data.showEquipment) { item = await ItemSavesUtilities.LoadItem(characterItemSaveKey); } if (item == null) { var defaultTypeID = GameplayDataSettings.ItemAssets.DefaultCharacterItemTypeID; item = await ItemAssetsCollection.InstantiateAsync(defaultTypeID); if (item == null) { Debug.LogError("[CreateCharacterModel] 无法通过默认角色类型 ID 实例化角色物品,请确认资源是否存在且配置正确。"); return; } } // 获取角色模型预制体 var model = GetCharacterModelPrefab_Reflection(); if (model == null) { Debug.LogError("[CreateCharacterModel] 通过反射获取角色模型预制体失败,请检查 GetCharacterModelPrefab_Reflection 方法实现。"); return; } characterControl = CreateCharacter( item, model, Vector3.zero, Quaternion.identity); if (characterControl == null) { Debug.LogError("[CreateCharacterModel] 角色创建失败,返回的 characterControl 为 null。"); return; } characterControl.enabled = false; characterControl.gameObject.name = ModelName; // 加载自定义面部设置 var customFaceSettingData = SavesSystem.Load(characterFaceSaveKey); if (!customFaceSettingData.savedSetting) { Debug.LogWarning("[CreateCharacterModel] 未能加载有效的 CustomFaceSettingData,将使用默认预设。"); if (GameplayDataSettings.CustomFaceData?.DefaultPreset?.settings == null) { Debug.LogError("[CreateCharacterModel] 默认面部预设也为空!无法应用面部设置。"); } else { customFaceSettingData = GameplayDataSettings.CustomFaceData.DefaultPreset.settings; } } if (characterControl.characterModel?.CustomFace != null) { characterControl.characterModel.CustomFace.LoadFromData(customFaceSettingData); } else { Debug.LogWarning("[CreateCharacterModel] 跳过面部数据加载:CustomFace 组件或数据为空。"); } // 添加移动组件 modelMove = characterControl.gameObject.GetComponent(); if (modelMove == null) { modelMove = characterControl.gameObject.AddComponent(); } Debug.LogWarning("这个是模型的动画组件报错,由于这个是部分初始化,导致内容不完全,不影响(其实是因为没影响就懒得一个个分析了,欸嘿(*^▽^*))"); HideCamera(); // SetModelShow(false); } private static void SetModelShow(bool show) { if (characterControl) { characterControl.gameObject.SetActive(show); } } private static void HideCamera() { if (!cameraModelObject) { var camera = FindObjectOfType(); if (camera == null) { Debug.LogWarning("[CreateCharacterModel] 场景中未找到 Camera 对象。"); } else { cameraModelObject = GameObjectUtils.FindObjectByPath(camera.gameObject, "Camera01_prefab"); if (cameraModelObject == null) { Debug.LogWarning("[CreateCharacterModel] 在 Camera 下未找到路径为 \"Camera01_prefab\" 的子对象。"); } } } if (cameraModelObject) { if (config.data.hideCamera) { cameraModelObject.SetActive(false); } else { cameraModelObject.SetActive(true); } } else { Debug.LogError("[CreateCharacterModel] 未找到摄像机模型对象,无法控制其显示状态。"); } } private static CharacterModel GetCharacterModelPrefab_Reflection() { // 获取 LevelManager 实例 var lm = GameplayDataSettings.Prefabs.LevelManagerPrefab; if (lm == null) { Debug.LogError("LevelManager 实例未找到!"); return null; } // 使用反射获取 LevelManager 中的 characterModel 字段 var field = typeof(LevelManager).GetField("characterModel", BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) { Debug.LogError("characterModel 字段在 LevelManager 中未找到!"); return null; } // 获取字段值并转换为 CharacterModel var modelPrefab = field.GetValue(lm) as CharacterModel; if (modelPrefab == null) { Debug.LogError("characterModel 字段的值为空!"); return null; } return modelPrefab; } /// /// 检查指定全限定类名的类型是否存在于已加载的程序集中。 /// /// 完整类名,如 "DuckovCustomModel.ModBehaviour" /// 如果存在返回 true,否则 false public static bool IsTypeLoaded(string fullTypeName) { if (string.IsNullOrWhiteSpace(fullTypeName)) return false; // 先尝试用 Type.GetType(适用于 mscorlib 和当前程序集) var type = Type.GetType(fullTypeName, throwOnError: false, ignoreCase: false); if (type != null) return true; // 遍历所有已加载的程序集 var assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) { try { type = assembly.GetType(fullTypeName, throwOnError: false, ignoreCase: false); if (type != null) return true; } catch (Exception) { // 某些程序集可能无法读取(如动态生成、权限问题等),跳过 continue; } } return false; } public static CharacterMainControl CreateCharacter( Item? itemInstance, CharacterModel modelPrefab, Vector3 pos, Quaternion rotation) { var character = Instantiate(GameplayDataSettings.Prefabs.CharacterPrefab, pos, rotation); var _characterModel = Instantiate(modelPrefab); character.SetCharacterModel(_characterModel); if (itemInstance == null) { if ((bool) (Object) character) Destroy(character.gameObject); return null; } character.SetItem(itemInstance); return character; } } }