using BrewMonster; using BrewMonster.Network; using CSNetwork; using CSNetwork.GPDataType; using CSNetwork.Protocols; using CSNetwork.Protocols.RPCData; using PerfectWorld.Scripts.Player; using System; using System.Collections; using System.Collections.Generic; using System.Runtime.InteropServices; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; 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(); CECHostPlayer m_pHostPlayer; 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 int value when value == EC_MsgDef.MSG_PM_FACTION_PVP_MASK_MODIFY: case int value1 when value1 == EC_MsgDef.MSG_PM_PLAYERATKRESULT: Debug.Log("EC_MsgDef.MSG_PM_FACTION_PVP_MASK_MODIFY"); TransmitMessage(Msg); break; case int value when value == EC_MsgDef.MSG_PM_PLAYERDIED: OnMsgPlayerDied(Msg); break; case int value when value == EC_MsgDef.MSG_PM_PLAYERREVIVE: OnMsgPlayerRevive(Msg); break; case int value when value == EC_MsgDef.MSG_PM_PLAYERRUNOUT: OnMsgPlayerRunOut(Msg); break; } } else { } 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 CECPlayer.CleearComActFlagAllRankNodesEvent(true)); pPlayer.PlayAction((int)CECPlayer.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); ElsePlayerEnter(info_Player_1, commandID); CECGameRun.Instance.Log("ElsePlayer has join"); } 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); // 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 = 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; } 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); // Release player resource if (pPlayer != null) { if (bExitGame) { // Player exited game - handle differently if needed } // Destroy the player GameObject if (pPlayer.gameObject != null) UnityEngine.Object.Destroy(pPlayer.gameObject); } } //private cmd_object_move ConvertToStruct(byte[] bytes) //{ // if (bytes.Length < Marshal.SizeOf()) // { // return default; // } // cmd_object_move result = new cmd_object_move(); // int preLenghtData = 0; // int lenghtDataType = Marshal.SizeOf(); // byte[] arrByteData = GetBytes(bytes, lenghtDataType, preLenghtData); // result.id = BitConverter.ToInt32(arrByteData); // preLenghtData += lenghtDataType; // lenghtDataType = Marshal.SizeOf(); // arrByteData = GetBytes(bytes, lenghtDataType, preLenghtData); // result.dest_X = BitConverter.ToSingle(arrByteData); // preLenghtData += lenghtDataType; // lenghtDataType = Marshal.SizeOf(); // arrByteData = GetBytes(bytes, lenghtDataType, preLenghtData); // result.dest_Y = BitConverter.ToSingle(arrByteData); // preLenghtData += lenghtDataType; // lenghtDataType = Marshal.SizeOf(); // arrByteData = GetBytes(bytes, lenghtDataType, preLenghtData); // result.dest_Z = BitConverter.ToSingle(arrByteData); // preLenghtData += lenghtDataType; // lenghtDataType = Marshal.SizeOf(); // arrByteData = GetBytes(bytes, lenghtDataType, preLenghtData); // result.use_time = BitConverter.ToUInt16(arrByteData); // preLenghtData += lenghtDataType; // lenghtDataType = Marshal.SizeOf(); // arrByteData = GetBytes(bytes, lenghtDataType, preLenghtData); // result.sSpeed = BitConverter.ToInt16(arrByteData); // preLenghtData += lenghtDataType; // result.move_mode = bytes[preLenghtData + 1]; // return result; //} 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 long value when value == EC_MsgDef.MSG_PM_PLAYEREQUIPDATA: if (msg.dwParam2 == S2C.EQUIP_DATA) cid = ((cmd_equip_data)msg.dwParam1).idPlayer; else // EQUIP_DATA_CHANGED cid = ((cmd_equip_data_changed)msg.dwParam1).idPlayer; break;*/ case long value when value == EC_MsgDef.MSG_PM_PLAYERBASEINFO: cid = (int)((playerbaseinfo_re)msg.dwParam1).Player.id; // Xoá khỏi cache //g_pGame.GetGameSession().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 (msg.dwParam2 == S2C.OBJECT_TAKEOFF) cid = ((cmd_object_takeoff)msg.dwParam1).object_id; else cid = ((cmd_object_landing)msg.dwParam1).object_id; break;*/ case long value when value == EC_MsgDef.MSG_PM_PLAYERATKRESULT: cmd_object_atk_result pCmdAtk = GPDataTypeHelper.FromBytes((byte[])msg.dwParam1); cid = pCmdAtk.attacker_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. default: System.Diagnostics.Debug.Assert(false, "Unknown message"); return false; } if (cid == 0) { System.Diagnostics.Debug.Assert(false, "cid = 0"); 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(); } } } 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; }; }