using BrewMonster; using BrewMonster.Managers; using BrewMonster.Network; using BrewMonster.Scripts; using CSNetwork; using CSNetwork.GPDataType; using CSNetwork.Protocols; using CSNetwork.Protocols.RPCData; using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Runtime.InteropServices; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using static Unity.Burst.Intrinsics.X86.Avx; namespace PerfectWorld.Scripts.Managers { namespace BrewMonster.Managers { [Serializable] public class EC_ManPlayer : IMsgHandler { Dictionary m_UkPlayerTab = new Dictionary(); Dictionary m_PlayerTab = new Dictionary(); private readonly object m_csPlayerTab = new object(); public int HandlerId => (int)MANAGER_INDEX.MAN_PLAYER; public bool ProcessMessage(ECMSG Msg) { if (Msg.iSubID == 0) { if (CECGameRun.Instance == null) return true; if (CECGameRun.Instance.GetHostPlayer() == null) return true; CECGameRun.Instance.GetHostPlayer().ProcessMessage(Msg); } else if (Msg.iSubID < 0) { switch ((int)Msg.dwMsg) { case int value when value == EC_MsgDef.MSG_PM_PLAYERINFO: { OnMsgPlayerInfo(Msg); break; } case int value when value == EC_MsgDef.MSG_PM_PLAYERMOVE: { OnMsgPlayerMove(Msg); break; } case int value when value == EC_MsgDef.MSG_PM_PLAYERLEVELUP: OnMsgPlayerLevelUp(Msg); break; case int value when value == EC_MsgDef.MSG_PM_PLAYERSTOPMOVE: { OnMsgPlayerStopMove(Msg); break; } case EC_MsgDef.MSG_PM_PLAYEREQUIPDATA: case EC_MsgDef.MSG_PM_PLAYERBASEINFO: case EC_MsgDef.MSG_PM_FACTION_PVP_MASK_MODIFY: case EC_MsgDef.MSG_PM_PLAYERATKRESULT: case EC_MsgDef.MSG_PM_CASTSKILL: case EC_MsgDef.MSG_PM_ENCHANTRESULT: case EC_MsgDef.MSG_PM_PLAYERDOEMOTE: case EC_MsgDef.MSG_PM_PLAYERGATHER: case EC_MsgDef.MSG_PM_PLAYERFLY: case EC_MsgDef.MSG_PM_PLAYERSITDOWN: case EC_MsgDef.MSG_PM_PLAYERMOUNT: case EC_MsgDef.MSG_PM_PLAYERCHGSHAPE: case EC_MsgDef.MSG_PM_PLAYERSKILLRESULT: TransmitMessage(Msg); break; case EC_MsgDef.MSG_PM_PLAYERDIED: OnMsgPlayerDied(Msg); break; case EC_MsgDef.MSG_PM_PLAYERREVIVE: OnMsgPlayerRevive(Msg); break; case EC_MsgDef.MSG_PM_PLAYERRUNOUT: OnMsgPlayerRunOut(Msg); break; case EC_MsgDef.MSG_PM_PICKUPMATTER: OnMsgPlayerPickupMatter(Msg); break; case EC_MsgDef.MSG_PM_PLAYEREXTPROP: OnMsgPlayerExtProp(Msg); break; case EC_MsgDef.MSG_PM_PLAYERDISAPPEAR: OnMsgPlayerDisappear(Msg); break; case EC_MsgDef.MSG_PM_PLAYEROUTOFVIEW: OnMsgPlayerOutOfView(Msg); break; case EC_MsgDef.MSG_PM_INVALIDOBJECT: OnMsgInvalidObject(Msg); break; case int value when value == EC_MsgDef.MSG_PM_PLAYERDUELOPT: // PLAYER_DUEL_START (229): server may send to both duelists; update host state if host is one of them // dwParam2 is ushort (pCmdHeader from GameSession); use Convert to avoid InvalidCastException when unboxing if (Convert.ToInt32(Msg.dwParam2) == CommandID.PLAYER_DUEL_START && Msg.dwParam1 is byte[] duelData && duelData.Length >= 8) { var pHost = GetHostPlayer(); if (pHost != null) { var method = pHost.GetType().GetMethod("OnMsgPlayerDuelStart", BindingFlags.Public | BindingFlags.Instance, null, new[] { typeof(byte[]) }, null); method?.Invoke(pHost, new object[] { duelData }); } } TransmitMessage(Msg); break; case EC_MsgDef.MSG_PM_PLAYEREXIT: OnMsgPlayerExit(Msg); break; case EC_MsgDef.MSG_PM_PLAYEREXTSTATE: OnMsgPlayerExtState(Msg); break; } } else { } return true; } public bool OnMsgPlayerExtState(ECMSG Msg) { int cid = 0; cmd_icon_state_notify cmd = new cmd_icon_state_notify(); if (Convert.ToInt32(Msg.dwParam2) == CommandID.UPDATE_EXT_STATE) { var pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); cid = pCmd.id; } else if (Convert.ToInt32(Msg.dwParam2) == CommandID.ICON_STATE_NOTIFY) { if (!cmd.Initialize((byte[])Msg.dwParam1)) { return false; } cid = cmd.id; } else { return false; } CECHostPlayer host = GetHostPlayer(); if (host != null && cid == host.GetCharacterID()) { // Call OnMsgPlayerExtState directly instead of ProcessMessage // ProcessMessage doesn't handle MSG_PM_PLAYEREXTSTATE // 直接调用OnMsgPlayerExtState而不是ProcessMessage // ProcessMessage不处理MSG_PM_PLAYEREXTSTATE host.ProcessMessage(Msg); } else { EC_ElsePlayer elsePlayer = SeekOutElsePlayer(cid); if (elsePlayer != null) { // Call OnMsgPlayerExtState directly instead of ProcessMessage // ProcessMessage doesn't handle MSG_PM_PLAYEREXTSTATE // 直接调用OnMsgPlayerExtState而不是ProcessMessage // ProcessMessage不处理MSG_PM_PLAYEREXTSTATE elsePlayer.OnMsgPlayerExtState(Msg); } if (Convert.ToInt32(Msg.dwParam2) == CommandID.ICON_STATE_NOTIFY && host != null && host.GetTeam() != null) { // TODO: Update host's team member's icon state // CECTeam pTeam = host.GetTeam(); // CECTeamMember pMember = pTeam.GetMemberByID(cid); // if (pMember != null) // pMember.ResetIconStates(cmd.states); } } return true; } private void OnMsgPlayerDied(ECMSG Msg) { cmd_player_died pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); EC_ElsePlayer pPlayer = SeekOutElsePlayer(pCmd.idPlayer); //if (pPlayer && !pPlayer.IsAboutToDie()) // pPlayer.Killed(pCmd.idKiller); EventBus.PublishChannel(pPlayer.GetCharacterID(), new ClearComActFlagAllRankNodesEvent(true)); pPlayer.PlayAction((int)PLAYER_ACTION_TYPE.ACT_GROUNDDIE); } private void OnMsgPlayerRevive(ECMSG Msg) { cmd_player_revive pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); CECHostPlayer pHost = GetHostPlayer(); if (pHost && pHost.GetCharacterID() == pCmd.idPlayer) { pHost.HandleRevive(pCmd.sReviveType, pCmd.pos); } else { EC_ElsePlayer pPlayer = SeekOutElsePlayer(pCmd.idPlayer); if (pPlayer) pPlayer.HandleRevive(pCmd.sReviveType, pCmd.pos); } } public void OnMsgPlayerInfo(ECMSG Msg) { int iHostID = Convert.ToInt32(Msg.dwParam3); int lenghtByte = Marshal.SizeOf(); byte[] byteArray = new byte[lenghtByte]; byte[] data = (byte[])Msg.dwParam1; for (int i = 0; i < lenghtByte; i++) { byteArray[i] = data[i]; } int cid = BitConverter.ToInt32(byteArray); int commandID = Convert.ToInt32(Msg.dwParam2); switch (commandID) { case CommandID.PLAYER_INFO_1: case CommandID.PLAYER_ENTER_WORLD: case CommandID.PLAYER_ENTER_SLICE: { if (cid != iHostID) { info_player_1 info_Player_1 = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); EC_ElsePlayer pPlayer = ElsePlayerEnter(info_Player_1, commandID); if (pPlayer != null) { if (!pPlayer.m_bBaseInfoReady) { UnityGameSession.GetRoleBaseInfo(1, new List { info_Player_1.cid }); } //Is equipment data ready if (!pPlayer.IsEquipDataReady()) { UnityGameSession.c2s_CmdGetOtherEquip(1, new List { info_Player_1.cid }); } } } break; } case CommandID.SELF_INFO_1: cmd_self_info_1 info = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); HostPlayerInfo1(info); break; case CommandID.PLAYER_INFO_2: break; case CommandID.PLAYER_INFO_3: break; case CommandID.PLAYER_INFO_4: break; case CommandID.PLAYER_INFO_1_LIST: { byte[] bytes = (byte[])Msg.dwParam1; cmd_player_info_1_list pCmd = GPDataTypeHelper.FromBytes(bytes); if (pCmd.count == 0) break; List a1 = new(); List a2 = new(); List a3 = new(); List a4 = new(); int lenght = Marshal.SizeOf(); int preSize = 0; byte[] pDataBuf = null; preSize += Marshal.SizeOf(); for (int i = 0; i < pCmd.count; i++) { pDataBuf = new byte[lenght]; for (int j = 0; j < pDataBuf.Length; j++) { pDataBuf[j] = bytes[preSize + j]; } info_player_1 Info = GPDataTypeHelper.FromBytes(pDataBuf); if (Info.cid != iHostID) { EC_ElsePlayer pPlayer = ElsePlayerEnter(Info, commandID); if (pPlayer != null) { if (!pPlayer.m_bCustomReady) { if (!pPlayer.m_bBaseInfoReady) a2.Add(Info.cid); else a3.Add(Info.cid); } // Is equipment data ready if (!pPlayer.m_bEquipReady) a1.Add(Info.cid); // TODO: Implement get faction /*/ // Get faction info if (pPlayer.GetFactionID() && !g_pGame.GetFactionMan().GetFaction(pPlayer.GetFactionID())) { int i(0); for (i = 0; i < a4.GetSize(); i++) if (a4[i] == pPlayer.GetFactionID()) break; if (i == a4.GetSize()) a4.Add(pPlayer.GetFactionID()); } //*/ } } // Calculate player info data size and skip it int iSize = Marshal.SizeOf(); if ((Info.state & PlayerNPCState.GP_STATE_ADV_MODE) != 0) iSize += Marshal.SizeOf() * 2; if ((Info.state & PlayerNPCState.GP_STATE_SHAPE) != 0) iSize += Marshal.SizeOf(); if ((Info.state & PlayerNPCState.GP_STATE_EMOTE) != 0) iSize += Marshal.SizeOf(); if ((Info.state & PlayerNPCState.GP_STATE_EXTEND_PROPERTY) != 0) iSize += Marshal.SizeOf() * NumberDWORDsPlayerNPC.OBJECT_EXT_STATE_COUNT; if ((Info.state & PlayerNPCState.GP_STATE_FACTION) != 0) iSize += (Marshal.SizeOf() + Marshal.SizeOf()); if ((Info.state & PlayerNPCState.GP_STATE_BOOTH) != 0) iSize += Marshal.SizeOf(); //// Parse effect data if ((Info.state & PlayerNPCState.GP_STATE_EFFECT) != 0) { iSize += Marshal.SizeOf(); byte byNum = bytes[preSize + iSize]; if (byNum > 0) iSize += byNum * Marshal.SizeOf(); } if ((Info.state & PlayerNPCState.GP_STATE_PARIAH) != 0) iSize += Marshal.SizeOf(); if ((Info.state & PlayerNPCState.GP_STATE_IN_MOUNT) != 0) iSize += Marshal.SizeOf() + Marshal.SizeOf(); // Parse bind data if ((Info.state & PlayerNPCState.GP_STATE_IN_BIND) != 0) iSize += Marshal.SizeOf() + Marshal.SizeOf(); // Parse spouse data if ((Info.state & PlayerNPCState.GP_STATE_SPOUSE) != 0) iSize += Marshal.SizeOf(); if ((Info.state & PlayerNPCState.GP_STATE_EQUIPDISABLED) != 0) iSize += Marshal.SizeOf(); if ((Info.state & PlayerNPCState.GP_STATE_PLAYERFORCE) != 0) iSize += Marshal.SizeOf(); if ((Info.state & PlayerNPCState.GP_STATE_MULTIOBJ_EFFECT) != 0) { int effectNum = Marshal.ReadInt32(bytes, iSize);//*(int*)(pDataBuf + iSize); iSize += Marshal.SizeOf(); if (effectNum > 0) iSize += effectNum * (Marshal.SizeOf() + Marshal.SizeOf()); } if ((Info.state & PlayerNPCState.GP_STATE_COUNTRY) != 0) iSize += Marshal.SizeOf(); if ((Info.state2 & PlayerNPCState2.GP_STATE2_TITLE) != 0) iSize += Marshal.SizeOf(); if ((Info.state2 & PlayerNPCState2.GP_STATE2_REINCARNATION) != 0) iSize += Marshal.SizeOf(); if ((Info.state2 & PlayerNPCState2.GP_STATE2_REALM) != 0) iSize += Marshal.SizeOf(); if ((Info.state2 & PlayerNPCState2.GP_STATE2_FACTION_PVP_MASK) != 0) iSize += Marshal.SizeOf(); // Goblin refine data if ((Info.state & PlayerNPCState.GP_STATE_GOBLINREFINE) != 0) iSize += Marshal.SizeOf(); //pDataBuf += iSize; preSize += iSize; } // Get both base info and custom data if (a2.Count > 0) UnityGameSession.GetRoleBaseInfo(a2.Count, a2); if (a1.Count > 0) UnityGameSession.c2s_CmdGetOtherEquip(a1.Count, a1); // Only get custom data if (a3.Count > 0) UnityGameSession.GetRoleCustomizeData(a3.Count, a3); break; } } } public void OnMsgPlayerMove(ECMSG Msg) { int iHostID = Convert.ToInt32(Msg.dwParam3); cmd_object_move pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); if (pCmd.use_time == 0) return; if (pCmd.id != iHostID) { EC_ElsePlayer pPlayer = SeekOutElsePlayer(pCmd.id); if (pPlayer) { pPlayer.MoveTo(pCmd); } } } private bool OnMsgPlayerLevelUp(ECMSG Msg) { cmd_level_up pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); CECHostPlayer pHost = GetHostPlayer(); if (pCmd.id == pHost.GetCharacterID()) { pHost.LevelUp(); } else { EC_ElsePlayer pPlayer = SeekOutElsePlayer(pCmd.id); if (pPlayer) pPlayer.LevelUp(); } return true; } public bool HostPlayerInfo1(cmd_self_info_1 info) { //bool isDoneWorldRender = false; //bool isDoneNPCRender = false; //Action actLoadChar = () => //{ // if (!isDoneNPCRender || !isDoneWorldRender) // { // return; // } // GameController.Instance.InitCharacter(info); //}; //string nameScene = "NPCRender"; //UnityGameSession.Instance.LoadScene(nameScene, LoadSceneMode.Single, (value) => //{ // isDoneNPCRender = value; // actLoadChar?.Invoke(); //}); //nameScene = "WorldRender"; //UnityGameSession.Instance.LoadScene(nameScene, LoadSceneMode.Additive, (value) => //{ // isDoneWorldRender = value; // actLoadChar?.Invoke(); //}); //UnityGameSession.Instance.LoadScene("HoangTest", LoadSceneMode.Single, (value) => //{ // isDoneWorldRender = value; // actLoadChar?.Invoke(); //}); CECGameRun.Instance.InitCharacter(info); return true; } public EC_ElsePlayer ElsePlayerEnter(info_player_1 info, int iCmd) { // If this player's id is in unknown table, remove it because this player // won't be unknown anymore if (m_UkPlayerTab.TryGetValue(info.cid, out int value)) { if (value != 0) // Pair.second != 0 { m_UkPlayerTab.Remove(info.cid); } } int iAppearFlag = (iCmd == (int)CommandID.PLAYER_ENTER_WORLD) ? (int)PlayerAppearFlag.APPEAR_ENTERWORLD : (int)PlayerAppearFlag.APPEAR_RUNINTOVIEW; // Has player been in active player table ? EC_ElsePlayer pPlayer = GetElsePlayer(info.cid); if (pPlayer != null) { // Check if the GameObject is still valid (not destroyed) if (pPlayer.gameObject != null) { // This player has existed in player table, call special initial function pPlayer.Init(info, iAppearFlag); return pPlayer; } else { // GameObject was destroyed but entry still exists in table - clean it up lock (m_csPlayerTab) { m_PlayerTab.Remove(info.cid); } } } // Create a new player if (!(pPlayer = CreateElsePlayer(info, iAppearFlag))) { return null; } lock (m_csPlayerTab) { if (m_PlayerTab.ContainsKey(info.cid)) { m_PlayerTab[info.cid] = pPlayer; } else { m_PlayerTab.Add(info.cid, pPlayer); } } return pPlayer; } private EC_ElsePlayer CreateElsePlayer(info_player_1 info, int iAppearFlag) { GameObject ob = CECGameRun.Instance.InitCharacter(info); EC_ElsePlayer elsePlayer; if (!ob.TryGetComponent(out elsePlayer)) { elsePlayer = ob.AddComponent(); } elsePlayer.Init(info, iAppearFlag); return elsePlayer; } public EC_ElsePlayer GetElsePlayer(int cid, long dwBornStamp = 0) { lock (m_csPlayerTab) { if (!m_PlayerTab.TryGetValue(cid, out var player)) return null; if (dwBornStamp != 0) { //TO DO: fix after GetBornStamp() is create in code //if (player.GetBornStamp() != dwBornStamp) return null; } return player; } } private EC_ElsePlayer SeekOutElsePlayer(int cid) { if (!m_PlayerTab.TryGetValue(cid, out var player)) { // Couldn't find this else player, put it into unknown player table m_UkPlayerTab[cid] = cid; return null; } return player; } public bool OnMsgPlayerStopMove(ECMSG Msg) { cmd_object_stop_move pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); EC_ElsePlayer pPlayer = SeekOutElsePlayer(pCmd.id); if (pPlayer) pPlayer.StopMoveTo(pCmd); return true; } public bool OnMsgPlayerRunOut(ECMSG Msg) { int id = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); CECHostPlayer pHost = GetHostPlayer(); if (pHost != null && id == pHost.GetCharacterID()) return true; // Don't process if it's the host player ElsePlayerLeave(id, false); return true; } public void OnMsgPlayerPickupMatter(ECMSG Msg) { cmd_matter_pickup pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); // CECHostPlayer pHost = GetHostPlayer(); EC_ManMessageMono.Instance.EC_ManMatter.RemoveMatter(pCmd.matter_id); } private void ElsePlayerLeave(int cid, bool bExitGame) { EC_ElsePlayer pPlayer = SeekOutElsePlayer(cid); if (pPlayer == null) return; // Remove from active player table lock (m_csPlayerTab) { m_PlayerTab.Remove(cid); } // If this player is selected by host, cancel the selection CECHostPlayer pHost = GetHostPlayer(); if (pHost != null && pHost.GetSelectedTarget() == cid) pHost.SelectTarget(0); UnityGameSession.Instance.GetC2SCmdCache().RemovePlayerBaseInfo(cid); // Release player resource if (pPlayer != null) { if (bExitGame) { // Player exited game - handle differently if needed } // Destroy the player GameObject if (pPlayer.gameObject != null) { PoolManager.Instance.Despawn(pPlayer.m_pPlayerCECModel.m_pPlayerModel); PrefabPoolManager.Instance.Despawn(pPlayer.gameObject); GameObject.Destroy(pPlayer); } } } private byte[] GetBytes(byte[] bytes, int length, int index) { byte[] arrByteData = new byte[length]; for (int i = 0; i < length; i++) { arrByteData[i] = bytes[i + index]; } return arrByteData; } public void Initialize() { } public bool TransmitMessage(ECMSG Msg) { int cid = 0; var host = CECGameRun.Instance.GetHostPlayer(); switch (Msg.dwMsg) { case EC_MsgDef.MSG_PM_PLAYEREQUIPDATA: var param2 = Convert.ToInt32(Msg.dwParam2); if (param2 == CommandID.EQUIP_DATA) { // cid = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1).idPlayer; var buffer = new byte[4]; Array.Copy((byte[])Msg.dwParam1, 2, buffer, 0, 4); cid = BitConverter.ToInt32(buffer, 0); } else // EQUIP_DATA_CHANGED { // cid = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1).idPlayer; var buffer = new byte[4]; Array.Copy((byte[])Msg.dwParam1, 2, buffer, 0, 4); cid = BitConverter.ToInt32(buffer, 0); } break; case EC_MsgDef.MSG_PM_PLAYERBASEINFO: cid = (int)((playerbaseinfo_re)Msg.dwParam1).Player.id; // Xoá khỏi cache UnityGameSession.Instance.GetC2SCmdCache().RemovePlayerBaseInfo(cid); break; //case long value when value == EC_MsgDef.MSG_PM_PLAYERCUSTOM: // cid = ((GetCustomData_Re)msg.dwParam1).cus_roleid; // break; case long value when value == EC_MsgDef.MSG_PM_PLAYERFLY: if (Convert.ToInt32(Msg.dwParam2) == CommandID.OBJECT_TAKEOFF) cid = (GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1)).object_id; else cid = (GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1)).object_id; break; case long value when value == EC_MsgDef.MSG_PM_PLAYERATKRESULT: cmd_object_atk_result pCmdAtk = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); cid = pCmdAtk.attacker_id; break; case EC_MsgDef.MSG_PM_CASTSKILL: switch (Convert.ToInt32(Msg.dwParam2)) { case CommandID.OBJECT_CAST_SKILL: cid = (GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1)).caster; break; case CommandID.OBJECT_CAST_INSTANT_SKILL: cid = (GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1)).caster; break; case CommandID.OBJECT_CAST_POS_SKILL: cid = (GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1)).caster; break; case CommandID.SKILL_INTERRUPTED: cid = (GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1)).caster; break; case CommandID.PLAYER_CAST_RUNE_SKILL: cid = (GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1)).caster; break; case CommandID.PLAYER_CAST_RUNE_INSTANT_SKILL: cid = (GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1)).caster; break; } break; case EC_MsgDef.MSG_PM_PLAYERDOEMOTE: if (Convert.ToInt32(Msg.dwParam2) == CommandID.OBJECT_DO_EMOTE) { cmd_object_do_emote pCmdDoEmote = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); cid = pCmdDoEmote.id; } else // Msg.dwParam2 == OBJECT_EMOTE_RESTORE { // cid = ((cmd_object_emote_restore*)Msg.dwParam1)->id; } break; case EC_MsgDef.MSG_PM_ENCHANTRESULT: cid = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1).caster; break; case EC_MsgDef.MSG_PM_PLAYERGATHER: if (Convert.ToInt32(Msg.dwParam2) == CommandID.PLAYER_GATHER_START) { cmd_player_gather_start cmdPlayerGatherStart = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); cid = cmdPlayerGatherStart.pid; } else if (Convert.ToInt32(Msg.dwParam2) == CommandID.PLAYER_GATHER_STOP) { cmd_player_gather_stop cmdPlayerGatherStop = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); cid = cmdPlayerGatherStop.pid; } else { cmd_mine_gathered cmdMineGathered = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); cid = cmdMineGathered.player_id; } break; case EC_MsgDef.MSG_PM_PLAYERFLY: if (Convert.ToInt32(Msg.dwParam2) == CommandID.OBJECT_TAKEOFF) cid = (GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1)).object_id; else // OBJECT_LANDING cid = (GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1)).object_id; break; case EC_MsgDef.MSG_PM_PLAYERSITDOWN: if (Convert.ToInt32(Msg.dwParam2) == CommandID.OBJECT_SIT_DOWN) cid = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1).id; else cid = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1).id; break; case EC_MsgDef.MSG_PM_PLAYERMOUNT: cid = (GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1)).id; break; // ⚠️ Các case khác cũng tương tự, chỉ việc lấy ra đúng trường id / caster / user ... // Do quá dài nên bạn có thể copy dần từng case từ C++ sang. case EC_MsgDef.MSG_PM_PLAYERCHGSHAPE: cid = (GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1)).idPlayer; break; case EC_MsgDef.MSG_PM_PLAYERSKILLRESULT: cid = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1).attacker_id; break; default: System.Diagnostics.Debug.Assert(false, "Unknown message"); return false; } if (cid == 0) { BMLogger.LogError("cid = 0, Msg.dwMsg = " + Msg.dwMsg); return false; } if (host != null && cid == host.GetCharacterID()) { host.ProcessMessage(Msg); } else { var elsePlayer = SeekOutElsePlayer(cid); if (elsePlayer != null) elsePlayer.ProcessMessage(Msg); } return true; } // Get a player (may be host or else player) by id public CECPlayer GetPlayer(int cid, uint dwBornStamp = 0) { CECHostPlayer pHost = GetHostPlayer(); if (pHost && pHost.GetCharacterID() == cid) return pHost; else return GetElsePlayer(cid, dwBornStamp); } public CECHostPlayer GetHostPlayer() { return CECGameRun.Instance.GetHostPlayer(); } /// Returns character IDs of all other players in the world (excluding host). Used e.g. by DlgArrangeTeam for nearby list. public List GetOtherPlayerCharacterIds() { var list = new List(); CECHostPlayer pHost = GetHostPlayer(); int idHost = pHost != null ? pHost.GetCharacterID() : 0; lock (m_csPlayerTab) { foreach (int cid in m_PlayerTab.Keys) { if (cid != idHost) list.Add(cid); } } return list; } public bool OnMsgPlayerExtProp(ECMSG Msg) { object pData; int idPlayer, iIndex; // BMLogger.LogError("OnMsgPlayerExtProp Msg.dwParam2=" + Msg.dwParam2); switch (Convert.ToInt32(Msg.dwParam2)) { case CommandID.PLAYER_EXT_PROP_BASE: { cmd_pep_base pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); idPlayer = pCmd.idPlayer; pData = pCmd.ep_base; iIndex = (int)ExtendPropertyClass.EXTPROPIDX_BASE; break; } case CommandID.PLAYER_EXT_PROP_MOVE: { cmd_pep_move pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); idPlayer = pCmd.idPlayer; pData = pCmd.ep_move; iIndex = (int)ExtendPropertyClass.EXTPROPIDX_MOVE; break; } case CommandID.PLAYER_EXT_PROP_ATK: { cmd_pep_attack pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); idPlayer = pCmd.idPlayer; pData = pCmd.ep_attack; iIndex = (int)ExtendPropertyClass.EXTPROPIDX_ATTACK; break; } case CommandID.PLAYER_EXT_PROP_DEF: { cmd_pep_def pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); idPlayer = pCmd.idPlayer; pData = pCmd.ep_def; iIndex = (int)ExtendPropertyClass.EXTPROPIDX_DEF; break; } default: return false; } if (!GPDataTypeHelper.ISPLAYERID(idPlayer)) { //ASSERT(ISPLAYERID(idPlayer)); return false; } //CECGameSession* pSession = g_pGame.GetGameSession(); if (idPlayer == GetHostPlayer().GetCharacterID()) { GetHostPlayer().SetPartExtendProps(iIndex, pData); } else { EC_ElsePlayer pPlayer = SeekOutElsePlayer(idPlayer); if (pPlayer) pPlayer.SetPartExtendProps(iIndex, pData); } return true; } // Get player candidates whom can be auto-selected by 'TAB' key public void TabSelectCandidates(int idCurSel, List aCands) { CECHostPlayer pHost = GetHostPlayer(); if (pHost == null) return; // Note: IsSkeletonReady() check is commented out in Unity codebase // if (!pHost.IsSkeletonReady()) // { // // Only when IsSkeletonReady() is true, GetDistToHost() is valid // return; // } // Trace all Else Players lock (m_csPlayerTab) { foreach (var kvp in m_PlayerTab) { EC_ElsePlayer pPlayer = kvp.Value; if (pPlayer == null) continue; if (!pPlayer.IsSelectable() || pPlayer.IsDead() || pPlayer.GetCharacterID() == idCurSel || pHost.AttackableJudge(pPlayer.GetCharacterID(), false) != 1) continue; float fDist = pPlayer.GetDistToHost(); if (fDist > EC_RoleTypes.EC_TABSEL_DIST || !pHost.CanSafelySelectWith(fDist)) continue; // Target is too far aCands.Add(pPlayer); } } } // Handler of MSG_PM_PLAYEREXIT public bool OnMsgPlayerExit(ECMSG Msg) { cmd_player_leave_world pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); ElsePlayerLeave(pCmd.id, true); return true; } bool OnMsgPlayerOutOfView(ECMSG Msg) { int id = Convert.ToInt32(Msg.dwParam1); ElsePlayerLeave(id, false); return true; } bool OnMsgPlayerDisappear(ECMSG Msg) { var pCmd = Convert.ToInt32(Msg.dwParam1); ElsePlayerLeave(pCmd, false); return true; } bool OnMsgInvalidObject(ECMSG Msg) { cmd_invalid_object pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); // Remove the player if it exists EC_ElsePlayer pPlayer = GetElsePlayer(pCmd.id); if (pPlayer) { ElsePlayerLeave(pCmd.id, false); } return true; } } } public struct EC_PLAYERLOADRESULT { public uint dwValidMask; public CECModel pPlayerModel; public int iShape; public CECModel pDummyModel; public CECModel pPetModel; /* CECFace pFaceModel; A3DShader pBodyShaders[3];*/ public CECModel pFlyNviagteModel; //CECPlayer::EquipsLoadResult EquipResult; }; }