diff --git a/Assets/AddressableAssetsData/AssetGroups/a61.asset b/Assets/AddressableAssetsData/AssetGroups/a61.asset index 7edce66d65..7670e6882d 100644 --- a/Assets/AddressableAssetsData/AssetGroups/a61.asset +++ b/Assets/AddressableAssetsData/AssetGroups/a61.asset @@ -2655,6 +2655,11 @@ MonoBehaviour: m_ReadOnly: 0 m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: 34322d27488583140acae7497762ccbc + m_Address: minimaps/161 + m_ReadOnly: 0 + m_SerializedLabels: [] + FlaggedDuringContentUpdateRestriction: 0 - m_GUID: 343d97392dfbe4113b96ae477e3867eb m_Address: litmodels/a61/7/litmodel_1007.bmd m_ReadOnly: 0 diff --git a/Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/击中/箭阵击中.prefab b/Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/飞行/箭阵击中.prefab old mode 100755 new mode 100644 similarity index 100% rename from Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/击中/箭阵击中.prefab rename to Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/飞行/箭阵击中.prefab diff --git a/Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/击中/箭阵击中.prefab.meta b/Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/飞行/箭阵击中.prefab.meta old mode 100755 new mode 100644 similarity index 100% rename from Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/击中/箭阵击中.prefab.meta rename to Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/飞行/箭阵击中.prefab.meta diff --git a/Assets/PerfectWorld/Scene/Bootstrap.unity b/Assets/PerfectWorld/Scene/Bootstrap.unity index 73241b4ef4..dbef5efbea 100644 --- a/Assets/PerfectWorld/Scene/Bootstrap.unity +++ b/Assets/PerfectWorld/Scene/Bootstrap.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f809da92f7a74929fe4911b38ecddcf5bfe0fa9f667ad04f6c927511246975ae -size 308267 +oid sha256:fdca6f6915cfc055b350581a53fbc4d2e19ab522da9eb954295d71d45d8aed58 +size 303299 diff --git a/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs b/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs index 20589903b2..3142c5dd05 100644 --- a/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs +++ b/Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs @@ -7,6 +7,7 @@ using UnityEngine; using UnityEngine.AddressableAssets; using UnityEngine.AddressableAssets.ResourceLocators; using UnityEngine.ResourceManagement.AsyncOperations; +using UnityEngine.U2D; namespace BrewMonster.Scripts { @@ -18,6 +19,7 @@ namespace BrewMonster.Scripts private Dictionary> _loadedPrefabAssets = new(); private Dictionary> _loadedTextAssets = new(); private Dictionary> _loadedAudioAssets = new(); + private Dictionary> _loadedSpriteAtlasAssets = new(); private Dictionary _loadedAssetReferenceCount = new(); @@ -174,6 +176,56 @@ namespace BrewMonster.Scripts } + AsyncOperationHandle _loadedSpriteAtlasHandle; + /// Load a sprite atlas asynchronously. + public async Task LoadSpriteAtlasAsync(string assetPath) + { + // increase the reference count of the asset. + if (!_loadedAssetReferenceCount.ContainsKey(assetPath)) + { + _loadedAssetReferenceCount[assetPath] = 0; + } + _loadedAssetReferenceCount[assetPath]++; + + // remove the asset from the release timestamp dictionary. So it won't be released. + RemoveFromReleaseAssetDictionary(assetPath); + + if (_loadedSpriteAtlasAssets.TryGetValue(assetPath, out _loadedSpriteAtlasHandle)) + { + if (_loadedTextAssetHandle.IsValid() && _loadedTextAssetHandle.Result != null) + { + BMLogger.Log($"AddressableManager: Loaded text asset from cache: {assetPath}"); + return _loadedSpriteAtlasHandle.Result; + } + else + { + BMLogger.Log($"AddressableManager: Text asset handle is invalid or result is null, need to load new one: {assetPath}"); + } + } + + try + { + var handle = Addressables.LoadAssetAsync(assetPath); + await handle.Task; + if (handle.OperationException != null) + { + BMLogger.Log($"AddressableManager: Failed to load Sprite Atlas '{assetPath}': {handle.OperationException.Message} {handle.OperationException.StackTrace}"); + #if UNITY_EDITOR + _invalidAssetPaths.Add(assetPath); + #endif + return null; + } + _loadedSpriteAtlasAssets[assetPath] = handle; + return handle.Result; + } + catch (Exception e) + { + BMLogger.LogError($"AddressableManager: Failed to load SpriteAtlas '{assetPath}': {e}"); + return null; + } + } + + AsyncOperationHandle _loadedPrefabHandle; /// /// Load an asset asynchronously. The address should look like this: "models/npcs/npc/魅灵首领/魅灵首领/魅灵首领.prefab" diff --git a/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs b/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs index f3ac9436a8..cce14ba1ff 100644 --- a/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs +++ b/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs @@ -1,8 +1,8 @@ using UnityEngine; using System; -using BrewMonster.UI; -using CSNetwork; + +//TODO: [DUCK] EC_Game shouldn't be in BrewMonster.Network namespace, it should be in BrewMonster.Scripts namespace. namespace BrewMonster.Network { public partial class EC_Game @@ -78,7 +78,7 @@ namespace BrewMonster.Network // return m_dwRealTickTime; // return Time.realtimeSinceStartup; // 0.018f is value to make mining process run fit with player animation. if have any issue => discussing with Mr. Drimdar - return (Time.unscaledDeltaTime - 0.018f) * 1000f;//-0.001f + return Mathf.Abs(Time.unscaledDeltaTime - 0.018f) * 1000f;//-0.001f } } } \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_EPWork.cs b/Assets/PerfectWorld/Scripts/Managers/EC_EPWork.cs index c4356919e9..c4354e57c3 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_EPWork.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_EPWork.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using BrewMonster.Network; using BrewMonster.Utils; using Random = UnityEngine.Random; - +using UnityEngine; namespace BrewMonster.Scripts { using WorkList = System.Collections.Generic.List; @@ -279,61 +279,56 @@ namespace BrewMonster.Scripts // class CECEPWorkSpell public class CECEPWorkSpell : CECEPWork { - CECCounter m_SkillCnt; - CECSkill m_pCurSkill; - int m_idCurSkillTarget; - - public CECEPWorkSpell(CECEPWorkMan pWorkMan, uint dwPeriod, CECSkill pSkill, int target) : base(CECEPWork.EP_work_ID.WORK_SPELL, pWorkMan) + CECCounter m_SkillCnt; + CECSkill m_pCurSkill; + int m_idCurSkillTarget; + public CECEPWorkSpell(CECEPWorkMan pWorkMan, uint dwPeriod, CECSkill pSkill, int target) : base(EP_work_ID.WORK_SPELL, pWorkMan) { m_pCurSkill = pSkill; m_idCurSkillTarget = target; + if (m_SkillCnt == null){ + m_SkillCnt = new CECCounter(); + } m_SkillCnt.SetPeriod(dwPeriod); m_SkillCnt.Reset(); } + // public CECEWorkSpell(){ + // if (m_pCurSkill != null){ + // m_pCurSkill = null; + // } + // } public override void Start() { - GetPlayer().m_iMoveMode = (int)MoveMode.MOVE_STAND; + GetPlayer().m_iMoveMode = (int)MoveMode.MOVE_STAND; } - public override void Tick(float dwDeltaTime) - { - //TO DO: fix later - //GetPlayer().m_FightCnt.IncCounter(dwDeltaTime); - //int iRealTime = g_pGame.GetRealTickTime(); - //if (m_SkillCnt.IncCounter(iRealTime)) - //{ - // Finish(); - //} - //else - //{ - // if (m_idCurSkillTarget != 0) - // { - // GetPlayer().TurnFaceTo(m_idCurSkillTarget); - // } - // if (GetPlayer().IsPlayingMoveAction() && !GetPlayer().IsWorkMoveRunning()) - // { // ���ƶ�ʩ����ֹͣ�ƶ�����һֱ�ڳ��������ƶ��������˴���ͣ - // GetPlayer().PlayAction(CECPlayer::ACT_FIGHTSTAND); - // } - // if (!GetPlayer().IsPlayingAction()) - // { - // GetPlayer().PlayAction((int)CECPlayer.PLAYER_ACTION_TYPE.ACT_FIGHTSTAND); // ���ܶ���������ɺ󡢲���ս��վ������ - // } - //} + public override void Tick(float dwDeltaTime){ + GetPlayer().m_FightCnt.IncCounter(dwDeltaTime *1000); + float iRealTime = EC_Game.GetRealTickTime(); + if (m_SkillCnt.IncCounter(Time.unscaledDeltaTime * 1000f, out float fCounter, out float fPeriod)){ + Finish(); + }else{ + if (m_idCurSkillTarget != 0){ + GetPlayer().TurnFaceTo(m_idCurSkillTarget); + } + if (GetPlayer().IsPlayingMoveAction() && !GetPlayer().IsWorkMoveRunning()){ // ´ÓÒÆ¶¯Ê©·¨µ½Í£Ö¹Òƶ¯¡¢»áÒ»Ö±ÔÚ³ÖÐø²¥·ÅÒÆ¶¯¶¯×÷£¬´Ë´¦ÔÝÍ£ + GetPlayer().PlayAction((int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND); + } + if (!GetPlayer().IsPlayingAction()){ + GetPlayer().PlayAction((int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND); // ¼¼Äܶ¯×÷²¥·ÅÍê³Éºó¡¢²¥·ÅÕ½¶·Õ¾Á¢¶¯×÷ + } + } } - public override void Cancel() - { - //TO DO: fix later - //if (m_pCurSkill != null) - //{ - // m_pCurSkill = null; - //} - //m_idCurSkillTarget = 0; - //GetPlayer().StopSkillAttackAction(); - //GetPlayer().TurnFaceTo(0); + public override void Cancel(){ + if (m_pCurSkill != null){ + m_pCurSkill = null; + } + m_idCurSkillTarget = 0; + GetPlayer().StopSkillAttackAction(); + GetPlayer().TurnFaceTo(0); } - public CECSkill GetSkill() - { + public CECSkill GetSkill(){ return m_pCurSkill; - } + } } public class CECEPWorkMan @@ -898,4 +893,43 @@ namespace BrewMonster.Scripts //GetPlayer().StopModelMove(GetPlayer().m_vStopDir, g_vAxisY, 150); } }; + public class CECEPWorkFlashMove : CECEPWork + { + private A3DVECTOR3 m_vServerPos; + private float m_fMoveSpeed; + public CECEPWorkFlashMove(CECEPWorkMan pWorkMan, A3DVECTOR3 vServerPos, float fMoveSpeed) + : base(CECEPWork.EP_work_ID.WORK_FLASHMOVE, pWorkMan) + { + m_vServerPos = vServerPos; + m_fMoveSpeed = fMoveSpeed; + } + public override void Start() + { + GetPlayer().m_iMoveMode = (int)MoveMode.MOVE_MOVE; + GetPlayer().PlayAction((int)PLAYER_ACTION_TYPE.ACT_JUMP_START, true, 0); + GetPlayer().PlayAction((int)PLAYER_ACTION_TYPE.ACT_JUMP_LOOP, false, 0, true); + } + public override void Tick(float dwDeltaTime) + { + base.Tick(dwDeltaTime); + A3DVECTOR3 vCurPos = GetPlayer().GetPos(); + A3DVECTOR3 vDir = m_vServerPos - vCurPos; + float fDist = vDir.Normalize(); + float fMoveDelta = m_fMoveSpeed * dwDeltaTime * 0.001f; + if (fMoveDelta >= fDist) + { + GetPlayer().SetPos(m_vServerPos); + Finish(); + } + else + { + vCurPos = vCurPos + vDir * fMoveDelta; + GetPlayer().SetPos(vCurPos); + } + } + public override void Cancel() + { + GetPlayer().SetPos(m_vServerPos); + } + } } diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_Skill.cs b/Assets/PerfectWorld/Scripts/Managers/EC_Skill.cs index 8857340faa..896e06d6de 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_Skill.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_Skill.cs @@ -111,6 +111,7 @@ namespace BrewMonster private bool m_bCooling; private int m_iChargeCnt; private int m_iChargeMax; + public int ChargeMax => m_iChargeMax; private bool m_bCharging; private static CECSkillStr l_SkillStr = new CECSkillStr(); diff --git a/Assets/PerfectWorld/Scripts/Move/CECCounter.cs b/Assets/PerfectWorld/Scripts/Move/CECCounter.cs index 2dfd24dfcd..e10c5f4601 100644 --- a/Assets/PerfectWorld/Scripts/Move/CECCounter.cs +++ b/Assets/PerfectWorld/Scripts/Move/CECCounter.cs @@ -40,6 +40,13 @@ public class CECCounter m_dwCounter += dwCounter; return (m_dwCounter >= m_dwPeriod) ? true : false; } + public bool IncCounter(float dwCounter, out float fCounter, out float fPeriod) + { + m_dwCounter += dwCounter; + fCounter = m_dwCounter; + fPeriod = m_dwPeriod; + return (m_dwCounter >= m_dwPeriod) ? true : false; + } // Decrease counter public void DecCounter(float dwCounter) diff --git a/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs b/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs index ef3b988eba..181c2f5356 100644 --- a/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs +++ b/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs @@ -2491,7 +2491,6 @@ namespace BrewMonster else sprintf(szAct, "%s_¿ÕÖзɽ£_Ò÷³ª_%s", data.action_prefix, data.action_weapon_suffix[weapon_type].suffix);*/ } - bool bHideFX = false; /*!CECOptimize::Instance().GetGFX().CanShowCast(GetCharacterID(), GetClassID());*/ if (!PlaySkillCastActionWithName(idSkill, szAct, bHideFX)) { @@ -2525,7 +2524,8 @@ namespace BrewMonster public bool IsHangerOn() { return m_bHangerOn; } public bool IsPlayingAction() { - return true /*GetLowerBodyAction() != -1*/ ; + var check = GetLowerBodyAction() != -1 ; + return check; } public bool PlaySkillCastActionWithName(int idSkill, string szActName, bool bNoFX/* =false */) { @@ -4052,26 +4052,32 @@ namespace BrewMonster public struct PlayActionEvent { + public ChannelAct ChannelAct; public string AnimationName; public int ITransTime; public bool IsForceStopPrevious; public bool IsLoop; public CECAttackEvent AttackEvent; - public PlayActionEvent(string shapeName, string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null, bool isLoop = false) - { - this.AnimationName = shapeName + animationName; - ITransTime = iTransTime; - IsForceStopPrevious = isForceStopPrevious; - AttackEvent = attackEvent; - IsLoop = isLoop; - } + public int Rank; public PlayActionEvent(string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null, bool isLoop = false) { + this.ChannelAct = null; this.AnimationName = animationName; ITransTime = iTransTime; IsForceStopPrevious = isForceStopPrevious; AttackEvent = attackEvent; IsLoop = isLoop; + Rank = 0; + } + public PlayActionEvent(ref ChannelAct channelAct, string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null, bool isLoop = false, int rank = 0) + { + this.ChannelAct = channelAct; + this.AnimationName = animationName; + ITransTime = iTransTime; + IsForceStopPrevious = isForceStopPrevious; + AttackEvent = attackEvent; + IsLoop = isLoop; + Rank = rank; } } public struct PLAYER_ACTION @@ -4081,6 +4087,7 @@ namespace BrewMonster }; public class QueueActionEvent { + public ChannelAct ChannelAct; public string AnimationName; public int ITransTime; public Action SetFlag; @@ -4088,9 +4095,11 @@ namespace BrewMonster public bool IsHitAnim; public bool IsForceStopPrevious; public bool IsLoop; + public int Rank; public QueueActionEvent(string animationName, Action setFlag, bool isHitAnim, CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false, bool isLoop = false) { + this.ChannelAct = null; this.AnimationName = animationName; SetFlag = setFlag; IsHitAnim = isHitAnim; @@ -4098,6 +4107,20 @@ namespace BrewMonster ITransTime = iTransTime; IsForceStopPrevious = isForceStopPrevious; IsLoop = isLoop; + Rank = 0; + } + public QueueActionEvent(ref ChannelAct channelAct, string animationName, Action setFlag, bool isHitAnim, + CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false, bool isLoop = false, int rank = 0) + { + this.ChannelAct = channelAct; + this.AnimationName = animationName; + SetFlag = setFlag; + IsHitAnim = isHitAnim; + AttackEvent = attackEvent; + ITransTime = iTransTime; + IsForceStopPrevious = isForceStopPrevious; + IsLoop = isLoop; + Rank = rank; } public void SetData(string shapeName, string animationName, Action setFlag, bool isHitAnim, diff --git a/Assets/PerfectWorld/Scripts/NPC/CECModel.cs b/Assets/PerfectWorld/Scripts/NPC/CECModel.cs index cce383018f..f3db65e1b6 100644 --- a/Assets/PerfectWorld/Scripts/NPC/CECModel.cs +++ b/Assets/PerfectWorld/Scripts/NPC/CECModel.cs @@ -10,6 +10,7 @@ using CombinedActMap = System.Collections.Generic.Dictionary; using CoGfxMap = System.Collections.Generic.Dictionary; using ConvexHullDataArray = System.Collections.Generic.List; using ECModelHookMap = System.Collections.Generic.Dictionary; +using ActQueue = System.Collections.Generic.List; using BrewMonster; using BrewMonster.Scripts.ECModel; using Unity.VisualScripting.FullSerializer; @@ -45,7 +46,110 @@ public enum ECMScriptVar enumECMVarSelf, enumECMVarCount } +public enum ActionChannel +{ + ACTCHA_DEFAULT = 0, + ACTCHA_WOUND = 1, + ACTCHA_MAX = 16, // Keep this value same with A3DSkinModelActionCore::ACTCHA_MAX +}; +public class A3DCombActDynData +{ + public A3DCombinedAction combinedAction; + public int nChannel; + public int m_dwUserData; + public bool IsAllActionFinished => m_EventNames.Count == 0; + public List m_EventNames = new List(); + public void SetUserData(int dwUserData) { m_dwUserData = dwUserData; } + public int GetUserData() { return m_dwUserData; } +} +public class ChannelActNode +{ + public byte m_Rank; + public A3DCombActDynData m_pActive; + public bool m_pActFlag; + public int m_dwFlagMode; + public ActQueue m_ActQueue; + public ChannelActNode() + { + m_Rank = 0; + m_pActive = null; + m_pActFlag = false; + m_dwFlagMode = 0; + if(m_ActQueue == null) + { + m_ActQueue = new ActQueue(); + } + m_ActQueue.Clear(); + } + public void RemoveQueuedActs() + { + m_ActQueue.Clear(); + } +} +public class ChannelAct +{ + public List m_RankNodes; + public ChannelAct() + { + Release(); + } + + public void Release() + { + if(m_RankNodes == null) + { + m_RankNodes = new List(); + } + m_RankNodes.Clear(); + } + + public ChannelActNode GetNodeByRank(byte rank) + { + if(m_RankNodes == null || m_RankNodes.Count == 0) + { + return null; + } + foreach(var node in m_RankNodes) + { + if(node.m_Rank == rank) + { + return node; + } + } + return null; + } + + public ChannelActNode GetHighestRankNode() + { + if(m_RankNodes == null || m_RankNodes.Count == 0) + { + return null; + } + ChannelActNode highestNode = m_RankNodes[0]; + foreach(var node in m_RankNodes) + { + if(node.m_Rank > highestNode.m_Rank) + { + highestNode = node; + } + } + return highestNode; + } + + public ChannelActNode RemoveNodeByRank(byte rank) + { + foreach(var node in m_RankNodes) + { + if(node.m_Rank == rank) + { + m_RankNodes.Remove(node); + return node; + } + } + return null; + } +}; public static class CECModelConstants { public const int ECM_SCRIPT_MAX_VAR_COUNT = 8; @@ -382,6 +486,15 @@ public class CECModel private Transform m_transform; public bool InheritParentId() => m_bInheritParentId; public void SetId(int nId) => m_nId = nId; + //16 is + ChannelAct[] m_ChannelActs = InitChannelActs(); + private static ChannelAct[] InitChannelActs() + { + var acts = new ChannelAct[(int)ActionChannel.ACTCHA_MAX]; + for (int i = 0; i < acts.Length; i++) + acts[i] = new ChannelAct(); + return acts; + } public void ClearComActFlag(bool bSignalCurrent) { ClearComActFlag(0, bSignalCurrent); } public void ClearComActFlag(int nChannel, bool bSignalCurrent) { @@ -672,11 +785,30 @@ public class CECModel } var actionInfos = combinedAction.m_ActLst; var isLoop = combinedAction.m_nLoops == 1; - EventBus.PublishChannel(m_nId, new PlayActionEvent(actionInfos[0].m_strName, nTransTime, bForceStop, attackEvent, isLoop)); + var node = m_ChannelActs[nChannel].GetNodeByRank(0); + if (node == null) + { + node = new ChannelActNode { m_Rank = 0 }; + m_ChannelActs[nChannel].m_RankNodes.Add(node); + } + var actData = new A3DCombActDynData + { + combinedAction = combinedAction, + nChannel = nChannel, + m_dwUserData = (int)dwUserData + }; + EventBus.PublishChannel(m_nId, new PlayActionEvent(ref m_ChannelActs[nChannel], actionInfos[0].m_strName, nTransTime, bForceStop, attackEvent, isLoop, node.m_Rank)); + actData.m_EventNames.Add(actionInfos[0].m_strName); + for(int i = 1; i < actionInfos.Count; i++) { - EventBus.PublishChannelClass(m_nId, new QueueActionEvent(actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false, isLoop)); + EventBus.PublishChannelClass(m_nId, new QueueActionEvent(ref m_ChannelActs[nChannel], actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false, isLoop, node.m_Rank)); + actData.m_EventNames.Add(actionInfos[i].m_strName); } + + node.m_pActive = actData; + + //Todo: should move those event logic to channel act because their control the animation life span. var eventInfoList = combinedAction.m_EventInfoLst; if(eventInfoList != null && eventInfoList.Count > 0) { @@ -716,25 +848,44 @@ public class CECModel return false; } A3DCombinedAction combinedAction = GetComActByName(szActName); - if(combinedAction == null) + if(combinedAction == null) { return false; } var actionInfos = combinedAction.m_ActLst; var isLoop = combinedAction.m_nLoops == 1; - EventBus.PublishChannelClass(m_nId, new QueueActionEvent(actionInfos[0].m_strName, null, false, attackEvent, nTransTime, bForceStopPrevAct, isLoop)); + var node = new ChannelActNode { m_Rank = (byte)m_ChannelActs[nChannel].m_RankNodes.Count}; + m_ChannelActs[nChannel].m_RankNodes.Add(node); + var actData = new A3DCombActDynData + { + // combinedAction = combinedAction, // not needed now + nChannel = nChannel, + m_dwUserData = (int)dwUserData + }; + EventBus.PublishChannelClass(m_nId, new QueueActionEvent(ref m_ChannelActs[nChannel], actionInfos[0].m_strName, null, false, attackEvent, nTransTime, bForceStopPrevAct, isLoop, node.m_Rank)); for(int i = 1; i < actionInfos.Count; i++) { - EventBus.PublishChannelClass(m_nId, new QueueActionEvent(actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false, isLoop)); + EventBus.PublishChannelClass(m_nId, new QueueActionEvent(ref m_ChannelActs[nChannel], actionInfos[i].m_strName, null, false, attackEvent, nTransTime, false, isLoop, node.m_Rank)); + actData.m_EventNames.Add(actionInfos[i].m_strName); } + node.m_pActive = actData; + //todo: should add sfx and gfx logic to channel act. currently we dont have logic for queue action. only available for play action. return true; } - public bool ClearComActFlagAllRankNodes(bool bSignalCurrent){ - EventBus.PublishChannel(m_nId, new ClearComActFlagAllRankNodesEvent(bSignalCurrent)); + public bool ClearComActFlagAllRankNodes(bool bSignalCurrent) + { + foreach (var ca in m_ChannelActs) + ca?.Release(); + //EventBus.PublishChannel(m_nId, new ClearComActFlagAllRankNodesEvent(bSignalCurrent)); return false; } - public uint GetCurActionUserData(){ - return 0; + + public int GetCurActionUserData() + { + var returnValue = -1; + if (m_ChannelActs[0].GetHighestRankNode() != null) + returnValue = m_ChannelActs[0].GetHighestRankNode().m_pActive.GetUserData(); + return returnValue; } public bool QueueAction(CECNPC.INFO iNFO, string szActName, ref bool pNewActFlag, int nTransTime = 200, uint dwUserData = 0, bool bForceStopPrevAct = false, bool bCheckTailDup = false, bool bNoFx = false, bool bResetSpeed = false /*joslian*/, bool bResetActFlag = false, uint dwNewFlagMode = COMACT_FLAG_MODE_NONE) @@ -846,8 +997,3 @@ public class CECModel // m_CoGfxMap[strKey] = pInfo; } } -// Action channel -public enum ActionChannel -{ - ACTCHA_WOUND = 1, -}; diff --git a/Assets/PerfectWorld/Scripts/Players/CECPlayerActionPlayPolicy.cs b/Assets/PerfectWorld/Scripts/Players/CECPlayerActionPlayPolicy.cs index 4a4dd77b79..1a65390cb9 100644 --- a/Assets/PerfectWorld/Scripts/Players/CECPlayerActionPlayPolicy.cs +++ b/Assets/PerfectWorld/Scripts/Players/CECPlayerActionPlayPolicy.cs @@ -450,13 +450,14 @@ namespace BrewMonster } public override bool IsPlayingMoveAction(){ if (GetModel()!=null){ - return IsMoveAction((int)GetModel().GetCurActionUserData()); + var userData = GetModel().GetCurActionUserData(); + return IsMoveAction((int)userData); } return false; } public override int GetLowerBodyAction(){ if (GetModel()!=null){ - return (int)GetModel().GetCurActionUserData(); + return GetModel().GetCurActionUserData(); } return -1; } diff --git a/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs b/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs index 390cd62ac3..c4eafb0a73 100644 --- a/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs +++ b/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs @@ -672,80 +672,70 @@ namespace BrewMonster // Get skill object (else players don't have skill lists, so we create a temporary skill reference) // For else players, we mainly need the skill ID for animation purposes int skillID = pCmd.skill; - + if ((m_pCurSkill = new CECSkill(pCmd.skill, pCmd.level)) == null) + { + BMLogger.LogError($"OnMsgPlayerCastSkill: Failed to create CECSkill for skillID={pCmd.skill}, level={pCmd.level}"); + return; + } // Store current skill target m_idCurSkillTarget = pCmd.target; - // Face the target - TurnFaceTo(pCmd.target); + uint dwPeriod = (uint)(pCmd.time + m_pCurSkill.GetExecuteTime()) * 10; + m_pEPWorkMan.StartNormalWork(new CECEPWorkSpell(m_pEPWorkMan, dwPeriod, new CECSkill(pCmd.skill, pCmd.level), pCmd.target)); + PlaySkillCastAction(m_pCurSkill.GetSkillID()); + // // Face the target + // TurnFaceTo(pCmd.target); - // Play skill cast animation - PlaySkillCastAction(skillID); + // // Play skill cast animation + // PlaySkillCastAction(skillID); - // Create a temporary skill object for tracking (if needed) - // Note: Else players don't maintain skill lists like host player does - // We create a minimal skill object just for the current cast - if (m_pCurSkill == null || m_pCurSkill.GetSkillID() != skillID) - { - // Create a temporary skill object with level 1 (we don't know the actual level) - m_pCurSkill = new CECSkill(skillID, 1); - } + // // Create a temporary skill object for tracking (if needed) + // // Note: Else players don't maintain skill lists like host player does + // // We create a minimal skill object just for the current cast + // if (m_pCurSkill == null || m_pCurSkill.GetSkillID() != skillID) + // { + // // Create a temporary skill object with level 1 (we don't know the actual level) + // m_pCurSkill = new CECSkill(skillID, 1); + // } - // Enter fight state - EnterFightState(); + // // Enter fight state + // EnterFightState(); break; } case CommandID.OBJECT_CAST_INSTANT_SKILL: { + StopCurPosWork(); + ClearCastingSkill(); + m_pEPWorkMan.FinishWork(CECEPWork.EP_work_ID.WORK_SPELL); cmd_object_cast_instant_skill pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - int skillID = pCmd.skill; - - m_idCurSkillTarget = pCmd.target; - - TurnFaceTo(pCmd.target); - PlaySkillCastAction(skillID); - - if (m_pCurSkill == null || m_pCurSkill.GetSkillID() != skillID) - { - m_pCurSkill = new CECSkill(skillID, 1); - } - - EnterFightState(); + PlaySkillCastAction(pCmd.skill); break; } case CommandID.OBJECT_CAST_POS_SKILL: { + StopCurPosWork(); + ClearCastingSkill(); + m_pEPWorkMan.FinishWork(CECEPWork.EP_work_ID.WORK_SPELL); + + cmd_object_cast_pos_skill pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - int skillID = pCmd.skill; + SetServerPos(pCmd.pos); - // For position-based skills, target is the position, not an object - // We still play the cast animation - PlaySkillCastAction(skillID); - - if (m_pCurSkill == null || m_pCurSkill.GetSkillID() != skillID) + float fDist = A3d_Magnitude(pCmd.pos - GetPos()); + if (fDist <= 0.0001f) { - m_pCurSkill = new CECSkill(skillID, 1); - } - - EnterFightState(); - break; - } - case CommandID.SKILL_PERFORM: - { - // Skill perform - the skill has finished casting and is being executed - // For else players, we keep m_pCurSkill until attack result is received - // This allows PlayAttackEffect to use the skill information - // Durative skills (channeling) will continue until interrupted - if (m_pCurSkill != null && m_pCurSkill.IsDurative()) - { - // For durative skills, we keep the skill active - // It will be cleared when SKILL_INTERRUPTED is received + SetPos(pCmd.pos); + return; } + int nExecuteTime = ElementSkill.GetExecuteTime((uint)pCmd.skill, pCmd.level); + nExecuteTime = Mathf.Max(nExecuteTime, 50); + + m_fMoveSpeed = 1.3f * fDist * 1000.0f / nExecuteTime; + m_pEPWorkMan.StartNormalWork(new CECEPWorkFlashMove(m_pEPWorkMan, pCmd.pos, m_fMoveSpeed)); break; } case CommandID.SKILL_INTERRUPTED: @@ -753,13 +743,10 @@ namespace BrewMonster // Skill was interrupted, clear current skill cmd_skill_interrupted pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); - - if (m_pCurSkill != null) - { - StopSkillCastAction(); - m_pCurSkill = null; - } - m_idCurSkillTarget = 0; + ClearComActFlagAllRankNodes(false); + ClearCastingSkill(); + m_pEPWorkMan.FinishWork(CECEPWork.EP_work_ID.WORK_SPELL); + StopSkillCastAction(); break; } default: @@ -768,7 +755,25 @@ namespace BrewMonster } } } - + private void ClearCastingSkill(){ + if (m_pCurSkill != null){ + m_pCurSkill = null; + } + m_idCurSkillTarget = 0; + } + private void StopCurPosWork() + { + if (m_pEPWorkMan.IsWorkRunning(CECEPWork.EP_work_ID.WORK_MOVE)){ + m_pEPWorkMan.FinishRunningWork(CECEPWork.EP_work_ID.WORK_MOVE); + } + if (m_pEPWorkMan.IsWorkRunning(CECEPWork.EP_work_ID.WORK_PASSIVEMOVE)){ + m_pEPWorkMan.FinishRunningWork(CECEPWork.EP_work_ID.WORK_PASSIVEMOVE); + } + if (m_pEPWorkMan.IsWorkRunning(CECEPWork.EP_work_ID.WORK_FLASHMOVE)){ + m_pEPWorkMan.FinishRunningWork(CECEPWork.EP_work_ID.WORK_FLASHMOVE); + } + } + private async void LoadAppearGfx() { if (!m_pAppearGFX && m_iAppearFlag == (int)PlayerAppearFlag.APPEAR_ENTERWORLD) diff --git a/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs b/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs index d5dfdfc43b..32999dd6d4 100644 --- a/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs +++ b/Assets/PerfectWorld/Scripts/Players/PlayerModelPreview.cs @@ -39,10 +39,15 @@ namespace BrewMonster.Scripts _loadVersion++; int version = _loadVersion; - ClearModels(); - if (roleInfos == null || roleInfos.Count == 0 || NPCManager.Instance == null) + { + ClearModels(); return; + } + + List oldModels = new List(playerModels); + playerModels.Clear(); + playerModelIds.Clear(); for (int i = 0; i < roleInfos.Count; i++) { @@ -68,6 +73,14 @@ namespace BrewMonster.Scripts ApplyRequestedModelVisibility(); } + + for(int i=0; i < oldModels.Count; i++) + { + if (oldModels[i] != null) + { + Destroy(oldModels[i]); + } + } } /// @@ -108,13 +121,36 @@ namespace BrewMonster.Scripts } } - public void ClearModels() + public void HideAllPlayerModels() { + _hasRequestedPlayerModelId = false; for (int i = 0; i < playerModels.Count; i++) { if (playerModels[i] != null) - Destroy(playerModels[i]); + { + playerModels[i].SetActive(false); + } } + } + + public void ClearModels() + { + //for (int i = 0; i < playerModels.Count; i++) + //{ + // if (playerModels[i] != null) + // { + // Destroy(playerModels[i]); + // } + //} + + for (int i = 0; i < playerModels.Count; i++) + { + if (playerModels[i] != null) + { + Destroy(playerModels[i]); + } + } + playerModels.Clear(); playerModelIds.Clear(); } @@ -123,14 +159,18 @@ namespace BrewMonster.Scripts { for (int i = 0; i < playerModels.Count; i++) { - if (playerModels[i] != null) + if (modelRoot != null) { - if (Application.isPlaying) - Destroy(playerModels[i]); - else - DestroyImmediate(playerModels[i]); + if(playerModels[i] != null) + { + if(Application.isPlaying) + Destroy(playerModels[i]); + else + DestroyImmediate(playerModels[i]); + } } } + playerModels.Clear(); playerModelIds.Clear(); } @@ -139,13 +179,17 @@ namespace BrewMonster.Scripts { BMLogger.Log($"LoadPlayerModel: {role.roleid}"); var elemendataman = BrewMonster.ElementDataManProvider.GetElementDataMan(); - GameObject prefab = await NPCManager.Instance.GetModelPlayer(role.occupation, role.gender); - if (prefab == null) - { + GameObject model = await NPCManager.Instance.GetModelPlayer(role.occupation, role.gender); + if(model == null) return null; - } + + model.SetActive(false); BMLogger.Log($"LoadPlayerModel: {role.roleid} - prefab loaded"); - GameObject model = Instantiate(prefab); + if (modelRoot != null) + { + model.transform.SetParent(modelRoot, false); + } + var playerDefaultEquipments = model.GetComponentInChildren(); if (playerDefaultEquipments == null) { diff --git a/Assets/PerfectWorld/Scripts/Skills/ElementSkill.cs b/Assets/PerfectWorld/Scripts/Skills/ElementSkill.cs index df4309c617..72a5ffd914 100644 --- a/Assets/PerfectWorld/Scripts/Skills/ElementSkill.cs +++ b/Assets/PerfectWorld/Scripts/Skills/ElementSkill.cs @@ -196,6 +196,15 @@ namespace BrewMonster.Scripts.Skills // ������ȴʱ�䣬��λ���� public virtual int GetCoolingTime() { return 5000; } // ����ִ��ʱ�䣬��λ���� + public static int GetExecuteTime(uint id, int level) + { + Skill s = Skill.Create(id, level); + if (s == null) + return 0; + + int ret = s.GetExecuteTime(); + return ret; + } public virtual int GetExecuteTime() { return 1000; } // Ŀ����������, 0:����Ŀ�꣬1:��ҪĿ�꣬2:Ŀ��������?��, 3:Ŀ������?����, 4:Ŀ������?���� public virtual int GetTargetType() { return 0; } diff --git a/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs b/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs index 8b127d6206..a90461ec17 100644 --- a/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs +++ b/Assets/PerfectWorld/Scripts/UI/Inventory/InventoryCharacterPreview.cs @@ -246,6 +246,11 @@ namespace BrewMonster.Scripts.UI.Inventory return; } + if (_previewInstance != null && _previewInstance != sourceRoot.gameObject) + { + DestroyPreviewInstance(); + } + if (!sourceRoot.gameObject.activeSelf) { sourceRoot.gameObject.SetActive(true); @@ -269,6 +274,15 @@ namespace BrewMonster.Scripts.UI.Inventory EnsureCameraBindings(); } + private void DestroyPreviewInstance() + { + if (_previewInstance != null) + { + Destroy(_previewInstance); + _previewInstance = null; + } + } + private Transform ResolveSourceModelRoot() { diff --git a/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs b/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs index 5e2cbc3791..5cbde28ad9 100644 --- a/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs +++ b/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs @@ -56,6 +56,11 @@ namespace BrewMonster.UI { Tech3CSDKWrapper.Instance.SetLoginCallback(OnLoginCallback); Tech3CSDKWrapper.Instance.SetLogoutCallback(OnLogoutCallback); + + if(PlayerModelPreview.Instance != null) + { + PlayerModelPreview.Instance.HideAllPlayerModels(); + } } private void OnDisable() @@ -102,7 +107,7 @@ namespace BrewMonster.UI { if (_roleInfos != null) { - _selectCharacterScreen.InitScreen(_roleInfos, OnClickSelectCharacter, OnCreateCharacterComplete); + _selectCharacterScreen.InitScreen(_roleInfos, OnClickSelectCharacter, OnCreateCharacterComplete, OnExitCharacterSelect); _roleInfos = null; } @@ -353,6 +358,13 @@ namespace BrewMonster.UI private async void OnEnterWorldComplete() { + // initialize the mini map + CECGameUIMan pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan(); + if (pGameUI != null) + { + pGameUI.m_pDlgMiniMap.InitializeMiniMap(); + } + await Task.Delay(2000); // Request all known packages: 0=Inventory,1=Equipment,2=Task UnityGameSession.RequestAllInventoriesAsync(() => { /*BMLogger.Log("Sent Inventory Detail Requests (all packs)");*/ }, 0, 1, 2); @@ -422,6 +434,21 @@ namespace BrewMonster.UI { BMLogger.LogError($"Logout failed -- errorCode: {errorCode}: {errorMessage}"); } + + _loginInProgress = false; + if (_loginButton != null) + _loginButton.interactable = true; + } + + private void OnExitCharacterSelect() + { + BMLogger.Log("Exiting character select, returning to login screen."); + if(_selectCharacterScreen != null) + _selectCharacterScreen.gameObject.SetActive(false); + + _loginInProgress = false; + if(_loginButton != null) + _loginButton.interactable = true; } } } diff --git a/Assets/PerfectWorld/Scripts/UI/MiniMap/CDlgMiniMap.cs b/Assets/PerfectWorld/Scripts/UI/MiniMap/CDlgMiniMap.cs index b557b233fa..90eccde575 100644 --- a/Assets/PerfectWorld/Scripts/UI/MiniMap/CDlgMiniMap.cs +++ b/Assets/PerfectWorld/Scripts/UI/MiniMap/CDlgMiniMap.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using BrewMonster; +using BrewMonster.Network; using BrewMonster.Scripts; using BrewMonster.Scripts.Extensions; using BrewMonster.UI; @@ -55,13 +56,15 @@ namespace PerfectWorld.UI.MiniMap private bool isShowMiniMap = true; CECHostPlayer m_pHostPlayer; + private float coordinateFactor = 0.5f; // the factor to convert the world coordinates to the mini map coordinates. + Vector3Int _lastIntHostPos = Vector3Int.zero; private int m_nMode; // TODO: currently, there is only get logic, not set logic private void Awake() { - LoadAllMiniMapTextures(); + // LoadAllMiniMapTextures(); _worldMapButton.onClick.AddListener(OnMiniMapClicked); } @@ -80,7 +83,6 @@ namespace PerfectWorld.UI.MiniMap m_pHostPlayer = GetHostPlayer(); if (m_pHostPlayer == null) return; - // TODO: This should be the position of the host player, not hardcoded. Transform hostTransform = m_pHostPlayer.transform; Vector3 vecPosHost = hostTransform.position; Vector3Int currentIntHostPos = new Vector3Int(Mathf.RoundToInt(vecPosHost.x) / 10 + 400, Mathf.RoundToInt(vecPosHost.y) / 10, Mathf.RoundToInt(vecPosHost.z) / 10 + 550); @@ -89,7 +91,7 @@ namespace PerfectWorld.UI.MiniMap txtHostPos.text = $"{currentIntHostPos.x}, {currentIntHostPos.z}, ↑{currentIntHostPos.y}"; _lastIntHostPos = currentIntHostPos; } - Vector2 hostPlayerPos = new Vector2(vecPosHost.x / 2, vecPosHost.z / 2); + Vector2 hostPlayerPos = new Vector2(vecPosHost.x * coordinateFactor, vecPosHost.z * coordinateFactor); _transformMiniMapParent.anchoredPosition = -hostPlayerPos; _hostPlayerIcon.localRotation = Quaternion.Euler(0, 0, -hostTransform.localRotation.eulerAngles.y); } @@ -117,6 +119,40 @@ namespace PerfectWorld.UI.MiniMap // dlg?.OnInitDialog(); } + + /// + /// Call this function when user enter the game world (after select role or when use GOTO to jump to a new instance). + /// This function will get the world instance data and setup the mini map. + /// + public async void InitializeMiniMap() + { + // get current world instance + var idInstance = CECGameRun.Instance?.GetWorld()?.GetInstanceID() ?? 161; + var worldInstance = EC_Game.GetGameRun()?.GetInstance(idInstance); + + if (worldInstance == null) + { + BMLogger.LogError("InitializeMiniMap: worldInstance is null"); + return; + } + // set the number of rows and columns of the mini map + nRow = (byte)worldInstance.GetRowNum(); + nCol = (byte)worldInstance.GetColNum(); + + + // use Addressable to load all the textures of the mini map + _spriteAtlas = await AddressableManager.Instance.LoadSpriteAtlasAsync($"minimaps/{idInstance}"); + + if (_spriteAtlas == null) + { + BMLogger.LogError("InitializeMiniMap: sprite atlas is null"); + return; + } + + LoadAllMiniMapTextures(); + } + + // keep this so we can load all textures of other map also. [ContextMenu("LoadAllMiniMapTextures")] public void LoadAllMiniMapTextures() @@ -142,7 +178,7 @@ namespace PerfectWorld.UI.MiniMap } } - +#if UNITY_EDITOR // this is for debuging/testing while this feature was in development [ContextMenu("MoveHostPlayerIconToPos")] public void MoveHostPlayerIconToPos() @@ -151,5 +187,6 @@ namespace PerfectWorld.UI.MiniMap _transformMiniMapParent.anchoredPosition = -hostPlayerPos; } +#endif } } \ No newline at end of file diff --git a/Assets/PerfectWorld/UI/surfaces/minimaps/a61/a61.spriteatlasv2 b/Assets/PerfectWorld/UI/surfaces/minimaps/a61/161.spriteatlasv2 similarity index 100% rename from Assets/PerfectWorld/UI/surfaces/minimaps/a61/a61.spriteatlasv2 rename to Assets/PerfectWorld/UI/surfaces/minimaps/a61/161.spriteatlasv2 diff --git a/Assets/PerfectWorld/UI/surfaces/minimaps/a61/a61.spriteatlasv2.meta b/Assets/PerfectWorld/UI/surfaces/minimaps/a61/161.spriteatlasv2.meta similarity index 94% rename from Assets/PerfectWorld/UI/surfaces/minimaps/a61/a61.spriteatlasv2.meta rename to Assets/PerfectWorld/UI/surfaces/minimaps/a61/161.spriteatlasv2.meta index 159e47e4e8..c8f8e51ca4 100644 --- a/Assets/PerfectWorld/UI/surfaces/minimaps/a61/a61.spriteatlasv2.meta +++ b/Assets/PerfectWorld/UI/surfaces/minimaps/a61/161.spriteatlasv2.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: b764c7c6d08a20e41a8ebfb3435954db +guid: 34322d27488583140acae7497762ccbc SpriteAtlasImporter: externalObjects: {} textureSettings: diff --git a/Assets/Prefabs/UI/SelectCharacterUI.prefab b/Assets/Prefabs/UI/SelectCharacterUI.prefab index 6cf572cc64..b237cd413f 100644 --- a/Assets/Prefabs/UI/SelectCharacterUI.prefab +++ b/Assets/Prefabs/UI/SelectCharacterUI.prefab @@ -989,8 +989,8 @@ MonoBehaviour: parentItems: {fileID: 2643174602035272289} createCharacterButton: {fileID: 2685968509838782728} _btnEnterGame: {fileID: 5173447691193350084} + _btnExit: {fileID: 1166159884785039946} createCharacterScreen: {fileID: 0} - playerModelPreview: {fileID: 0} --- !u!1 &7510180475820570348 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Scripts/PlayerVisual.cs b/Assets/Scripts/PlayerVisual.cs index 57940f9f58..e79b9b083e 100644 --- a/Assets/Scripts/PlayerVisual.cs +++ b/Assets/Scripts/PlayerVisual.cs @@ -14,6 +14,8 @@ namespace BrewMonster public int ITransTime; public CECAttackEvent AttackEvent; public bool IsLoop; + public ChannelAct ChannelAct; + public int Rank; } public class PlayerVisual : MonoBehaviour { @@ -48,14 +50,16 @@ namespace BrewMonster { AnimationName = @event.AnimationName, IsForceStopPrevious = @event.IsForceStopPrevious, - AttackEvent = @event.AttackEvent + AttackEvent = @event.AttackEvent, + ChannelAct = @event.ChannelAct, + Rank = @event.Rank }); _animationList = _animationQueue.Select(q => q.AnimationName).ToList(); return; } previousAnimationName = @event.AnimationName; InternalPlayAnimation(@event.AnimationName, @event.ITransTime, FadeMode, @event.IsLoop); - ApplyAttackSignalOnAnimationEnd(@event.AttackEvent); + ApplyAnimationEndCallbacks(@event.AttackEvent, @event.ChannelAct, @event.Rank); } public void InitPlayerEventDoneHandler() { @@ -156,7 +160,9 @@ namespace BrewMonster IsForceStopPrevious = @event.IsForceStopPrevious, ITransTime = @event.ITransTime, AttackEvent = @event.AttackEvent, - IsLoop = @event.IsLoop + IsLoop = @event.IsLoop, + ChannelAct = @event.ChannelAct, + Rank = @event.Rank }); _animationList = _animationQueue.Select(q => q.AnimationName).ToList(); if (!isHit) @@ -222,18 +228,21 @@ namespace BrewMonster _animationList = _animationQueue.Select(q => q.AnimationName).ToList(); previousAnimationName = animationQueue.AnimationName; InternalPlayAnimation(animationQueue.AnimationName, animationQueue.ITransTime, FadeMode, animationQueue.IsLoop); - ApplyAttackSignalOnAnimationEnd(animationQueue.AttackEvent); + ApplyAnimationEndCallbacks(animationQueue.AttackEvent, animationQueue.ChannelAct, animationQueue.Rank); } - private void ApplyAttackSignalOnAnimationEnd(CECAttackEvent attackEvent) - { - if (attackEvent == null || _currentState == null) - { - return; - } + private void ApplyAnimationEndCallbacks(CECAttackEvent attackEvent, ChannelAct channelAct, int rank) + { + if (_currentState == null) return; _currentState.Events.OnEnd = () => { - attackEvent.m_bSignaled = true; + if (attackEvent != null) + attackEvent.m_bSignaled = true; + channelAct.GetNodeByRank((byte)rank).m_pActive.m_EventNames.Remove(_currentAnimationName); + if(channelAct.GetNodeByRank((byte)rank).m_pActive.IsAllActionFinished) + { + //channelAct.RemoveNodeByRank((byte)rank); + } }; } void ApplyDamage() diff --git a/Assets/Scripts/SelecScreenCharacter.cs b/Assets/Scripts/SelecScreenCharacter.cs index 249bb89897..682ff14f5c 100644 --- a/Assets/Scripts/SelecScreenCharacter.cs +++ b/Assets/Scripts/SelecScreenCharacter.cs @@ -18,11 +18,13 @@ namespace BrewMonster.UI [SerializeField] private RectTransform parentItems; [SerializeField] private Button createCharacterButton; [SerializeField] private Button _btnEnterGame; + [SerializeField] private Button _btnExit; [SerializeField] private CreateCharacterScreen createCharacterScreen; private CharacterItemUI _selectingCharacterItemUI; private Action _onClickItemChar; private Action _onCreateCharacterComplete; + private Action _onExit; private List _roleInfos; private Coroutine _showModelReadyCoroutine; @@ -33,6 +35,11 @@ namespace BrewMonster.UI _btnEnterGame.onClick.AddListener(OnClickedEnterGame); _btnEnterGame.gameObject.SetActive(false); + if(_btnExit != null) + { + _btnExit.onClick.AddListener(OnClickedExit); + } + if (_roleInfos != null && _roleInfos.Count > 0) { PlayerModelPreview.Instance?.ShowAllPlayerModels(_roleInfos); @@ -57,10 +64,11 @@ namespace BrewMonster.UI } } - public void InitScreen(List roleInfos, Action OnClickItemChar, Action onCreateCharacterComplete = null) + public void InitScreen(List roleInfos, Action OnClickItemChar, Action onCreateCharacterComplete = null, Action onExit = null) { _onClickItemChar = OnClickItemChar; _onCreateCharacterComplete = onCreateCharacterComplete; + _onExit = onExit; // Clear existing items if (parentItems != null) @@ -110,7 +118,7 @@ namespace BrewMonster.UI addButton.onClick.AddListener(OnCreateCharacterClicked); } } - + } else { @@ -120,13 +128,13 @@ namespace BrewMonster.UI createCharacterButton.gameObject.SetActive(true); } } - + // Load player preview 3D models PlayerModelPreview.Instance?.ShowAllPlayerModels(roleInfos); } else { - if (PlayerModelPreview.Instance != null) + if (PlayerModelPreview.Instance != null) PlayerModelPreview.Instance.ShowAllPlayerModels(null); // If roleInfos is null, show createCharacterButton if (createCharacterButton != null) @@ -143,7 +151,7 @@ namespace BrewMonster.UI return; } - if(_selectingCharacterItemUI!=null) + if (_selectingCharacterItemUI != null) { _selectingCharacterItemUI.SetFocus(false); } @@ -230,5 +238,16 @@ namespace BrewMonster.UI BMLogger.LogError("No role selected"); } } + + private void OnClickedExit() + { + _onExit?.Invoke(); + gameObject.SetActive(false); + + if(PlayerModelPreview.Instance != null) + { + PlayerModelPreview.Instance.HideAllPlayerModels(); + } + } } }