Files
DuckovMods/CharacterPreview/ModBehaviour.cs

299 lines
10 KiB
C#
Raw Permalink Normal View History

using System;
2025-11-18 18:45:14 +08:00
using System.IO;
using System.Reflection;
2025-11-18 18:45:14 +08:00
using Cysharp.Threading.Tasks;
using Duckov.Utilities;
2025-11-18 18:45:14 +08:00
using ItemStatsSystem;
using Saves;
using UnityEngine;
using UnityEngine.SceneManagement;
using Object = UnityEngine.Object;
namespace CharacterPreview
{
public class ModBehaviour : Duckov.Modding.ModBehaviour
{
2025-11-18 18:45:14 +08:00
private static CharacterMainControl characterControl;
public static ModelMove modelMove;
private const string characterFaceSaveKey = "CustomFace_MainCharacter";
2025-11-18 18:45:14 +08:00
private const string characterItemSaveKey = "MainCharacterItemData";
private const string ModelName = "CharacterPreviewModel";
2025-11-18 18:45:14 +08:00
public static Config config;
private static GameObject cameraModelObject;
private void OnDestroy()
{
config.Save();
}
protected override void OnAfterSetup()
{
2025-11-18 18:45:14 +08:00
var path=Path.Combine(info.path,"config.json");
config = Config.Load(path);
SceneManager.sceneLoaded+=OnSceneLoaded;
AddListen();
}
protected override void OnBeforeDeactivate()
{
2025-11-18 18:45:14 +08:00
SceneManager.sceneLoaded -= OnSceneLoaded;
RemoveModel();
}
private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
if (scene.name == "MainMenu")
{
2025-11-18 18:45:14 +08:00
AddListen();
// _ = CreateCharacterModel();
}
}
2025-11-18 18:45:14 +08:00
private void AddListen()
{
2025-11-18 18:45:14 +08:00
var canvasObj = GameObject.Find("Canvas");
if (canvasObj == null)
{
Debug.LogWarning("Canvas not found");
2025-11-18 18:45:14 +08:00
return;
}
var mainMenu=GameObjectUtils.FindObjectByPath(canvasObj, "MainMenuContainer");
if (!mainMenu)
{
Debug.LogWarning("MainMenuContainer not found");
2025-11-18 18:45:14 +08:00
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")
{
2025-11-18 18:45:14 +08:00
Debug.LogWarning(
$"[CreateCharacterModel] 当前场景为 \"{SceneManager.GetActiveScene().name}\",非主菜单界面 \"MainMenu\",无法创建角色模型。");
return;
}
2025-11-18 18:45:14 +08:00
Item? item = null;
if (config.data.showEquipment)
{
item = await ItemSavesUtilities.LoadItem(characterItemSaveKey);
}
2025-11-18 18:45:14 +08:00
if (item == null)
{
2025-11-18 18:45:14 +08:00
var defaultTypeID = GameplayDataSettings.ItemAssets.DefaultCharacterItemTypeID;
item = await ItemAssetsCollection.InstantiateAsync(defaultTypeID);
if (item == null)
{
2025-11-18 18:45:14 +08:00
Debug.LogError("[CreateCharacterModel] 无法通过默认角色类型 ID 实例化角色物品,请确认资源是否存在且配置正确。");
return;
}
}
2025-11-18 18:45:14 +08:00
// 获取角色模型预制体
var model = GetCharacterModelPrefab_Reflection();
if (model == null)
{
Debug.LogError("[CreateCharacterModel] 通过反射获取角色模型预制体失败,请检查 GetCharacterModelPrefab_Reflection 方法实现。");
return;
}
characterControl = CreateCharacter(
item, model, Vector3.zero, Quaternion.identity);
if (characterControl == null)
{
2025-11-18 18:45:14 +08:00
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;
}
}
2025-11-18 18:45:14 +08:00
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);
}
2025-11-19 10:17:55 +08:00
2025-11-18 18:45:14 +08:00
private static void HideCamera()
{
if (!cameraModelObject)
{
2025-11-18 18:45:14 +08:00
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] 未找到摄像机模型对象,无法控制其显示状态。");
}
}
2025-11-18 18:45:14 +08:00
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;
}
2025-11-18 18:45:14 +08:00
// 获取字段值并转换为 CharacterModel
var modelPrefab = field.GetValue(lm) as CharacterModel;
if (modelPrefab == null)
{
Debug.LogError("characterModel 字段的值为空!");
return null;
}
return modelPrefab;
}
2025-11-18 18:45:14 +08:00
/// <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,
2025-11-18 18:45:14 +08:00
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;
}
}
}