This commit is contained in:
VDH
2025-11-13 18:57:24 +07:00
parent 62575718f6
commit 621c833793
13 changed files with 1001 additions and 337 deletions
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 75a0cc0fd8902794a883916febf9855b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,33 @@
using UnityEditor;
using UnityEngine;
namespace BrewMonster
{
public static class ResetStaticUtilityEditor
{
[MenuItem("Tools/Reset Static Fields/Run Now", priority = 10)]
public static void RunNow()
{
int count = ResetStaticUtility.ResetAll(logEach: true);
EditorUtility.DisplayDialog("Reset Static Fields", $"Reset completed.\nFields processed: {count}", "OK");
}
private const string AutoRunPath = "Tools/Reset Static Fields/Auto Reset On Play";
[MenuItem(AutoRunPath, priority = 11)]
public static void ToggleAutoRunOnPlay()
{
bool enabled = ResetStaticUtility.GetAutoRunOnPlay();
ResetStaticUtility.SetAutoRunOnPlay(!enabled);
}
[MenuItem(AutoRunPath, validate = true)]
public static bool ToggleAutoRunOnPlayValidate()
{
Menu.SetChecked(AutoRunPath, ResetStaticUtility.GetAutoRunOnPlay());
return true;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 4f472ae43a592b64cb9876ad7a36eb3a
@@ -1,25 +1,26 @@
using BrewMonster;
using BrewMonster.Assets.PerfectWorld.Scripts.Common;
using BrewMonster.Managers;
using CSNetwork.GPDataType;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.VisualScripting;
using UnityEngine;
using static CECAttacksMan;
public class CECAttacksMan : MonoSingleton<CECAttacksMan>
public class CECAttacksMan : Singleton<CECAttacksMan>
{
private readonly LinkedList<CECAttackEvent> m_AttackLinkedList = new LinkedList<CECAttackEvent>();
private CECMultiSectionSkillMan m_pMultiSkillGfxComposerMan;
#if UNITY_EDITOR
public List<CECAttackEvent> m_AttackList = new List<CECAttackEvent>();
public List<CECAttackEvent> m_AttackList = new List<CECAttackEvent>();
#endif
private void Update()
{
#if UNITY_EDITOR
m_AttackList = m_AttackLinkedList.ToList();
m_AttackList = m_AttackLinkedList.ToList();
#endif
var node = m_AttackLinkedList.First;
while (node != null)
@@ -68,7 +69,22 @@ public class CECAttacksMan : MonoSingleton<CECAttacksMan>
newEvent.UpdateTargetFlag();
return m_AttackLinkedList.Last.Value;
}
public bool GetSkillSectionActionSuffix(int skill, int section, out string suffix)
{
// TODO: Implement multi-section skill logic
// 待实现:多段技能逻辑
if (m_pMultiSkillGfxComposerMan != null)
{
CECMultiSectionSkillMan::SectionInfo info = m_pMultiSkillGfxComposerMan.GetSecionInfo(skill, section);
if (info && info->action_suffix != "0") // 0 表示技能没有后缀
{
suffix = info->action_suffix;
return true;
}
}
suffix = null;
return false;
}
public CECAttackEvent AddSkillAttack(int idHost, int idCastTarget, int idTarget, int idWeapon, int idSkill, int nSkillLevel, uint dwModifier, int nDamage)
{
var newEvent = new CECAttackEvent(
@@ -104,6 +120,207 @@ public class CECAttacksMan : MonoSingleton<CECAttacksMan>
}
/// <summary>
/// Manager for multi-section skills
/// 多段技能管理器
/// </summary>
public class CECMultiSectionSkillMan
{
/// <summary>
/// Section information for multi-section skills
/// 多段技能的段信息
/// </summary>
[Serializable]
public class SectionInfo
{
public int skill_id; // 技能ID / Skill ID
public byte section; // 段号 / Section number
public string action_suffix; // 动作后缀 / Action suffix
public A3DSkillGfxComposer pComposer; // 技能特效组合器 / Skill GFX composer
public SectionInfo()
{
skill_id = 0;
section = 1;
action_suffix = string.Empty;
pComposer = null;
}
}
// 用于多段技能的sgc映射 / Map for multi-section skill SGC files
private readonly Dictionary<string, A3DSkillGfxComposer> m_SgcName2ComposerMap = new Dictionary<string, A3DSkillGfxComposer>();
// 多段技能组合器列表 / Multi-section skill composer list
private readonly List<SectionInfo> m_MultiSectionSkillComposerVec = new List<SectionInfo>();
public CECMultiSectionSkillMan()
{
}
~CECMultiSectionSkillMan()
{
Release();
}
/// <summary>
/// Release resources
/// 释放资源
/// </summary>
public void Release()
{
m_MultiSectionSkillComposerVec.Clear();
foreach (var kvp in m_SgcName2ComposerMap)
{
if (kvp.Value != null)
{
// TODO: Implement proper disposal if A3DSkillGfxComposer has cleanup
// kvp.Value.Release();
}
}
m_SgcName2ComposerMap.Clear();
}
/// <summary>
/// Load configuration from file
/// 从文件加载配置
/// </summary>
/// <param name="szFile">Configuration file path / 配置文件路径</param>
/// <returns>Success / 是否成功</returns>
public bool LoadConfig(string szFile)
{
// TODO: Implement file loading using Unity's file system
// This would require porting AScriptFile functionality or using Unity's TextAsset
BMLogger.LogWarning($"CECMultiSectionSkillMan.LoadConfig: Not yet implemented for {szFile}");
/*
// Original C++ logic:
// 1. Open script file
// 2. Parse skill ID followed by { }
// 3. Inside braces, parse comma-separated values: section,suffix,sgc
// 4. Load or reuse A3DSkillGfxComposer for each SGC file
// 5. Store SectionInfo in vector
// Example file format:
// skill_id
// {
// section,suffix,sgc_file
// section,suffix,sgc_file
// }
*/
return false;
}
/// <summary>
/// Play multi-section skill effect
/// 播放多段技能特效
/// </summary>
/// <param name="nSkillID">Skill ID / 技能ID</param>
/// <param name="section">Skill section / 技能段数</param>
/// <param name="nHostID">Host character ID / 施法者ID</param>
/// <param name="nCastTargetID">Cast target ID / 施法目标ID</param>
/// <param name="Targets">Target data list / 目标数据列表</param>
/// <param name="bIsGoblinSkill">Is goblin skill / 是否为精灵技能</param>
public void Play(int nSkillID, int section, int nHostID, int nCastTargetID,
List<TARGET_DATA> Targets, bool bIsGoblinSkill = false)
{
foreach (var info in m_MultiSectionSkillComposerVec)
{
if (nSkillID == info.skill_id && section == info.section && info.pComposer != null)
{
// TODO: Implement A3DSkillGfxComposer.Play method
// info.pComposer.Play(nHostID, nCastTargetID, Targets, bIsGoblinSkill);
BMLogger.Log($"CECMultiSectionSkillMan.Play: Skill {nSkillID}, Section {section}");
return;
}
}
}
/// <summary>
/// Get skill GFX composer for specific skill and section
/// 获取指定技能和段数的特效组合器
/// </summary>
/// <param name="skill">Skill ID / 技能ID</param>
/// <param name="section">Section number / 段号</param>
/// <returns>Skill GFX composer or null / 技能特效组合器或null</returns>
public A3DSkillGfxComposer GetSkillGfxComposer(int skill, int section)
{
foreach (var info in m_MultiSectionSkillComposerVec)
{
if (skill == info.skill_id && section == info.section && info.pComposer != null)
{
return info.pComposer;
}
}
return null;
}
/// <summary>
/// Get section information for specific skill and section
/// 获取指定技能和段数的段信息
/// </summary>
/// <param name="skill">Skill ID / 技能ID</param>
/// <param name="section">Section number / 段号</param>
/// <returns>Section info or null / 段信息或null</returns>
public SectionInfo GetSecionInfo(int skill, int section)
{
foreach (var info in m_MultiSectionSkillComposerVec)
{
if (skill == info.skill_id && section == info.section)
{
return info;
}
}
return null;
}
}
/// <summary>
/// Placeholder class for A3DSkillGfxComposer
/// A3DSkillGfxComposer的占位类
/// </summary>
public class A3DSkillGfxComposer
{
public uint m_dwFlyTime; // 飞行时间 / Fly time in milliseconds
public A3DSkillGfxComposer()
{
m_dwFlyTime = 0;
}
/// <summary>
/// Load composer from file
/// 从文件加载组合器
/// </summary>
public bool Load(string sgcFile)
{
// TODO: Implement SGC file loading
BMLogger.LogWarning($"A3DSkillGfxComposer.Load: Not yet implemented for {sgcFile}");
return false;
}
/// <summary>
/// Initialize composer
/// 初始化组合器
/// </summary>
public void Init(object pSkillGfxMan)
{
// TODO: Implement initialization
}
/// <summary>
/// Play skill effect
/// 播放技能特效
/// </summary>
/* public void Play(int nHostID, int nCastTargetID, List<TARGET_DATA> targets, bool bIsGoblinSkill = false)
{
// TODO: Implement skill effect playback
BMLogger.Log($"A3DSkillGfxComposer.Play: Host {nHostID}, Target {nCastTargetID}");
}*/
}
[Serializable]
public class CECAttackEvent
{
@@ -194,241 +411,242 @@ public class CECAttackEvent
return true;
}
bool DoFire()
{
float vFlyScale = 1.0f;
float vHitScale = 1.0f;
public void SetSkillSection(int nSection) { m_nSkillSection = nSection; }
bool DoFire()
{
float vFlyScale = 1.0f;
float vHitScale = 1.0f;
m_bDoFired = true;
m_bDoFired = true;
if( GPDataTypeHelper.ISPLAYERID(m_idHost) )
{
if( m_idSkill != 0 )
{
// const A3DSkillGfxComposer* pComposer = NULL;
//
// // we use skill composed gfx to present the skill effect
// if (m_nSkillSection>0) // ¶à¶Î¼¼ÄÜ
// {
// CECMultiSectionSkillMan pMan = m_pManager.GetMultiSkillGfxComposerMan();
// if(pMan)
// {
// pMan->Play(m_idSkill, m_nSkillSection,m_idHost, m_idCastTarget, m_targets,GNET::ElementSkill::IsGoblinSkill(m_idSkill));
// pComposer = pMan->GetSkillGfxComposer(m_idSkill, m_nSkillSection);
// }
// }
// else
// {
// if(GNET::ElementSkill::IsGoblinSkill(m_idSkill))
// m_pManager->GetSkillGfxComposerMan()->Play(m_idSkill, m_idHost, m_idCastTarget, m_targets, true);
// else
// m_pManager->GetSkillGfxComposerMan()->Play(m_idSkill, m_idHost, m_idCastTarget, m_targets);
// pComposer = m_pManager->GetSkillGfxComposerMan()->GetSkillGfxComposer(m_idSkill);
// }
//
// if (pComposer && pComposer->m_dwFlyTime == 0) // ¼¼ÄÜgfxûÓзÉÐÐʵ¼Ê£¬ÔòÂíÉÏÍ·¶¥Ã°×Ö
// {
// m_timeToDoDamage = 1;
// }
// else
// {
// A3DVECTOR3 vecHost, vecTarget;
// // now we estimated a time to do damage
// if( m_targets.size() && _get_pos_by_id(m_idHost, vecHost) && _get_pos_by_id(m_targets[0].idTarget, vecTarget) )
// {
// m_timeToDoDamage = int(Magnitude(vecHost - vecTarget) / 20.0f * 1000.0f);
// a_ClampFloor(m_timeToDoDamage, 10ul);
// }
// }
}
else if( m_idWeapon != 0 )
{
// first determine gfx used
// const char * szFlyGFX = NULL;
// const char * szHitGFX = NULL;
//
// // using weapon gfx
// DATA_TYPE dt;
// const void * pData = g_pGame->GetElementDataMan()->get_data_ptr(
// m_idWeapon, ID_SPACE_ESSENCE, dt);
// ASSERT(dt == DT_WEAPON_ESSENCE || dt == DT_PROJECTILE_ESSENCE);
//
// if( dt == DT_PROJECTILE_ESSENCE )
// {
// // Ô¶³ÌÎäÆ÷£¬Ê¹Óõ¯Ò©µÄЧ¹û
// PROJECTILE_ESSENCE * pProjectile = (PROJECTILE_ESSENCE *) pData;
//
// szFlyGFX = pProjectile->file_firegfx + 4; // skip gfx/
// szHitGFX = pProjectile->file_hitgfx + 4; // skip gfx/
// }
// else if (dt == DT_WEAPON_ESSENCE)
// {
// // ½ü³ÌÎïÀí¹¥»÷£¬Ê¹ÓÃÎäÆ÷µÄЧ¹û
// WEAPON_ESSENCE * pWeapon = (WEAPON_ESSENCE *) pData;
// WEAPON_SUB_TYPE * pWeaponType = (WEAPON_SUB_TYPE*) g_pGame->GetElementDataMan()->get_data_ptr(pWeapon->id_sub_type, ID_SPACE_ESSENCE, dt);
// ASSERT(dt == DT_WEAPON_SUB_TYPE);
// szFlyGFX = NULL;
// szHitGFX = pWeaponType->file_hitgfx + 4; // skip gfx/
// }
//
// bool bHideFlyGfx = !CECOptimize::Instance().GetGFX().CanShowFly(m_idHost);
// bool bHideHitGfx = !CECOptimize::Instance().GetGFX().CanShowHit(m_idHost);
// int nNumTargets = m_targets.size();
// for(int i=0; i<nNumTargets; i++)
// {
// const TARGET_DATA& data = m_targets[i];
//
// const char * pszFlyGFX = szFlyGFX;
// const char * pszHitGFX = szHitGFX;
//
// if( data.dwModifier & MOD_NULLITY )
// pszHitGFX = "³ÌÐòÁªÈë\\»÷ÖÐ\\ÎÞЧ¹¥»÷»÷ÖÐ.gfx";
//
// if (bHideFlyGfx) pszFlyGFX = NULL;
// if (bHideHitGfx) pszHitGFX = NULL;
//
// g_pGame->GetGameRun()->GetWorld()->GetSkillGfxMan()->AddSkillGfxEvent(m_idHost, data.idTarget,
// pszFlyGFX, pszHitGFX, m_timeToDoDamage, false, enumLinearMove, 1, 0, NULL, vFlyScale, vHitScale, data.dwModifier);
// }
}
else
{
// without weapon
// ʹÓÃÈ­Ì×ÀàµÄ»÷ÖÐЧ¹û
DATA_TYPE dt = DATA_TYPE.DT_INVALID;
var pData = ElementDataManProvider.GetElementDataMan().get_data_ptr(183, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
WEAPON_SUB_TYPE pWeaponType = (WEAPON_SUB_TYPE) pData;
if (GPDataTypeHelper.ISPLAYERID(m_idHost))
{
if (m_idSkill != 0)
{
// const A3DSkillGfxComposer* pComposer = NULL;
//
// // we use skill composed gfx to present the skill effect
// if (m_nSkillSection>0) // ¶à¶Î¼¼ÄÜ
// {
// CECMultiSectionSkillMan pMan = m_pManager.GetMultiSkillGfxComposerMan();
// if(pMan)
// {
// pMan->Play(m_idSkill, m_nSkillSection,m_idHost, m_idCastTarget, m_targets,GNET::ElementSkill::IsGoblinSkill(m_idSkill));
// pComposer = pMan->GetSkillGfxComposer(m_idSkill, m_nSkillSection);
// }
// }
// else
// {
// if(GNET::ElementSkill::IsGoblinSkill(m_idSkill))
// m_pManager->GetSkillGfxComposerMan()->Play(m_idSkill, m_idHost, m_idCastTarget, m_targets, true);
// else
// m_pManager->GetSkillGfxComposerMan()->Play(m_idSkill, m_idHost, m_idCastTarget, m_targets);
// pComposer = m_pManager->GetSkillGfxComposerMan()->GetSkillGfxComposer(m_idSkill);
// }
//
// if (pComposer && pComposer->m_dwFlyTime == 0) // ¼¼ÄÜgfxûÓзÉÐÐʵ¼Ê£¬ÔòÂíÉÏÍ·¶¥Ã°×Ö
// {
// m_timeToDoDamage = 1;
// }
// else
// {
// A3DVECTOR3 vecHost, vecTarget;
// // now we estimated a time to do damage
// if( m_targets.size() && _get_pos_by_id(m_idHost, vecHost) && _get_pos_by_id(m_targets[0].idTarget, vecTarget) )
// {
// m_timeToDoDamage = int(Magnitude(vecHost - vecTarget) / 20.0f * 1000.0f);
// a_ClampFloor(m_timeToDoDamage, 10ul);
// }
// }
}
else if (m_idWeapon != 0)
{
// first determine gfx used
// const char * szFlyGFX = NULL;
// const char * szHitGFX = NULL;
//
// // using weapon gfx
// DATA_TYPE dt;
// const void * pData = g_pGame->GetElementDataMan()->get_data_ptr(
// m_idWeapon, ID_SPACE_ESSENCE, dt);
// ASSERT(dt == DT_WEAPON_ESSENCE || dt == DT_PROJECTILE_ESSENCE);
//
// if( dt == DT_PROJECTILE_ESSENCE )
// {
// // Ô¶³ÌÎäÆ÷£¬Ê¹Óõ¯Ò©µÄЧ¹û
// PROJECTILE_ESSENCE * pProjectile = (PROJECTILE_ESSENCE *) pData;
//
// szFlyGFX = pProjectile->file_firegfx + 4; // skip gfx/
// szHitGFX = pProjectile->file_hitgfx + 4; // skip gfx/
// }
// else if (dt == DT_WEAPON_ESSENCE)
// {
// // ½ü³ÌÎïÀí¹¥»÷£¬Ê¹ÓÃÎäÆ÷µÄЧ¹û
// WEAPON_ESSENCE * pWeapon = (WEAPON_ESSENCE *) pData;
// WEAPON_SUB_TYPE * pWeaponType = (WEAPON_SUB_TYPE*) g_pGame->GetElementDataMan()->get_data_ptr(pWeapon->id_sub_type, ID_SPACE_ESSENCE, dt);
// ASSERT(dt == DT_WEAPON_SUB_TYPE);
// szFlyGFX = NULL;
// szHitGFX = pWeaponType->file_hitgfx + 4; // skip gfx/
// }
//
// bool bHideFlyGfx = !CECOptimize::Instance().GetGFX().CanShowFly(m_idHost);
// bool bHideHitGfx = !CECOptimize::Instance().GetGFX().CanShowHit(m_idHost);
// int nNumTargets = m_targets.size();
// for(int i=0; i<nNumTargets; i++)
// {
// const TARGET_DATA& data = m_targets[i];
//
// const char * pszFlyGFX = szFlyGFX;
// const char * pszHitGFX = szHitGFX;
//
// if( data.dwModifier & MOD_NULLITY )
// pszHitGFX = "³ÌÐòÁªÈë\\»÷ÖÐ\\ÎÞЧ¹¥»÷»÷ÖÐ.gfx";
//
// if (bHideFlyGfx) pszFlyGFX = NULL;
// if (bHideHitGfx) pszHitGFX = NULL;
//
// g_pGame->GetGameRun()->GetWorld()->GetSkillGfxMan()->AddSkillGfxEvent(m_idHost, data.idTarget,
// pszFlyGFX, pszHitGFX, m_timeToDoDamage, false, enumLinearMove, 1, 0, NULL, vFlyScale, vHitScale, data.dwModifier);
// }
}
else
{
// without weapon
// ʹÓÃÈ­Ì×ÀàµÄ»÷ÖÐЧ¹û
DATA_TYPE dt = DATA_TYPE.DT_INVALID;
var pData = ElementDataManProvider.GetElementDataMan().get_data_ptr(183, ID_SPACE.ID_SPACE_ESSENCE, ref dt);
WEAPON_SUB_TYPE pWeaponType = (WEAPON_SUB_TYPE)pData;
bool bHideHitGfx = false;//!CECOptimize::Instance().GetGFX().CanShowHit(m_idHost);
string szGFX= null;
int nNumTargets = m_targets.Count();
for(int i=0; i<nNumTargets; i++)
{
TARGET_DATA data = m_targets[i];
// szGFX = pWeaponType->file_hitgfx + 4; // skip gfx/
string fullGfx = pWeaponType.GetFileHitGfx();
szGFX = fullGfx.Length > 4 ? fullGfx.Substring(4) : string.Empty;
if ((data.dwModifier & (int)MOD.MOD_NULLITY) != 0)
szGFX = "程序联入\\击中\\无效攻击击中.gfx";//Program link\Hit\InvalidAttackHit.gfx
if (bHideHitGfx) szGFX = null;
// g_pGame->GetGameRun()->GetWorld()->GetSkillGfxMan()->AddSkillGfxEvent(m_idHost, data.idTarget, NULL,
// szGFX, m_timeToDoDamage, false, GfxMoveMode.enumLinearMove, 1, 0, NULL, vFlyScale, vHitScale, data.dwModifier);
var target = EC_ManMessageMono.Instance?.GetObject(data.idTarget, 0)?.gameObject.transform;
if (target == null)
{
BMLogger.LogError("Target is null!");
return false;
}
var vfx = CECGameRun.Instance.GetTestVfx();
vfx.transform.position = target.position;
CECGameRun.Instance.DestroyTestVfx(vfx, 1f);
}
}
}
else if( GPDataTypeHelper.ISNPCID(m_idHost) )
{
// if( m_idSkill != 0 )
// {
// const A3DSkillGfxComposer* pComposer = NULL;
// // we use skill composed gfx to present the skill effect
// if (m_nSkillSection>0) // ¶à¶Î¼¼ÄÜ
// {
// CECMultiSectionSkillMan* pMan = m_pManager->GetMultiSkillGfxComposerMan();
// if(pMan)
// {
// pMan->Play(m_idSkill, m_nSkillSection,m_idHost, m_idCastTarget, m_targets);
// pComposer = pMan->GetSkillGfxComposer(m_idSkill, m_nSkillSection);
// }
// }
// else
// {
// m_pManager->GetSkillGfxComposerMan()->Play(m_idSkill, m_idHost, m_idCastTarget, m_targets);
// pComposer = m_pManager->GetSkillGfxComposerMan()->GetSkillGfxComposer(m_idSkill);
// }
//
// if (pComposer && pComposer->m_dwFlyTime == 0) // ¼¼ÄÜûÓзÉÐÐʱ¼ä£¬ÔòÖ±½ÓÍ·¶¥Ã°×Ö
// {
// m_timeToDoDamage = 1;
// }
// else
// {
// A3DVECTOR3 vecHost, vecTarget;
// // now we estimated a time to do damage
// if( m_targets.size() && _get_pos_by_id(m_idHost, vecHost) && _get_pos_by_id(m_targets[0].idTarget, vecTarget) )
// {
// m_timeToDoDamage = int(Magnitude(vecHost - vecTarget) / 20.0f * 1000.0f);
// a_ClampFloor(m_timeToDoDamage, 10ul);
// }
// }
// }
// else
// {
// CECNPC * pNPC = g_pGame->GetGameRun()->GetWorld()->GetNPCMan()->GetNPC(m_idHost);
// if (!pNPC)
// return true;
//
// const char * szFlyGFX = NULL;
// const char * szHitGFX = NULL;
//
// if (pNPC->IsMonsterNPC())
// {
// const MONSTER_ESSENCE * pEssence = ((CECMonster *)pNPC)->GetDBEssence();
//
// szFlyGFX = pEssence->file_gfx_short + 4; // skip gfx/
// szHitGFX = pEssence->file_gfx_short_hit + 4; // skip gfx/
// }
// else if (pNPC->IsPetNPC())
// {
// //szFlyGFX = "";
// const PET_ESSENCE* pEssence = ((CECPet*)pNPC)->GetDBEssence();
//
// szFlyGFX = pEssence->file_gfx_short + 4; //"²ß»®ÁªÈë\\ͨÓ÷ÉÐÐ\\¹­¼ý·ÉÐÐ.gfx";
//
// szHitGFX = "²ß»®ÁªÈë\\¹ÖÎï»÷ÖÐ\\¹ÖÎïÈⲫ»÷ÖÐ.gfx";
// }
// else
// return false;
//
// if( !szFlyGFX[0] )
// szFlyGFX = NULL;
//
// if( !szHitGFX[0] )
// szHitGFX = NULL;
//
// bool bHideFlyGfx = !CECOptimize::Instance().GetGFX().CanShowFly(m_idHost);
// bool bHideHitGfx = !CECOptimize::Instance().GetGFX().CanShowHit(m_idHost);
// int nNumTargets = m_targets.size();
// for(int i=0; i<nNumTargets; i++)
// {
// const TARGET_DATA& data = m_targets[i];
//
// const char * pszFlyGFX = szFlyGFX;
// const char * pszHitGFX = szHitGFX;
// if( data.nDamage <= 0 )
// {
// pszHitGFX = NULL;
// }
// else if( data.dwModifier & MOD_NULLITY )
// {
// pszHitGFX = "³ÌÐòÁªÈë\\»÷ÖÐ\\ÎÞЧ¹¥»÷»÷ÖÐ.gfx";
// }
//
// if (bHideFlyGfx) pszFlyGFX = NULL;
// if (bHideHitGfx) pszHitGFX = NULL;
//
// g_pGame->GetGameRun()->GetWorld()->GetSkillGfxMan()->AddSkillGfxEvent(m_idHost, data.idTarget,
// pszFlyGFX, pszHitGFX, m_timeToDoDamage, false, enumLinearMove, 1,
// 0, NULL, vFlyScale, vHitScale, data.dwModifier);
// }
// }
}
else
return true;
return true;
}
bool bHideHitGfx = false;//!CECOptimize::Instance().GetGFX().CanShowHit(m_idHost);
string szGFX = null;
int nNumTargets = m_targets.Count();
for (int i = 0; i < nNumTargets; i++)
{
TARGET_DATA data = m_targets[i];
// szGFX = pWeaponType->file_hitgfx + 4; // skip gfx/
string fullGfx = pWeaponType.GetFileHitGfx();
szGFX = fullGfx.Length > 4 ? fullGfx.Substring(4) : string.Empty;
if ((data.dwModifier & (int)MOD.MOD_NULLITY) != 0)
szGFX = "程序联入\\击中\\无效攻击击中.gfx";//Program link\Hit\InvalidAttackHit.gfx
if (bHideHitGfx) szGFX = null;
// g_pGame->GetGameRun()->GetWorld()->GetSkillGfxMan()->AddSkillGfxEvent(m_idHost, data.idTarget, NULL,
// szGFX, m_timeToDoDamage, false, GfxMoveMode.enumLinearMove, 1, 0, NULL, vFlyScale, vHitScale, data.dwModifier);
var target = EC_ManMessageMono.Instance?.GetObject(data.idTarget, 0)?.gameObject.transform;
if (target == null)
{
BMLogger.LogError("Target is null!");
return false;
}
var vfx = CECGameRun.Instance.GetTestVfx();
vfx.transform.position = target.position;
CECGameRun.Instance.DestroyTestVfx(vfx, 1f);
}
}
}
else if (GPDataTypeHelper.ISNPCID(m_idHost))
{
// if( m_idSkill != 0 )
// {
// const A3DSkillGfxComposer* pComposer = NULL;
// // we use skill composed gfx to present the skill effect
// if (m_nSkillSection>0) // ¶à¶Î¼¼ÄÜ
// {
// CECMultiSectionSkillMan* pMan = m_pManager->GetMultiSkillGfxComposerMan();
// if(pMan)
// {
// pMan->Play(m_idSkill, m_nSkillSection,m_idHost, m_idCastTarget, m_targets);
// pComposer = pMan->GetSkillGfxComposer(m_idSkill, m_nSkillSection);
// }
// }
// else
// {
// m_pManager->GetSkillGfxComposerMan()->Play(m_idSkill, m_idHost, m_idCastTarget, m_targets);
// pComposer = m_pManager->GetSkillGfxComposerMan()->GetSkillGfxComposer(m_idSkill);
// }
//
// if (pComposer && pComposer->m_dwFlyTime == 0) // ¼¼ÄÜûÓзÉÐÐʱ¼ä£¬ÔòÖ±½ÓÍ·¶¥Ã°×Ö
// {
// m_timeToDoDamage = 1;
// }
// else
// {
// A3DVECTOR3 vecHost, vecTarget;
// // now we estimated a time to do damage
// if( m_targets.size() && _get_pos_by_id(m_idHost, vecHost) && _get_pos_by_id(m_targets[0].idTarget, vecTarget) )
// {
// m_timeToDoDamage = int(Magnitude(vecHost - vecTarget) / 20.0f * 1000.0f);
// a_ClampFloor(m_timeToDoDamage, 10ul);
// }
// }
// }
// else
// {
// CECNPC * pNPC = g_pGame->GetGameRun()->GetWorld()->GetNPCMan()->GetNPC(m_idHost);
// if (!pNPC)
// return true;
//
// const char * szFlyGFX = NULL;
// const char * szHitGFX = NULL;
//
// if (pNPC->IsMonsterNPC())
// {
// const MONSTER_ESSENCE * pEssence = ((CECMonster *)pNPC)->GetDBEssence();
//
// szFlyGFX = pEssence->file_gfx_short + 4; // skip gfx/
// szHitGFX = pEssence->file_gfx_short_hit + 4; // skip gfx/
// }
// else if (pNPC->IsPetNPC())
// {
// //szFlyGFX = "";
// const PET_ESSENCE* pEssence = ((CECPet*)pNPC)->GetDBEssence();
//
// szFlyGFX = pEssence->file_gfx_short + 4; //"²ß»®ÁªÈë\\ͨÓ÷ÉÐÐ\\¹­¼ý·ÉÐÐ.gfx";
//
// szHitGFX = "²ß»®ÁªÈë\\¹ÖÎï»÷ÖÐ\\¹ÖÎïÈⲫ»÷ÖÐ.gfx";
// }
// else
// return false;
//
// if( !szFlyGFX[0] )
// szFlyGFX = NULL;
//
// if( !szHitGFX[0] )
// szHitGFX = NULL;
//
// bool bHideFlyGfx = !CECOptimize::Instance().GetGFX().CanShowFly(m_idHost);
// bool bHideHitGfx = !CECOptimize::Instance().GetGFX().CanShowHit(m_idHost);
// int nNumTargets = m_targets.size();
// for(int i=0; i<nNumTargets; i++)
// {
// const TARGET_DATA& data = m_targets[i];
//
// const char * pszFlyGFX = szFlyGFX;
// const char * pszHitGFX = szHitGFX;
// if( data.nDamage <= 0 )
// {
// pszHitGFX = NULL;
// }
// else if( data.dwModifier & MOD_NULLITY )
// {
// pszHitGFX = "³ÌÐòÁªÈë\\»÷ÖÐ\\ÎÞЧ¹¥»÷»÷ÖÐ.gfx";
// }
//
// if (bHideFlyGfx) pszFlyGFX = NULL;
// if (bHideHitGfx) pszHitGFX = NULL;
//
// g_pGame->GetGameRun()->GetWorld()->GetSkillGfxMan()->AddSkillGfxEvent(m_idHost, data.idTarget,
// pszFlyGFX, pszHitGFX, m_timeToDoDamage, false, enumLinearMove, 1,
// 0, NULL, vFlyScale, vHitScale, data.dwModifier);
// }
// }
}
else
return true;
return true;
}
private bool DoDamage()
{
@@ -477,7 +695,7 @@ bool DoFire()
else if (GPDataTypeHelper.ISPLAYERID(idTarget))
{
CECPlayer pPlayer = EC_ManMessageMono.Instance.GetECManPlayer.GetPlayer(idTarget);
CECPlayer pPlayer = EC_ManMessageMono.Instance.GetECManPlayer.GetPlayer(idTarget);
//BMLogger.LogError("HoangDev: CECPlayer pPlayer = " + pPlayer );
if (!pPlayer)
@@ -606,15 +824,15 @@ enum MOD
};
enum GfxMoveMode
{
enumLinearMove = 0, // Linear
enumParabolicMove, // Parabolic
enumMissileMove, // Missile
enumMeteoricMove, // Meteoric (shooting star)
enumHelixMove, // Helix (spiral)
enumCurvedMove, // Curved
enumAccMove, // Accelerated
enumOnTarget, // Targeted
enumLink, // Linked
enumRandMove, // Random movement
enumMoveModeNum
enumLinearMove = 0, // Linear
enumParabolicMove, // Parabolic
enumMissileMove, // Missile
enumMeteoricMove, // Meteoric (shooting star)
enumHelixMove, // Helix (spiral)
enumCurvedMove, // Curved
enumAccMove, // Accelerated
enumOnTarget, // Targeted
enumLink, // Linked
enumRandMove, // Random movement
enumMoveModeNum
};
@@ -66,6 +66,9 @@ namespace PerfectWorld.Scripts.Managers
case int value when value == EC_MsgDef.MSG_PM_PLAYERRUNOUT:
OnMsgPlayerRunOut(Msg);
break;
case int value when value == EC_MsgDef.MSG_PM_CASTSKILL:
TransmitMessage(Msg);
break;
}
}
else
@@ -496,12 +499,12 @@ namespace PerfectWorld.Scripts.Managers
{
}
public bool TransmitMessage(ECMSG msg)
public bool TransmitMessage(ECMSG Msg)
{
int cid = 0;
var host = CECGameRun.Instance.GetHostPlayer();
switch (msg.dwMsg)
switch (Msg.dwMsg)
{
/*case long value when value == EC_MsgDef.MSG_PM_PLAYEREQUIPDATA:
if (msg.dwParam2 == S2C.EQUIP_DATA)
@@ -511,7 +514,7 @@ namespace PerfectWorld.Scripts.Managers
break;*/
case long value when value == EC_MsgDef.MSG_PM_PLAYERBASEINFO:
cid = (int)((playerbaseinfo_re)msg.dwParam1).Player.id;
cid = (int)((playerbaseinfo_re)Msg.dwParam1).Player.id;
// Xoá khỏi cache
//g_pGame.GetGameSession().GetC2SCmdCache().RemovePlayerBaseInfo(cid);
break;
@@ -527,8 +530,20 @@ namespace PerfectWorld.Scripts.Managers
cid = ((cmd_object_landing)msg.dwParam1).object_id;
break;*/
case long value when value == EC_MsgDef.MSG_PM_PLAYERATKRESULT:
cmd_object_atk_result pCmdAtk = GPDataTypeHelper.FromBytes<cmd_object_atk_result>((byte[])msg.dwParam1);
cmd_object_atk_result pCmdAtk = GPDataTypeHelper.FromBytes<cmd_object_atk_result>((byte[])Msg.dwParam1);
cid = pCmdAtk.attacker_id;
break;
case long value when value == EC_MsgDef.MSG_PM_CASTSKILL:
switch (Convert.ToInt32(Msg.dwParam2))
{
case int value2 when value2 == CommandID.OBJECT_CAST_SKILL: cid = (GPDataTypeHelper.FromBytes<cmd_object_cast_skill>((byte[]) Msg.dwParam1)).caster; break;
/* case CommandID.OBJECT_CAST_INSTANT_SKILL: cid = ((cmd_object_cast_instant_skill*)Msg.dwParam1)->caster; break;
case CommandID.OBJECT_CAST_POS_SKILL: cid = ((cmd_object_cast_pos_skill*)Msg.dwParam1)->caster; break;
case CommandID.SKILL_INTERRUPTED: cid = ((cmd_skill_interrupted*)Msg.dwParam1)->caster; break;
case CommandID.PLAYER_CAST_RUNE_SKILL: cid = ((cmd_player_cast_rune_skill*)Msg.dwParam1)->caster; break;
case CommandID.PLAYER_CAST_RUNE_INSTANT_SKILL: cid = ((cmd_player_cast_rune_instant_skill*)Msg.dwParam1)->caster; break;*/
}
break;
// ⚠️ Các case khác cũng tương tự, chỉ việc lấy ra đúng trường id / caster / user ...
// Do quá dài nên bạn có thể copy dần từng case từ C++ sang.
@@ -546,13 +561,13 @@ namespace PerfectWorld.Scripts.Managers
if (host != null && cid == host.GetCharacterID())
{
host.ProcessMessage(msg);
host.ProcessMessage(Msg);
}
else
{
var elsePlayer = SeekOutElsePlayer(cid);
if (elsePlayer != null)
elsePlayer.ProcessMessage(msg);
elsePlayer.ProcessMessage(Msg);
}
return true;
+247 -71
View File
@@ -21,8 +21,9 @@ public abstract class CECPlayer : CECObject
{
[SerializeField] protected Transform parentModel;
[SerializeField] protected TextMeshProUGUI txtName;
[ResetStatic]
private static PLAYER_ACTION[] _default_actions;
[ResetStatic]
private static PLAYER_ACTION[] _turning_actions;
PLAYER_ACTION[] m_PlayerActions;
[SerializeField] internal INFO m_PlayerInfo;
@@ -56,6 +57,8 @@ public abstract class CECPlayer : CECObject
protected static PLAYER_LEVELEXP_CONFIG _player_levelup_exp;
private CECPlayerActionController m_pActionController;
private enumWingType m_wingType;
private int m_idCurSkillTarget;
protected CECSkill m_pCurSkill;
protected int NUM_WEAPON_TYPE = 15;
public static readonly int[] m_sciStateIDForStateAction = { 117 };
@@ -158,6 +161,7 @@ public abstract class CECPlayer : CECObject
m_iFashionWeaponType = -1;
m_uAttackType = DEFAULT_ACTION_TYPE;
AttachWeapon();
}
@@ -182,6 +186,7 @@ public abstract class CECPlayer : CECObject
public static void InitStaticRes()
{
BMLogger.LogError("HoangDev: InitStaticRes");
BuildActionList();
DATA_TYPE dt = default;
_player_levelup_exp = (PLAYER_LEVELEXP_CONFIG)ElementDataManProvider.GetElementDataMan()
@@ -208,7 +213,7 @@ public abstract class CECPlayer : CECObject
{
if (_default_actions == null)
{
// thay cho hashtab trong C++
Dictionary<string, PLAYER_ACTION_INFO_CONFIG> actionMap =
new Dictionary<string, PLAYER_ACTION_INFO_CONFIG>(100);
@@ -234,10 +239,18 @@ public abstract class CECPlayer : CECObject
{
if (!actionMap.TryAdd(data.ActionName, data))
{
}
}
if (!string.IsNullOrEmpty(data.ActionName) && data.ActionName[0] != '0')
{
if (!skillActionMap.TryAdd(data.Name, data))
{
}
}
}
///
CECStringTab actionNames = new CECStringTab();
actionNames.Init("actions_player", false);
@@ -542,89 +555,88 @@ public abstract class CECPlayer : CECObject
if (CECAttacksMan.Instance.FindAttackByAttacker(GetPlayerInfo().cid))
{
BMLogger.LogError("CECAttacksMan::FindAttackByAttacker != NULL");
ClearComActFlagAllRankNodes(true);
}
// melee attack
CECAttackEvent pAttack = CECAttacksMan.Instance.AddMeleeAttack(
CECAttackEvent pAttack1 = CECAttacksMan.Instance.AddMeleeAttack(
GetPlayerInfo().cid, idTarget, idWeapon, dwModifier, nDamage, nTimeFly);
if (pAttack != null)
if (pAttack1 != null)
{
if (!IsDead() && (dwModifier & (uint)MOD.MOD_RETORT) == 0
&& (dwModifier & (uint)MOD.MOD_ATTACK_AURA) == 0
&& PlayAttackAction(nAttackSpeed, ref piAttackTime, pAttack)
&& PlayAttackAction(nAttackSpeed, ref piAttackTime, pAttack1)
&& (dwModifier & (uint)MOD.MOD_BEAT_BACK) == 0)
{
}
else
{
pAttack1.m_bSignaled = true;
}
}
}
else
{
if (skillLevel == 0)
{
if (m_pCurSkill != null)
skillLevel = m_pCurSkill.GetSkillLevel();
else
skillLevel = 1;
}
CECAttackEvent pAttack = null;
// first try to find if there is already a skill attack event in attackman
CECAttackerEvents attackerEvents = CECAttacksMan.Instance.FindAttackByAttacker(GetPlayerInfo().cid);
if (attackerEvents)
{
CECAttackEvent pAttack1 = attackerEvents.Find(idSkill, nSection);
if (pAttack1 != null)
{
// Ãæ¹¥»÷µÄ·ÇµÚÒ»´ÎÉ˺¦ÏûÏ¢
pAttack1.AddTarget(idTarget, dwModifier, nDamage);
goto EXIT;
}
else
{
attackerEvents.Signal();
}
}
if (ElementSkill.IsGoblinSkill((uint)idSkill) &&
ElementSkill.GetType((uint)idSkill) == 2)
{
pAttack = CECAttacksMan.Instance.AddSkillAttack(
GetPlayerInfo().cid, GetPlayerInfo().cid, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage);
}
else
{
// begin a skill attack
pAttack = CECAttacksMan.Instance.AddSkillAttack(
GetPlayerInfo().cid, m_idCurSkillTarget, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage);
}
if (pAttack != null)
{
pAttack.SetSkillSection(nSection);
if (!IsDead() && (dwModifier & (uint)MOD.MOD_RETORT) == 0
&& (dwModifier & (uint)MOD.MOD_ATTACK_AURA) == 0
&& PlaySkillAttackAction(idSkill, nAttackSpeed, null, nSection, &pAttack.m_bSignaled)
&& (dwModifier & (uint)MOD.MOD_BEAT_BACK) == 0)
{
}
else
{
pAttack.m_bSignaled = true;
}
}
EXIT:
// // For skill attacking, time is always set to 0
if (piAttackTime != 0)
piAttackTime = 0;
}
//else
//{
// if (skillLevel == 0)
// {
// if (m_pCurSkill)
// skillLevel = m_pCurSkill.GetSkillLevel();
// else
// skillLevel = 1;
// }
// CECAttackEvent pAttack1 = null;
// // first try to find if there is already a skill attack event in attackman
// CECAttackerEvents attackerEvents = g_pGame.GetGameRun().GetWorld().GetAttacksMan().FindAttackByAttacker(GetPlayerInfo().cid);
// if (attackerEvents)
// {
// CECAttackEvent pAttack1 = attackerEvents.Find(idSkill, nSection);
// if (pAttack1 != null)
// {
// // Ãæ¹¥»÷µÄ·ÇµÚÒ»´ÎÉ˺¦ÏûÏ¢
// pAttack1.AddTarget(idTarget, dwModifier, nDamage);
// goto EXIT;
// }
// else
// {
// attackerEvents.Signal();
// }
// }
// if (ElementSkill::IsGoblinSkill(idSkill) &&
// GNET::ElementSkill::GetType(idSkill) == 2)
// {
// pAttack = g_pGame.GetGameRun().GetWorld().GetAttacksMan().AddSkillAttack(
// GetPlayerInfo().cid, GetPlayerInfo().cid, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage);
// }
// else
// {
// // begin a skill attack
// pAttack = g_pGame.GetGameRun().GetWorld().GetAttacksMan().AddSkillAttack(
// GetPlayerInfo().cid, m_idCurSkillTarget, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage);
// }
// if (pAttack)
// {
// pAttack.SetSkillSection(nSection);
// if (!IsDead() && (dwModifier & CECAttackEvent::MOD_RETORT) == 0
// && (dwModifier & CECAttackEvent::MOD_ATTACK_AURA) == 0
// && PlaySkillAttackAction(idSkill, nAttackSpeed, NULL, nSection, &pAttack.m_bSignaled)
// && (dwModifier & CECAttackEvent::MOD_BEAT_BACK) == 0)
// {
// }
// else
// {
// pAttack.m_bSignaled = true;
// }
// }
//EXIT:
// // For skill attacking, time is always set to 0
// if (piAttackTime)
// *piAttackTime = 0;
//}
}
private void ClearComActFlagAllRankNodes(bool v)
@@ -1135,9 +1147,7 @@ public abstract class CECPlayer : CECObject
int weapon_type = GetShowingWeaponType();
PLAYER_ACTION_INFO_CONFIG data = _default_skill_actions[(uint)idSkill];
if (data.action_prefix == null || data.action_prefix.Length == 0 || data.action_prefix[0] == 0)
if (!_default_skill_actions.TryGetValue((uint)idSkill, out PLAYER_ACTION_INFO_CONFIG data) || data.action_prefix == null || data.action_prefix.Length == 0 || data.action_prefix[0] == 0)
{
// Check if it's a target item skill
if (ElementSkill.GetCommonCoolDown((uint)idSkill) > 1 << 4)
@@ -1154,6 +1164,7 @@ public abstract class CECPlayer : CECObject
if (GetMoveEnv() == (int)MoveEnvironment.MOVEENV_GROUND)
{
szAct = EC_Utility.BuildActionName(data, weapon_type, "_Ò÷³ª_");
BMLogger.LogError($"HoangDev: PlaySkillCastAction szAct={szAct} ");
}
else
{
@@ -1197,6 +1208,171 @@ public abstract class CECPlayer : CECObject
return m_pActionController != null
&& m_pActionController.PlaySkillCastActionWithName(idSkill, szActName, bNoFX);
}
public bool PlaySkillAttackAction(int idSkill, int nAttackSpeed, ref int piAttackTime, int nSection = 0, CECAttackEvent attackEvent = null)
{
if (_pPlayerModel == null)
return false;
string szAct = "";
int weapon_type = GetShowingWeaponType();
if (!_default_skill_actions.TryGetValue((uint)idSkill, out PLAYER_ACTION_INFO_CONFIG data) ||
data.action_prefix == null || data.action_prefix.Length == 0 || data.action_prefix[0] == 0)
{
// Check if it's a target item skill / 检查是否为目标道具技能
// if (GNET::ElementSkill::GetCommonCoolDown(idSkill) > 1 << 4)
// {
// data = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_USING_TARGET_ITEM].data;
// if (data == null || data.action_prefix == null || data.action_prefix.Length == 0 || data.action_prefix[0] == 0)
// return false;
// }
// else
return false;
}
int nTime1, nTime2;
bool bInfinite = false;
// CECModel pRightHandWeapon = GetRightHandWeapon(); // 获取右手武器 / Get right hand weapon
bool bHideFX = false; // !CECOptimize::Instance().GetGFX().CanShowAttack(GetCharacterID(), GetClassID());
var atkMan = CECAttacksMan.Instance;
if (GetMoveEnv() == (int)MoveEnvironment.MOVEENV_GROUND)
{
// 地面动作 / Ground action
szAct = EC_Utility.BuildActionName(data, weapon_type, "_施法行_");
GetSkillSectionActionName(ref szAct, idSkill, nSection);
if (!PlaySkillAttackActionWithName(idSkill, szAct, bHideFX, attackEvent))
{
return false;
}
// nTime1 = m_pPlayerModel->GetComActTimeSpanByName(szAct); // 获取动作时长 / Get action time span
// pAct = m_pPlayerModel->GetComActByName(szAct);
// if (pAct) bInfinite |= pAct->IsInfinite();
nTime1 = 1000; // 临时值 / Temporary value
szAct = $"{data.action_prefix}_施法行_{data.action_weapon_suffix[weapon_type].suffix}";
GetSkillSectionActionName(ref szAct, idSkill, nSection);
QueueSkillAttackActionWithName(idSkill, szAct, 0, bHideFX);
// nTime2 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
// pAct = m_pPlayerModel->GetComActByName(szAct);
// if (pAct) bInfinite |= pAct->IsInfinite();
nTime2 = 1000; // 临时值 / Temporary value
}
else
{
// 空中动作 / Air action
string szActionMiddleName = null;
if ((m_wingType == enumWingType.WINGTYPE_WING && IsFlying()) ||
(m_iProfession == PROFESSION.PROF_ANGEL) ||
(m_iProfession == PROFESSION.PROF_ARCHOR) ||
(m_iProfession == PROFESSION.PROF_MONK) ||
(m_iProfession == PROFESSION.PROF_GHOST))
{
szActionMiddleName = "空中翅膀"; // Air with wings / 空中翅膀
}
else
{
szActionMiddleName = "空中飞剑"; // Air with sword / 空中飞剑
}
szAct = $"{data.action_prefix}_{szActionMiddleName}_施法行_{data.action_weapon_suffix[weapon_type].suffix}";
GetSkillSectionActionName(ref szAct, idSkill, nSection);
if (!PlaySkillAttackActionWithName(idSkill, szAct, bHideFX, attackEvent))
{
return false;
}
// if (pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon->PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, ACT_CASTSKILL, bHideFX);
// nTime1 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
// pAct = m_pPlayerModel->GetComActByName(szAct);
// if (pAct) bInfinite |= pAct->IsInfinite();
nTime1 = 1000; // 临时值 / Temporary value
szAct = $"{data.action_prefix}_{szActionMiddleName}_施法行_{data.action_weapon_suffix[weapon_type].suffix}";
GetSkillSectionActionName(ref szAct, idSkill, nSection);
QueueSkillAttackActionWithName(idSkill, szAct, 0, bHideFX);
// if (pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon->QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, ACT_CASTSKILL, false, false, bHideFX);
// nTime2 = m_pPlayerModel->GetComActTimeSpanByName(szAct);
// pAct = m_pPlayerModel->GetComActByName(szAct);
// if (pAct) bInfinite |= pAct->IsInfinite();
nTime2 = 1000; // 临时值 / Temporary value
}
// int nExecuteTime = GNET::ElementSkill::GetExecuteTime(idSkill, 0); // 获取技能执行时间 / Get skill execute time
int nExecuteTime = 2000; // 临时值 / Temporary value
// 调整动画速度以匹配攻击速度 / Adjust animation speed to match attack speed
if (!bInfinite)
{
if (nExecuteTime > 0)
{
float vScale = (nTime1 + nTime2) / (float)nExecuteTime;
// m_pPlayerModel->SetPlaySpeed(vScale * 1.2f);
// if (pRightHandWeapon && IsUsingMagicWeapon())
// pRightHandWeapon->SetPlaySpeed(vScale * 1.2f);
}
piAttackTime = nTime1 + nTime2;
}
else
{
// 动作循环,返回技能决定的执行时间 / Action loops, return skill-determined execute time
piAttackTime = nExecuteTime;
}
ShowWeaponByConfig(data);
// UpdateWeaponHangerPosBySkillAction(idSkill); // 根据技能播放的动作,更改武器悬挂位置 / Update weapon hanger position based on skill action
return true;
}
// 播放技能攻击动作(带名称)/ Play skill attack action with name
public bool PlaySkillAttackActionWithName(int idSkill, string szActName, bool bNoFX = false, CECAttackEvent attackEvent = null)
{
return m_pActionController != null
&& m_pActionController.PlaySkillAttackActionWithName(idSkill, szActName, bNoFX, attackEvent != null ? new bool[] { attackEvent.m_bSignaled } : null, 0);
}
// 队列播放技能攻击动作(带名称)/ Queue skill attack action with name
public bool QueueSkillAttackActionWithName(int idSkill, string szActName, int nTransTime = 200, bool bNoFX = false, bool bResetSpeed = false, bool bResetActFlag = false, bool[] pNewActFlag = null, uint dwNewFlagMode = 0)
{
return m_pActionController != null
&& m_pActionController.QueueSkillAttackActionWithName(idSkill, szActName, nTransTime, bNoFX, bResetSpeed, bResetActFlag, pNewActFlag, dwNewFlagMode);
}
// 获取技能段动作名称 / Get skill section action name
private void GetSkillSectionActionName(ref string szAct, int idSkill, int nSection)
{
if (nSection != 0)
{
var pAtkMan = CECAttacksMan.Instance;
if (pAtkMan != null && pAtkMan.GetSkillSectionActionSuffix(idSkill, nSection, out string suffix))
{
szAct += "_" + suffix;
}
}
}
// 判断是否在飞行 / Check if flying
public bool IsFlying()
{
// 临时实现 / Temporary implementation
return m_iMoveEnv == (int)MoveEnvironment.MOVEENV_AIR;
}
bool GetSkillStateActionName(int skill, int state, string name1, string name2)
{
/* for (int i = 0; i < (int)m_SkillStateActionVec.size(); i++)
@@ -203,7 +203,13 @@ namespace BrewMonster.Scripts.Skills
public virtual int SetLevel(int level) { return 0; }
// 󼶱?
public virtual int GetMaxLevel() { return 0; }
public static byte GetType(uint id)
{
SkillStub s = SkillStub.GetStub(id);
if (s != null)
return s.GetType();
return 0;
}
// Ƿ
public virtual bool IsWarmup() { return false; }
// ʹúǷԶ
@@ -0,0 +1,17 @@
using System;
namespace BrewMonster
{
[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)]
public sealed class ResetStaticAttribute : Attribute
{
public bool ClearCollection { get; }
public ResetStaticAttribute(bool clearCollection = false)
{
ClearCollection = clearCollection;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: c3a0cdab3c60efe4c922639dc31fd198
@@ -0,0 +1,181 @@
using System;
using System.Linq;
using System.Reflection;
using UnityEngine;
namespace BrewMonster
{
public static class ResetStaticUtility
{
private const string AutoRunOnPlayPrefsKey = "ResetStaticUtility.AutoRunOnPlay";
public static int ResetAll(bool logEach = false, Func<Assembly, bool> assemblyFilter = null)
{
int resetCount = 0;
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in assemblies)
{
if (assembly.IsDynamic)
{
continue;
}
if (assemblyFilter == null)
{
string name = assembly.GetName().Name;
if (!(name == "Assembly-CSharp" || name == "Assembly-CSharp-firstpass" || name.StartsWith("Assembly-CSharp-")))
{
continue;
}
}
else if (!assemblyFilter(assembly))
{
continue;
}
Type[] types;
try
{
types = assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
types = ex.Types.Where(t => t != null).ToArray();
}
catch (Exception ex)
{
Debug.LogWarning($"[ResetStatic] Failed to enumerate types for assembly {assembly.FullName}: {ex}");
continue;
}
foreach (var type in types)
{
if (type == null)
{
continue;
}
FieldInfo[] fields = type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
foreach (var field in fields)
{
if (field.IsLiteral || field.IsInitOnly)
{
continue;
}
var attr = field.GetCustomAttribute<ResetStaticAttribute>(false);
if (attr == null)
{
continue;
}
try
{
object newValue = null;
object currentValue = field.GetValue(null);
if (field.FieldType.IsValueType)
{
newValue = Activator.CreateInstance(field.FieldType);
field.SetValue(null, newValue);
resetCount++;
if (logEach)
{
Debug.Log($"[ResetStatic] {type.FullName}.{field.Name} set to default({field.FieldType.Name}).");
}
continue;
}
if (attr.ClearCollection && currentValue != null)
{
bool cleared = TryClearCollection(currentValue);
if (cleared)
{
resetCount++;
if (logEach)
{
Debug.Log($"[ResetStatic] {type.FullName}.{field.Name} collection cleared.");
}
continue;
}
}
field.SetValue(null, null);
resetCount++;
if (logEach)
{
Debug.Log($"[ResetStatic] {type.FullName}.{field.Name} set to null.");
}
}
catch (Exception ex)
{
Debug.LogWarning($"[ResetStatic] Failed to reset {type.FullName}.{field.Name}: {ex}");
}
}
}
}
return resetCount;
}
private static bool TryClearCollection(object instance)
{
try
{
if (instance is System.Collections.IDictionary dictionary)
{
dictionary.Clear();
return true;
}
if (instance is System.Collections.IList list)
{
list.Clear();
return true;
}
// Try generic ICollection<T>.Clear()
var clearMethod = instance.GetType().GetMethod("Clear", BindingFlags.Instance | BindingFlags.Public, null, Type.EmptyTypes, null);
if (clearMethod != null)
{
clearMethod.Invoke(instance, null);
return true;
}
}
catch (Exception ex)
{
Debug.LogWarning($"[ResetStatic] Failed to clear collection of type {instance.GetType().FullName}: {ex}");
}
return false;
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void AutoResetOnPlay()
{
#if UNITY_EDITOR
bool enabled = UnityEditor.EditorPrefs.GetBool(AutoRunOnPlayPrefsKey, true);
if (!enabled)
{
return;
}
#endif
ResetAll(logEach: false);
}
#if UNITY_EDITOR
public static bool GetAutoRunOnPlay()
{
return UnityEditor.EditorPrefs.GetBool(AutoRunOnPlayPrefsKey, true);
}
public static void SetAutoRunOnPlay(bool enabled)
{
UnityEditor.EditorPrefs.SetBool(AutoRunOnPlayPrefsKey, enabled);
}
#endif
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 1e3ede496bb135a4da6506adbcb7bbf2
+2 -2
View File
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:951300c91d8eb0444ef6f6d4231547c757908cba80c036bc743d186711fca527
size 33032375
oid sha256:37b57414ce51a79ba81ede1be7122f4a6b5b4fc856e9bb741aba9e533fd8d64c
size 33032374
+10 -6
View File
@@ -61,7 +61,6 @@ public partial class CECHostPlayer : CECPlayer
private int m_iRoleCreateTime;
private int m_iRoleLastLoginTime; // Role last login time
private int m_iAccountTotalCash;
private int m_idCurSkillTarget;
private List<CECObject> m_aTabSels = new List<CECObject>();
private List<CECSkill> m_aPtSkills = new List<CECSkill>();
@@ -409,7 +408,6 @@ public partial class CECHostPlayer : CECPlayer
case int value when value == EC_MsgDef.MSG_HST_DIED: OnMsgHstDied(Msg); break;
case int value when value == EC_MsgDef.MSG_HST_GOTO: OnMsgHstGoto(Msg); break;
case int value when value == EC_MsgDef.MSG_PM_CASTSKILL: OnMsgPlayerCastSkill(Msg); break;
}
}
@@ -422,8 +420,7 @@ public partial class CECHostPlayer : CECPlayer
bool bActionStartSkill = false;
int iActionTime = 1000;
//CECPlayerWrapper pWrapper = CECAutoPolicy.GetInstance().GetPlayerWrapper();
BMLogger.LogError("HoangDev OnMsgPlayerCastSkill Msg.dwParam2 " + (int)Msg.dwParam2);
switch ((int)Msg.dwParam2)
switch (Convert.ToInt32(Msg.dwParam2))
{
case CommandID.OBJECT_CAST_SKILL:
{
@@ -781,7 +778,7 @@ public partial class CECHostPlayer : CECPlayer
break;*/
}
if (bActionStartSkill)
/* if (bActionStartSkill)
AP_ActionEvent(AP_EVENT_STARTSKILL, iActionTime);
if (bDoOtherThing)
@@ -798,7 +795,7 @@ public partial class CECHostPlayer : CECPlayer
if (idTarget != 0 && idTarget != m_PlayerInfo.cid)
NormalAttackObject(idTarget, true);
}
}
}*/
}
private void OnMsgHstSkillData(ECMSG Msg)
{
@@ -1452,7 +1449,14 @@ public partial class CECHostPlayer : CECPlayer
isRun = value;
}
public override void SetUpPlayer()
{
base.SetUpPlayer();
m_IncantCnt = new CECCounter();
m_IncantCnt.SetPeriod(1000);
m_IncantCnt.Reset(true);
}
public void InitCharacter(cmd_self_info_1 role)
{
SetUpPlayer();