NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/GameWrapper/Team/TeamPreviewNode.cs

693 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using System;
using UnityEngine;
using UnityEngine.Playables;
using Cysharp.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;
using Framework;
using Random = UnityEngine.Random;
using GameWrapper.Team;
using PhxhSDK;
using Constants = Framework.Constants;
public class TeamPreviewNode : MonoBehaviour
{
private const string VehicleBatteryPointName = "Battery_point01";
private const string DEFAULT_SKINID_KEY = "DefaultSkinID";
private const int DEFAULT_SKIN_ID = 1;
public Transform[] characterPos;
public Transform[] vehiclesPos;
public Transform cRoot;
public Transform vRoot;
public RenderTexture RTexture => _rTexture;
private Dictionary<int, GameObject> _vehicleDic;
private Dictionary<int, GameObject> _characterDic;
private uint[] _vehicleIDs;
private uint[] _charIDs;
private bool _isLoading;
private int _teamIdx;
private bool _isReleasing;
private RenderTexture _rTexture;
private Dictionary<string, int> _assetsLoadDic = new Dictionary<string, int>();
private List<object> _emojiMgrList = new List<object>();
#region Static
public static async UniTask<TeamPreviewNode> LoadNode()
{
var prefab = await AssetManager.Instance.LoadAssetAsync<GameObject>(Framework.Constants.TEAM_EDIT_PREFAB_PATH);
var go = Instantiate(prefab, Vector3.up, Quaternion.identity);
var component = go.GetComponent<TeamPreviewNode>();
return component;
}
public static void ReleaseNode(TeamPreviewNode node)
{
node.ReleaseRt();
node.RestoreOriginalShaders();
Destroy(node.gameObject);
}
private void ReleaseRt()
{
if (_rTexture)
{
RenderTexturePool.Instance.Destroy(_rTexture);
_rTexture = null;
}
}
#endregion
#region MainLife
private void Awake()
{
_characterDic = new Dictionary<int, GameObject>();
_vehicleDic = new Dictionary<int, GameObject>();
EventManager.Instance.Register(EventManager.EventName.TeamEditCharacterModelCreate,
(Action<CharAddData>)OnCharModelCreate);
EventManager.Instance.Register(EventManager.EventName.TeamEditCharacterModelClear,
(Action<int>)OnCharModelClear);
EventManager.Instance.Register(EventManager.EventName.TeamEditVehicleModelCreate,
(Action<VehicleAddData>)OnVehicleModelCreate);
EventManager.Instance.Register(EventManager.EventName.TeamEditVehicleModelClear,
(Action<int>)OnVehicleModelClear);
EventManager.Instance.Register(EventManager.EventName.TeamEditAllModelClear, ClearAllGo);
EventManager.Instance.Register<ValueTuple<int, bool>>(EventManager.EventName.TeamEditModelUpdate, RefreshNode);
EventManager.Instance.Register(EventManager.EventName.TeamCameraSet, _OnTeamEditCameraSet);
}
private void OnDestroy()
{
EventManager.Instance.Unregister(EventManager.EventName.TeamEditCharacterModelCreate,
(Action<CharAddData>)OnCharModelCreate);
EventManager.Instance.Unregister(EventManager.EventName.TeamEditCharacterModelClear,
(Action<int>)OnCharModelClear);
EventManager.Instance.Unregister(EventManager.EventName.TeamEditVehicleModelCreate,
(Action<VehicleAddData>)OnVehicleModelCreate);
EventManager.Instance.Unregister(EventManager.EventName.TeamEditVehicleModelClear,
(Action<int>)OnVehicleModelClear);
EventManager.Instance.Unregister(EventManager.EventName.TeamEditAllModelClear, ClearAllGo);
EventManager.Instance.Unregister<ValueTuple<int, bool>>(EventManager.EventName.TeamEditModelUpdate,
RefreshNode);
EventManager.Instance.Unregister(EventManager.EventName.TeamCameraSet, _OnTeamEditCameraSet);
UnLoad();
AssetManager.Instance.Unload(Constants.TEAM_EDIT_PREFAB_PATH);
}
private void UnLoad()
{
foreach (var kv in _assetsLoadDic)
{
var path = kv.Key;
AssetManager.Instance.Unload(path);
}
foreach (var emojiMgr in _emojiMgrList)
{
TeamServiceHandle.CharacterService.DisposeEmojiManager(emojiMgr);
}
_emojiMgrList.Clear();
_characterDic.Clear();
_vehicleDic.Clear();
}
private void ClearObjs()
{
foreach (Transform child in cRoot)
{
Destroy(child.gameObject);
}
foreach (Transform child in vRoot)
{
Destroy(child.gameObject);
}
_characterDic.Clear();
_vehicleDic.Clear();
}
#endregion
#region 对外方法
/// <summary>
/// 刷新节点
/// </summary>
public async UniTask Refresh()
{
ClearObjs();
var teamCamera = TeamServiceHandle.TeamEditCameraObj.teamEditCamera;
teamCamera.targetTexture = _rTexture;
for (var i = 0; i < _charIDs.Length; i++)
{
var id = _charIDs[i];
var isValid = TeamServiceHandle.CharacterService.CharacterDataDicContainsKey(id);
if (isValid)
{
var trans = characterPos[i];
if (!_isLoading)
{
_isLoading = true;
await AddCharacterGo(trans, id, i);
}
}
}
for (var i = 0; i < _vehicleIDs.Length; i++)
{
var id = _vehicleIDs[i];
var isValid = TeamServiceHandle.VehicleService.VehicleDataDicContainsKey(id);
if (isValid)
{
var trans = vehiclesPos[i];
if (!_isLoading)
{
_isLoading = true;
await AddVehicleGo(trans, id, i);
}
}
}
_isLoading = false;
}
public void SetData(int teamIdx, uint[] charIDs, uint[] vehicleIDs)
{
_teamIdx = teamIdx;
_charIDs = (uint[])charIDs.Clone();
_vehicleIDs = vehicleIDs;
}
public void CreateRt()
{
if (!_rTexture)
{
_rTexture = RenderTexturePool.Instance.Create("TeamPreviewNode", Screen.width,
Screen.height);
}
}
public void Clear()
{
ClearAllGo();
_rTexture.Release();
}
#endregion
#region 加载模型
/// <summary>
/// 添加角色模型
/// </summary>
async UniTask AddCharacterGo(Transform trans, uint id, int idx)
{
var charData = TeamServiceHandle.CharacterService.GetCharacterData(id);
// 获取角色配置信息
var charCfg = GetField<object>(charData, "Cfg");
var skinID = GetField<uint>(charData, "SkinID") > 0
? (int)GetField<uint>(charData, "SkinID")
: GetDefaultSkinId();
var roleID = GetField<int>(charCfg, "RoleID");
var data = TeamServiceHandle.TableService.GetSkinConfig(skinID, roleID);
if (data != null)
{
var nameID = GetField<string>(data, "NameID");
var prefabPath = TeamServiceHandle.CharacterService.GetCharacterDisplayModelPath(nameID);
var prefab = await AssetManager.Instance.LoadAssetAsync<GameObject>(prefabPath);
_assetsLoadDic.TryAdd(prefabPath, (int)id);
if (!trans)
{
return;
}
var go = Instantiate(prefab, trans.position, trans.rotation, cRoot.transform);
if (go)
{
_characterDic[idx] = go;
// TODO 层级优化
go.SetLayerEx(9);
var anim = go.GetComponentInChildren<Animator>();
var playableDir = go.GetComponent<PlayableDirector>();
if (playableDir)
{
playableDir.enabled = false;
}
if (anim)
{
int randomIdx = Random.Range(0, 3);
switch (randomIdx)
{
case 1:
{
anim.Play("standready001");
break;
}
case 2:
{
anim.Play("standready001");
break;
}
default:
{
anim.Play("squatready001");
break;
}
}
}
// 处理角色表情
object charSingleData = null;
if (TeamServiceHandle.TableService.TryGetCharacterAttriData((int)id, out var data2))
{
charSingleData = data2;
var eyesColor = GetField<string>(charSingleData, "EmojiEyesColor");
var eyeBrowsType = GetField<string>(charSingleData, "EmojiEyeBowsType");
var eyeBrowsColor = GetField<string>(charSingleData, "EmojiEyeBowsColor");
var defaultEmojiId = GetField<int>(charSingleData, "DefaultDisplayEmojiId");
var emojiMgr = TeamServiceHandle.CharacterService.CreateEmojiManager(
go, eyesColor, eyeBrowsType, eyeBrowsColor, true);
TeamServiceHandle.CharacterService.SwitchEmoji(emojiMgr, defaultEmojiId);
_emojiMgrList.Add(emojiMgr);
}
}
}
_isLoading = false;
}
/// <summary>
/// 添加载具模型
/// </summary>
async UniTask AddVehicleGo(Transform trans, uint id, int idx)
{
var vehicleData = TeamServiceHandle.VehicleService.GetVehicleData(id);
if (vehicleData != null)
{
var vehicleCfg = GetField<object>(vehicleData, "Cfg");
var vehicleId = GetField<int>(vehicleCfg, "ID");
var prefabPath = TeamServiceHandle.VehicleService.GetVehicleGameModelPath(vehicleId);
var prefab = await AssetManager.Instance.LoadAssetAsync<GameObject>(prefabPath);
ApplyVehicleShader(prefab);
_assetsLoadDic.TryAdd(prefabPath, (int)id);
if (!trans) return;
var go = Instantiate(prefab, trans.position, trans.rotation, vRoot.transform);
if (go)
{
_vehicleDic[idx] = go;
// TODO 层级优化
go.SetLayerEx(9);
go.transform.localScale = new Vector3(1.5f, 1.5f, 1.5f);
// 炮台部分
var config = TeamServiceHandle.VehicleService.CombineConfigData(vehicleData);
// 获取武器ID
var weaponId = GetField<long>(config, "weaponId");
// 炮台挂点
var allTrans = go.GetComponentsInChildren<Transform>();
var fireTrans = allTrans.First(t => t.name == VehicleBatteryPointName);
var rawConfig = TeamServiceHandle.TableService.GetBatteryConfig(weaponId);
var modelPath = GetField<string>(rawConfig, "ModelPath");
var batteryPath = TeamServiceHandle.VehicleService.GetBatteryModelPath(modelPath);
var sampleObj = await AssetManager.Instance.LoadAssetAsync<GameObject>(batteryPath);
if (sampleObj != null)
{
var rootObj = UnityEngine.Object.Instantiate(sampleObj, fireTrans);
// TODO 层级优化
go.SetLayerEx(9);
rootObj.transform.localPosition = Vector3.zero;
rootObj.transform.localRotation = Quaternion.identity;
rootObj.transform.localScale = Vector3.one;
}
else
{
Debug.LogError($"加载炮台失败: {batteryPath}");
}
//设置涂装
var vehicleDev = TeamServiceHandle.VehicleService.GetVehicleDevelopment(id);
var paintCfg = GetField<int[]>(vehicleDev, "paint_set");
if (paintCfg != null)
{
for (int i = 1; i < (int)TeamPaintType.Max; i++)
{
var paintID = paintCfg[i];
if (paintID == 0)
continue;
var paintPath = TeamServiceHandle.VehicleService.GetVehiclePaintPath((int)id, paintID);
//加载涂装材质球
var material = await TeamServiceHandle.VehicleService.GetVehiclePaintMaterial(paintPath);
var root = TeamServiceHandle.VehicleService.FindVehiclePartRoot(go, (int)id, (TeamPaintType)i);
if (material != null && root != null)
{
var instanceMaterial = new Material(material);
var renderers = root.GetComponent<SkinnedMeshRenderer>();
renderers.materials = new Material[] { instanceMaterial };
}
}
}
else
Debug.LogError("载具涂装配置为空!");
}
}
_isLoading = false;
}
/// <summary>
/// 设置游戏对象及其子对象的层级
/// </summary>
private void SetLayerRecursively(GameObject obj, int layer)
{
obj.layer = layer;
foreach (Transform child in obj.transform)
{
SetLayerRecursively(child.gameObject, layer);
}
}
/// <summary>
/// 更换模型shader
/// </summary>
private void ChangeModelShader(GameObject prefab)
{
var vehicleShader = TeamServiceHandle.TeamService.GetVehicleShader();
var vehicleRenderers = prefab.GetComponentsInChildren<Renderer>(true);
if (vehicleShader != null)
{
foreach (var vehicleRenderer in vehicleRenderers)
{
foreach (var material in vehicleRenderer.sharedMaterials)
{
material.shader = vehicleShader;
}
}
}
}
private Dictionary<Renderer, Shader[]> originalShaderDic = new Dictionary<Renderer, Shader[]>();
/// <summary>
/// 替换Shader并缓存原始Shader 用于解决场景切换后模型蒙上未知来源阴影
/// </summary>
private void ApplyVehicleShader(GameObject prefab)
{
var vehicleShader = TeamServiceHandle.TeamService.GetVehicleShader();
if (vehicleShader == null) return;
var vehicleRenderers = prefab.GetComponentsInChildren<Renderer>(true);
foreach (var vehicleRenderer in vehicleRenderers)
{
if (!originalShaderDic.ContainsKey(vehicleRenderer))
{
var originalShaders = new Shader[vehicleRenderer.sharedMaterials.Length];
for (int i = 0; i < vehicleRenderer.sharedMaterials.Length; i++)
{
originalShaders[i] = vehicleRenderer.sharedMaterials[i].shader;
}
originalShaderDic[vehicleRenderer] = originalShaders;
}
// 替换 Shader
foreach (var mat in vehicleRenderer.sharedMaterials)
{
mat.shader = vehicleShader;
}
}
}
/// <summary>
/// 还原Shader
/// </summary>
private void RestoreOriginalShaders()
{
foreach (var kvp in originalShaderDic)
{
var origRenderer = kvp.Key;
var originalShaders = kvp.Value;
var materials = origRenderer.sharedMaterials;
for (int i = 0; i < materials.Length && i < originalShaders.Length; i++)
{
materials[i].shader = originalShaders[i];
}
}
originalShaderDic.Clear();
}
/// <summary>
/// 根据索引加载角色模型
/// </summary>
private async UniTask LoadCharacterModel(uint id, int idx)
{
if (idx < 0) return;
if (_isLoading) return;
if (_charIDs[idx] != id)
{
ClearCharacterGo(idx);
_charIDs[idx] = id;
_isLoading = true;
await AddCharacterGo(characterPos[idx], id, idx);
}
}
/// <summary>
/// 根据索引加载载具模型
/// </summary>
private async UniTask LoadVehicleModel(uint id, int idx)
{
if (idx < 0) return;
if (_isLoading) return;
if (_vehicleIDs[idx] != id)
{
ClearVehicleGo(idx);
_vehicleIDs[idx] = id;
_isLoading = true;
await AddVehicleGo(vehiclesPos[idx], id, idx);
}
}
#endregion
#region 清除模型
/// <summary>
/// 指挥官清空后使用
/// </summary>
private void ClearAllGo()
{
for (int i = 0; i < characterPos.Length; i++)
{
ClearCharacterGo(i);
}
for (int i = 0; i < vehiclesPos.Length; i++)
{
ClearVehicleGo(i);
}
}
private void ClearCharacterGo(int idx)
{
if (_isLoading)
{
return;
}
_isLoading = true;
if (_characterDic.TryGetValue(idx, out var go))
{
if (go)
{
DestroyImmediate(go);
_charIDs[idx] = TeamServiceHandle.TeamService.GetTeamNoneID();
_characterDic.Remove(idx);
}
}
_isLoading = false;
}
private void ClearVehicleGo(int idx)
{
if (_isLoading)
{
return;
}
_isLoading = true;
if (_vehicleDic.TryGetValue(idx, out var go))
{
if (go)
{
DestroyImmediate(go);
_vehicleIDs[idx] = TeamServiceHandle.TeamService.GetTeamNoneID();
_vehicleDic.Remove(idx);
}
}
_isLoading = false;
}
#endregion
#region 事件监听
private async void RefreshNode(ValueTuple<int, bool> data)
{
var team = TeamServiceHandle.TeamService.GetTeamByIndex(data.Item1, data.Item2);
if (team == null) return;
var charIDs = TeamServiceHandle.TeamService.GetAllCharacters(team);
var vehicleIDs = TeamServiceHandle.TeamService.GetVehicleIDs(team);
SetData(data.Item1, charIDs, vehicleIDs);
await Refresh();
}
private async void OnCharModelCreate(CharAddData charAddData)
{
await LoadCharacterModel(charAddData.ID, charAddData.Idx);
}
private void OnCharModelClear(int idx)
{
if (idx >= 0)
{
ClearCharacterGo(idx);
}
}
private async void OnVehicleModelCreate(VehicleAddData vehicleAddData)
{
await LoadVehicleModel(vehicleAddData.ID, vehicleAddData.Idx);
}
private void OnVehicleModelClear(int idx)
{
if (idx >= 0)
{
ClearVehicleGo(idx);
}
}
private void _OnTeamEditCameraSet()
{
if (TeamServiceHandle.TeamEditCameraObj != null && TeamServiceHandle.TeamEditCameraObj.teamEditCamera != null)
{
TeamServiceHandle.TeamEditCameraObj.SetCameraAntialiasing(
TeamServiceHandle.TeamEditCameraObj.teamEditCamera);
}
}
#endregion
#region Helpers
private int GetDefaultSkinId()
{
return DEFAULT_SKIN_ID;
}
// 通过反射获取对象字段值
// 通过反射获取对象字段值,添加更健壮的类型转换
private T GetField<T>(object obj, string fieldName)
{
if (obj == null) return default;
try
{
var field = obj.GetType().GetField(fieldName);
if (field != null)
{
var value = field.GetValue(obj);
if (value == null) return default;
// 尝试直接转换
if (value is T typedValue)
return typedValue;
// 尝试从其他类型转换
try
{
return (T)Convert.ChangeType(value, typeof(T));
}
catch
{
Debug.LogWarning($"无法将类型 {value.GetType()} 转换为 {typeof(T)} - 字段名: {fieldName}");
return default;
}
}
var property = obj.GetType().GetProperty(fieldName);
if (property != null)
{
var value = property.GetValue(obj);
if (value == null) return default;
// 尝试直接转换
if (value is T typedValue)
return typedValue;
// 尝试从其他类型转换
try
{
return (T)Convert.ChangeType(value, typeof(T));
}
catch
{
Debug.LogWarning($"无法将类型 {value.GetType()} 转换为 {typeof(T)} - 属性名: {fieldName}");
return default;
}
}
Debug.LogWarning($"对象 {obj.GetType()} 中未找到字段或属性: {fieldName}");
return default;
}
catch (Exception ex)
{
Debug.LogError($"从对象 {obj.GetType()} 获取字段 {fieldName} 时发生异常: {ex.Message}");
return default;
}
}
#endregion
}