NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Gameplay/Emoji/UnitEmojiManager.cs

332 lines
11 KiB
C#

using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using Framework;
using Gameplay.Effect;
using PhxhSDK;
using UnityEngine;
using Constants = Framework.Constants;
namespace Gameplay.Emoji
{
public class UnitEmojiManager
{
// public readonly Character.Character character;
public GameObject rootObj;
private Material _matBg;
private Material _matUp;
private Material _matMid;
private Material _matDown;
private string _oldImgPathBg;
private string _oldImgPathUp;
private string _oldImgPathMid;
private string _oldImgPathDown;
private List<int> _emojiEffectIds;
private List<EffectPlayingData> _effectDatas;
private Color _eyeColor;
private Color _eyeBowColor;
private string _bowType;
private static readonly int MainColor = Shader.PropertyToID("_MainColor");
private static readonly int MaskTex = Shader.PropertyToID("_MaskTex");
private Skeleton _skeleton;
private Texture _cacheMaskTex;
private static readonly int MainTex = Shader.PropertyToID("_MainTex");
private static readonly int ShadowScale = Shader.PropertyToID("_shadowScale");
private static readonly int FaceTex = Shader.PropertyToID("_FaceTex");
private static readonly int SkinColor = Shader.PropertyToID("_SkinColor");
private static readonly int EyeColor = Shader.PropertyToID("_EyeColor");
private static readonly int EyeBrowColor = Shader.PropertyToID("_EyeBrowColor");
private Dictionary<string, int> _cacheLoadCount = new Dictionary<string, int>();
public bool forceTop;
private static readonly int ZTest = Shader.PropertyToID("_ZTest");
internal UnitEmojiManager(GameObject obj,
string eyeColor,
string bowType,
string eyebowColor, bool forceTop = false)
{
// Character_1
rootObj = obj;
_eyeColor = ColorUtility.TryParseHtmlString(eyeColor, out var color) ? color : Color.white;
_eyeBowColor = ColorUtility.TryParseHtmlString(eyebowColor, out var color2) ? color2 : Color.white;
_bowType = bowType;
if (obj.transform.childCount <= 0)
{
DebugUtil.LogError("节点不匹配:" + obj.name);
return;
}
var collectorTrans = obj.transform.GetChild(0);
var collector = new ComponentCollector(collectorTrans.gameObject);
_skeleton = new Skeleton(collector.Transforms, obj.transform);
this.forceTop = forceTop;
_BindObj();
}
public void Dispose()
{
if (_cacheMaskTex != null)
{
Object.Destroy(_cacheMaskTex);
_cacheMaskTex = null;
}
_UnloadLoadTextures();
}
private void _UnloadLoadTextures()
{
foreach (var kv in _cacheLoadCount)
{
var path = kv.Key;
var count = kv.Value;
for (var i = 0; i < count; ++i)
{
AssetManager.Instance.Unload(path);
}
}
}
private void _BindObj()
{
var emojiObj = _skeleton.GetBone("F_emoji");
if (emojiObj != null)
{
// 删除
Object.Destroy(emojiObj.gameObject);
}
var newEmojiObj = _skeleton.GetBone("G_emoji");
if (newEmojiObj == null)
{
DebugUtil.LogError($"模型 {rootObj.name} 找不到表情的骨骼:G_emoji");
return;
}
rootObj = newEmojiObj.gameObject;
var meshRender = rootObj.GetComponentInChildren<MeshRenderer>();
// 这里直接去Inst的
var mats = meshRender.sharedMaterials;
if (mats.Length != 4)
{
DebugUtil.LogError("表情的材质球数量不对");
return;
}
_matUp = Object.Instantiate(mats[0]);
// 设置_ZTest
if (forceTop)
{
_matUp.SetInt(ZTest, (int)UnityEngine.Rendering.CompareFunction.Always);
}
else
{
_matUp.SetInt(ZTest, (int)UnityEngine.Rendering.CompareFunction.LessEqual);
}
_matMid = Object.Instantiate(mats[1]);
// 设置_ZTest
if (forceTop)
{
_matMid.SetInt(ZTest, (int)UnityEngine.Rendering.CompareFunction.Always);
}
else
{
_matMid.SetInt(ZTest, (int)UnityEngine.Rendering.CompareFunction.LessEqual);
}
_matDown = Object.Instantiate(mats[2]);
_matBg = Object.Instantiate(mats[3]);
meshRender.materials = new[]
{
_matUp, _matMid, _matDown, _matBg
};
_emojiEffectIds = new List<int>();
_effectDatas = new List<EffectPlayingData>();
}
public void Show()
{
if (rootObj == null)
{
DebugUtil.LogError("表情的根节点为空");
return;
}
if (rootObj.activeSelf) return;
rootObj.SetActive(true);
}
public void Hide()
{
if (!rootObj.activeSelf) return;
rootObj.SetActive(false);
}
private bool _CheckIsEmpty(string imgName)
{
if (string.IsNullOrEmpty(imgName)) return true;
if (imgName == "0") return true;
if (!int.TryParse(imgName, out var result))
{
return true;
}
if (result == 0)
{
return true;
}
return false;
}
private string _GetFixNum(string imgName)
{
if (imgName.Length < 2)
{
return "0" + imgName;
}
return imgName;
}
private async UniTask<T> _LoadTexture<T>(string imgPath) where T : Texture
{
if (_cacheLoadCount.ContainsKey(imgPath))
{
_cacheLoadCount[imgPath]++;
}
else
{
_cacheLoadCount[imgPath] = 1;
}
return await AssetManager.Instance.LoadAssetAsync<T>(imgPath);
}
public async void SwitchEmoji(int emojiId)
{
if (_matUp == null) return;
if (emojiId == 0) return;
#if UNITY_EDITOR
var emojiCfg = EditorTableManager.instance.tables.EmojiConfig.Get(emojiId);
#else
var emojiCfg = TableManager.Instance.Tables.EmojiConfig.Get(emojiId);
#endif
if (emojiCfg == null)
{
DebugUtil.LogError("无效的emojiId:{0}", emojiId);
return;
}
// 眉毛 T_emoji_eyebows_1_01
// 眼睛 T_emoji_eyes_01
// 嘴巴 T_emoji_mouth_01
// 背景 T_emoji_acc_01
const string emptyPath = "T_emoji_empty";
const string prefix = "Assets/Art/Character/Models/Emoji/Tex/";
var imgPathBg = _CheckIsEmpty(emojiCfg.BgImg) ? emptyPath : $"T_emoji_acc_{_GetFixNum(emojiCfg.BgImg)}";
var imgPathUp = _CheckIsEmpty(emojiCfg.UpImg) ? emptyPath : $"T_emoji_eyebows_{_bowType}_{_GetFixNum(emojiCfg.UpImg)}";
var imgPathUpMask = _CheckIsEmpty(emojiCfg.UpImg) ? emptyPath : $"T_emoji_eyebows_{_bowType}_{_GetFixNum(emojiCfg.UpImg)}_mask";
var imgPathMid = _CheckIsEmpty(emojiCfg.MidImg) ? emptyPath : $"T_emoji_eyes_{_GetFixNum(emojiCfg.MidImg)}";
var imgPathMidMask = _CheckIsEmpty(emojiCfg.MidImg) ? emptyPath : $"T_emoji_eyes_{_GetFixNum(emojiCfg.MidImg)}_mask";
var imgPathDown = _CheckIsEmpty(emojiCfg.DownImg) ? emptyPath : $"T_emoji_mouth_{_GetFixNum(emojiCfg.DownImg)}";
imgPathBg = prefix + imgPathBg + ".png";
imgPathUp = prefix + imgPathUp + ".png";
imgPathMid = prefix + imgPathMid + ".png";
imgPathDown = prefix + imgPathDown + ".png";
imgPathMidMask = prefix + imgPathMidMask + ".png";
imgPathUpMask = prefix + imgPathUpMask + ".png";
if (_oldImgPathBg != imgPathBg)
{
_oldImgPathBg = imgPathBg;
_matBg.mainTexture = await _LoadTexture<Texture>(imgPathBg);
}
if (_oldImgPathUp != imgPathUp)
{
_oldImgPathUp = imgPathUp;
var isWithMask = AssetManager.Instance.CanLocateAsset<Texture>(imgPathUpMask);
if (isWithMask)
{
var maskTex = await _LoadTexture<Texture>(imgPathUpMask);
_matUp.SetTexture(MaskTex, maskTex);
}
else
{
_matUp.SetTexture(MaskTex, null);
}
_matUp.mainTexture = await _LoadTexture<Texture>(imgPathUp);
_matUp.SetColor(MainColor, _eyeBowColor);
}
if (_oldImgPathMid != imgPathMid)
{
_oldImgPathMid = imgPathMid;
var isWithMask = AssetManager.Instance.CanLocateAsset<Texture>(imgPathMidMask);
if (isWithMask)
{
var maskTex = await _LoadTexture<Texture>(imgPathMidMask);
_matMid.SetTexture(MaskTex, maskTex);
}
else
{
_matMid.SetTexture(MaskTex, null);
}
_matMid.mainTexture = await _LoadTexture<Texture>(imgPathMid);
_matMid.SetColor(MainColor, _eyeColor);
}
if (_oldImgPathDown != imgPathDown)
{
_oldImgPathDown = imgPathDown;
_matDown.mainTexture = await _LoadTexture<Texture>(imgPathDown);
}
// 特效的判定
var effectIds = emojiCfg.EffectIds;
var isSame = _CheckSame(effectIds, _emojiEffectIds);
if (!isSame)
{
// 销毁旧的
for (var i = 0; i < _effectDatas.Count; ++i)
{
var effectData = _effectDatas[i];
effectData.Destroy();
}
_effectDatas.Clear();
_emojiEffectIds = effectIds;
if (Application.isPlaying)
{
// 获取特效
for (var i = 0; i < _emojiEffectIds.Count; ++i)
{
var effectId = _emojiEffectIds[i];
var effectData = EffectManager.instance.PlayEffectById(effectId, rootObj.transform.position, rootObj.transform.rotation, rootObj.transform);
_effectDatas.Add(effectData);
}
}
}
Show();
}
private static bool _CheckSame(IReadOnlyList<int> a,
IReadOnlyList<int> b)
{
if (a.Count != b.Count) return false;
for (var i = 0; i < a.Count; ++i)
{
if (a[i] != b[i]) return false;
}
return true;
}
}
}