Files
test/Assets/PerfectWorld/Scripts/Managers/CECSkillGfxMan.cs
2025-12-02 16:46:47 +07:00

878 lines
28 KiB
C#

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;
}
/// <summary>
/// Get the skill GFX composer
/// 获取技能特效组合器
/// </summary>
public A3DSkillGfxComposer GetComposer()
{
return m_pComposer;
}
/// <summary>
/// Get the original host ID (considering reverse mode)
/// 获取原始施法者ID(考虑反向模式)
/// </summary>
/* 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;
}
/// <summary>
/// Get the original target ID (considering reverse mode)
/// 获取原始目标ID(考虑反向模式)
/// </summary>
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;
}*/
/// <summary>
/// Get target direction and up vector
/// 获取目标方向和上向量
/// </summary>
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;
}
/// <summary>
/// Get target center position
/// 获取目标中心位置
/// </summary>
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;
}
/// <summary>
/// Tick update
/// 更新
/// </summary>
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);
}
/// <summary>
/// Handle target hit event
/// 处理命中目标事件
/// </summary>
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
}
}*/
}
/// <summary>
/// Load hit GFX with modifier checks
/// 加载命中特效(带修饰符检查)
/// </summary>
/*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;
}*/
/// <summary>
/// Set hit GFX
/// 设置命中特效
/// </summary>
/*public void SetHitGfx(A3DGFXEx pHitGfx)
{
// if (m_dwModifier & CECAttackEvent::MOD_CRITICAL_STRIKE)
// pHitGfx->SetActualScale(pHitGfx->GetScale() * 2.0f);
m_pHitGfx = pHitGfx;
}*/
// ===== Helper functions (static) =====
// 辅助函数(静态)
/// <summary>
/// Get position by ID (player or NPC)
/// 根据ID获取位置(玩家或NPC)
/// </summary>
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;
}
/// <summary>
/// Get direction and up vector by ID
/// 根据ID获取方向和上向量
/// </summary>
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;
}
/// <summary>
/// Get scale by ID (height from AABB)
/// 根据ID获取缩放(从AABB获取高度)
/// </summary>
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;
}
/// <summary>
/// Get ECModel GFX property by ID
/// 根据ID获取ECModel GFX属性
/// </summary>
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;
}
}
/// <summary>
/// Skill GFX Manager
/// 技能特效管理器
/// </summary>
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<CECSkillGfxEvent> m_EventLst; // 活动事件列表 / Active event list
protected LinkedList<CECSkillGfxEvent>[] 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<CECSkillGfxEvent>();
m_FreeLst = new LinkedList<CECSkillGfxEvent>[(int)GfxMoveMode.enumMoveModeNum];
// Initialize free lists for each move mode
// 为每种移动模式初始化空闲列表
for (int i = 0; i < (int)GfxMoveMode.enumMoveModeNum; i++)
{
m_FreeLst[i] = new LinkedList<CECSkillGfxEvent>();
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;
}
/// <summary>
/// Get empty event from pool or create new one
/// 从池中获取空事件或创建新事件
/// </summary>
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;
}
}
/// <summary>
/// Push event to active list
/// 将事件推送到活动列表
/// </summary>
public void PushEvent(A3DSkillGfxEvent pEvent)
{
if (pEvent is CECSkillGfxEvent cecEvent)
{
m_EventLst.AddLast(cecEvent);
}
}
/// <summary>
/// Get target scale by ID
/// 根据ID获取目标缩放
/// </summary>
public float GetTargetScale(long nTargetId)
{
return CECSkillGfxEvent._get_scale_by_id(m_pPlayerMan, m_pNPCMan, (int)nTargetId);
}
/// <summary>
/// Get ECModel GFX property by ID
/// 根据ID获取ECModel GFX属性
/// </summary>
public override bool GetPropertyById(long nId, ref ECMODEL_GFX_PROPERTY pProperty)
{
return CECSkillGfxEvent._get_ecm_property_by_id(nId, out pProperty);
}
/// <summary>
/// Release all events
/// 释放所有事件
/// </summary>
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();
}
}
/// <summary>
/// Tick update all events
/// 更新所有事件
/// </summary>
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;
}
/// <summary>
/// Render all events
/// 渲染所有事件
/// </summary>
public bool Render(CECViewport pViewport)
{
/*var node = m_EventLst.First;
while (node != null)
{
node.Value.Render();
node = node.Next;
}*/
return true;
}
}
/// <summary>
/// Manager wrapper for SkillGfxMan
/// SkillGfxMan的管理器包装类
/// </summary>
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());
}
/// <summary>
/// Get the internal SkillGfxMan pointer
/// 获取内部SkillGfxMan指针
/// </summary>
public A3DSkillGfxMan GetPtr()
{
return m_GfxMan;
}
/// <summary>
/// Release resources
/// 释放资源
/// </summary>
public virtual void Release()
{
m_GfxMan.Release();
}
/// <summary>
/// Tick update
/// 更新
/// </summary>
public virtual bool Tick(uint dwDeltaTime)
{
return m_GfxMan.Tick(dwDeltaTime);
}
/// <summary>
/// Render
/// 渲染
/// </summary>
public bool Render(CECViewport pViewport)
{
return m_GfxMan.Render(pViewport);
}
/// <summary>
/// Add skill GFX event
/// 添加技能特效事件
/// </summary>
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
);
}
}
/// <summary>
/// Viewport placeholder for CECViewport
/// CECViewport的占位符类
/// </summary>
public class CECViewport
{
// TODO: Implement viewport functionality
// 待实现:视口功能
}
/// <summary>
/// Optimize settings placeholder
/// 优化设置占位符
/// </summary>
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;
}
}
}
/// <summary>
/// Skill GFX Composer position info
/// 技能特效组合器位置信息
/// </summary>
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;
}
}
/// <summary>
/// Extended A3DSkillGfxComposer with position info
/// 扩展的A3DSkillGfxComposer(带位置信息)
/// </summary>
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
}
}