Files
test/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs
T
2026-05-05 11:37:26 +07:00

380 lines
16 KiB
C#

using System.Collections.Generic;
using BrewMonster.Scripts.Managers;
using CSNetwork.Protocols.RPCData;
using Cysharp.Threading.Tasks;
using UnityEngine;
namespace BrewMonster.Scripts
{
public class PlayerModelPreview : MonoSingleton<PlayerModelPreview>
{
[SerializeField] private Transform modelRoot;
public List<GameObject> playerModels = new();
public List<int> playerModelIds = new();
private int _loadVersion;
private bool _hasRequestedPlayerModelId;
private int _requestedPlayerModelId;
private void Awake()
{
if (modelRoot == null)
modelRoot = transform;
}
private void OnDestroy()
{
ClearModelsImmediate();
}
/// <summary>
/// Loads one preview instance per role (via <see cref="NPCManager.GetModelPlayer"/>).
/// All instances stay hidden until <see cref="ShowPlayerModel"/> is called.
/// </summary>
public async void ShowAllPlayerModels(List<RoleInfo> roleInfos)
{
BMLogger.Log($"ShowAllPlayerModels: {roleInfos.Count}");
_loadVersion++;
int version = _loadVersion;
ClearModels();
if (roleInfos == null || roleInfos.Count == 0 || NPCManager.Instance == null)
return;
for (int i = 0; i < roleInfos.Count; i++)
{
RoleInfo role = roleInfos[i];
GameObject model = await LoadPlayerModel(role);
if (model == null)
continue;
if (version != _loadVersion)
{
Destroy(model);
return;
}
model.transform.SetParent(modelRoot, false);
model.transform.localPosition = Vector3.zero;
model.transform.localRotation = Quaternion.identity;
model.SetActive(false);
playerModels.Add(model);
playerModelIds.Add(role.roleid);
ApplyRequestedModelVisibility();
}
}
/// <summary>
/// Shows the preview for the given role id (matches <see cref="RoleInfo.roleid"/>). Hides all others.
/// </summary>
public void ShowPlayerModel(int playerModelId)
{
//int n = Mathf.Min(playerModels.Count, playerModelIds.Count);
//for (int i = 0; i < n; i++)
//{
// GameObject go = playerModels[i];
// if (go == null)
// continue;
// go.SetActive(playerModelIds[i] == playerModelId);
//}
_hasRequestedPlayerModelId = true;
_requestedPlayerModelId = playerModelId;
ApplyRequestedModelVisibility();
}
/// <summary>
/// Applies the visibility of player models based on the requested player model id.
/// </summary>
private void ApplyRequestedModelVisibility()
{
if(!_hasRequestedPlayerModelId)
return;
int n = Mathf.Min(playerModels.Count, playerModelIds.Count);
for (int i = 0; i < n; i++)
{
GameObject go = playerModels[i];
if(go == null)
continue;
go.SetActive(playerModelIds[i] == _requestedPlayerModelId);
}
}
public void HideAllPlayerModels()
{
_hasRequestedPlayerModelId = false;
for (int i = 0; i < playerModels.Count; i++)
{
if (playerModels[i] != null)
{
playerModels[i].SetActive(false);
}
}
}
public void ClearModels()
{
//for (int i = 0; i < playerModels.Count; i++)
//{
// if (playerModels[i] != null)
// {
// Destroy(playerModels[i]);
// }
//}
playerModels.Clear();
playerModelIds.Clear();
if(modelRoot != null)
{
foreach (Transform child in modelRoot)
{
Destroy(child.gameObject);
}
}
}
private void ClearModelsImmediate()
{
for (int i = 0; i < playerModels.Count; i++)
{
if (modelRoot != null)
{
if(playerModels[i] != null)
{
if(Application.isPlaying)
Destroy(playerModels[i]);
else
DestroyImmediate(playerModels[i]);
}
}
}
playerModels.Clear();
playerModelIds.Clear();
}
private async UniTask<GameObject> LoadPlayerModel(RoleInfo role)
{
BMLogger.Log($"LoadPlayerModel: {role.roleid}");
var elemendataman = BrewMonster.ElementDataManProvider.GetElementDataMan();
GameObject model = await NPCManager.Instance.GetModelPlayer(role.occupation, role.gender);
if(model == null)
return null;
model.SetActive(false);
BMLogger.Log($"LoadPlayerModel: {role.roleid} - prefab loaded");
if (modelRoot != null)
{
model.transform.SetParent(modelRoot, false);
}
var playerDefaultEquipments = model.GetComponentInChildren<PlayerDefaultEquipments>();
if (playerDefaultEquipments == null)
{
return null;
}
DATA_TYPE DataType = default;
bool useDefaultUpper = true;
bool useDefaultLower = true;
bool useDefaultWrist = true;
bool useDefaultFoot = true;
GRoleInventory equipment;
for(int i = 0; i < role.equipment.Count; i++)
{
equipment = role.equipment[i];
var equipData = elemendataman.get_data_ptr((uint)equipment.id, ID_SPACE.ID_SPACE_ESSENCE, ref DataType);
switch (DataType)
{
case DATA_TYPE.DT_WEAPON_ESSENCE:
if (equipData == null) break;
var weaponData = (WEAPON_ESSENCE)equipData;
string fileModelRight = AFile.NormalizePath(weaponData.FileModelRight, true).ToLower();
string fileModelLeft = AFile.NormalizePath(weaponData.FileModelLeft, true).ToLower();
GameObject weaponPrefab = null;
if (!string.IsNullOrEmpty(fileModelRight))
{
weaponPrefab = await AddressableManager.Instance.LoadPrefabAsync(fileModelRight);
var weaponObject = Instantiate(weaponPrefab);
if (weaponObject != null)
{
weaponObject.transform.SetParent(FindChildObjectRecursive(model.transform, CECPlayer._hh_right_hand_weapon).transform);
weaponObject.transform.localPosition = weaponPrefab.transform.localPosition;
weaponObject.transform.localRotation = weaponPrefab.transform.localRotation;
weaponObject.transform.localScale = Vector3.one;
weaponObject.SetActive(true);
}
}
if (!string.IsNullOrEmpty(fileModelLeft))
{
weaponPrefab = await AddressableManager.Instance.LoadPrefabAsync(fileModelLeft);
var weaponObject = Instantiate(weaponPrefab);
if (weaponObject != null)
{
weaponObject.transform.SetParent(FindChildObjectRecursive(model.transform, CECPlayer._hh_left_hand_weapon).transform);
weaponObject.transform.localPosition = weaponPrefab.transform.localPosition;
weaponObject.transform.localRotation = weaponPrefab.transform.localRotation;
weaponObject.transform.localScale = Vector3.one;
weaponObject.SetActive(true);
}
}
break;
case DATA_TYPE.DT_ARMOR_ESSENCE:
if (equipData == null) break;
var pArmor = (ARMOR_ESSENCE)equipData;
var nLocation = pArmor.equip_location;
// BMLogger.Log($"ShowEquipments():: Armor Essence: {pArmor.RealName}");
var armorSkinPath = CECPlayer._GenEquipmentSkinPath(role.occupation, role.gender, pArmor.RealName);
if (!armorSkinPath.EndsWith(".ecm"))
{
armorSkinPath += ".ecm";
}
var armorPrefab = await AddressableManager.Instance.LoadPrefabAsync(armorSkinPath);
if (armorPrefab != null)
{
var armorObject = Instantiate(armorPrefab);
armorObject.transform.SetParent(GetSkeletonBuilder(model)?.transform);
armorObject.transform.localPosition = Vector3.zero;
armorObject.transform.localRotation = Quaternion.identity;
armorObject.transform.localScale = Vector3.one;
var skinnedMeshRenderer = armorObject.GetComponent<SkinnedMeshRenderer>();
var skinnedMeshRenderereFromDataList = armorObject.GetComponentsInChildren<SkinnedMeshRenderFromData>();
foreach (var skinnedMeshRenderereFromData in skinnedMeshRenderereFromDataList)
{
if (skinnedMeshRenderereFromData != null)
{
skinnedMeshRenderereFromData._skinnedMeshRenderer.bones = GetSkeletonBuilder(model).GetBones(skinnedMeshRenderereFromData.BoneNames);
skinnedMeshRenderereFromData._skinnedMeshRenderer.rootBone = skinnedMeshRenderereFromData._skinnedMeshRenderer.bones[^1];
}
}
// disable/enable the default equipment
switch (nLocation)
{
case (uint)CECPlayer.SkinIndex.SKIN_UPPER_BODY_INDEX:
useDefaultUpper = false;
break;
case (uint)CECPlayer.SkinIndex.SKIN_LOWER_INDEX:
useDefaultLower = false;
break;
case (uint)CECPlayer.SkinIndex.SKIN_WRIST_INDEX:
useDefaultWrist = false;
break;
case (uint)CECPlayer.SkinIndex.SKIN_FOOT_INDEX:
useDefaultFoot = false;
break;
}
}
break;
//TODO: Handle Wings later
// case DATA_TYPE.DT_WINGMANWING_ESSENCE:
// m_wingType = enumWingType.WINGTYPE_WING;
// //ChangeWing(pResult, static_cast<const WINGMANWING_ESSENCE*>(pEquip)->file_model);
// var pWingData = (WINGMANWING_ESSENCE)equipData;
// //string path1 = "models/players/通用装备/翅膀/天鹅之翼/天鹅之翼_Test.ecm";
// //var pWingPrefab = await AddressableManager.Instance.LoadPrefabAsync(path1);
// var pWingPrefab = await AddressableManager.Instance.LoadPrefabAsync(pWingData.FileModel.ToLower().Replace('\\', '/'));
// //Transform parentWing = FindChildRecursive(_pPlayerModel.transform, "HH_chibang");
// if(pWingPrefab != null)
// {
// var pflySwordObject = Instantiate(pWingPrefab).transform;
// pflySwordObject.parent = m_pPlayerCECModel.m_skeletonBuilder.GetHook("HH_chibang").transform;
// pflySwordObject.localPosition = Vector3.zero;
// pflySwordObject.localRotation = Quaternion.identity;
// pflySwordObject.localScale = Vector3.one;
// m_Wing = pflySwordObject.transform;
// m_Wing.gameObject.SetActive(false);
// }
// BMLogger.Log($"ShowEquipments():: Wingman Wing Essence: {pWingData.id} {pWingData.Name} -- {pWingData.FileModel}");
// break;
default:
break;
switch (equipment.pos)
{
case InventoryConst.EQUIPIVTR_BODY:
useDefaultUpper = false;
break;
case InventoryConst.EQUIPIVTR_LEG:
useDefaultLower = false;
break;
case InventoryConst.EQUIPIVTR_WRIST:
useDefaultWrist = false;
break;
case InventoryConst.EQUIPIVTR_FOOT:
useDefaultFoot = false;
break;
}
}
}
playerDefaultEquipments.DefaultUpper.SetActive(useDefaultUpper);
playerDefaultEquipments.DefaultLower.SetActive(useDefaultLower);
playerDefaultEquipments.DefaultWirst.SetActive(useDefaultWrist);
playerDefaultEquipments.DefaultFoot.SetActive(useDefaultFoot);
return model;
}
private GameObject FindChildObjectRecursive(Transform parent, string name)
{
foreach (Transform child in parent)
{
if (child.name == name)
{
return child.gameObject;
}
var childObject = FindChildObjectRecursive(child, name);
if (childObject != null)
{
return childObject;
}
}
return null;
}
private SkeletonBuilder GetSkeletonBuilder(GameObject characterModel)
{
if (characterModel == null)
{
return null;
}
SkeletonBuilder skeletonBuilder = null;
if (skeletonBuilder == null)
{
skeletonBuilder = characterModel.GetComponentInChildren<SkeletonBuilder>();
}
return skeletonBuilder;
}
public void ReloadRoleModel(RoleInfo roleInfo)
{
if (roleInfo == null)
return;
ShowAllPlayerModels(new List<RoleInfo> { roleInfo });
ShowPlayerModel(roleInfo.roleid);
}
}
}