From cb3c3531c0972ed1085cdd6d6c6e9670b47edf55 Mon Sep 17 00:00:00 2001 From: HungDK <> Date: Mon, 2 Mar 2026 14:38:56 +0700 Subject: [PATCH] Add send invite, respond of duel, team, ui handle --- .../Scripts/Managers/EC_ManPlayer.cs | 12 ------ .../CSNetwork/C2SCommand/C2SCommandFactory.cs | 12 ++++++ .../Scripts/Network/CSNetwork/GPDataType.cs | 15 +++++++ .../Scripts/Network/CSNetwork/GameSession.cs | 17 ++++++++ .../Scripts/Network/UnityGameSession.cs | 8 ++++ Assets/Scripts/CECHostPlayer.cs | 39 +++++++++++++++++++ 6 files changed, 91 insertions(+), 12 deletions(-) diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs b/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs index f387e0a2ca..707a76639d 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs @@ -33,18 +33,6 @@ namespace PerfectWorld.Scripts.Managers { if (CECGameRun.Instance == null) return true; if (CECGameRun.Instance.GetHostPlayer() == null) return true; - // Duel invite: show accept/reject popup (origin uses MSG_PM_DUELOPT with command DUEL_RECV_REQUEST = 214) - // dwParam2 is ushort (pCmdHeader from GameSession); use Convert to avoid InvalidCastException when unboxing - if ((int)Msg.dwMsg == EC_MsgDef.MSG_PM_DUELOPT && Convert.ToInt32(Msg.dwParam2) == CommandID.DUEL_RECV_REQUEST && Msg.dwParam1 is byte[] pDataBuf && pDataBuf.Length >= 4) - { - int inviterId = BitConverter.ToInt32(pDataBuf, 0); - CECUIManager.Instance?.ShowMessageBox( - title: "", - message: "You have received a duel request. Do you accept?", - messageBoxType: MessageBoxType.BothYesNoButton, - onClickedYes: () => UnityGameSession.c2s_CmdDuelReply(true, inviterId), - onClickedNo: () => UnityGameSession.c2s_CmdDuelReply(false, inviterId)); - } CECGameRun.Instance.GetHostPlayer().ProcessMessage(Msg); } else if (Msg.iSubID < 0) diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs index b4e93c6fac..6082666510 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs @@ -818,6 +818,18 @@ namespace CSNetwork.C2SCommand return SerializeCommand(CommandID.TEAM_INVITE, new cmd_team_new_member { idMember = idPlayer }); } + /// C2S: accept team invite from leader. idLeader = who sent the invite, team_seq = invite sequence from TEAM_LEADER_INVITE. + public static Octets CreateTeamAgreeInviteCommand(int idLeader, int team_seq) + { + return SerializeCommand(CommandID.TEAM_AGREE_INVITE, new cmd_team_agree_invite { idLeader = idLeader, team_seq = team_seq }); + } + + /// C2S: reject team invite from leader. + public static Octets CreateTeamRejectInviteCommand(int idLeader) + { + return SerializeCommand(CommandID.TEAM_REJECT_INVITE, new cmd_team_reject_invite { idLeader = idLeader }); + } + /// C2S: request duel with target player (same payload shape as team invite). public static Octets CreateDuelRequestCommand(int idTarget) { diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs index 2fcbaa4fc5..67ca8d2495 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs @@ -2208,6 +2208,21 @@ namespace CSNetwork.GPDataType public int idMember; } + /// C2S: accept team invite. idLeader = who sent the invite, team_seq = invite sequence. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct cmd_team_agree_invite + { + public int idLeader; + public int team_seq; + } + + /// C2S: reject team invite. idLeader = who sent the invite. + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct cmd_team_reject_invite + { + public int idLeader; + } + /// C2S duel reply (origin: who = inviter id, param = 0 accept / non-zero reject reason). [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct cmd_duel_reply diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs index 2cd0e8486d..073a93dabf 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs @@ -840,6 +840,9 @@ namespace CSNetwork case CommandID.TEAM_MEMBER_DATA: EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_TEAMMEMBERDATA, (int)MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader); break; + case CommandID.TEAM_LEADER_INVITE: + EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_TEAMINVITE, (int)MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader); + break; case CommandID.TEAM_MEMBER_LEAVE: EC_ManMessage.PostMessage(EC_MsgDef.MSG_PM_LEAVETEAM, (int)MANAGER_INDEX.MAN_PLAYER, -1, pDataBuf, pCmdHeader); break; @@ -1863,6 +1866,20 @@ namespace CSNetwork SendProtocol(g); } + public void c2s_SendCmdTeamAgreeInvite(int idLeader, int team_seq) + { + var g = new gamedatasend(); + g.Data = C2SCommandFactory.CreateTeamAgreeInviteCommand(idLeader, team_seq); + SendProtocol(g); + } + + public void c2s_SendCmdTeamRejectInvite(int idLeader) + { + var g = new gamedatasend(); + g.Data = C2SCommandFactory.CreateTeamRejectInviteCommand(idLeader); + SendProtocol(g); + } + public void c2s_SendCmdDuelRequest(int idTarget) { var g = new gamedatasend(); diff --git a/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs b/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs index 2ea519aff2..6d4da53a7c 100644 --- a/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs @@ -599,6 +599,14 @@ namespace BrewMonster.Network { Instance._gameSession.c2s_SendCmdTeamInvite(idPlayer); } + public static void c2s_CmdTeamAgreeInvite(int idLeader, int team_seq) + { + Instance._gameSession.c2s_SendCmdTeamAgreeInvite(idLeader, team_seq); + } + public static void c2s_CmdTeamRejectInvite(int idLeader) + { + Instance._gameSession.c2s_SendCmdTeamRejectInvite(idLeader); + } public static void c2s_CmdDuelRequest(int idTarget) { Instance._gameSession.c2s_SendCmdDuelRequest(idTarget); diff --git a/Assets/Scripts/CECHostPlayer.cs b/Assets/Scripts/CECHostPlayer.cs index 63405d1aee..cede52a8c3 100644 --- a/Assets/Scripts/CECHostPlayer.cs +++ b/Assets/Scripts/CECHostPlayer.cs @@ -608,6 +608,7 @@ namespace BrewMonster case EC_MsgDef.MSG_HST_JOINTEAM: OnMsgHstJoinTeam(Msg); break; case EC_MsgDef.MSG_HST_LEAVETEAM: OnMsgHstLeaveTeam(Msg); break; case EC_MsgDef.MSG_HST_NEWTEAMMEM: OnMsgHstNewTeamMem(Msg); break; + case EC_MsgDef.MSG_HST_TEAMINVITE: OnMsgHstTeamInvite(Msg); break; case EC_MsgDef.MSG_HST_TEAMMEMBERDATA: OnMsgHstTeamMemberData(Msg); break; case EC_MsgDef.MSG_PM_DUELOPT: OnMsgHstDuelOpt(Msg); break; case EC_MsgDef.MSG_HST_CLEARTESSERA: OnMsgHstClearTessera(Msg); break; @@ -653,6 +654,18 @@ namespace BrewMonster idOpp = BitConverter.ToInt32(data, 0); switch (cmdId) { + case CommandID.DUEL_RECV_REQUEST: + // Duel invite: show accept/reject popup (origin MSG_PM_DUELOPT with command DUEL_RECV_REQUEST = 214) + if (idOpp != 0) + { + CECUIManager.Instance?.ShowMessageBox( + title: "", + message: "You have received a duel request. Do you accept?", + messageBoxType: MessageBoxType.BothYesNoButton, + onClickedYes: () => UnityGameSession.c2s_CmdDuelReply(true, idOpp), + onClickedNo: () => UnityGameSession.c2s_CmdDuelReply(false, idOpp)); + } + break; case CommandID.DUEL_PREPARE: m_pvp.iDuelState = Duel_state.DUEL_ST_PREPARE; m_pvp.idDuelOpp = idOpp; @@ -683,6 +696,32 @@ namespace BrewMonster } } + /// Host received a team invite (MSG_HST_TEAMINVITE). Payload is cmd_team_leader_invite: idLeader, seq, pickFlag. Shows accept/reject message box and sends reply. + private void OnMsgHstTeamInvite(ECMSG Msg) + { + byte[] data = Msg.dwParam1 as byte[]; + int idLeader = 0; + int team_seq = 0; + if (data != null && data.Length >= 8) + { + idLeader = BitConverter.ToInt32(data, 0); + team_seq = BitConverter.ToInt32(data, 4); + } + else if (data != null && data.Length >= 4) + { + idLeader = BitConverter.ToInt32(data, 0); + } + if (idLeader == 0) + return; + int seqCapture = team_seq; + CECUIManager.Instance?.ShowMessageBox( + title: "", + message: "You have received a team invite. Do you accept?", + messageBoxType: MessageBoxType.BothYesNoButton, + onClickedYes: () => UnityGameSession.c2s_CmdTeamAgreeInvite(idLeader, seqCapture), + onClickedNo: () => UnityGameSession.c2s_CmdTeamRejectInvite(idLeader)); + } + /// Called when MSG_PM_PLAYERDUELOPT (229) is received; server may send duel start to both participants. If host is one of the two ids, set duel state. public void OnMsgPlayerDuelStart(byte[] data) {