diff --git a/Assets/PerfectWorld/Scripts/Common/DataProcess/elementdataman.cs b/Assets/PerfectWorld/Scripts/Common/DataProcess/elementdataman.cs index d15158babc..168cad3e10 100644 --- a/Assets/PerfectWorld/Scripts/Common/DataProcess/elementdataman.cs +++ b/Assets/PerfectWorld/Scripts/Common/DataProcess/elementdataman.cs @@ -1504,6 +1504,15 @@ namespace ModelRenderer.Scripts.GameData } break; // TODO: Add other id spaces here. + case ID_SPACE.ID_SPACE_CONFIG: + foreach (var item in config_id_data_type_map) + { + if (item.Value == dataType) + { + return item.Key; + } + } + break; default: return 0; } diff --git a/Assets/Scripts/MainFiles.meta b/Assets/PerfectWorld/Scripts/MainFiles.meta similarity index 100% rename from Assets/Scripts/MainFiles.meta rename to Assets/PerfectWorld/Scripts/MainFiles.meta diff --git a/Assets/PerfectWorld/Scripts/MainFiles/CECGameRun.cs b/Assets/PerfectWorld/Scripts/MainFiles/CECGameRun.cs new file mode 100644 index 0000000000..4f4a6eb598 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/MainFiles/CECGameRun.cs @@ -0,0 +1,24 @@ +using BrewMonster; +using CSNetwork.GPDataType; +using System; +using UnityEngine; + +public class CECGameRun +{ + private CECWorld m_pWorld; + public CECWorld GetWorld() { return m_pWorld; } + public bool StartGame(int idInst, Vector3 vHostPos) + { + if (!JumpToInstance(idInst, vHostPos)) + { + BMLogger.LogError ( "CECGameRun::StartGame, Failed to create game world."); + return false; + } + return true; + } + + private bool JumpToInstance(int idInst, Vector3 vHostPos, int iParallelWorldID = 0) + { + return true; + } +} diff --git a/Assets/PerfectWorld/Scripts/MainFiles/CECGameRun.cs.meta b/Assets/PerfectWorld/Scripts/MainFiles/CECGameRun.cs.meta new file mode 100644 index 0000000000..7cf0ff7a64 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/MainFiles/CECGameRun.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 923b4102fc6857a4e94d7a662b2e6e1a \ No newline at end of file diff --git a/Assets/Scripts/MainFiles/EC_Game.cs b/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.cs similarity index 76% rename from Assets/Scripts/MainFiles/EC_Game.cs rename to Assets/PerfectWorld/Scripts/MainFiles/EC_Game.cs index 615f715b06..e8fb988a5a 100644 --- a/Assets/Scripts/MainFiles/EC_Game.cs +++ b/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.cs @@ -8,6 +8,7 @@ namespace BrewMonster.Network #region Fields private static ATaskTemplMan m_pTaskMan; // Task template manager private static elementdataman m_pElementDataMan; // global element templates manager + private static CECGameRun m_pGameRun; // Game running object #endregion #region Properties @@ -29,8 +30,15 @@ namespace BrewMonster.Network Debug.LogError("[Dat]- CECGame::Init, Storage task Init Failed!"); return false; } + m_pGameRun = new CECGameRun(); + if (m_pGameRun == null) + { + BMLogger.LogError("CECGame::Init"); + return false; + } return true; } + public static CECGameRun GetGameRun() { return m_pGameRun; } #endregion } } \ No newline at end of file diff --git a/Assets/Scripts/MainFiles/EC_Game.cs.meta b/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.cs.meta similarity index 100% rename from Assets/Scripts/MainFiles/EC_Game.cs.meta rename to Assets/PerfectWorld/Scripts/MainFiles/EC_Game.cs.meta diff --git a/Assets/PerfectWorld/Scripts/Managers/CECAttacksMan.cs b/Assets/PerfectWorld/Scripts/Managers/CECAttacksMan.cs new file mode 100644 index 0000000000..153edaebc4 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Managers/CECAttacksMan.cs @@ -0,0 +1,357 @@ +using BrewMonster; +using CSNetwork.GPDataType; +using System; +using System.Collections; +using System.Collections.Generic; +using Unity.VisualScripting; +using UnityEngine; +using static CECAttacksMan; + +public class CECAttacksMan : MonoSingleton +{ + private readonly LinkedList m_AttackLinkedList = new LinkedList(); + + + + private void Update() + { + var node = m_AttackLinkedList.First; + while (node != null) + { + var next = node.Next; + if (node.Value.m_bFinished) + m_AttackLinkedList.Remove(node); + else node.Value.Tick((uint)(Time.deltaTime * 1000)); + node = next; + } + } + + public CECAttackerEvents FindAttackByAttacker(int idHost) + { + CECAttackerEvents result = new CECAttackerEvents(); + + foreach (var attack in m_AttackLinkedList) + { + if (attack.m_idHost == idHost) + { + result.Add(attack); + } + } + + return result; + } + + public CECAttackEvent AddMeleeAttack(int idHost, int idTarget, int idWeapon, uint dwModifier, int nDamage, int nTimeFly = 10) + { + var newEvent = new CECAttackEvent( + this, + idHost, + 0, // idCastTarget + idTarget, + idWeapon, + 0, // idSkill + 0, // nSkillLevel + dwModifier, + nDamage, + 200, // timeToBeFired + nTimeFly // timeToDoDamage + ); + m_AttackLinkedList.AddLast(newEvent); + + newEvent.UpdateTargetFlag(); + return m_AttackLinkedList.Last.Value; + } + + public CECAttackEvent AddSkillAttack(int idHost, int idCastTarget, int idTarget, int idWeapon, int idSkill, int nSkillLevel, uint dwModifier, int nDamage) + { + var newEvent = new CECAttackEvent( + this, + idHost, + idCastTarget, + idTarget, + idWeapon, + idSkill, + nSkillLevel, + dwModifier, + nDamage, + 200, // timeToBeFired + 1000 // timeToDoDamage + ); + m_AttackLinkedList.AddLast(newEvent); + + newEvent.UpdateTargetFlag(); + return m_AttackLinkedList.Last.Value; + } + + // === thêm tạm để code có thể compile === + public void AddAttack(CECAttackEvent evt) + { + m_AttackLinkedList.AddLast(evt); + } + public class TARGET_DATA + { + public int idTarget; + public uint dwModifier; + public int nDamage; + } + + +} +public class CECAttackEvent +{ + public CECAttacksMan? m_pManager; + + public bool m_bSignaled; + public bool m_bDoFired; + public bool m_bDoDamaged; + public bool m_bFinished; + + public uint m_timeLived; + public uint m_timeToBeFired; + public uint m_timeToDoDamage; + + public int m_idHost; + public int m_idCastTarget; + public List m_targets = new List(); + + public int m_idWeapon; + public int m_idSkill; + public int m_nSkillLevel; + public int m_nSkillSection; + + public CECAttackEvent() { } + + public CECAttackEvent(CECAttacksMan? pManager, int idHost, int idCastTarget, int idTarget, + int idWeapon, int idSkill, int nSkillLevel, uint dwModifier, + int nDamage, int nTimeToBeFired, int nTimeToDoDamage) + { + m_pManager = pManager; + m_idHost = idHost; + m_idCastTarget = idCastTarget; + m_idWeapon = idWeapon; + m_idSkill = idSkill; + m_nSkillLevel = nSkillLevel; + m_timeToBeFired = (uint)nTimeToBeFired; + m_timeToDoDamage = (uint)nTimeToDoDamage; + + AddTarget(idTarget, dwModifier, nDamage); + } + public bool Tick(uint dwDeltaTime) + { + m_timeLived += dwDeltaTime; + + if (!m_bSignaled) + { + if (m_timeLived > 3500) + { + // too long time, this event will be deleted now + m_bFinished = true; + //DoFire(); + DoDamage(); + } + + return true; + } + else + { + if (m_timeToBeFired != 0) + { + if (m_timeToBeFired <= dwDeltaTime) + { + m_timeToBeFired = 0; + + // Fire here + //DoFire(); + } + else + m_timeToBeFired -= dwDeltaTime; + } + else if (m_timeToDoDamage != 0) + { + if (m_timeToDoDamage <= dwDeltaTime) + { + m_timeToDoDamage = 0; + + // Do damage here + DoDamage(); + } + else + m_timeToDoDamage -= dwDeltaTime; + } + } + + return true; + } + + private bool DoDamage() + { + m_bDoDamaged = true; + m_bFinished = true; + + /* CECGameRun pGameRun = g_pGame-GetGameRun(); + int idHostPlayer = pGameRun->GetHostPlayer()->GetCharacterID();*/ + + // Get host name + /* ACString strHostName; + CECObject* pHostObject = pGameRun->GetWorld()->GetObject(m_idHost, 0); + if (pHostObject) + { + if (ISNPCID(m_idHost)) + strHostName = ((CECNPC*)pHostObject)->GetName(); + else if (ISPLAYERID(m_idHost)) + strHostName = GetPlayerName((CECPlayer*)pHostObject); + }*/ + + int nNumTargets = m_targets.Count; + for (int i = 0; i < nNumTargets; i++) + { + TARGET_DATA data = m_targets[i]; + int idTarget = data.idTarget; + string strName; + + if (GPDataTypeHelper.ISNPCID(idTarget)) + { + CECNPC pNPC = null; + if ((data.dwModifier & (uint)MOD.MOD_SUCCESS) != 0) + pNPC = EC_ManMessageMono.Instance._CECNPCMan.GetNPCFromAll(idTarget); + else + { + pNPC = EC_ManMessageMono.Instance._CECNPCMan.GetNPCFromAll(idTarget); + if (!pNPC) + return true; + + //strName = pNPC->GetNameToShow(); + } + + if (!pNPC) + return true; + + pNPC.Damaged(data.nDamage, data.dwModifier); + } + else if (GPDataTypeHelper.ISPLAYERID(idTarget)) + { + /* CECPlayer* pPlayer = pGameRun->GetWorld()->GetPlayerMan()->GetPlayer(idTarget); + if (!pPlayer) + return true; + + strName = GetPlayerName(pPlayer); + + pPlayer->Damaged(data.nDamage, data.dwModifier, m_idSkill);*/ + } + + /* if (data.nDamage > 0) + { + if (m_idHost == idHostPlayer) + { + if (!strName.IsEmpty()) + pGameRun->AddFixedChannelMsg(FIXMSG_DODAMAGE, GP_CHAT_DAMAGE, strName, data.nDamage); + } + else if (data.idTarget == idHostPlayer) + { + if (!strHostName.IsEmpty()) + pGameRun->AddFixedChannelMsg(FIXMSG_BEDAMAGED, GP_CHAT_DAMAGE, strHostName, data.nDamage); + } + }*/ + } + + return true; + } + + public bool AddTarget(int idTarget, uint dwModifier, int nDamage) + { + m_targets.Add(new TARGET_DATA + { + idTarget = idTarget, + dwModifier = dwModifier, + nDamage = nDamage + }); + return true; + } + public bool UpdateTargetFlag() + { + // update all targets' bAboutToDie flag + + int nNumTargets = m_targets.Count; + for (int i = 0; i < nNumTargets; i++) + { + TARGET_DATA data = m_targets[i]; + /* + if( data.dwModifier & MOD_DEADLYSTRIKE ) + { + int idTarget = data.idTarget; + if (ISNPCID(idTarget)) + { + CECNPC* pNPC = g_pGame->GetGameRun()->GetWorld()->GetNPCMan()->GetNPC(idTarget); + if (!pNPC) + return true; + + pNPC->SetAboutToDie(true); + } + else if (ISPLAYERID(idTarget)) + { + CECPlayer* pPlayer = g_pGame->GetGameRun()->GetWorld()->GetPlayerMan()->GetPlayer(idTarget); + if (!pPlayer) + return true; + + pPlayer->SetAboutToDie(true); + } + }*/ + } + + return true; + } +} +public class CECAttackerEvents +{ + private readonly List m_list = new List(); + + public void Add(CECAttackEvent? evt) + { + if (evt != null) + m_list.Add(evt); + } + + public bool IsEmpty() => m_list.Count == 0; + public int Count() => m_list.Count; + + public CECAttackEvent? Find(int idSkill = 0, int nSkillSection = 0) + { + foreach (var evt in m_list) + { + if (evt.m_idSkill == idSkill && evt.m_nSkillSection == nSkillSection) + return evt; + } + return null; + } + + public void Signal() + { + foreach (var evt in m_list) + evt.m_bSignaled = true; + m_list.Clear(); + } + + public static implicit operator bool(CECAttackerEvents events) + { + return !events.IsEmpty(); + } +} +enum MOD + + { + MOD_PHYSIC_ATTACK_RUNE = 0x0001, // ÎïÀí¹¥»÷ÓÅ»¯·ûÉúЧ + MOD_MAGIC_ATTACK_RUNE = 0x0002, // ·¨Êõ¹¥»÷ÓÅ»¯·ûÉúЧ + MOD_PHYSIC_DEFENCE_RUNE = 0x0004, // ÎïÀí·ÀÓùÓÅ»¯·ûÉúЧ + MOD_MAGIC_DEFENCE_RUNE = 0x0008, // ·¨Êõ·ÀÓùÓÅ»¯·ûÉúЧ + MOD_CRITICAL_STRIKE = 0x0010, // ±¬»÷ + MOD_RETORT = 0x0020, // ·´Õð + MOD_NULLITY = 0x0040, // ÎÞЧ¹¥»÷ + MOD_IMMUNE = 0x0080, // ÃâÒßÁ˴˴ι¥»÷£¬ÓÅÏȼ¶¸ßÓÚÎÞЧ + MOD_ENCHANT_FAILED = 0x0100, // enchant ʧ°Ü + MOD_SUCCESS = 0x0200, // ³É¹¦ + MOD_DODGE_DAMAGE = 0x0400, // É˺¦¶ãÉÁ + MOD_DODGE_DEBUFF = 0x0800, // ״̬¶ãÉÁ + MOD_ATTACK_AURA = 0x1000, // ¹â»·¹¥»÷ + MOD_REBOUND = 0x2000, // ·´µ¯ + MOD_BEAT_BACK = 0x4000, // ·´»÷ +}; \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Managers/CECAttacksMan.cs.meta b/Assets/PerfectWorld/Scripts/Managers/CECAttacksMan.cs.meta new file mode 100644 index 0000000000..1de015f587 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Managers/CECAttacksMan.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 92009c5b4b0fd894790865cf674545fa \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Managers/CECNPCMan.cs b/Assets/PerfectWorld/Scripts/Managers/CECNPCMan.cs index 941257fdb8..d2ab1ac931 100644 --- a/Assets/PerfectWorld/Scripts/Managers/CECNPCMan.cs +++ b/Assets/PerfectWorld/Scripts/Managers/CECNPCMan.cs @@ -6,6 +6,7 @@ using System; using System.Buffers.Binary; using System.Collections.Generic; using System.Runtime.InteropServices; +using Unity.VisualScripting; using UnityEngine; public class CECNPCMan : CECObject, IMsgHandler @@ -203,6 +204,22 @@ public class CECNPCMan : CECObject, IMsgHandler return npc; } + public CECNPC GetNPCFromAll(int nid) + { + CECNPC pNPC = GetNPC(nid); + if (pNPC) + return pNPC; + + // Search from disappear array ? + /*for (int i = 0; i < m_aDisappearNPCs.GetSize(); i++) + { + CECNPC* pNPC = m_aDisappearNPCs[i]; + if (pNPC->GetNPCID() == nid) + return pNPC; + }*/ + + return null; + } public CECNPC CreateNPC(info_npc Info, bool bBornInSight, ReadOnlySpan packet, int infoOffset) { CECNPC pNPC = null; diff --git a/Assets/PerfectWorld/Scripts/Managers/DamageTextManager.cs b/Assets/PerfectWorld/Scripts/Managers/DamageTextManager.cs new file mode 100644 index 0000000000..9e3b9ce9af --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Managers/DamageTextManager.cs @@ -0,0 +1,85 @@ +using UnityEngine; +using System.Collections.Generic; +using TMPro; +using DG.Tweening; // cần DOTween + +public class DamageTextManager : MonoBehaviour +{ + public static DamageTextManager Instance { get; private set; } + + [Header("Prefab")] + [SerializeField] private TextMeshPro damageTextPrefab; + + [Header("Settings")] + [SerializeField] private int poolSize = 20; + [SerializeField] private Vector3 offset = new Vector3(0, 2f, 0); + [SerializeField] private float riseDistance = 1.5f; + [SerializeField] private float riseDuration = 0.8f; + + private readonly Queue pool = new(); + + private void Awake() + { + // Singleton + if (Instance != null && Instance != this) + { + Destroy(gameObject); + return; + } + Instance = this; + DontDestroyOnLoad(gameObject); + + // Tạo sẵn pool + for (int i = 0; i < poolSize; i++) + { + var textObj = Instantiate(damageTextPrefab, transform); + textObj.gameObject.SetActive(false); + pool.Enqueue(textObj); + } + } + + /// + /// Gọi để spawn text damage + /// + public void SpawnDamage(Vector3 worldPos, int damage, Color color, float scale = 1f) + { + var text = GetFromPool(); + text.text = damage.ToString(); + text.color = color; + text.fontSize = 6; + text.transform.localScale = Vector3.one * scale; + + Vector3 startPos = worldPos + offset; + text.transform.position = startPos; + text.gameObject.SetActive(true); + + // Hiệu ứng bay lên + mờ dần + text.transform.DOMoveY(startPos.y + riseDistance, riseDuration).SetEase(Ease.OutQuad); + text.DOFade(0f, riseDuration) + .SetEase(Ease.InQuad) + .OnComplete(() => + { + text.alpha = 1f; + text.gameObject.SetActive(false); + ReturnToPool(text); + }); + } + + private TextMeshPro GetFromPool() + { + if (pool.Count > 0) + { + return pool.Dequeue(); + } + + // Nếu hết pool, tạo thêm + var text = Instantiate(damageTextPrefab, transform); + text.gameObject.SetActive(false); + return text; + } + + private void ReturnToPool(TextMeshPro text) + { + pool.Enqueue(text); + } +} diff --git a/Assets/PerfectWorld/Scripts/Managers/DamageTextManager.cs.meta b/Assets/PerfectWorld/Scripts/Managers/DamageTextManager.cs.meta new file mode 100644 index 0000000000..e705cb5a3e --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Managers/DamageTextManager.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e7981b037b60f4a4989ff59265a308ad \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkMelee.cs b/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkMelee.cs index 126b9e1c93..a9f954569f 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkMelee.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkMelee.cs @@ -148,7 +148,7 @@ class CECHPWorkMelee : CECHPWork protected virtual void OnFirstTick() { m_pHost.m_iMoveMode = (int)MoveMode.MOVE_STAND; - m_pHost.PlayAction((int)EC_Player.PLAYER_ACTION_TYPE.ACT_ATTACK_1 + Random.Range(0, 3), true, 200, false); + m_pHost.PlayAction((int)CECPlayer.PLAYER_ACTION_TYPE.ACT_ATTACK_1 + Random.Range(0, 3), true, 200, false); m_idTarget = m_pHost.m_idSelTarget; } diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkTrace.cs b/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkTrace.cs index 1498b51fc3..31e56cc2d4 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkTrace.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkTrace.cs @@ -139,7 +139,7 @@ public abstract class CECTracedObject } else { - EC_Player pPlayer = pObject.GetComponent(); + CECPlayer pPlayer = pObject.GetComponent(); fTouchRadius = pPlayer.GetTouchRadius(); } return m_pHost.CanTouchTarget(vHostPos, vTargetPos, fTouchRadius, iTouchReason, fMaxCut); @@ -384,7 +384,7 @@ public class CECTracedPlayer : CECTracedObject { return true; } - EC_Player pPlayer = GetTargetObject() as EC_Player; + CECPlayer pPlayer = GetTargetObject() as CECPlayer; if (pPlayer.IsElsePlayer()) { if (pPlayer.IsDead()) @@ -615,10 +615,10 @@ public class CECHPWorkTrace : CECHPWork { // Continue tracing object float fDeltaTime = dwDeltaTime /** 0.001f*/; - if (m_pHost.m_iMoveEnv == EC_Player.Move_environment.MOVEENV_GROUND) + if (m_pHost.m_iMoveEnv == CECPlayer.Move_environment.MOVEENV_GROUND) { // Play appropriate actions - if (!m_pHost.IsJumping() && !m_pHost.IsPlayingAction((int)EC_Player.PLAYER_ACTION_TYPE.ACT_TRICK_RUN) && + if (!m_pHost.IsJumping() && !m_pHost.IsPlayingAction((int)CECPlayer.PLAYER_ACTION_TYPE.ACT_TRICK_RUN) && m_pHost.m_iMoveMode != (int)MoveMode.MOVE_SLIDE) { int iAction = m_pHost.GetMoveStandAction(true); @@ -810,7 +810,7 @@ public class CECHPWorkTrace : CECHPWork if (m_pHost.m_iMoveMode == (int)MoveMode.MOVE_SLIDE) { - m_pHost.PlayAction((int)EC_Player.PLAYER_ACTION_TYPE.ACT_JUMP_LOOP, false, 200, false); + m_pHost.PlayAction((int)CECPlayer.PLAYER_ACTION_TYPE.ACT_JUMP_LOOP, false, 200, false); // This will cause stop moming after we slide down. A3DVECTOR3 vDir = vTargetPos - vCurPos; diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs b/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs index 70ad7df4c7..59f5c69bbf 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs @@ -183,7 +183,7 @@ namespace PerfectWorld.Scripts.Managers // For equipping, we need to find an empty equipment slot // Use the new method that checks for available slots (especially for finger items) byte equipLocation = EC_IvtrType.GetAvailableEquipLocationForItem(currentSelectedItem.TemplateId); - if (equipLocation >= (byte)EC_IvtrType.IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR) + if (equipLocation >= (byte)IndexOfIteminEquipmentInventory.SIZE_EQUIPIVTR) { Debug.LogWarning($"[InventoryUI] Could not determine equip location for item {currentSelectedItem.TemplateId}"); return; diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrType.cs b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrType.cs index d42c58746d..17919062e5 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrType.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrType.cs @@ -5,43 +5,54 @@ using BrewMonster; namespace PerfectWorld.Scripts.Managers { + public enum IndexOfIteminEquipmentInventory : byte + { + EQUIPIVTR_WEAPON = 0, + EQUIPIVTR_HEAD = 1, + EQUIPIVTR_NECK = 2, + EQUIPIVTR_SHOULDER = 3, + EQUIPIVTR_BODY = 4, + EQUIPIVTR_WAIST = 5, + EQUIPIVTR_LEG = 6, + EQUIPIVTR_FOOT = 7, + EQUIPIVTR_WRIST = 8, + EQUIPIVTR_FINGER1 = 9, + EQUIPIVTR_FINGER2 = 10, + EQUIPIVTR_PROJECTILE = 11, + EQUIPIVTR_FLYSWORD = 12, + EQUIPIVTR_FASHION_BODY = 13, + EQUIPIVTR_FASHION_LEG = 14, + EQUIPIVTR_FASHION_FOOT = 15, + EQUIPIVTR_FASHION_WRIST = 16, + EQUIPIVTR_RUNE = 17, + EQUIPIVTR_BIBLE = 18, + EQUIPIVTR_SPEAKER = 19, + EQUIPIVTR_AUTOHP = 20, + EQUIPIVTR_AUTOMP = 21, + EQUIPIVTR_POCKET = 22, + EQUIPIVTR_GOBLIN = 23, + EQUIPIVTR_CERTIFICATE = 24, + EQUIPIVTR_FASHION_HEAD = 25, + EQUIPIVTR_FORCE_TOKEN = 26, + EQUIPIVTR_DYNSKILLEQUIP1 = 27, + EQUIPIVTR_DYNSKILLEQUIP2 = 28, + EQUIPIVTR_FASHION_WEAPON = 29, + SIZE_EQUIPIVTR = 30, + EQUIPIVTR_UNUSED1 = SIZE_EQUIPIVTR, + EQUIPIVTR_UNUSED2 = 31, + EQUIPIVTR_GENERALCARD1, + EQUIPIVTR_GENERALCARD2, + EQUIPIVTR_GENERALCARD3, + EQUIPIVTR_GENERALCARD4 = 35, + EQUIPIVTR_GENERALCARD5, + EQUIPIVTR_GENERALCARD6, + SIZE_ALL_EQUIPIVTR, + SIZE_GENERALCARD_EQUIPIVTR = SIZE_ALL_EQUIPIVTR - EQUIPIVTR_GENERALCARD1, + } + public static class EC_IvtrType { - public enum IndexOfIteminEquipmentInventory : byte - { - EQUIPIVTR_WEAPON = 0, - EQUIPIVTR_HEAD = 1, - EQUIPIVTR_NECK = 2, - EQUIPIVTR_SHOULDER = 3, - EQUIPIVTR_BODY = 4, - EQUIPIVTR_WAIST = 5, - EQUIPIVTR_LEG = 6, - EQUIPIVTR_FOOT = 7, - EQUIPIVTR_WRIST = 8, - EQUIPIVTR_FINGER1 = 9, - EQUIPIVTR_FINGER2 = 10, - EQUIPIVTR_PROJECTILE = 11, - EQUIPIVTR_FLYSWORD = 12, - EQUIPIVTR_FASHION_BODY = 13, - EQUIPIVTR_FASHION_LEG = 14, - EQUIPIVTR_FASHION_FOOT = 15, - EQUIPIVTR_FASHION_WRIST = 16, - EQUIPIVTR_RUNE = 17, - EQUIPIVTR_BIBLE = 18, - EQUIPIVTR_SPEAKER = 19, - EQUIPIVTR_AUTOHP = 20, - EQUIPIVTR_AUTOMP = 21, - EQUIPIVTR_POCKET = 22, - EQUIPIVTR_GOBLIN = 23, - EQUIPIVTR_CERTIFICATE = 24, - EQUIPIVTR_FASHION_HEAD = 25, - EQUIPIVTR_FORCE_TOKEN = 26, - EQUIPIVTR_DYNSKILLEQUIP1 = 27, - EQUIPIVTR_DYNSKILLEQUIP2 = 28, - EQUIPIVTR_FASHION_WEAPON = 29, - SIZE_EQUIPIVTR = 30, - } - + public static byte GetEquipLocationForItem(int templateId) { try diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs b/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs index 0db2223156..08ccef2f90 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs @@ -470,7 +470,7 @@ namespace PerfectWorld.Scripts.Managers } // Get a player (may be host or else player) by id - public EC_Player GetPlayer(int cid, uint dwBornStamp = 0) + public CECPlayer GetPlayer(int cid, uint dwBornStamp = 0) { CECHostPlayer pHost = GetHostPlayer(); if (pHost && pHost.GetCharacterID() == cid) diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_Object.cs b/Assets/PerfectWorld/Scripts/Managers/EC_Object.cs index 6ee388cece..c77b1b4136 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_Object.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_Object.cs @@ -185,7 +185,7 @@ public class CECObject : MonoBehaviour return 0; if (pObject.IsPlayer()) - return ((EC_Player)pObject).GetCharacterID(); + return ((CECPlayer)pObject).GetCharacterID(); else if (pObject.IsNPC()) return ((CECNPC)pObject).GetNPCID(); //else if (pObject.IsMatter()) diff --git a/Assets/Scripts/Move.meta b/Assets/PerfectWorld/Scripts/Move.meta similarity index 100% rename from Assets/Scripts/Move.meta rename to Assets/PerfectWorld/Scripts/Move.meta diff --git a/Assets/Scripts/Move/AAssist.cs b/Assets/PerfectWorld/Scripts/Move/AAssist.cs similarity index 100% rename from Assets/Scripts/Move/AAssist.cs rename to Assets/PerfectWorld/Scripts/Move/AAssist.cs diff --git a/Assets/Scripts/Move/AAssist.cs.meta b/Assets/PerfectWorld/Scripts/Move/AAssist.cs.meta similarity index 100% rename from Assets/Scripts/Move/AAssist.cs.meta rename to Assets/PerfectWorld/Scripts/Move/AAssist.cs.meta diff --git a/Assets/Scripts/Move/CECCounter.cs b/Assets/PerfectWorld/Scripts/Move/CECCounter.cs similarity index 100% rename from Assets/Scripts/Move/CECCounter.cs rename to Assets/PerfectWorld/Scripts/Move/CECCounter.cs diff --git a/Assets/Scripts/Move/CECCounter.cs.meta b/Assets/PerfectWorld/Scripts/Move/CECCounter.cs.meta similarity index 100% rename from Assets/Scripts/Move/CECCounter.cs.meta rename to Assets/PerfectWorld/Scripts/Move/CECCounter.cs.meta diff --git a/Assets/Scripts/Move/CECHostMove.cs b/Assets/PerfectWorld/Scripts/Move/CECHostMove.cs similarity index 99% rename from Assets/Scripts/Move/CECHostMove.cs rename to Assets/PerfectWorld/Scripts/Move/CECHostMove.cs index dd3115dc98..3589a2b441 100644 --- a/Assets/Scripts/Move/CECHostMove.cs +++ b/Assets/PerfectWorld/Scripts/Move/CECHostMove.cs @@ -85,7 +85,7 @@ public class CECHostMove float fSpeed = 0f; switch (m_pHost.GetMoveEnv()) { - case EC_Player.Move_environment.MOVEENV_AIR: + case CECPlayer.Move_environment.MOVEENV_AIR: iMoveMode |= (int)GPMoveMode.GP_MOVE_AIR; fSpeed = m_pHost.GetFlySpeed(); diff --git a/Assets/Scripts/Move/CECHostMove.cs.meta b/Assets/PerfectWorld/Scripts/Move/CECHostMove.cs.meta similarity index 100% rename from Assets/Scripts/Move/CECHostMove.cs.meta rename to Assets/PerfectWorld/Scripts/Move/CECHostMove.cs.meta diff --git a/Assets/Scripts/Move/EC_Player.cs b/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs similarity index 56% rename from Assets/Scripts/Move/EC_Player.cs rename to Assets/PerfectWorld/Scripts/Move/CECPlayer.cs index 9ace0ed5ea..70ef68c201 100644 --- a/Assets/Scripts/Move/EC_Player.cs +++ b/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs @@ -1,26 +1,34 @@ using BrewMonster; using CSNetwork.GPDataType; using ModelRenderer.Scripts.GameData; +using PerfectWorld.Scripts.Managers; using PerfectWorld.Scripts.Player; using System; using System.Collections.Generic; +using Unity.VisualScripting; using UnityEngine; -public abstract class EC_Player : CECObject +public abstract class CECPlayer : CECObject { private static PLAYER_ACTION[] _default_actions; private static PLAYER_ACTION[] _turning_actions; PLAYER_ACTION[] m_PlayerActions; [SerializeField] internal INFO m_PlayerInfo; - protected GameObject m_pPlayerModel; + protected GameObject _pPlayerModel; protected float rotationSpeed = 5; internal int m_iMoveMode; // Player's move mode - internal int m_idSelTarget; // Ñ¡ÖÐÄ¿±êµÄID - uint m_dwStates; // Player's basic states + internal int m_idSelTarget; + protected int m_iShape; // Ñ¡ÖÐÄ¿±êµÄID + protected uint m_dwStates; // Player's basic states + protected uint m_uAttackType; + protected int[] m_aEquips; protected ROLEEXTPROP m_ExtProps; // Extend properties - protected float m_fTouchRad = 0.3f; // Touch radius + protected int m_iFashionWeaponType; + protected float m_fTouchRad = 0.3f; // Touch radius + protected bool m_bWeaponAttached; protected int m_iBattleCamp = Player_camp_in_battle.GP_BATTLE_CAMP_NONE; // Battle this player belongs to - byte m_factionPVPMask; // pvp mask + byte m_factionPVPMask; // pvp mask + protected uint m_dwResFlags; // pvp mask protected ROLEBASICPROP m_BasicProps; public int m_iMoveEnv = Move_environment.MOVEENV_GROUND; // Move environment public bool m_bWalkRun; @@ -28,7 +36,12 @@ public abstract class EC_Player : CECObject public A3DAABB m_aabb = new A3DAABB(); // Player's aabb£¬ÓÃÓÚÏÔʾµÄaabb£¬ÊÜËõ·ÅÓ°Ïì public int m_iProfession; // Profession public float m_fScaleBySkill; - public int m_iGender; // Gender + public int m_iGender; // Gender + protected bool m_bFashionMode; + + protected int NUM_WEAPON_TYPE = 15; + + public MOVECONST m_MoveConst; // Const used when moving control public MOVECONST[] aMoveConsts = new MOVECONST[PROFESSION.NUM_PROFESSION * GENDER.NUM_GENDER] @@ -103,6 +116,12 @@ public abstract class EC_Player : CECObject protected void Awake() { m_PlayerActions = _default_actions; + m_iShape = 0; + m_aEquips = new int[(int)IndexOfIteminEquipmentInventory.SIZE_ALL_EQUIPIVTR]; + } + public void SetUpPlayer() + { + m_dwResFlags = 0; } public void SetPlayerInfor(INFO playinfo) { @@ -127,9 +146,12 @@ public abstract class EC_Player : CECObject BuildActionList(); } - public bool IsDead(){ return (m_dwStates & PlayerNPCState.GP_STATE_CORPSE) != 0; } + public bool IsDead() { return (m_dwStates & PlayerNPCState.GP_STATE_CORPSE) != 0; } public bool IsValidAction(int iIndex) { return (iIndex >= 0 && iIndex < (int)PLAYER_ACTION_TYPE.ACT_MAX) ? true : false; } + public int GetCharacterID() { return m_PlayerInfo.cid; } + + private static void BuildActionList() { if (_default_actions == null) @@ -233,6 +255,7 @@ public abstract class EC_Player : CECObject public PLAYER_ACTION_TYPE type; public PLAYER_ACTION_INFO_CONFIG data; }; + public INFO GetPlayerInfo() { return m_PlayerInfo; } public enum PLAYER_ACTION_TYPE { // 0 @@ -368,8 +391,301 @@ public abstract class EC_Player : CECObject ACT_MAX, ACT_CASTSKILL // Chỉ là placeholder cho skill actions } + public void PlayAttackEffect(int idTarget, int idSkill, int skillLevel, int nDamage, + uint dwModifier, int nAttackSpeed, ref int piAttackTime/* NULL */, int nSection = 0) + { + /* if (!IsAllResReady()) + return;*/ - public float GetTouchRadius(){ return m_fTouchRad; } + if (idSkill == 0) + { + int idWeapon = IsShapeChanged() ? 0 : GetWeaponID(); + + int nTimeFly = 10; + if (idWeapon != 0) + { + // ¿´¿´ÊDz»ÊÇÔ¶³ÌÎäÆ÷ + DATA_TYPE dt = default; + WEAPON_ESSENCE? pWeapon = (WEAPON_ESSENCE)ElementDataManProvider.GetElementDataMan().get_data_ptr((uint)idWeapon, ID_SPACE.ID_SPACE_ESSENCE, ref dt); + + if (dt == DATA_TYPE.DT_WEAPON_ESSENCE && pWeapon != null && pWeapon.Value.require_projectile != 0) + { + nTimeFly = 700; + + if (m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_PROJECTILE] != 0) + idWeapon = m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_PROJECTILE]; + } + } + + if (CECAttacksMan.Instance.FindAttackByAttacker(GetPlayerInfo().cid)) + { + // Unity animation làm hộ r + //ClearComActFlagAllRankNodes(true); + } + + // melee attack + CECAttackEvent pAttack = CECAttacksMan.Instance.AddMeleeAttack( + GetPlayerInfo().cid, idTarget, idWeapon, dwModifier, nDamage, nTimeFly); + + if (pAttack != null) + { + if (!IsDead() && (dwModifier & (uint)MOD.MOD_RETORT) == 0 + && (dwModifier & (uint)MOD.MOD_ATTACK_AURA) == 0 + && PlayAttackAction(nAttackSpeed, out piAttackTime, ref pAttack.m_bSignaled) + && (dwModifier & (uint)MOD.MOD_BEAT_BACK) == 0) + { + } + else + { + pAttack.m_bSignaled = true; + } + } + } + else + { + /* if (skillLevel == 0) + { + if (m_pCurSkill) + 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 = g_pGame->GetGameRun()->GetWorld()->GetAttacksMan()->FindAttackByAttacker(GetPlayerInfo().cid); + if (attackerEvents) + { + if (CECAttackEvent * pAttack = attackerEvents.Find(idSkill, nSection)) + { + // Ãæ¹¥»÷µÄ·ÇµÚÒ»´ÎÉ˺¦ÏûÏ¢ + pAttack->AddTarget(idTarget, dwModifier, nDamage); + goto EXIT; + } + else + { + attackerEvents.Signal(); + } + } + if (GNET::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;*/ + } + } + public bool PlayAttackAction(int nAttackSpeed, out int attackTime, ref bool pActFlag) + { + attackTime = 0; + + if (_pPlayerModel == null) + return false; + + int nRand = UnityEngine.Random.Range(0, 4); + string szAct = string.Empty; + + //int weapon_type = GetShowingWeaponType(); + + int nTime1 = 0, nTime2 = 0; + int iAction = (int)PLAYER_ACTION_TYPE.ACT_ATTACK_1 + nRand; + PLAYER_ACTION action = m_PlayerActions[iAction]; + + if (string.IsNullOrEmpty(action.data.ActionPrefix)) + return false; + + ShowWeaponByConfig(action.data); + + /* var pRightHandWeapon = GetRightHandWeapon(); + bool bHideFX = !CECOptimize.Instance.GFX.CanShowAttack(GetCharacterID(), GetClassID());*/ + + // ============================== + // Ground Attack + // ============================== + if (GetMoveEnv() == (int)MoveEnvironment.MOVEENV_GROUND) + { + // “起” 动作(挥起) + szAct = EC_Utility.BuildActionName(action, 0, "Æð"); + EventBus.PublishChannel(m_PlayerInfo.cid, new PlayActionEvent(szAct)); + szAct = EC_Utility.BuildActionName(action, 0, "Âä"); + EventBus.PublishChannel(m_PlayerInfo.cid, new QueueActionEvent(szAct)); + //PlayNonSkillActionWithName(iAction, szAct, true, 200, true, ref pActFlag, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX); + /* + if (pRightHandWeapon != null && IsUsingMagicWeapon()) + pRightHandWeapon.PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, iAction, bHideFX); + + nTime1 = _pPlayerModel.GetComActTimeSpanByName(szAct); + + // “收” 动作(挥下) + szAct = $"{action.data.action_prefix}_{action.data.action_weapon_suffix[weapon_type].suffix}Âä"; + QueueNonSkillActionWithName(iAction, szAct, 0, false, bHideFX); + + if (pRightHandWeapon != null && IsUsingMagicWeapon()) + pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, iAction, false, false, bHideFX); + + nTime2 = _pPlayerModel.GetComActTimeSpanByName(szAct);*/ + } + // ============================== + // Air Attack + // ============================== + else + { + /*string szActionMiddleName; + + if ((m_wingType == WINGTYPE_WING && IsFlying()) || + GetProfession() == PROF_ANGEL || + GetProfession() == PROF_ARCHOR || + GetProfession() == PROF_MONK || + GetProfession() == PROF_GHOST) + { + szActionMiddleName = "¿ÕÖгá°ò"; // tấn công trên không + } + else + { + szActionMiddleName = "¿ÕÖзɽ£"; // rơi xuống hoặc bay + } + + szAct = $"{action.data.action_prefix}_{szActionMiddleName}_{action.data.action_weapon_suffix[weapon_type].suffix}Æð"; + PlayNonSkillActionWithName(iAction, szAct, true, 200, bHideFX, ref pActFlag, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX); + + if (pRightHandWeapon != null && IsUsingMagicWeapon()) + pRightHandWeapon.PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, iAction, bHideFX); + + nTime1 = m_pPlayerModel.GetComActTimeSpanByName(szAct); + + szAct = $"{action.data.action_prefix}_{szActionMiddleName}_{action.data.action_weapon_suffix[weapon_type].suffix}Âä"; + QueueNonSkillActionWithName(iAction, szAct, 0, false, bHideFX); + + if (pRightHandWeapon != null && IsUsingMagicWeapon()) + pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, iAction, false, false, bHideFX); + + nTime2 = m_pPlayerModel.GetComActTimeSpanByName(szAct);*/ + } + + // ============================== + // Kết thúc bằng FightStand + // ============================== + PLAYER_ACTION stand_action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND]; + szAct = EC_Utility.BuildActionName(stand_action, 0); + EventBus.PublishChannel(m_PlayerInfo.cid, new QueueActionEvent(szAct)); + + /* QueueNonSkillActionWithName(ACT_FIGHTSTAND, szAct, 300, false, bHideFX, true); + + if (pRightHandWeapon != null && IsUsingMagicWeapon()) + pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 300, iAction, false, false, bHideFX, true);*/ + + // ============================== + // Điều chỉnh tốc độ phát animation theo tốc độ tấn công + // ============================== + /* if (nAttackSpeed > 0) + { + float vScale = (nTime1 + nTime2) / (float)nAttackSpeed; + if (vScale > 0f) + { + m_pPlayerModel.SetPlaySpeed(vScale); + + if (pRightHandWeapon != null && IsUsingMagicWeapon()) + pRightHandWeapon.SetPlaySpeed(vScale); + } + } + + attackTime = nTime1 + nTime2;*/ + + // ============================== + // Cập nhật vị trí weapon hanger (vũ khí) + // ============================== + //UpdateWeaponHangerPosByAction(iAction); + + return true; + } + public bool m_bShowWeapon; + public void ShowWeaponByConfig(PLAYER_ACTION_INFO_CONFIG p) + { + m_bShowWeapon = p.hide_weapon != 0 ? false : true; + //ShowWeapon(m_bShowWeapon); + } + public int GetShowingWeaponType() + { + int weapon_type = 0; + if (CanShowFashionWeapon((int)m_uAttackType, m_iFashionWeaponType) && m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_WEAPON] != 0) + { + weapon_type = (m_iFashionWeaponType == DEFAULT_ACTION_TYPE || !IsWeaponAttached()) ? + 10 : m_iFashionWeaponType; + } + else + { + weapon_type = (m_uAttackType == DEFAULT_ACTION_TYPE || !IsWeaponAttached()) ? + 10 : (int)m_uAttackType; + } + return weapon_type; + } + + public bool IsWeaponAttached() + { + return m_bWeaponAttached; + } + public bool InFashionMode() { return m_bFashionMode; } + public bool CanShowFashionWeapon(int weapon_type, int fashion_weapon_type) + { + return IsFashionWeaponTypeFit(weapon_type, fashion_weapon_type) && InFashionMode(); + } + public bool IsFashionWeaponTypeFit(int weapon_type, int fashion_weapon_type) + { + if (fashion_weapon_type < 0 || fashion_weapon_type >= NUM_WEAPON_TYPE) return false; + FASHION_WEAPON_CONFIG? pConfig = GetFashionConfig(); + if (null == pConfig) + { + BMLogger.LogError("CECPlayer::GetFashionConfig, Failed to load fashion weapon config"); + return false; + } + int fashion_weapon_mask = (int)pConfig.Value.action_mask[fashion_weapon_type]; + return (fashion_weapon_mask & (1 << GetWeaponType(weapon_type))) != 0; + } + public FASHION_WEAPON_CONFIG GetFashionConfig() + { + FASHION_WEAPON_CONFIG? pFashionConfig = null; + if (null == pFashionConfig) + { + elementdataman pDataMan = ElementDataManProvider.GetElementDataMan(); + DATA_TYPE DataType = DATA_TYPE.DT_FASHION_WEAPON_CONFIG; + uint tid = pDataMan.get_id_with_data_type(ID_SPACE.ID_SPACE_CONFIG, DataType); + + if (tid != 0) + { + pFashionConfig = (FASHION_WEAPON_CONFIG)pDataMan.get_data_ptr(tid, ID_SPACE.ID_SPACE_CONFIG, ref DataType); + BMLogger.LogError($"HoangDev : get_data_ptr {pFashionConfig.GetType()}"); + } + } + return pFashionConfig.Value; + } + public float GetTouchRadius() { return m_fTouchRad; } // Is player in battle public bool IsInBattle() { return m_iBattleCamp != Player_camp_in_battle.GP_BATTLE_CAMP_NONE; } @@ -383,6 +699,8 @@ public abstract class EC_Player : CECObject return true; } + public const uint DEFAULT_ACTION_TYPE = 0xFFFFFFFF; + public static int GetWeaponType(int iWeaponType) { return iWeaponType == DEFAULT_ACTION_TYPE ? 10 : iWeaponType; } public bool IsInFactionPVP() => (m_factionPVPMask & 0x01) != 0; public bool CanAttackFactionPVPMineCar() => (m_factionPVPMask & 0x02) != 0; public bool CanAttackFactionPVPMineBase() => (m_factionPVPMask & 0x04) != 0; @@ -462,9 +780,11 @@ public abstract class EC_Player : CECObject } // Get move environment - public int GetMoveEnv(){ return m_iMoveEnv; } + public int GetMoveEnv() { return m_iMoveEnv; } + public bool IsShapeChanged() { return m_iShape != 0; } + public int GetWeaponID() { return m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_WEAPON] & 0xffff; } + public bool IsAllResReady() { return (m_dwResFlags & (uint)PlayerResourcesReadyFlag.RESFG_ALL) == (uint)PlayerResourcesReadyFlag.RESFG_ALL; } // Get character ID - public int GetCharacterID(){ return m_PlayerInfo.cid; } } public struct PlayActionEvent { @@ -474,6 +794,15 @@ public struct PlayActionEvent this.AnimationName = animationName; } } + +public struct QueueActionEvent +{ + public string AnimationName; + public QueueActionEvent(string animationName) + { + this.AnimationName = animationName; + } +} [Serializable] public struct INFO { @@ -487,7 +816,15 @@ public struct INFO this.crc_e = crc_; } } +public enum PlayerResourcesReadyFlag +{ + RESFG_SKELETON = 0x01, + RESFG_SKIN = 0x02, + RESFG_CUSTOM = 0x04, + RESFG_ASSEMBLED = 0x08, + RESFG_ALL = 0x0f, +}; public static class Duel_state // Duel state { public const int DUEL_ST_NONE = 0, diff --git a/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs.meta b/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs.meta new file mode 100644 index 0000000000..091511b0f9 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 041192bec8f11c747a80df312c2df184 \ No newline at end of file diff --git a/Assets/Scripts/Move/EC_CDR.cs b/Assets/PerfectWorld/Scripts/Move/EC_CDR.cs similarity index 100% rename from Assets/Scripts/Move/EC_CDR.cs rename to Assets/PerfectWorld/Scripts/Move/EC_CDR.cs diff --git a/Assets/Scripts/Move/EC_CDR.cs.meta b/Assets/PerfectWorld/Scripts/Move/EC_CDR.cs.meta similarity index 100% rename from Assets/Scripts/Move/EC_CDR.cs.meta rename to Assets/PerfectWorld/Scripts/Move/EC_CDR.cs.meta diff --git a/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs b/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs index 4ec062951a..fb3e92850b 100644 --- a/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs +++ b/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs @@ -264,6 +264,63 @@ public class CECNPC : CECObject } } } + public void Damaged(int iDamage, uint dwModifier/* 0 */) + { + if (iDamage == -1 || iDamage == -2) + { + // when else player hit this npc iDamage is -1, + // so if iDamage is -1 we will shoud the wounded animation + if (iDamage == -1) + PlayModelAction((int)NPCActionIndex. ACT_WOUNDED); + DamageTextManager.Instance.SpawnDamage(transform.position, iDamage, Color.red, 1.0f); + + /*if ((dwModifier & (uint)MOD.MOD_IMMUNE) != 0 *//* && !IsImmuneDisable()*//*) + textma + else if (dwModifier & CECAttackEvent::MOD_NULLITY) + BubbleText(BUBBLE_INVALIDHIT, 0); + else if (dwModifier & CECAttackEvent::MOD_ENCHANT_FAILED) + BubbleText(BUBBLE_LOSE, 0); + else if (dwModifier & CECAttackEvent::MOD_SUCCESS) + BubbleText(BUBBLE_SUCCESS, 0); + else if (dwModifier & CECAttackEvent::MOD_DODGE_DEBUFF) + BubbleText(BUBBLE_DODGE_DEBUFF, 0);*/ + } + else + { + // this message is related to the host, so we should show a pop up message + // Popup a damage decal + /* bool bDeadlyStrike = (dwModifier & CECAttackEvent::MOD_CRITICAL_STRIKE) ? true : false; + bool bRetort = (dwModifier & CECAttackEvent::MOD_RETORT) ? true : false;*/ + + if (iDamage > 0) + { + PlayModelAction((int)NPCActionIndex.ACT_WOUNDED); + DamageTextManager.Instance.SpawnDamage(transform.position, iDamage, Color.red, 1.0f); + /* int p1 = 0; + if (bDeadlyStrike) + p1 |= 0x0001; + else if (bRetort) + p1 |= 0x0002;*/ + + /* if (dwModifier & CECAttackEvent::MOD_REBOUND) + BubbleText(BUBBLE_REBOUND, (DWORD)iDamage); + else if (dwModifier & CECAttackEvent::MOD_BEAT_BACK) + BubbleText(BUBBLE_BEAT_BACK, (DWORD)iDamage); + else + BubbleText(BUBBLE_DAMAGE, (DWORD)iDamage, p1);*/ + } + /* else if ((dwModifier & CECAttackEvent::MOD_IMMUNE) && !IsImmuneDisable()) + BubbleText(BUBBLE_IMMUNE, 0); + else if (dwModifier & CECAttackEvent::MOD_NULLITY) + BubbleText(BUBBLE_INVALIDHIT, 0); + else if (dwModifier & CECAttackEvent::MOD_ENCHANT_FAILED) + BubbleText(BUBBLE_LOSE, 0); + else if (dwModifier & CECAttackEvent::MOD_SUCCESS) + BubbleText(BUBBLE_SUCCESS, 0); + else + BubbleText(BUBBLE_HITMISSED, 0);*/ + } + } public void WorkFinished(int iWorkID) { diff --git a/Assets/PerfectWorld/Scripts/NPC/NPCVisual.cs b/Assets/PerfectWorld/Scripts/NPC/NPCVisual.cs index 61401dbabe..a1d89d59de 100644 --- a/Assets/PerfectWorld/Scripts/NPC/NPCVisual.cs +++ b/Assets/PerfectWorld/Scripts/NPC/NPCVisual.cs @@ -1,4 +1,5 @@ using Animancer; +using BrewMonster; using UnityEngine; public class NPCVisual : MonoBehaviour @@ -6,10 +7,11 @@ public class NPCVisual : MonoBehaviour [SerializeField] NamedAnimancerComponent namedAnimancer; public bool TryPlayAction(string animationName) { + BMLogger.LogError("HoangDev: TryPlayAction: " + animationName); if (namedAnimancer == null) return false; if (namedAnimancer.IsPlaying(animationName)) return false; - return namedAnimancer.TryPlay("慢速移动") == null; + return namedAnimancer.TryPlay(animationName) == null; } public void InitNPCEventDoneHandler() { diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs index 68f9330312..1b516eac83 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs @@ -846,6 +846,15 @@ namespace CSNetwork.GPDataType public byte[] content; }; + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct cmd_host_attack_result + { + public int idTarget; + public int iDamage; // Èç¹ûÊÇ0±íʾûÓл÷ÖÐ + public int attack_flag; // ±ê¼Ç¸Ã¹¥»÷ÊÇ·ñÓй¥»÷ÓÅ»¯·ûºÍ·ÀÓùÓÅ»¯·ûºÍÖØ»÷·¢Éú + public byte attack_speed; + }; + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct cmd_own_ivtr_detail_info { diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs index e406bbd7f3..147f6f09bc 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs @@ -319,7 +319,7 @@ namespace CSNetwork } var pCmdHeader = BitConverter.ToUInt16(byteArrHeader); //sss - _logger.Info($"### GameDataSend: CMDID {pCmdHeader}"); + BMLogger.LogError($"### GameDataSend: CMDID {pCmdHeader}"); int iHostID = _selectedRole.roleid; switch (pCmdHeader) { @@ -339,7 +339,6 @@ namespace CSNetwork case CommandID.PLAYER_INFO_00: case CommandID.SELF_INFO_1: // OnMsgPlayerInfo(-1, pDataBuf, pCmdHeader); - _logger.Info($"HoangDev : EC_MsgDef.MSG_PM_PLAYERINFO"); EC_ManMessage.PostMessage(EC_MsgDef.MSG_PM_PLAYERINFO, (int)MANAGER_INDEX.MAN_PLAYER, -1, pDataBuf, pCmdHeader, iHostID, _selectedRole); break; case CommandID.OBJECT_MOVE: @@ -352,7 +351,6 @@ namespace CSNetwork } else if (ISNPCID(idObjMove)) { - _logger.Info("HoangDev : NPC OBJECT_MOVE"); EC_ManMessage.PostMessage(EC_MsgDef.MSG_NM_NPCMOVE, (int)MANAGER_INDEX.MAN_NPC, 0, pDataBuf, pCmdHeader); } break; @@ -365,7 +363,6 @@ namespace CSNetwork } else if (ISNPCID(id1)) { - _logger.Info("HoangDev : NPC OBJECT_MOVE"); EC_ManMessage.PostMessage(EC_MsgDef.MSG_NM_NPCSTOPMOVE, (int)MANAGER_INDEX.MAN_NPC, 0, pDataBuf, pCmdHeader); } break; @@ -374,7 +371,6 @@ namespace CSNetwork case CommandID.OWN_IVTR_DETAIL_DATA: case CommandID.GET_OWN_MONEY: case CommandID.CHANGE_IVTR_SIZE: - _logger.Info($"HUNG INVENTORY2"); EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_IVTRINFO, (int)MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader, iHostID); break; case CommandID.EXG_IVTR_ITEM: @@ -385,7 +381,6 @@ namespace CSNetwork case CommandID.MOVE_EQUIP_ITEM: case CommandID.UNFREEZE_IVTR_SLOT: case CommandID.PLAYER_EQUIP_TRASHBOX_ITEM: - _logger.Info($"HUNG EQUIP ITEM: " + pCmdHeader); EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_ITEMOPERATION, (int)MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader); break; case CommandID.MATTER_INFO_LIST: @@ -398,7 +393,6 @@ namespace CSNetwork EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_PICKUPITEM, (int)MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader); break; case CommandID.HOST_CORRECT_POS: - _logger.Info($"HoangDev HOST_CORRECT_POSHOST_CORRECT_POSHOST_CORRECT_POS"); EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_CORRECTPOS, (int)MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader, iHostID); break; case CommandID.OWN_ITEM_INFO: @@ -409,7 +403,6 @@ namespace CSNetwork case CommandID.NPC_INFO_00: case CommandID.NPC_ENTER_WORLD: case CommandID.NPC_VISIBLE_TID_NOTIFY: - _logger.Info($"HoangDev :NPC_VISIBLE_TID_NOTIFY"); EC_ManMessage.PostMessage(EC_MsgDef.MSG_NM_NPCINFO, (int)MANAGER_INDEX.MAN_NPC, 0, pDataBuf, pCmdHeader, dwDataSize); break; case CommandID.TASK_DATA: @@ -429,12 +422,10 @@ namespace CSNetwork EC_ManMessage.PostMessage(EC_MsgDef.MSG_NM_NPCATKRESULT, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader); break; case CommandID.HOST_ATTACKRESULT: - BMLogger.LogError("HoangDev : HOST_ATTACKRESULT"); EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_ATKRESULT, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader); break; case CommandID.HOST_ATTACKED: - BMLogger.LogError("HoangDev : HOST_ATTACKED"); - EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_ATKRESULT, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader); + EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_ATTACKED, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader); break; case CommandID.ERROR_MESSAGE: diff --git a/Assets/PerfectWorld/Scripts/Network/EC_ManMessageMono.cs b/Assets/PerfectWorld/Scripts/Network/EC_ManMessageMono.cs index 57599c37b2..76741ba3a6 100644 --- a/Assets/PerfectWorld/Scripts/Network/EC_ManMessageMono.cs +++ b/Assets/PerfectWorld/Scripts/Network/EC_ManMessageMono.cs @@ -74,8 +74,8 @@ namespace BrewMonster if (!(pObject = EC_ManPlayer.GetPlayer(idObject))) return null; - if ((iAliveFlag == 1 && (pObject as EC_Player).IsDead()) || - (iAliveFlag == 2 && !(pObject as EC_Player).IsDead())) + if ((iAliveFlag == 1 && (pObject as CECPlayer).IsDead()) || + (iAliveFlag == 2 && !(pObject as CECPlayer).IsDead())) return null; } //else if (GPDataTypeHelper.ISMATTERID(idObject)) diff --git a/Assets/Scripts/PlayerState.meta b/Assets/PerfectWorld/Scripts/PlayerState.meta similarity index 100% rename from Assets/Scripts/PlayerState.meta rename to Assets/PerfectWorld/Scripts/PlayerState.meta diff --git a/Assets/Scripts/PlayerState/PlayerIdleState.cs b/Assets/PerfectWorld/Scripts/PlayerState/PlayerIdleState.cs similarity index 94% rename from Assets/Scripts/PlayerState/PlayerIdleState.cs rename to Assets/PerfectWorld/Scripts/PlayerState/PlayerIdleState.cs index dab799fc4a..00f87ae540 100644 --- a/Assets/Scripts/PlayerState/PlayerIdleState.cs +++ b/Assets/PerfectWorld/Scripts/PlayerState/PlayerIdleState.cs @@ -1,5 +1,5 @@ using UnityEngine; -using static EC_Player; +using static CECPlayer; public class PlayerIdleState : PlayerState { diff --git a/Assets/Scripts/PlayerState/PlayerIdleState.cs.meta b/Assets/PerfectWorld/Scripts/PlayerState/PlayerIdleState.cs.meta similarity index 100% rename from Assets/Scripts/PlayerState/PlayerIdleState.cs.meta rename to Assets/PerfectWorld/Scripts/PlayerState/PlayerIdleState.cs.meta diff --git a/Assets/Scripts/PlayerState/PlayerMoveState.cs b/Assets/PerfectWorld/Scripts/PlayerState/PlayerMoveState.cs similarity index 95% rename from Assets/Scripts/PlayerState/PlayerMoveState.cs rename to Assets/PerfectWorld/Scripts/PlayerState/PlayerMoveState.cs index e82e7f53a4..b46ef1e484 100644 --- a/Assets/Scripts/PlayerState/PlayerMoveState.cs +++ b/Assets/PerfectWorld/Scripts/PlayerState/PlayerMoveState.cs @@ -1,5 +1,5 @@ using UnityEngine; -using static EC_Player; +using static CECPlayer; public class PlayerMoveState : PlayerState { diff --git a/Assets/Scripts/PlayerState/PlayerMoveState.cs.meta b/Assets/PerfectWorld/Scripts/PlayerState/PlayerMoveState.cs.meta similarity index 100% rename from Assets/Scripts/PlayerState/PlayerMoveState.cs.meta rename to Assets/PerfectWorld/Scripts/PlayerState/PlayerMoveState.cs.meta diff --git a/Assets/Scripts/PlayerState/PlayerState.cs b/Assets/PerfectWorld/Scripts/PlayerState/PlayerState.cs similarity index 100% rename from Assets/Scripts/PlayerState/PlayerState.cs rename to Assets/PerfectWorld/Scripts/PlayerState/PlayerState.cs diff --git a/Assets/Scripts/PlayerState/PlayerState.cs.meta b/Assets/PerfectWorld/Scripts/PlayerState/PlayerState.cs.meta similarity index 100% rename from Assets/Scripts/PlayerState/PlayerState.cs.meta rename to Assets/PerfectWorld/Scripts/PlayerState/PlayerState.cs.meta diff --git a/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs b/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs index bc96829d14..c784cddac4 100644 --- a/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs +++ b/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs @@ -7,7 +7,7 @@ using UnityEngine; namespace PerfectWorld.Scripts.Player { - public class EC_ElsePlayer : EC_Player + public class EC_ElsePlayer : CECPlayer { A3DVECTOR3 m_vMoveDir; // Player's velocity A3DVECTOR3 m_vServerPos; // Player's real position on server diff --git a/Assets/Scripts/Task.meta b/Assets/PerfectWorld/Scripts/Task.meta similarity index 100% rename from Assets/Scripts/Task.meta rename to Assets/PerfectWorld/Scripts/Task.meta diff --git a/Assets/Scripts/Task/ATaskTemplMan.cs b/Assets/PerfectWorld/Scripts/Task/ATaskTemplMan.cs similarity index 100% rename from Assets/Scripts/Task/ATaskTemplMan.cs rename to Assets/PerfectWorld/Scripts/Task/ATaskTemplMan.cs diff --git a/Assets/Scripts/Task/ATaskTemplMan.cs.meta b/Assets/PerfectWorld/Scripts/Task/ATaskTemplMan.cs.meta similarity index 100% rename from Assets/Scripts/Task/ATaskTemplMan.cs.meta rename to Assets/PerfectWorld/Scripts/Task/ATaskTemplMan.cs.meta diff --git a/Assets/Scripts/Task/CECTaskInterface.cs b/Assets/PerfectWorld/Scripts/Task/CECTaskInterface.cs similarity index 100% rename from Assets/Scripts/Task/CECTaskInterface.cs rename to Assets/PerfectWorld/Scripts/Task/CECTaskInterface.cs diff --git a/Assets/Scripts/Task/CECTaskInterface.cs.meta b/Assets/PerfectWorld/Scripts/Task/CECTaskInterface.cs.meta similarity index 100% rename from Assets/Scripts/Task/CECTaskInterface.cs.meta rename to Assets/PerfectWorld/Scripts/Task/CECTaskInterface.cs.meta diff --git a/Assets/Scripts/Task/TaskExpAnalyser.cs b/Assets/PerfectWorld/Scripts/Task/TaskExpAnalyser.cs similarity index 100% rename from Assets/Scripts/Task/TaskExpAnalyser.cs rename to Assets/PerfectWorld/Scripts/Task/TaskExpAnalyser.cs diff --git a/Assets/Scripts/Task/TaskExpAnalyser.cs.meta b/Assets/PerfectWorld/Scripts/Task/TaskExpAnalyser.cs.meta similarity index 100% rename from Assets/Scripts/Task/TaskExpAnalyser.cs.meta rename to Assets/PerfectWorld/Scripts/Task/TaskExpAnalyser.cs.meta diff --git a/Assets/Scripts/Task/TaskInterface.cs b/Assets/PerfectWorld/Scripts/Task/TaskInterface.cs similarity index 100% rename from Assets/Scripts/Task/TaskInterface.cs rename to Assets/PerfectWorld/Scripts/Task/TaskInterface.cs diff --git a/Assets/Scripts/Task/TaskInterface.cs.meta b/Assets/PerfectWorld/Scripts/Task/TaskInterface.cs.meta similarity index 100% rename from Assets/Scripts/Task/TaskInterface.cs.meta rename to Assets/PerfectWorld/Scripts/Task/TaskInterface.cs.meta diff --git a/Assets/Scripts/Task/TaskProcess.cs b/Assets/PerfectWorld/Scripts/Task/TaskProcess.cs similarity index 100% rename from Assets/Scripts/Task/TaskProcess.cs rename to Assets/PerfectWorld/Scripts/Task/TaskProcess.cs diff --git a/Assets/Scripts/Task/TaskProcess.cs.meta b/Assets/PerfectWorld/Scripts/Task/TaskProcess.cs.meta similarity index 100% rename from Assets/Scripts/Task/TaskProcess.cs.meta rename to Assets/PerfectWorld/Scripts/Task/TaskProcess.cs.meta diff --git a/Assets/Scripts/Task/TaskTempl.cs b/Assets/PerfectWorld/Scripts/Task/TaskTempl.cs similarity index 100% rename from Assets/Scripts/Task/TaskTempl.cs rename to Assets/PerfectWorld/Scripts/Task/TaskTempl.cs diff --git a/Assets/Scripts/Task/TaskTempl.cs.meta b/Assets/PerfectWorld/Scripts/Task/TaskTempl.cs.meta similarity index 100% rename from Assets/Scripts/Task/TaskTempl.cs.meta rename to Assets/PerfectWorld/Scripts/Task/TaskTempl.cs.meta diff --git a/Assets/Scripts/Task/TaskTest.cs b/Assets/PerfectWorld/Scripts/Task/TaskTest.cs similarity index 100% rename from Assets/Scripts/Task/TaskTest.cs rename to Assets/PerfectWorld/Scripts/Task/TaskTest.cs diff --git a/Assets/Scripts/Task/TaskTest.cs.meta b/Assets/PerfectWorld/Scripts/Task/TaskTest.cs.meta similarity index 100% rename from Assets/Scripts/Task/TaskTest.cs.meta rename to Assets/PerfectWorld/Scripts/Task/TaskTest.cs.meta diff --git a/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs b/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs index 69e41729c5..36d0d24ca4 100644 --- a/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs +++ b/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs @@ -52,6 +52,12 @@ namespace BrewMonster.UI _usernameInputField.text = "test004"; _passwordInputField.text = "123456"; } + if (Input.GetKeyUp(KeyCode.Tab)) + { + _usernameInputField.text = "test005"; + _passwordInputField.text = "123456"; + OnLoginButtonClicked(); + } #endif } diff --git a/Assets/Scenes/NPCRender.unity b/Assets/Scenes/NPCRender.unity index 0e9c05f0b5..3b99004f1b 100644 --- a/Assets/Scenes/NPCRender.unity +++ b/Assets/Scenes/NPCRender.unity @@ -812,6 +812,11 @@ MonoBehaviour: - {fileID: 7400000, guid: 29895f3687b86a24ba1bff2318b1d817, type: 2} - {fileID: 7400000, guid: 9b5c3773d9888954c95132e25788ae54, type: 2} - {fileID: 7400000, guid: 5f21aa4feb9cf1e49b63d5e7b7d9ad58, type: 2} + - {fileID: 7400000, guid: 4c93f18fe5082524d8ccda024f7988ad, type: 2} + - {fileID: 7400000, guid: bc909de03ae7dcc4d824253bf652de1d, type: 2} + - {fileID: 7400000, guid: 211cf985d64485e4ca42f7d8d6509e87, type: 2} + - {fileID: 7400000, guid: caa9485da71a78b4da087ae69bf7120d, type: 2} + - {fileID: 7400000, guid: 233ca05b3510f614e8b2ea31731dc298, type: 2} --- !u!21 &19752687 Material: serializedVersion: 8 @@ -75381,6 +75386,182 @@ Mesh: offset: 0 size: 0 path: +--- !u!1 &927529342 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 927529343} + - component: {fileID: 927529345} + - component: {fileID: 927529344} + m_Layer: 0 + m_Name: DamageText + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &927529343 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 927529342} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1336646766} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 9000} + m_SizeDelta: {x: 20, y: 5} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &927529344 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 927529342} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 2 + m_fontSizeBase: 2 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_TextWrappingMode: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_ActiveFontFeatures: 6e72656b + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_EmojiFallbackSupport: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 0 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + _SortingLayer: 0 + _SortingLayerID: 0 + _SortingOrder: 0 + m_hasFontAssetChanged: 0 + m_renderer: {fileID: 927529345} + m_maskType: 0 +--- !u!23 &927529345 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 927529342} + m_Enabled: 1 + m_CastShadows: 0 + m_ReceiveShadows: 0 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_AdditionalVertexStreams: {fileID: 0} --- !u!1 &928368405 GameObject: m_ObjectHideFlags: 0 @@ -104206,6 +104387,7 @@ GameObject: m_Component: - component: {fileID: 1336646766} - component: {fileID: 1336646767} + - component: {fileID: 1336646768} m_Layer: 0 m_Name: NPC Manager m_TagString: Untagged @@ -104225,7 +104407,8 @@ Transform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: [] + m_Children: + - {fileID: 927529343} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &1336646767 @@ -104241,6 +104424,23 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: modelPlayerCharacter: {fileID: 960760103} +--- !u!114 &1336646768 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1336646764} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e7981b037b60f4a4989ff59265a308ad, type: 3} + m_Name: + m_EditorClassIdentifier: + damageTextPrefab: {fileID: 927529344} + poolSize: 20 + offset: {x: 0, y: 2, z: 0} + riseDistance: 1.5 + riseDuration: 0.8 --- !u!1 &1338403792 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/CECHostPlayer.cs b/Assets/Scripts/CECHostPlayer.cs index 967a427bec..90f39a6d4b 100644 --- a/Assets/Scripts/CECHostPlayer.cs +++ b/Assets/Scripts/CECHostPlayer.cs @@ -1,6 +1,7 @@ using BrewMonster; using BrewMonster.Network; using CSNetwork; +using CSNetwork.Common; using CSNetwork.GPDataType; using CSNetwork.Protocols; using CSNetwork.Protocols.RPCData; @@ -12,13 +13,14 @@ using System.IO; using System.Runtime.InteropServices; using System.Text; using TMPro; +using UnityEditor.Experimental.GraphView; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.SceneManagement; using UnityEngine.UI; using Scene = UnityEngine.SceneManagement.Scene; -public class CECHostPlayer : EC_Player +public class CECHostPlayer : CECPlayer { [SerializeField] private TextMeshPro txtName; [SerializeField] private CharacterController controller; @@ -92,12 +94,12 @@ public class CECHostPlayer : EC_Player public void SetModelHostPlayer() { - m_pPlayerModel = NPCManager.Instance.GetModelPlayer(); + _pPlayerModel = NPCManager.Instance.GetModelPlayer(); Scene scene = SceneManager.GetSceneByName("WorldRender"); - SceneManager.MoveGameObjectToScene(m_pPlayerModel, scene); - m_pPlayerModel.transform.SetParent(parentModel); - m_pPlayerModel.transform.localPosition = Vector3.zero; - m_pPlayerModel.SetActive(true); + SceneManager.MoveGameObjectToScene(_pPlayerModel, scene); + _pPlayerModel.transform.SetParent(parentModel); + _pPlayerModel.transform.localPosition = Vector3.zero; + _pPlayerModel.SetActive(true); } private void Start() { @@ -133,20 +135,20 @@ public class CECHostPlayer : EC_Player { CECObject clickedObject = hit.collider.gameObject.GetComponent(); - if(clickedObject != null) + if (clickedObject != null) { int idObject = CECObject.GetObjectID(clickedObject); if (idObject != 0) { CECNPC pNPC = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(idObject); - if(pNPC != null) + if (pNPC != null) { if (!pNPC.IsDead()/* && m_idSelTarget == idObject*/) { idTraceTarget = idObject; idSelTarget = idObject; } - if (idTraceTarget != 0) + if (idTraceTarget != 0) { if (AttackableJudge(idObject, bForceAttack) == 1) iTraceReason = CECHPWorkTrace.Trace_reason.TRACE_ATTACK; @@ -339,11 +341,61 @@ public class CECHostPlayer : EC_Player case int value when value == EC_MsgDef.MSG_HST_PICKUPITEM: OnMsgHstPickupItem(Msg); break; - case int value when value == EC_MsgDef.MSG_HST_SELTARGET: + case int value when value == EC_MsgDef.MSG_HST_SELTARGET: OnMsgHstSelTarget(Msg); break; + case int value when value == EC_MsgDef.MSG_HST_ATKRESULT: OnMsgHstAttackResult(Msg); break; + //case int value when value == EC_MsgDef.MSG_HST_ATTACKED: OnMsgHstAttacked(Msg); break; + case int value when value == EC_MsgDef.MSG_HST_HURTRESULT: OnMsgHstHurtResult(Msg); break; } } + public void OnMsgHstAttackResult(ECMSG Msg) + { + BMLogger.LogError($"dwParam1 type = {Msg.dwParam1?.GetType()}"); + byte[] data = Msg.dwParam1 as byte[]; + cmd_host_attack_result pCmd = EC_Utility.ByteArrayToStructure(data); + int iAttackTime = 0; + PlayAttackEffect(pCmd.idTarget, 0, 0, pCmd.iDamage, (uint)pCmd.attack_flag, pCmd.attack_speed * 50, ref iAttackTime); + TurnFaceTo(pCmd.idTarget); + + if (iAttackTime != 0) + { + if (m_pWorkMan.GetRunningWork(CECHPWork.Host_work_ID.WORK_HACKOBJECT) is CECHPWorkMelee pCurWork) + { + pCurWork.SetIdleTime(iAttackTime); + } + } + } + private void OnMsgHstHurtResult(ECMSG Msg) + { + /* BMLogger.LogError("HoangDev : OnMsgHstHurtResult"); + int cmd = Convert.ToInt32(Msg.dwParam2); + if (cmd == CommandID.BE_HURT) + { + cmd_be_hurt pCmd = (cmd_be_hurt)Msg.dwParam1; + if (pCmd.damage != 0) + Damaged(pCmd->damage); + } + else if (cmd == CommandID.HURT_RESULT) + { + cmd_hurt_result pCmd = (cmd_hurt_result)Msg.dwParam1; + if (pCmd.target_id == m_PlayerInfo.cid) + return; // Host himself will receive BE_HURT, so ignore this. + + if (UnityGameSession.Instance.GameSession.ISPLAYERID(pCmd.target_id)) + { + CECElsePlayer pTarget = m_pPlayerMan.GetElsePlayer(pCmd.target_id); + if (pTarget) + pTarget->Damaged(pCmd->damage); + } + else if (UnityGameSession.Instance.GameSession.ISNPCID(pCmd.target_id)) + { + CECNPC pTarget = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(pCmd.target_id); + if (pTarget) + pTarget.Damaged(pCmd.damage); + } + }*/ + } public void OnMsgHstPickupItem(in ECMSG Msg) { var data = Msg.dwParam1 as byte[]; @@ -351,85 +403,44 @@ public class CECHostPlayer : EC_Player switch (cmd) { case CommandID.PICKUP_ITEM: - { - // Parse the pickup item data from the server response - if (data != null && data.Length >= 16) { - int tid = BitConverter.ToInt32(data, 0); - int expire_date = BitConverter.ToInt32(data, 4); - uint iAmount = BitConverter.ToUInt32(data, 8); - uint iSlotAmount = BitConverter.ToUInt32(data, 12); - byte byPackage = data[16]; - byte bySlot = data[17]; - - Debug.Log($"[Inventory] PICKUP_ITEM: tid={tid}, expire_date={expire_date}, iAmount={iAmount}, iSlotAmount={iSlotAmount}, byPackage={byPackage}, bySlot={bySlot}"); - - // Notify pickupItem script about successful pickup - pickupItem pickupScript = UnityEngine.Object.FindFirstObjectByType(); - if (pickupScript != null) + // Parse the pickup item data from the server response + if (data != null && data.Length >= 16) { - pickupScript.OnPickupSuccess(tid); - } - - // Create new inventory item data - var newItem = new InventoryItemData - { - Package = byPackage, - Slot = bySlot, - TemplateId = tid, - ExpireDate = expire_date, - State = 0, - Count = (int)iAmount, - Crc = 0, - Content = null - }; - - // Add item to inventory - EC_Inventory.SetItem(byPackage, bySlot, newItem); - - Debug.Log($"[Inventory] Successfully added item {tid} to package {byPackage}, slot {bySlot} with count {iAmount}"); - - // Trigger UI refresh if an EC_InventoryUI is present in scene - var ui = GameObject.FindFirstObjectByType(); - if (ui != null) - { - ui.RefreshAll(); - } - } - else - { - Debug.LogWarning("[Inventory] PICKUP_ITEM: Invalid data length"); - } - break; - } - } - } - public void OnMsgHstItemOperation(ECMSG Msg) - { - var data = Msg.dwParam1 as byte[]; - int cmd = Convert.ToInt32(Msg.dwParam2); - switch (cmd) - { - case CommandID.PLAYER_DROP_ITEM: - { - // Parse the drop item data from the server response - if (data != null && data.Length >= 6) - { - byte byPackage = data[0]; - byte bySlot = data[1]; - int count = BitConverter.ToInt32(data, 2); - int tid = BitConverter.ToInt32(data, 6); - byte reason = data[10]; - - Debug.Log($"[Inventory] PLAYER_DROP_ITEM: package={byPackage}, slot={bySlot}, count={count}, tid={tid}, reason={reason}"); - - // Update the inventory by removing the item - bool success = EC_Inventory.RemoveItem(byPackage, bySlot, count); - - if (success) - { - Debug.Log($"[Inventory] Successfully removed {count} items from package {byPackage}, slot {bySlot}"); - + int tid = BitConverter.ToInt32(data, 0); + int expire_date = BitConverter.ToInt32(data, 4); + uint iAmount = BitConverter.ToUInt32(data, 8); + uint iSlotAmount = BitConverter.ToUInt32(data, 12); + byte byPackage = data[16]; + byte bySlot = data[17]; + + Debug.Log($"[Inventory] PICKUP_ITEM: tid={tid}, expire_date={expire_date}, iAmount={iAmount}, iSlotAmount={iSlotAmount}, byPackage={byPackage}, bySlot={bySlot}"); + + // Notify pickupItem script about successful pickup + pickupItem pickupScript = UnityEngine.Object.FindFirstObjectByType(); + if (pickupScript != null) + { + pickupScript.OnPickupSuccess(tid); + } + + // Create new inventory item data + var newItem = new InventoryItemData + { + Package = byPackage, + Slot = bySlot, + TemplateId = tid, + ExpireDate = expire_date, + State = 0, + Count = (int)iAmount, + Crc = 0, + Content = null + }; + + // Add item to inventory + EC_Inventory.SetItem(byPackage, bySlot, newItem); + + Debug.Log($"[Inventory] Successfully added item {tid} to package {byPackage}, slot {bySlot} with count {iAmount}"); + // Trigger UI refresh if an EC_InventoryUI is present in scene var ui = GameObject.FindFirstObjectByType(); if (ui != null) @@ -439,15 +450,56 @@ public class CECHostPlayer : EC_Player } else { - Debug.LogWarning($"[Inventory] Failed to remove items from package {byPackage}, slot {bySlot}"); + Debug.LogWarning("[Inventory] PICKUP_ITEM: Invalid data length"); } + break; } - else + } + } + public void OnMsgHstItemOperation(ECMSG Msg) + { + var data = Msg.dwParam1 as byte[]; + int cmd = Convert.ToInt32(Msg.dwParam2); + switch (cmd) + { + case CommandID.PLAYER_DROP_ITEM: { - Debug.LogWarning("[Inventory] PLAYER_DROP_ITEM: Invalid data length"); + // Parse the drop item data from the server response + if (data != null && data.Length >= 6) + { + byte byPackage = data[0]; + byte bySlot = data[1]; + int count = BitConverter.ToInt32(data, 2); + int tid = BitConverter.ToInt32(data, 6); + byte reason = data[10]; + + Debug.Log($"[Inventory] PLAYER_DROP_ITEM: package={byPackage}, slot={bySlot}, count={count}, tid={tid}, reason={reason}"); + + // Update the inventory by removing the item + bool success = EC_Inventory.RemoveItem(byPackage, bySlot, count); + + if (success) + { + Debug.Log($"[Inventory] Successfully removed {count} items from package {byPackage}, slot {bySlot}"); + + // Trigger UI refresh if an EC_InventoryUI is present in scene + var ui = GameObject.FindFirstObjectByType(); + if (ui != null) + { + ui.RefreshAll(); + } + } + else + { + Debug.LogWarning($"[Inventory] Failed to remove items from package {byPackage}, slot {bySlot}"); + } + } + else + { + Debug.LogWarning("[Inventory] PLAYER_DROP_ITEM: Invalid data length"); + } + break; } - break; - } case CommandID.EQUIP_ITEM: { byte index_inv = data[0]; @@ -592,6 +644,7 @@ public class CECHostPlayer : EC_Player if (txtName != null) txtName.text = roleName; transform.position = pos; SetModelHostPlayer(); + m_dwResFlags = (uint)PlayerResourcesReadyFlag.RESFG_ALL; Debug.LogError("Pos Character = " + pos); joystick = FindAnyObjectByType(); EventBus.Subscribe(JoystickRelease); @@ -932,7 +985,7 @@ public class CECHostPlayer : EC_Player return Mathf.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z); } - public int GetCharacterID(){ return m_PlayerInfo.cid; } + public int GetCharacterID() { return m_PlayerInfo.cid; } public bool CannotAttack() { return (m_dwLIES & (uint)Logic_Influence_Extned_states.LIES_DISABLEFIGHT) != 0; } @@ -1001,17 +1054,19 @@ public class CECHostPlayer : EC_Player A3DVECTOR3 vector = new A3DVECTOR3(gameObject.transform.position.x, gameObject.transform.position.y, gameObject.transform.position.z); return CanTouchTarget(vector, vTargetPos, fTargetRad, iReason, fMaxCut); } - public bool IsRooting() { + public bool IsRooting() + { var mask = (uint)(Logic_Influence_Extned_states.LIES_ROOT | Logic_Influence_Extned_states.LIES_SLEEP | Logic_Influence_Extned_states.LIES_STUN); - return (m_dwLIES & mask) != 0; } + return (m_dwLIES & mask) != 0; + } bool IsInFortress() { return m_fortressEnter.role_in_war != 0; } bool IsPVPOpen() { return m_pvp.bEnable; } // Get faction ID - int GetFactionID(){ return m_idFaction; } + int GetFactionID() { return m_idFaction; } public bool IsJumping() { return m_iJumpCount > 0; } diff --git a/Assets/Scripts/EC_Utility.cs b/Assets/Scripts/EC_Utility.cs index d1ef9f4cfb..b6f2e32cdb 100644 --- a/Assets/Scripts/EC_Utility.cs +++ b/Assets/Scripts/EC_Utility.cs @@ -3,8 +3,9 @@ using CSNetwork.GPDataType; using System; using System.Collections; using System.Runtime.InteropServices; +using System.Text; using UnityEngine; -using static EC_Player; +using static CECPlayer; public static class EC_Utility { @@ -32,16 +33,21 @@ public static class EC_Utility } } public static float FIX8TOFLOAT(int x) => x / 256.0f; - public static T ByteArrayToStructure(byte[] bytes) where T : struct + public static T ByteArrayToStructure(byte[] data) where T : struct { - GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + int size = Marshal.SizeOf(typeof(T)); + if (data.Length < size) + throw new ArgumentException($"Data length {data.Length} < struct size {size}"); + + IntPtr ptr = Marshal.AllocHGlobal(size); try { - return Marshal.PtrToStructure(handle.AddrOfPinnedObject()); + Marshal.Copy(data, 0, ptr, size); + return Marshal.PtrToStructure(ptr); } finally { - handle.Free(); + Marshal.FreeHGlobal(ptr); } } public static Vector3 glb_DecompressDirH(byte byDir) @@ -72,7 +78,18 @@ public static class EC_Utility { return Mathf.Sqrt(v.x * v.x + v.z * v.z); } - public static string BuildActionName(PLAYER_ACTION action, int weaponType) + public static string FixGBKString(string input) + { + // Giả sử input hiện đang là "Æð" + // B1: lấy bytes theo "Latin1" (mỗi ký tự 1 byte giữ nguyên giá trị gốc) + byte[] bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(input); + + // B2: giải mã lại bằng GBK (Code page 936) + string decoded = Encoding.GetEncoding(936).GetString(bytes); + + return decoded; + } + public static string BuildActionName(PLAYER_ACTION action, int weaponType, string tail = "") { string prefix = action.data.ActionPrefix ?? string.Empty; string suffix = string.Empty; @@ -83,8 +100,8 @@ public static class EC_Utility { suffix = action.data.action_weapon_suffix[weaponType].Suffix ?? string.Empty; } - - return $"{prefix}_{suffix}"; + var tailFixed = FixGBKString(tail); + return $"{prefix}_{suffix}{tailFixed}"; } // Build pvp mask diff --git a/Assets/Scripts/GameController.cs b/Assets/Scripts/GameController.cs index bdd3c803f6..1a1f7dcfe9 100644 --- a/Assets/Scripts/GameController.cs +++ b/Assets/Scripts/GameController.cs @@ -54,7 +54,7 @@ public class GameController : MonoBehaviour Debug.LogError("null prefab"); return; } - EC_Player.InitStaticRes(); + CECPlayer.InitStaticRes(); hostPlayer = Instantiate(characterPrefab, transform); hostPlayer.InitCharacter(info); cinemachineCamera.Follow = hostPlayer.transform; diff --git a/Assets/Scripts/InitializePlayer.cs b/Assets/Scripts/InitializePlayer.cs index 74f9de84a2..ad87a38c5f 100644 --- a/Assets/Scripts/InitializePlayer.cs +++ b/Assets/Scripts/InitializePlayer.cs @@ -5,11 +5,11 @@ public class InitializePlayer /*: IAutoInitialize*/ { public void Dispose() { - EC_Player.Dispose(); + CECPlayer.Dispose(); } public void Initialize() { - EC_Player.InitStaticRes(); + CECPlayer.InitStaticRes(); } } diff --git a/Assets/Scripts/Move/EC_Player.cs.meta b/Assets/Scripts/Move/EC_Player.cs.meta deleted file mode 100644 index 165da5cb56..0000000000 --- a/Assets/Scripts/Move/EC_Player.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: be4a22babee7846459b0421234a44c99 \ No newline at end of file diff --git a/Assets/Scripts/PlayerVisual.cs b/Assets/Scripts/PlayerVisual.cs index 08fab98c64..3b9d526de7 100644 --- a/Assets/Scripts/PlayerVisual.cs +++ b/Assets/Scripts/PlayerVisual.cs @@ -1,5 +1,7 @@ -using Animancer; +using Animancer; +using BrewMonster; using System; +using System.Collections.Generic; using UnityEngine; public class PlayerVisual : MonoBehaviour @@ -9,10 +11,16 @@ public class PlayerVisual : MonoBehaviour [SerializeField] private INFO _playerInfo; + [SerializeField] private AnimancerState _currentState; + private readonly Queue _animationQueue = new Queue(); + private void PlayActionEventHandler(PlayActionEvent @event) { - BrewMonster.BMLogger.Log("PlayActionEventHandler : "+@event.AnimationName); - namedAnimancer.TryPlay(@event.AnimationName); + _currentState = namedAnimancer.TryPlay(@event.AnimationName); + if(_currentState == null) + { + BMLogger.LogError("HoangDev: PlayActionEventHandler Failed "); + } } public void InitHostPlayerEventDoneHandler() @@ -23,7 +31,7 @@ public class PlayerVisual : MonoBehaviour BrewMonster.BMLogger.LogError("animancer == null"); return; } - var player = GetComponentInParent(); + var player = GetComponentInParent(); if(player == null) { BrewMonster.BMLogger.LogError("player == null"); @@ -31,7 +39,44 @@ public class PlayerVisual : MonoBehaviour } _playerInfo = player.GetPlayInfo(); EventBus.SubscribeChannel(_playerInfo.cid, PlayActionEventHandler); + EventBus.SubscribeChannel(_playerInfo.cid, QueueActionEventHandler); } + + private void QueueActionEventHandler(QueueActionEvent @event) + { + if(!EnqueueAnimation(@event.AnimationName)) + { + BMLogger.LogError("HoangDev : EnqueueAnimation Failed"); + } + } + public bool EnqueueAnimation(string animName) + { + if (namedAnimancer == null) return false; + _animationQueue.Enqueue(animName); + if (!namedAnimancer.IsPlaying()) + PlayNext(); + else + { + if (_currentState == null) return false; + _currentState.Events.OnEnd = PlayNext; + } + return true; + } + + private void PlayNext() + { + if (_animationQueue.Count == 0) + { + return; + } + + string animName = _animationQueue.Dequeue(); + var state = namedAnimancer.TryPlay(animName); + + // Khi clip kết thúc thì gọi tiếp cái kế tiếp + state.Events.OnEnd = PlayNext; + } + private void OnDestroy() { EventBus.UnsubscribeAllInChannel(_playerInfo.cid);