Files
DuckovMods/CharacterPreview/ModBehaviour.cs
2025-11-18 19:12:34 +08:00

305 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<ShowListen>();
if (!listen)
{
mainMenu.AddComponent<ShowListen>();
}
}
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<CustomFaceSettingData>(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<ModelMove>();
if (modelMove == null)
{
modelMove = characterControl.gameObject.AddComponent<ModelMove>();
}
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<Camera>();
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;
}
/// <summary>
/// 检查指定全限定类名的类型是否存在于已加载的程序集中。
/// </summary>
/// <param name="fullTypeName">完整类名,如 "DuckovCustomModel.ModBehaviour"</param>
/// <returns>如果存在返回 true否则 false</returns>
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;
}
}
}