adust plan

This commit is contained in:
VDH
2026-02-24 10:32:25 +07:00
parent e9522193c6
commit 335d44f496
4 changed files with 198 additions and 147 deletions
@@ -147,11 +147,11 @@ namespace BrewMonster
pEvent.SetTargetID(nTargetID);
pEvent.SetFlyTimeSpan(dwFlyTimeSpan);
pEvent.SetDelay(dwDelayTime);
//pEvent.SetReverse(bReverse);
//if (param.value.fVal != float.MinValue) pEvent.SetParam(param);
pEvent.SetReverse(bReverse);
pEvent.SetParam(param);
pEvent.SetTraceTarget(bTraceTarget);
pEvent.SetModifier(dwModifier);
//pEvent.SetIsCluster(bCluster);
pEvent.SetIsCluster(bCluster);
pEvent.SetFadeOut(bFadeOut);
pEvent.SetGoblinSkill(bIsGoblinSkill);
@@ -190,7 +190,6 @@ namespace BrewMonster
#if !_SKILLGFXCOMPOSER
pEvent.Tick(0);
#endif
pComposer.SpawnGFX(nTargetID);
PushEvent(pEvent);
return true;
}
@@ -202,7 +201,7 @@ namespace BrewMonster
public class A3DSkillGfxEvent
{
protected A3DSkillGfxComposer m_pComposer;
//protected CGfxMoveBase m_pMoveMethod;
protected CGfxMoveBase m_pMoveMethod;
//protected A3DGFXEx m_pFlyGfx; // 飞行特效 / Fly effect
//protected A3DGFXEx m_pHitGfx; // 命中特效 / Hit effect
protected uint m_dwFlyTimeSpan; // 飞行时间 / Flight time
@@ -248,7 +247,7 @@ namespace BrewMonster
m_bGfxDisableCamShake = false;
m_bHostECMCreatedByGfx = false;
//m_pMoveMethod = CGfxMoveBase.CreateMoveMethod(mode);
m_pMoveMethod = CGfxMoveBase.CreateMoveMethod(mode);
}
~A3DSkillGfxEvent()
@@ -333,16 +332,16 @@ namespace BrewMonster
public void SetHostModelCreatedByGfx(bool b) { m_bHostECMCreatedByGfx = b; }
public bool GetHostModelCreatedByGfx() { return m_bHostECMCreatedByGfx; }
public void SetComposer(A3DSkillGfxComposer pComposer) { m_pComposer = pComposer; }
//public CGfxMoveBase GetMoveMethod() { return m_pMoveMethod; }
//public GfxMoveMode GetMode() { return m_pMoveMethod.GetMode(); }
//public GfxHitPos GetHitPos() { return m_pMoveMethod.GetHitPos(); }
public CGfxMoveBase GetMoveMethod() { return m_pMoveMethod; }
public GfxMoveMode GetMode() { return m_pMoveMethod.GetMode(); }
public GfxHitPos GetHitPos() { return m_pMoveMethod.GetHitPos(); }
/* public A3DGFXEx GetFlyGfx() { return m_pFlyGfx; }
public A3DGFXEx GetHitGfx() { return m_pHitGfx; }*/
public void SetFlyTimeSpan(uint dwSpan) { m_dwFlyTimeSpan = dwSpan; }
public void SetDelay(uint dwDelay) { m_dwDelayTime = dwDelay; }
//public void SetReverse(bool bReverse) { m_pMoveMethod.SetReverse(bReverse); }
//public void SetParam(GFX_SKILL_PARAM param) { m_pMoveMethod.SetParam(param); }
//public void SetIsCluster(bool bCluster) { m_pMoveMethod.SetIsCluster(bCluster); }
public void SetReverse(bool bReverse) { m_pMoveMethod.SetReverse(bReverse); }
public void SetParam(GFX_SKILL_PARAM param) { m_pMoveMethod.SetParam(param); }
public void SetIsCluster(bool bCluster) { m_pMoveMethod.SetIsCluster(bCluster); }
public void SetTraceTarget(bool bTrace) { m_bTraceTarget = bTrace; }
public void SetFadeOut(bool bFadeOut) { m_bFadeOut = bFadeOut; }
public bool IsFinished() { return m_enumState == GfxSkillEventState.enumFinished; }
@@ -393,32 +392,17 @@ namespace BrewMonster
if (m_enumState == GfxSkillEventState.enumFinished) return; // 结束 / Finished
else if (m_enumState == GfxSkillEventState.enumHit) // 命中 / Hit
{
/* if (m_pHitGfx == null || m_pHitGfx.GetState() == ST_STOP)
m_enumState = GfxSkillEventState.enumFinished;
else
{
if (!m_bTargetExist || (m_bHitGfxInfinite && m_pHitGfx.GetTimeElapse() > 5000)) // HIT_GFX_MAX_TIMESPAN = 5000
m_enumState = GfxSkillEventState.enumFinished;
else
{
if (m_bTraceTarget)
{
Matrix4x4 matTran = Matrix4x4.identity;
Vector3 targetCenter = GetTargetCenter();
matTran.SetColumn(3, new Vector4(targetCenter.x, targetCenter.y, targetCenter.z, 1));
//m_pHitGfx.SetParentTM(matTran);
}
//m_pHitGfx.TickAnimation(dwDeltaTime);
}
}*/
// In Unity, hit GFX is auto-destroyed via Destroy(obj, 3f) in CECSkillGfxEvent.
// Transition to Finished immediately — the hit GFX cleanup is handled by Unity's timer.
// 在Unity中,命中特效通过Destroy(obj, 3f)自动销毁。立即转为Finished状态。
m_enumState = GfxSkillEventState.enumFinished;
}
else if (m_dwCurSpan > m_dwFlyTimeSpan) // 飞行超时 / Flight timeout
{
if (!m_bTargetExist)
m_enumState = GfxSkillEventState.enumFinished;
/* else
HitTarget(GetTargetCenter());*/
else
HitTarget(GetTargetCenter());
}
else if (!m_bTargetExist)
m_enumState = GfxSkillEventState.enumFinished;
@@ -431,40 +415,20 @@ namespace BrewMonster
else
{
m_enumState = GfxSkillEventState.enumFlying;
/* m_pMoveMethod.SetMaxFlyTime(m_dwFlyTimeSpan);
m_pMoveMethod.StartMove(m_vHostPos, m_vTargetPos);*/
m_pMoveMethod.SetMaxFlyTime(m_dwFlyTimeSpan);
m_pMoveMethod.StartMove(m_vHostPos, m_vTargetPos);
/* if (m_pFlyGfx != null)
{
Vector3 vDir, vUp;
if (m_pMoveMethod.GetMode() == GfxMoveMode.enumOnTarget && m_pMoveMethod.IsReverse() && GetTargetDirAndUp(out vDir, out vUp))
m_pFlyGfx.SetParentTM(a3d_TransformMatrix(vDir, vUp, m_pMoveMethod.GetPos()));
else
m_pFlyGfx.SetParentTM(_build_matrix(m_pMoveMethod.GetMoveDir(), m_pMoveMethod.GetPos()));
m_pFlyGfx.Start(true);
m_pMoveMethod.UpdateGfxParam(m_pFlyGfx, m_vHostPos, m_vTargetPos);
m_pFlyGfx.TickAnimation(0);
}*/
// Fly GFX spawning is handled by CECSkillGfxEvent.Tick() when it detects Wait→Flying transition
// 飞行特效的生成由CECSkillGfxEvent.Tick()在检测到Wait→Flying转换时处理
}
}
else
else // enumFlying state / 飞行状态
{
/* if (m_pMoveMethod.TickMove(dwDeltaTime, m_vHostPos, m_vTargetPos)) // 目标被命中 / Target hit
HitTarget(GetTargetCenter());*/
/*else if (m_pFlyGfx != null)
{
Vector3 vDir, vUp;
if (m_pMoveMethod.TickMove(dwDeltaTime, m_vHostPos, m_vTargetPos)) // 目标被命中 / Target hit
HitTarget(GetTargetCenter());
if (m_pMoveMethod.GetMode() == GfxMoveMode.enumOnTarget && m_pMoveMethod.IsReverse() && GetTargetDirAndUp(out vDir, out vUp))
m_pFlyGfx.SetParentTM(a3d_TransformMatrix(vDir, vUp, m_pMoveMethod.GetPos()));
else
m_pFlyGfx.SetParentTM(_build_matrix(m_pMoveMethod.GetMoveDir(), m_pMoveMethod.GetPos()));
m_pMoveMethod.UpdateGfxParam(m_pFlyGfx, m_vHostPos, m_vTargetPos);
m_pFlyGfx.TickAnimation(dwDeltaTime);
}*/
// Fly GFX transform update is handled by CECSkillGfxEvent.Tick()
// 飞行特效的变换更新由CECSkillGfxEvent.Tick()处理
}
}
@@ -141,6 +141,8 @@ namespace BrewMonster
private void Update()
{
uint dwDeltaTime = (uint)(Time.deltaTime * 1000);
#if UNITY_EDITOR
if (m_AttackList.Count == 0)
m_AttackList = m_targets.ToList();
@@ -152,9 +154,13 @@ namespace BrewMonster
//BMLogger.LogError("HoangDev: Update CECAttackEvent node.Value.m_bFinished: " + node.Value.m_bFinished);
if (node.Value.m_bFinished)
m_targets.Remove(node);
else node.Value.Tick((uint)(Time.deltaTime * 1000));
else node.Value.Tick(dwDeltaTime);
node = next;
}
// Tick skill GFX events (fly/hit GFX state machine)
// 更新技能特效事件(飞行/命中特效状态机)
SkillGfxMan.InstanceSub.Tick(dwDeltaTime);
}
bool FileExists(string relativePath)
{
@@ -454,6 +460,36 @@ namespace BrewMonster
};
}
/// <summary>
/// Load SkillStub GFX parameters onto this composer.
/// 将SkillStub的GFX参数加载到此组合器上。
/// </summary>
public void LoadFromSkillStub(BrewMonster.Scripts.Skills.SkillStub stub)
{
if (stub == null) return;
m_MoveMode = stub.m_MoveMode;
m_TargetMode = stub.m_TargetMode;
m_AttFlyMode = stub.m_AttFlyMode;
m_AttHitMode = stub.m_AttHitMode;
m_dwFlyTime = stub.m_dwFlyTime;
m_bTraceTarget = stub.m_bTraceTarget;
m_FlyCluster = new GfxCluster
{
m_ulCount = stub.m_FlyClusterCount,
m_dwInterv = stub.m_FlyClusterInterval
};
m_bOneHit = stub.m_bOneHit;
m_bFadeOut = stub.m_bFadeOut;
m_bRelScl = stub.m_bRelScl;
m_fDefTarScl = stub.m_fDefTarScl;
m_param = stub.m_param;
}
// GFX prefab accessors / GFX预制体访问器
public GameObject GetFlyGFX() => flyGFX;
public GameObject GetHitGFX() => hitGFX;
public GameObject GetHitGrdGFX() => hitGrdGFX;
/// <summary>
/// Load composer from file
/// 从文件加载组合器
@@ -465,11 +501,6 @@ namespace BrewMonster
#endif
public async Task<bool> Load(SkillStub skillStub, string flyGFXPath, string hitGrdGFXPath, string hitGFXPath)
{
#if !UNITY_EDITOR
string flyGfxName = flyGFXPath;
string hitGfxName = hitGFXPath;
string hitGrdGfxName = hitGrdGFXPath;
#else
flyGfxName = flyGFXPath;
hitGfxName = hitGFXPath;
hitGrdGfxName = hitGrdGFXPath;
@@ -537,19 +568,8 @@ namespace BrewMonster
return true;
}
public void SpawnGFX(long IDTarget)
{
#if UNITY_EDITOR
BMLogger.LogError("HoangDev: Load A3DSkillGfxComposer GFX name: " + flyGfxName);
BMLogger.LogError("HoangDev: Load A3DSkillGfxComposer GFX name: " + hitGfxName);
BMLogger.LogError("HoangDev: Load A3DSkillGfxComposer GFX name: " + hitGrdGfxName);
#endif
var obj = EC_ManMessageMono.Instance.GetObject(IDTarget, 0);
if (obj != null && flyGFX != null)
{
GameObject.Instantiate(flyGFX, obj.transform.position, flyGFX.gameObject.transform.rotation, obj.transform);
}
}
// SpawnGFX temp hack REMOVED — GFX spawning now handled by CECSkillGfxEvent state machine
// SpawnGFX临时代码已删除 — GFX生成现在由CECSkillGfxEvent状态机处理
/// <summary>
/// Initialize composer
/// 初始化组合器
@@ -567,45 +587,33 @@ namespace BrewMonster
{
bool bCastInTargets = false;
/* char szFly = m_szFlyGfx[0] ? m_szFlyGfx : NULL;
char szHit = m_szHitGfx[0] ? m_szHitGfx : NULL;*/
// Determine GFX names from loaded prefabs / 从已加载的预制体确定GFX名称
string szFly = flyGFX != null ? flyGfxName : null;
string szHit = hitGFX != null ? hitGfxName : null;
/*# ifndef _SKILLGFXCOMPOSER
if (!CECOptimize::Instance().GetGFX().CanShowFly(nHostID))
{
a_LogOutput(1, "[SKILL_GFX_FLOW] ====> Fly GFX hidden by optimization");
szFly = NULL;
}
if (!CECOptimize::Instance().GetGFX().CanShowHit(nHostID))
{
a_LogOutput(1, "[SKILL_GFX_FLOW] ====> Hit GFX hidden by optimization");
szHit = NULL;
}
#endif*/
// TODO Phase 2: Optimization checks / 第二阶段:优化检查
// if (!CECOptimize.Instance.GetGFX().CanShowFly(nHostID)) szFly = null;
// if (!CECOptimize.Instance.GetGFX().CanShowHit(nHostID)) szHit = null;
// Log target details
if (targets != null && targets.Count > 0)
{
for (int i = 0; i < targets.Count; i++)
{
var tar = targets[i];
if (nCastTargetID == tar.idTarget)
bCastInTargets = true;
AddOneTarget(nCastTargetID, nHostID, "" /*szFly*/, ""/*szHit*/, tar, i == 0, bIsGoblinSkill);
AddOneTarget(nCastTargetID, nHostID, szFly, szHit, tar, i == 0, bIsGoblinSkill);
}
}
else
{
}
if (nCastTargetID != 0 && !bCastInTargets)
{
TARGET_DATA tar = default;
tar.idTarget = nCastTargetID;
tar.dwModifier = 0;
AddOneTarget(nCastTargetID, nHostID, ""/*szFly*/, ""/*szHit*/, tar, false, bIsGoblinSkill);
AddOneTarget(nCastTargetID, nHostID, szFly, szHit, tar, false, bIsGoblinSkill);
}
}
@@ -642,10 +650,10 @@ namespace BrewMonster
}
// 计算缩放 / Calculate scale
/* if (m_bRelScl)
fScale = m_pSkillGfxMan.GetTargetScale(_Target) / m_fDefTarScl * m_fHitGfxScale;
else
fScale = m_fHitGfxScale;*/
if (m_bRelScl)
fScale = SkillGfxMan.InstanceSub.GetTargetScale(_Target) / m_fDefTarScl * m_fHitGfxScale;
else
fScale = m_fHitGfxScale;
// 根据目标类型决定是否显示特效 / Determine whether to show effects based on target type
if ((nCastTargetID != 0 && tar.idTarget != nCastTargetID)
@@ -675,8 +683,8 @@ namespace BrewMonster
(int)m_FlyCluster.m_ulCount,
m_FlyCluster.m_dwInterv,
m_param,
0/*m_fFlyGfxScale*/,
0/*fScale*/,
m_fFlyGfxScale,
fScale,
tar.dwModifier,
m_bOneHit,
m_bFadeOut,
@@ -981,9 +989,13 @@ public class CECAttackEvent
}
else
{
// TODO: Implement SkillGfxComposerMan
// m_pManager.GetSkillGfxComposerMan().Play(m_idSkill, m_idHost, m_idCastTarget, m_targets);
// pComposer = m_pManager.GetSkillGfxComposerMan().GetSkillGfxComposer(m_idSkill);
// NPC regular skill GFX / NPC常规技能特效
var composerMan = m_pManager?.GetSkillGfxComposerMan();
if (composerMan != null)
{
composerMan.Play(m_idSkill, m_idHost, m_idCastTarget, m_targets);
pComposer = composerMan.GetSkillGfxComposer(m_idSkill);
}
}
if (pComposer != null && pComposer.m_dwFlyTime == 0) // 技能没有飞行时间,则直接头顶冒字 / Skill has no fly time, show damage immediately
@@ -15,6 +15,9 @@ namespace BrewMonster
protected EC_ManPlayer m_pPlayerMan; // 玩家管理器 / Player manager
protected CECNPCMan m_pNPCMan; // NPC管理器 / NPC manager
private GameObject m_flyGfxInstance; // 飞行特效实例 / Fly GFX instance
private GameObject m_hitGfxInstance; // 命中特效实例 / Hit GFX instance
public CECSkillGfxEvent(GfxMoveMode mode) : base(mode)
{
m_pPlayerMan = EC_ManMessageMono.Instance?.GetECManPlayer;
@@ -34,7 +37,7 @@ namespace BrewMonster
/// Get the original host ID (considering reverse mode)
/// 获取原始施法者ID(考虑反向模式)
/// </summary>
/* public long GetOriginalHost()
public long GetOriginalHost()
{
// GFX 特效显示,技能的原始的攻击者和目标被位置,提供了方法,查询原始攻击者
// GFX effects display, original attacker and target positions swapped, provides method to query original attacker
@@ -50,7 +53,7 @@ namespace BrewMonster
// 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
@@ -122,7 +125,8 @@ namespace BrewMonster
/// </summary>
public override void Tick(uint dwDeltaTime)
{
/*if (GetComposer() != null)
// Update host and target positions / 更新施法者和目标位置
if (GetComposer() != null)
{
SGC_POS_INFO pHostPos, pTargetPos;
@@ -192,51 +196,115 @@ namespace BrewMonster
Vector3.zero,
null,
false);
}*/
}
// Track state before base.Tick() to detect transitions / 在base.Tick()前记录状态以检测转换
GfxSkillEventState prevState = m_enumState;
base.Tick(dwDeltaTime);
// Spawn fly GFX when entering Flying state / 进入飞行状态时生成飞行特效
if (prevState == GfxSkillEventState.enumWait && m_enumState == GfxSkillEventState.enumFlying)
SpawnFlyGfx();
// Update fly GFX transform during Flying / 飞行期间更新飞行特效变换
if (m_enumState == GfxSkillEventState.enumFlying)
UpdateFlyGfxTransform();
}
/// <summary>
/// Handle target hit event
/// 处理命中目标事件
/// Handle target hit event - destroy fly GFX and spawn hit GFX
/// 处理命中目标事件 - 销毁飞行特效并生成命中特效
/// </summary>
protected override void HitTarget(Vector3 vTarget)
{
base.HitTarget(vTarget);
DestroyFlyGfx();
SpawnHitGfx(vTarget);
// now show some special hit gfx
// 现在显示一些特殊命中
/* if (CECOptimize.Instance.GetGFX().CanShowHit(GetOriginalHost()))
// TODO Phase 2: Special hit effects (rune, critical, nullity)
// TODO 第二阶段:特殊命中效果(符石、暴击、无效)
}
// ===== GFX Instance Management =====
// GFX实例管理
/// <summary>
/// Spawn fly GFX at movement position
/// 在移动位置生成飞行特效
/// </summary>
private void SpawnFlyGfx()
{
if (m_pComposer == null) return;
GameObject prefab = m_pComposer.GetFlyGFX();
if (prefab == null) return;
Vector3 pos = m_pMoveMethod.GetPos();
Vector3 dir = m_pMoveMethod.GetMoveDir();
Quaternion rot = dir.sqrMagnitude > 1e-4f ? Quaternion.LookRotation(dir) : Quaternion.identity;
m_flyGfxInstance = GameObject.Instantiate(prefab, pos, rot);
BMLogger.Log($"[GFX_FLOW] SpawnFlyGfx at {pos}, prefab={prefab.name}");
}
/// <summary>
/// Update fly GFX transform to follow movement
/// 更新飞行特效变换以跟随移动
/// </summary>
private void UpdateFlyGfxTransform()
{
if (m_flyGfxInstance == null) return;
m_flyGfxInstance.transform.position = m_pMoveMethod.GetPos();
Vector3 dir = m_pMoveMethod.GetMoveDir();
if (dir.sqrMagnitude > 1e-4f)
m_flyGfxInstance.transform.rotation = Quaternion.LookRotation(dir);
}
/// <summary>
/// Destroy fly GFX instance
/// 销毁飞行特效实例
/// </summary>
private void DestroyFlyGfx()
{
if (m_flyGfxInstance != null)
{
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(...)
}
GameObject.Destroy(m_flyGfxInstance);
m_flyGfxInstance = null;
}
}
if ((m_dwModifier & CECAttackEvent.MOD_MAGIC_ATTACK_RUNE) != 0)
{
// 程序联入\\符石\\法攻符石特效.gfx
// Program integration\\Rune\\Magic attack rune effect.gfx
// TODO: Play GFX
}
/// <summary>
/// Spawn hit GFX at target position
/// 在目标位置生成命中特效
/// </summary>
private void SpawnHitGfx(Vector3 vTarget)
{
if (m_pComposer == null) return;
GameObject prefab = m_pComposer.GetHitGFX();
if (prefab == null) return;
if ((m_dwModifier & CECAttackEvent.MOD_PHYSIC_DEFENCE_RUNE) != 0)
{
// 程序联入\\符石\\物防符石特效.gfx
// Program integration\\Rune\\Physical defense rune effect.gfx
// TODO: Play GFX
}
Quaternion rot = Quaternion.identity;
if (m_bHostExist)
{
Vector3 dir = vTarget - m_vHostPos;
dir.y = 0;
if (dir.sqrMagnitude > 1e-6f) rot = Quaternion.LookRotation(dir);
}
if ((m_dwModifier & CECAttackEvent.MOD_MAGIC_DEFENCE_RUNE) != 0)
{
// 程序联入\\符石\\法防符石特效.gfx
// Program integration\\Rune\\Magic defense rune effect.gfx
// TODO: Play GFX
}
}*/
m_hitGfxInstance = GameObject.Instantiate(prefab, vTarget, rot);
GameObject.Destroy(m_hitGfxInstance, 3.0f); // auto-cleanup / 自动清理
BMLogger.Log($"[GFX_FLOW] SpawnHitGfx at {vTarget}, prefab={prefab.name}");
}
/// <summary>
/// Clean up GFX instances on Resume (return to pool)
/// 在Resume时清理GFX实例(返回池)
/// </summary>
public new void Resume()
{
DestroyFlyGfx();
// Hit GFX is auto-destroyed by Unity's Destroy timer, don't null it here
// 命中特效由Unity的Destroy计时器自动销毁,不在此处置null
m_hitGfxInstance = null;
base.Resume();
}
/// <summary>
@@ -672,7 +740,7 @@ namespace BrewMonster
{
m_EventLst.Remove(node);
pEvent.Resume();
//m_FreeLst[(int)pEvent.GetMode()].AddLast(pEvent);
m_FreeLst[(int)pEvent.GetMode()].AddLast(pEvent);
}
else
{
@@ -50,8 +50,15 @@ namespace BrewMonster
return false;
}
// Load SkillStub GFX parameters (MoveMode, FlyTime, TargetMode, clusters, etc.)
// 从SkillStub加载GFX参数(移动模式、飞行时间、目标模式、群集等)
SkillStub stub = SkillStub.GetStub((uint)nSkillID);
if (stub != null)
{
composer.LoadFromSkillStub(stub);
}
// In original C++: composer->Init(g_pGame->GetGameRun()->GetWorld()->GetSkillGfxMan()->GetPtr());
// Not wired in Unity yet; keep placeholder init to allow future hookup.
composer.Init(A3DSkillGfxMan.Instance);
m_ComposerMap[nSkillID] = composer;