using BrewMonster; using BrewMonster.Managers; using BrewMonster.Network; using CSNetwork.GPDataType; using PerfectWorld.Scripts.Managers.BrewMonster.Managers; using System; using System.Collections.Generic; using UnityEngine; namespace BrewMonster { public class CECSkillGfxEvent : A3DSkillGfxEvent { protected EC_ManPlayer m_pPlayerMan; // 玩家管理器 / Player manager protected CECNPCMan m_pNPCMan; // NPC管理器 / NPC manager public CECSkillGfxEvent(GfxMoveMode mode) : base(mode) { m_pPlayerMan = EC_ManMessageMono.Instance?.GetECManPlayer; m_pNPCMan = EC_ManMessageMono.Instance?.CECNPCMan; } /// /// Get the skill GFX composer /// 获取技能特效组合器 /// public A3DSkillGfxComposer GetComposer() { return m_pComposer; } /// /// Get the original host ID (considering reverse mode) /// 获取原始施法者ID(考虑反向模式) /// /* public long GetOriginalHost() { // GFX 特效显示,技能的原始的攻击者和目标被位置,提供了方法,查询原始攻击者 // GFX effects display, original attacker and target positions swapped, provides method to query original attacker return m_pMoveMethod.IsReverse() ? m_nTargetID : m_nHostID; } /// /// Get the original target ID (considering reverse mode) /// 获取原始目标ID(考虑反向模式) /// public long GetOriginalTarget() { // GFX 特效显示,技能的原始的攻击者和目标被位置,提供了方法,查询原始目标 // GFX effects display, original attacker and target positions swapped, provides method to query original target return m_pMoveMethod.IsReverse() ? m_nHostID : m_nTargetID; }*/ /// /// Get target direction and up vector /// 获取目标方向和上向量 /// public override bool GetTargetDirAndUp(out Vector3 vDir, out Vector3 vUp) { if (!m_bTargetDirAndUpExist) { vDir = Vector3.zero; vUp = Vector3.zero; return false; } vDir = m_vTargetDir; vUp = m_vTargetUp; return true; } /// /// Get target center position /// 获取目标中心位置 /// public override Vector3 GetTargetCenter() { Vector3 vTargetCenter = Vector3.zero; // if composer has been set // use the composer's parameter to make the hook information affect. // 如果已设置组合器,使用组合器的参数来影响挂点信息 if (GetComposer() != null) { A3DSkillGfxComposer pComposer = GetComposer(); _get_pos_by_id( m_pPlayerMan, m_pNPCMan, (int)m_nTargetID, out vTargetCenter, pComposer.m_HitPos.HitPos, false, pComposer.m_HitPos.szHook, pComposer.m_HitPos.bRelHook, pComposer.m_HitPos.vOffset, pComposer.m_HitPos.szHanger, pComposer.m_HitPos.bChildHook); } else { _get_pos_by_id( m_pPlayerMan, m_pNPCMan, (int)m_nTargetID, out vTargetCenter, GfxHitPos.enumHitCenter, false, null, false, Vector3.zero, null, false); } return vTargetCenter; } /// /// Tick update /// 更新 /// public override void Tick(uint dwDeltaTime) { /*if (GetComposer() != null) { SGC_POS_INFO pHostPos, pTargetPos; if (m_pMoveMethod.IsReverse()) { pHostPos = m_pComposer.m_FlyEndPos; pTargetPos = m_pComposer.m_FlyPos; } else { pHostPos = m_pComposer.m_FlyPos; pTargetPos = m_pComposer.m_FlyEndPos; } m_bHostExist = _get_pos_by_id( m_pPlayerMan, m_pNPCMan, (int)m_nHostID, out m_vHostPos, pHostPos.HitPos, m_bIsGoblinSkill, pHostPos.szHook, pHostPos.bRelHook, pHostPos.vOffset, pHostPos.szHanger, pHostPos.bChildHook); m_bTargetExist = _get_pos_by_id( m_pPlayerMan, m_pNPCMan, (int)m_nTargetID, out m_vTargetPos, pTargetPos.HitPos, false, pTargetPos.szHook, pTargetPos.bRelHook, pTargetPos.vOffset, pTargetPos.szHanger, pTargetPos.bChildHook); m_bTargetDirAndUpExist = _get_dir_and_up_by_id(m_pPlayerMan, m_pNPCMan, (int)m_nTargetID, out m_vTargetDir, out m_vTargetUp); } else { m_bHostExist = _get_pos_by_id( m_pPlayerMan, m_pNPCMan, (int)m_nHostID, out m_vHostPos, m_pMoveMethod.GetHitPos(), m_bIsGoblinSkill, null, false, Vector3.zero, null, false); m_bTargetExist = _get_pos_by_id( m_pPlayerMan, m_pNPCMan, (int)m_nTargetID, out m_vTargetPos, m_pMoveMethod.GetHitPos(), false, null, false, Vector3.zero, null, false); }*/ base.Tick(dwDeltaTime); } /// /// Handle target hit event /// 处理命中目标事件 /// protected override void HitTarget(Vector3 vTarget) { base.HitTarget(vTarget); // now show some special hit gfx // 现在显示一些特殊的命中特效 /* if (CECOptimize.Instance.GetGFX().CanShowHit(GetOriginalHost())) { if ((m_dwModifier & CECAttackEvent.MOD_PHYSIC_ATTACK_RUNE) != 0) { // 程序联入\\符石\\物攻符石特效.gfx // Program integration\\Rune\\Physical attack rune effect.gfx // TODO: Play GFX - g_pGame->GetGFXCaster()->PlayAutoGFXEx(...) } if ((m_dwModifier & CECAttackEvent.MOD_MAGIC_ATTACK_RUNE) != 0) { // 程序联入\\符石\\法攻符石特效.gfx // Program integration\\Rune\\Magic attack rune effect.gfx // TODO: Play GFX } if ((m_dwModifier & CECAttackEvent.MOD_PHYSIC_DEFENCE_RUNE) != 0) { // 程序联入\\符石\\物防符石特效.gfx // Program integration\\Rune\\Physical defense rune effect.gfx // TODO: Play GFX } if ((m_dwModifier & CECAttackEvent.MOD_MAGIC_DEFENCE_RUNE) != 0) { // 程序联入\\符石\\法防符石特效.gfx // Program integration\\Rune\\Magic defense rune effect.gfx // TODO: Play GFX } }*/ } /// /// Load hit GFX with modifier checks /// 加载命中特效(带修饰符检查) /// /*public A3DGFXEx LoadHitGfx(A3DDevice pDev, string szPath) { if ((m_dwModifier & CECAttackEvent.MOD_NULLITY) != 0) { // 程序联入\\击中\\无效攻击击中.gfx // Program integration\\Hit\\Invalid attack hit.gfx szPath = "程序联入\\击中\\无效攻击击中.gfx"; } // TODO: return AfxGetGFXExMan()->LoadGfx(pDev, szPath); return null; }*/ /// /// Set hit GFX /// 设置命中特效 /// /*public void SetHitGfx(A3DGFXEx pHitGfx) { // if (m_dwModifier & CECAttackEvent::MOD_CRITICAL_STRIKE) // pHitGfx->SetActualScale(pHitGfx->GetScale() * 2.0f); m_pHitGfx = pHitGfx; }*/ // ===== Helper functions (static) ===== // 辅助函数(静态) /// /// Get position by ID (player or NPC) /// 根据ID获取位置(玩家或NPC) /// private static bool _get_pos_by_id( EC_ManPlayer pPlayerMan, CECNPCMan pNPCMan, int nID, out Vector3 vPos, GfxHitPos HitPos, bool bIsGoblinSkill = false, string szHook = null, bool bRelHook = false, Vector3 pOffset = default, string szHanger = null, bool bChildHook = false) { vPos = Vector3.zero; if (GPDataTypeHelper.ISPLAYERID(nID)) { CECPlayer pPlayer = pPlayerMan?.GetPlayer(nID); if (pPlayer != null) { if (bIsGoblinSkill) { // TODO: Handle goblin skill position // if (pPlayer->GetGoblinModel()) // vPos = pPlayer->GetGoblinModel()->GetModel()->GetModelAABB().Center; // else // return false; return false; } else { // currently hook does not affect the Goblin Skill // 目前挂点不影响小精灵技能 while (true) { if (string.IsNullOrEmpty(szHook)) break; // TODO: Get player model and hook position /*CECModel pModel = pPlayer->GetPlayerModel(); if (!pModel) break; if (szHanger && bChildHook) pModel = pModel->GetChildModel(szHanger); if (!pModel) break; A3DSkinModel* pSkin = pModel->GetA3DSkinModel(); A3DSkeletonHook* pHook = pSkin->GetSkeletonHook(szHook, true); if (!pHook) break; if (bRelHook) vPos = pHook->GetAbsoluteTM() * pOffset; else { vPos = pSkin->GetAbsoluteTM() * pOffset; vPos = vPos - pSkin->GetAbsoluteTM().GetRow(3) + pHook->GetAbsoluteTM().GetRow(3); } return true;*/ break; } if (HitPos == GfxHitPos.enumHitBottom) { vPos = pPlayer.GetPosVector3(); } else { // TODO: Get player AABB // const A3DAABB& aabb = pPlayer->GetPlayerAABB(); // vPos = aabb.Center; // vPos.y += aabb.Extents.y * .5f; vPos = pPlayer.GetPosVector3(); vPos.y += 1.0f; // Default height offset / 默认高度偏移 } } return true; } } else if (GPDataTypeHelper.ISNPCID(nID)) { CECNPC pNPC = pNPCMan?.GetNPCFromAll(nID); if (pNPC != null) { while (true) { // TODO: Get NPC hook position /*A3DSkeletonHook* pHook = pNPC->GetSgcHook(szHanger, bChildHook, szHook); if (!pHook) break; A3DSkinModel *pSkin = pNPC->GetSgcSkinModel(szHanger, bChildHook, szHook); if (bRelHook) vPos = pHook->GetAbsoluteTM() * pOffset; else { vPos = pSkin->GetAbsoluteTM() * pOffset; vPos = vPos - pSkin->GetAbsoluteTM().GetRow(3) + pHook->GetAbsoluteTM().GetRow(3); } return true;*/ break; } if (HitPos == GfxHitPos.enumHitBottom) { vPos = pNPC.GetPosVector3(); } else { // TODO: Get NPC AABB // const A3DAABB& aabb = pNPC->GetPickAABB(); // vPos = aabb.Center; // vPos.y += aabb.Extents.y * .5f; vPos = pNPC.GetPosVector3(); vPos.y += 1.0f; // Default height offset / 默认高度偏移 } return true; } } return false; } /// /// Get direction and up vector by ID /// 根据ID获取方向和上向量 /// private static bool _get_dir_and_up_by_id( EC_ManPlayer pPlayerMan, CECNPCMan pNPCMan, int nId, out Vector3 vDir, out Vector3 vUp) { vDir = Vector3.zero; vUp = Vector3.zero; if (GPDataTypeHelper.ISPLAYERID(nId)) { CECPlayer pPlayer = pPlayerMan?.GetPlayer(nId); if (pPlayer != null) { // TODO: Get player direction and up // vDir = pPlayer->GetDir(); // vUp = pPlayer->GetUp(); vDir = pPlayer.transform.forward; vUp = pPlayer.transform.up; return true; } } else if (GPDataTypeHelper.ISNPCID(nId)) { CECNPC pNPC = pNPCMan?.GetNPCFromAll(nId); if (pNPC != null) { // TODO: Get NPC direction and up // vDir = pNPC->GetDir(); // vUp = pNPC->GetUp(); vDir = pNPC.transform.forward; vUp = pNPC.transform.up; return true; } } return false; } /// /// Get scale by ID (height from AABB) /// 根据ID获取缩放(从AABB获取高度) /// public static float _get_scale_by_id( EC_ManPlayer pPlayerMan, CECNPCMan pNPCMan, int nID) { if (GPDataTypeHelper.ISPLAYERID(nID)) { CECPlayer pPlayer = pPlayerMan?.GetPlayer(nID); if (pPlayer != null) { // TODO: Get player AABB // const A3DAABB& aabb = pPlayer->GetPlayerAABB(); // return aabb.Maxs.y - aabb.Mins.y; return 1.0f; } } else if (GPDataTypeHelper.ISNPCID(nID)) { CECNPC pNPC = pNPCMan?.GetNPCFromAll(nID); if (pNPC != null) { // TODO: Get NPC AABB // const A3DAABB& aabb = pNPC->GetPickAABB(); // return aabb.Maxs.y - aabb.Mins.y; return 1.0f; } } return 1.0f; } /// /// Get ECModel GFX property by ID /// 根据ID获取ECModel GFX属性 /// public static bool _get_ecm_property_by_id(long nID, out ECMODEL_GFX_PROPERTY pProperty) { pProperty = new ECMODEL_GFX_PROPERTY(); int _32bitID = (int)nID; if (GPDataTypeHelper.ISPLAYERID(_32bitID)) { // TODO: Get player model properties /*CECPlayer* pPlayer = g_pGame->GetGameRun()->GetWorld()->GetPlayerMan()->GetPlayer(_32bitID); if (!pPlayer) return false; CECModel* pModel = pPlayer->GetPlayerModel(); if (!pModel) return false; pProperty->bGfxUseLod = pModel->IsGfxUseLOD(); pProperty->bGfxDisableCamShake = pModel->GetDisableCamShake(); pProperty->bHostECMCreatedByGfx = pModel->IsCreatedByGfx();*/ return true; } else if (GPDataTypeHelper.ISNPCID(_32bitID)) { // TODO: Get NPC properties /*CECNPC* pNPC = g_pGame->GetGameRun()->GetWorld()->GetNPCMan()->GetNPC(_32bitID); if (!pNPC || !pNPC->HasModel()) return false; pNPC->GetEcmProperty(&pProperty);*/ return true; } return false; } } /// /// Skill GFX Manager /// 技能特效管理器 /// public class SkillGfxMan : A3DSkillGfxMan { public static SkillGfxMan _instancesub; public static SkillGfxMan InstanceSub { get { if (_instancesub == null) { _instancesub = new SkillGfxMan(EC_Game.GetGameRun()); } return _instancesub; } set { _instancesub = value; } } private const int DEFAULT_EVENT_BUF_SIZE = 10; // 默认事件缓冲区大小 / Default event buffer size public LinkedList m_EventLst; // 活动事件列表 / Active event list protected LinkedList[] m_FreeLst; // 空闲事件列表(按移动模式分类) / Free event lists (categorized by move mode) protected EC_ManPlayer m_pPlayerMan; // 玩家管理器 / Player manager protected CECNPCMan m_pNPCMan; // NPC管理器 / NPC manager public SkillGfxMan(CECGameRun pGameRun) { m_EventLst = new LinkedList(); m_FreeLst = new LinkedList[(int)GfxMoveMode.enumMoveModeNum]; // Initialize free lists for each move mode // 为每种移动模式初始化空闲列表 for (int i = 0; i < (int)GfxMoveMode.enumMoveModeNum; i++) { m_FreeLst[i] = new LinkedList(); for (int j = 0; j < DEFAULT_EVENT_BUF_SIZE; j++) { CECSkillGfxEvent pEvent = new CECSkillGfxEvent((GfxMoveMode)i); m_FreeLst[i].AddLast(pEvent); } } // TODO: Get managers from game run // m_pPlayerMan = pGameRun?.GetWorld()?.GetPlayerMan(); // m_pNPCMan = pGameRun?.GetWorld()?.GetNPCMan(); m_pPlayerMan = EC_ManMessageMono.Instance?.GetECManPlayer; m_pNPCMan = EC_ManMessageMono.Instance?.CECNPCMan; } /// /// Get empty event from pool or create new one /// 从池中获取空事件或创建新事件 /// public A3DSkillGfxEvent GetEmptyEvent(GfxMoveMode mode) { int modeIndex = (int)mode; if (m_FreeLst[modeIndex].Count == 0) { return new CECSkillGfxEvent(mode); } else { CECSkillGfxEvent pEvent = m_FreeLst[modeIndex].Last.Value; m_FreeLst[modeIndex].RemoveLast(); pEvent.Resume(); return pEvent; } } /// /// Push event to active list /// 将事件推送到活动列表 /// public void PushEvent(A3DSkillGfxEvent pEvent) { if (pEvent is CECSkillGfxEvent cecEvent) { m_EventLst.AddLast(cecEvent); } } /// /// Get target scale by ID /// 根据ID获取目标缩放 /// public float GetTargetScale(long nTargetId) { return CECSkillGfxEvent._get_scale_by_id(m_pPlayerMan, m_pNPCMan, (int)nTargetId); } /// /// Get ECModel GFX property by ID /// 根据ID获取ECModel GFX属性 /// public override bool GetPropertyById(long nId, ref ECMODEL_GFX_PROPERTY pProperty) { return CECSkillGfxEvent._get_ecm_property_by_id(nId, out pProperty); } /// /// Release all events /// 释放所有事件 /// public void Release() { // Release active events // 释放活动事件 m_EventLst.Clear(); // Release free lists // 释放空闲列表 for (int i = 0; i < (int)GfxMoveMode.enumMoveModeNum; i++) { m_FreeLst[i].Clear(); } } /// /// Tick update all events /// 更新所有事件 /// public bool Tick(uint dwDeltaTime) { var node = m_EventLst.First; while (node != null) { var nextNode = node.Next; CECSkillGfxEvent pEvent = node.Value; if (pEvent.IsFinished()) { m_EventLst.Remove(node); pEvent.Resume(); //m_FreeLst[(int)pEvent.GetMode()].AddLast(pEvent); } else { pEvent.Tick(dwDeltaTime); } node = nextNode; } return true; } /// /// Render all events /// 渲染所有事件 /// public bool Render(CECViewport pViewport) { /*var node = m_EventLst.First; while (node != null) { node.Value.Render(); node = node.Next; }*/ return true; } } /// /// Manager wrapper for SkillGfxMan /// SkillGfxMan的管理器包装类 /// public class CECSkillGfxMan : CECManager { protected SkillGfxMan m_GfxMan; // 技能特效管理器 / Skill GFX manager public CECSkillGfxMan(CECGameRun pGameRun) : base(pGameRun) { m_GfxMan = new SkillGfxMan(pGameRun); // TODO: m_GfxMan.Init(g_pGame->GetA3DDevice()); } /// /// Get the internal SkillGfxMan pointer /// 获取内部SkillGfxMan指针 /// public A3DSkillGfxMan GetPtr() { return m_GfxMan; } /// /// Release resources /// 释放资源 /// public virtual void Release() { m_GfxMan.Release(); } /// /// Tick update /// 更新 /// public virtual bool Tick(uint dwDeltaTime) { return m_GfxMan.Tick(dwDeltaTime); } /// /// Render /// 渲染 /// public bool Render(CECViewport pViewport) { return m_GfxMan.Render(pViewport); } /// /// Add skill GFX event /// 添加技能特效事件 /// public bool AddSkillGfxEvent( int nHostID, int nTargetID, string szFlyGfx, string szHitGfx, uint dwFlyTimeSpan, bool bTraceTarget = true, GfxMoveMode FlyMode = GfxMoveMode.enumLinearMove, int nFlyGfxCount = 1, uint dwInterval = 0, GFX_SKILL_PARAM? param = null, float fFlyGfxScale = 1.0f, float fHitGfxScale = 1.0f, uint dwModifier = 0) { return m_GfxMan.AddSkillGfxEvent( null, nHostID, nTargetID, szFlyGfx, szHitGfx, dwFlyTimeSpan, bTraceTarget, FlyMode, nFlyGfxCount, dwInterval, param ?? default, fFlyGfxScale, fHitGfxScale, dwModifier, false, // bOnlyOneHit false, // bFadeOut false, // bIsGoblinSkill false // bReverse ); } } /// /// Viewport placeholder for CECViewport /// CECViewport的占位符类 /// public class CECViewport { // TODO: Implement viewport functionality // 待实现:视口功能 } /// /// Optimize settings placeholder /// 优化设置占位符 /// public class CECOptimize { private static CECOptimize _instance; public static CECOptimize Instance => _instance ?? (_instance = new CECOptimize()); private GFXOptimize _gfxOptimize = new GFXOptimize(); public GFXOptimize GetGFX() { return _gfxOptimize; } public class GFXOptimize { public bool CanShowHit(long hostId) { // TODO: Implement optimization check // 待实现:优化检查 return true; } public bool CanShowFly(long hostId) { // TODO: Implement optimization check // 待实现:优化检查 return true; } } } /// /// Skill GFX Composer position info /// 技能特效组合器位置信息 /// public class SGC_POS_INFO { public GfxHitPos HitPos; // 命中位置类型 / Hit position type public string szHook; // 挂点名称 / Hook name public bool bRelHook; // 是否相对挂点 / Is relative to hook public Vector3 vOffset; // 偏移量 / Offset public string szHanger; // 挂载者名称 / Hanger name public bool bChildHook; // 是否子挂点 / Is child hook public SGC_POS_INFO() { HitPos = GfxHitPos.enumHitCenter; szHook = null; bRelHook = false; vOffset = Vector3.zero; szHanger = null; bChildHook = false; } } /// /// Extended A3DSkillGfxComposer with position info /// 扩展的A3DSkillGfxComposer(带位置信息) /// public partial class A3DSkillGfxComposer { public SGC_POS_INFO m_FlyPos = new SGC_POS_INFO(); // 飞行起始位置信息 / Fly start position info public SGC_POS_INFO m_FlyEndPos = new SGC_POS_INFO(); // 飞行结束位置信息 / Fly end position info public SGC_POS_INFO m_HitPos = new SGC_POS_INFO(); // 命中位置信息 / Hit position info } }