using AxibugEmuOnline.Client.ClientCore; using AxibugEmuOnline.Client.Common; using AxibugEmuOnline.Client.Event; using AxibugEmuOnline.Client.Network; using AxibugProtobuf; using AxiReplay; using Google.Protobuf; using System; using System.Collections.Generic; using System.Linq; namespace AxibugEmuOnline.Client.Manager { public class AppRoom { public Protobuf_Room_MiniInfo mineRoomMiniInfo { get; private set; } = null; public bool InRoom => mineRoomMiniInfo != null; public bool IsHost => mineRoomMiniInfo?.HostPlayerUID == App.user.userdata.UID; public bool IsScreenProviderUID => mineRoomMiniInfo?.ScreenProviderUID == App.user.userdata.UID; public RoomGameState RoomState => mineRoomMiniInfo.GameState; public int MinePlayerIdx => GetMinePlayerIndex(); public int WaitStep { get; private set; } = -1; public byte[] RawData { get; private set; } = null; public NetReplay netReplay { get; private set; } Dictionary dictRoomListID2Info = new Dictionary(); struct S_PlayerMiniInfo { public long UID; public string NickName; } Protobuf_Room_List _Protobuf_Room_List = new Protobuf_Room_List(); Protobuf_Room_Get_Screen _Protobuf_Room_Get_Screen = new Protobuf_Room_Get_Screen(); Protobuf_Room_Create _Protobuf_Room_Create = new Protobuf_Room_Create(); Protobuf_Room_Join _Protobuf_Room_Join = new Protobuf_Room_Join(); Protobuf_Room_Leave _Protobuf_Room_Leave = new Protobuf_Room_Leave(); Protobuf_Room_Player_Ready _Protobuf_Room_Player_Ready = new Protobuf_Room_Player_Ready(); Protobuf_Room_SinglePlayerInputData _Protobuf_Room_SinglePlayerInputData = new Protobuf_Room_SinglePlayerInputData(); Protobuf_Screnn_Frame _Protobuf_Screnn_Frame = new Protobuf_Screnn_Frame(); public AppRoom() { NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomList, RecvGetRoomList); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomListUpdate, RecvGetRoomListUpdate); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomGetScreen, RecvRoomGetScreen); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomCreate, RecvCreateRoom); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomJoin, RecvJoinRoom); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomLeave, RecvLeavnRoom); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomMyRoomStateChanged, RecvRoomMyRoomStateChange); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomWaitStep, RecvRoom_WaitStep); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomHostPlayerUpdateStateRaw, RecvHostPlayer_UpdateStateRaw); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomSynPlayerInput, RecvHostSyn_RoomFrameAllInputData); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdScreen, OnScreen); } #region 房间列表管理 bool AddOrUpdateRoomList(Protobuf_Room_MiniInfo roomInfo) { bool bNew = !dictRoomListID2Info.ContainsKey(roomInfo.RoomID); dictRoomListID2Info[roomInfo.RoomID] = roomInfo; return bNew; } bool RemoveRoomList(int roomId) { if (dictRoomListID2Info.ContainsKey(roomId)) { dictRoomListID2Info.Remove(roomId); return true; } return false; } /// /// 获取单个房间MiniInfo /// /// /// /// public bool GetRoomListMiniInfo(int roomId, out Protobuf_Room_MiniInfo MiniInfo) { if (dictRoomListID2Info.ContainsKey(roomId)) { MiniInfo = dictRoomListID2Info[roomId]; return true; } MiniInfo = null; return false; } public List GetRoomList() { List result = new List(); foreach (var item in dictRoomListID2Info) { result.Add(item.Value); } return result; } #endregion #region Replay public void InitRePlay() { netReplay = new NetReplay(); netReplay.ResetData(); } public void ReleaseRePlay() { netReplay.ResetData(); } #endregion #region 房间管理 int GetMinePlayerIndex() { if (mineRoomMiniInfo == null) return -1; if (mineRoomMiniInfo.Player1UID == App.user.userdata.UID) return 0; if (mineRoomMiniInfo.Player2UID == App.user.userdata.UID) return 1; if (mineRoomMiniInfo.Player3UID == App.user.userdata.UID) return 2; if (mineRoomMiniInfo.Player4UID == App.user.userdata.UID) return 3; return -1; } long[] GetRoom4PlayerUIDs() { if (mineRoomMiniInfo == null) return null; long[] result = new long[4]; if (mineRoomMiniInfo.Player1UID > 0) result[0] = mineRoomMiniInfo.Player1UID; if (mineRoomMiniInfo.Player2UID > 0) result[1] = mineRoomMiniInfo.Player2UID; if (mineRoomMiniInfo.Player3UID > 0) result[2] = mineRoomMiniInfo.Player3UID; if (mineRoomMiniInfo.Player4UID > 0) result[3] = mineRoomMiniInfo.Player4UID; return result; } S_PlayerMiniInfo[] GetRoom4PlayerMiniInfos() { if (mineRoomMiniInfo == null) return null; S_PlayerMiniInfo[] result = new S_PlayerMiniInfo[4]; if (mineRoomMiniInfo.Player1UID > 0) { result[0].UID = mineRoomMiniInfo.Player1UID; result[0].NickName = mineRoomMiniInfo.Player1NickName; } if (mineRoomMiniInfo.Player2UID > 0) { result[1].UID = mineRoomMiniInfo.Player2UID; result[1].NickName = mineRoomMiniInfo.Player2NickName; } if (mineRoomMiniInfo.Player3UID > 0) { result[2].UID = mineRoomMiniInfo.Player3UID; result[2].NickName = mineRoomMiniInfo.Player3NickName; } if (mineRoomMiniInfo.Player4UID > 0) { result[3].UID = mineRoomMiniInfo.Player4UID; result[3].NickName = mineRoomMiniInfo.Player4NickName; } return result; } #endregion /// /// 获取所有房间列表 /// /// public void SendGetRoomList() { App.log.Info("拉取房间列表"); App.network.SendToServer((int)CommandID.CmdRoomList, ProtoBufHelper.Serizlize(_Protobuf_Room_List)); } /// /// 获取所有房间列表 /// /// void RecvGetRoomList(byte[] reqData) { App.log.Info("取得完整房间列表"); Protobuf_Room_List_RESP msg = ProtoBufHelper.DeSerizlize(reqData); dictRoomListID2Info.Clear(); for (int i = 0; i < msg.RoomMiniInfoList.Count; i++) AddOrUpdateRoomList(msg.RoomMiniInfoList[i]); Eventer.Instance.PostEvent(EEvent.OnRoomListAllUpdate); } /// /// 获取单个列表更新 /// /// void RecvGetRoomListUpdate(byte[] reqData) { App.log.Debug("单个房间状态更新"); Protobuf_Room_Update_RESP msg = ProtoBufHelper.DeSerizlize(reqData); if (msg.UpdateType == 0) { if (AddOrUpdateRoomList(msg.RoomMiniInfo)) { Eventer.Instance.PostEvent(EEvent.OnRoomListSingleAdd, msg.RoomMiniInfo.RoomID); } else { Eventer.Instance.PostEvent(EEvent.OnRoomListSingleUpdate, msg.RoomMiniInfo.RoomID); } } else { RemoveRoomList(msg.RoomMiniInfo.RoomID); Eventer.Instance.PostEvent(EEvent.OnRoomListSingleClose, msg.RoomMiniInfo.RoomID); } } /// /// 获取房间画面快照 /// /// public void SendGetRoomScreen(int RoomID) { _Protobuf_Room_Get_Screen.RoomID = RoomID; App.log.Info($"获取房间画面快照"); App.network.SendToServer((int)CommandID.CmdRoomGetScreen, ProtoBufHelper.Serizlize(_Protobuf_Room_Get_Screen)); } /// /// 获取单个房间画面 /// /// void RecvRoomGetScreen(byte[] reqData) { App.log.Debug("单个房间状态更新"); Protobuf_Room_Get_Screen_RESP msg = ProtoBufHelper.DeSerizlize(reqData); //解压 byte[] data = Helper.DecompressByteArray(msg.RawBitmap.ToArray()); Eventer.Instance.PostEvent(EEvent.OnRoomGetRoomScreen, msg.RoomID, data); } /// /// 创建房间 /// /// /// /// public void SendCreateRoom(int GameRomID, int JoinPlayerIdx, string GameRomHash = null) { _Protobuf_Room_Create.JoinPlayerIdx = JoinPlayerIdx; _Protobuf_Room_Create.GameRomID = GameRomID; _Protobuf_Room_Create.GameRomHash = GameRomHash; App.log.Info($"创建房间"); App.network.SendToServer((int)CommandID.CmdRoomCreate, ProtoBufHelper.Serizlize(_Protobuf_Room_Create)); } /// /// 创建房间成功 /// /// void RecvCreateRoom(byte[] reqData) { App.log.Debug("创建房间成功"); Protobuf_Room_Create_RESP msg = ProtoBufHelper.DeSerizlize(reqData); mineRoomMiniInfo = msg.RoomMiniInfo; InitRePlay(); Eventer.Instance.PostEvent(EEvent.OnMineRoomCreated); OverlayManager.PopTip($"房间创建成功"); } /// /// 创建房间 /// /// /// /// public void SendJoinRoom(int RoomID, int JoinPlayerIdx) { _Protobuf_Room_Join.RoomID = RoomID; _Protobuf_Room_Join.PlayerNum = JoinPlayerIdx; App.log.Info($"加入房间"); App.network.SendToServer((int)CommandID.CmdRoomJoin, ProtoBufHelper.Serizlize(_Protobuf_Room_Join)); } /// /// 加入房间成功 /// /// void RecvJoinRoom(byte[] reqData) { App.log.Debug("加入房间成功"); Protobuf_Room_Join_RESP msg = ProtoBufHelper.DeSerizlize(reqData); mineRoomMiniInfo = msg.RoomMiniInfo; InitRePlay(); { Eventer.Instance.PostEvent(EEvent.OnMineJoinRoom); OverlayManager.PopTip($"已进入[{msg.RoomMiniInfo.GetHostNickName()}]的房间"); } } /// /// 离开房间 /// /// public void SendLeavnRoom() { if (!InRoom) return; _Protobuf_Room_Leave.RoomID = mineRoomMiniInfo.RoomID; App.log.Info($"LeavnRoom"); App.network.SendToServer((int)CommandID.CmdRoomLeave, ProtoBufHelper.Serizlize(_Protobuf_Room_Leave)); } /// /// 离开房间成功 /// /// void RecvLeavnRoom(byte[] reqData) { App.log.Debug("离开房间成功"); Protobuf_Room_Leave_RESP msg = ProtoBufHelper.DeSerizlize(reqData); ReleaseRePlay(); mineRoomMiniInfo = null; Eventer.Instance.PostEvent(EEvent.OnMineLeavnRoom); OverlayManager.PopTip($"你已经离开房间"); } void RecvRoomMyRoomStateChange(byte[] reqData) { Protobuf_Room_MyRoom_State_Change msg = ProtoBufHelper.DeSerizlize(reqData); long[] oldRoomPlayer = GetRoom4PlayerUIDs(); mineRoomMiniInfo = msg.RoomMiniInfo; long[] newRoomPlayer = GetRoom4PlayerUIDs(); for (int i = 0; i < 4; i++) { long OldPlayer = oldRoomPlayer[i]; long NewPlayer = newRoomPlayer[i]; if (OldPlayer == NewPlayer) continue; //位置之前有人,但是离开了 if (OldPlayer > 0) { Eventer.Instance.PostEvent(EEvent.OnOtherPlayerLeavnRoom, i, OldPlayer); UserDataBase oldplayer = App.user.GetUserByUid(OldPlayer); string oldPlayName = oldplayer != null ? oldplayer.NickName : "Player"; OverlayManager.PopTip($"[{oldPlayName}]离开房间,手柄位:P{i}"); if (NewPlayer > 0)//而且害换了一个玩家 { Eventer.Instance.PostEvent(EEvent.OnOtherPlayerJoinRoom, i, NewPlayer); mineRoomMiniInfo.GetPlayerNameByPlayerIdx((uint)i, out string PlayerName); OverlayManager.PopTip($"[{PlayerName}]进入房间,手柄位:P{i}"); } } else //之前没人 { Eventer.Instance.PostEvent(EEvent.OnOtherPlayerJoinRoom, i, NewPlayer); mineRoomMiniInfo.GetPlayerNameByPlayerIdx((uint)i, out string PlayerName); OverlayManager.PopTip($"[{PlayerName}]进入房间,手柄位:P{i}"); } } } /// /// 上报即时存档 /// /// public void SendHostRaw(byte[] RawData) { //压缩 byte[] compressRawData = Helper.CompressByteArray(RawData); Protobuf_Room_HostPlayer_UpdateStateRaw msg = new Protobuf_Room_HostPlayer_UpdateStateRaw() { LoadStateRaw = Google.Protobuf.ByteString.CopyFrom(compressRawData) }; App.log.Info($"上报即时存档数据 原数据大小:{RawData.Length},压缩后;{compressRawData.Length}"); App.network.SendToServer((int)CommandID.CmdRoomHostPlayerUpdateStateRaw, ProtoBufHelper.Serizlize(msg)); } void RecvRoom_WaitStep(byte[] reqData) { Protobuf_Room_WaitStep_RESP msg = ProtoBufHelper.DeSerizlize(reqData); if (WaitStep != msg.WaitStep) { WaitStep = msg.WaitStep; if (WaitStep == 1) { byte[] decompressRawData = Helper.DecompressByteArray(msg.LoadStateRaw.ToByteArray()); App.log.Info($"收到即时存档数据 解压后;{decompressRawData.Length}"); RawData = decompressRawData; ReleaseRePlay(); } Eventer.Instance.PostEvent(EEvent.OnRoomWaitStepChange, WaitStep); } } void RecvHostPlayer_UpdateStateRaw(byte[] reqData) { Protobuf_Room_HostPlayer_UpdateStateRaw_RESP msg = ProtoBufHelper.DeSerizlize(reqData); App.log.Info($"鸡翅孙当上报成功"); } /// /// 即时存档加载完毕 /// public void SendRoomPlayerReady() { App.log.Debug("上报准备完毕"); App.network.SendToServer((int)CommandID.CmdRoomPlayerReady, ProtoBufHelper.Serizlize(_Protobuf_Room_Player_Ready)); } /// /// 同步上行 /// public void SendRoomSingelPlayerInput(uint FrameID, uint InputData) { _Protobuf_Room_SinglePlayerInputData.FrameID = FrameID; _Protobuf_Room_SinglePlayerInputData.InputData = InputData; App.network.SendToServer((int)CommandID.CmdRoomSingelPlayerInput, ProtoBufHelper.Serizlize(_Protobuf_Room_SinglePlayerInputData)); } ulong TestAllData = 0; void RecvHostSyn_RoomFrameAllInputData(byte[] reqData) { Protobuf_Room_Syn_RoomFrameAllInputData msg = ProtoBufHelper.DeSerizlize(reqData); if (TestAllData != msg.InputData) { TestAllData = msg.InputData; App.log.Debug($"ServerFrameID->{msg.ServerFrameID} FrameID->{msg.FrameID} ClientFrame->{netReplay.mCurrClientFrameIdx} InputData->{msg.InputData}"); } netReplay.InData(new ReplayStep() { FrameStartID = (int)msg.FrameID, InPut = msg.InputData }, (int)msg.ServerFrameID); } public void SendScreen(byte[] RenderBuffer) { //压缩 byte[] comData = Helper.CompressByteArray(RenderBuffer); _Protobuf_Screnn_Frame.FrameID = 0; _Protobuf_Screnn_Frame.RawBitmap = ByteString.CopyFrom(comData); App.network.SendToServer((int)CommandID.CmdScreen, ProtoBufHelper.Serizlize(_Protobuf_Screnn_Frame)); } public void OnScreen(byte[] reqData) { Protobuf_Screnn_Frame msg = ProtoBufHelper.DeSerizlize(reqData); //解压 byte[] data = Helper.DecompressByteArray(msg.RawBitmap.ToArray()); } public void ChangeCurrRoomPlayerName(long uid) { UserDataBase userdata = App.user.GetUserByUid(uid); if (userdata == null) return; if (mineRoomMiniInfo == null) { if (mineRoomMiniInfo.Player1UID == uid) mineRoomMiniInfo.Player1NickName = userdata.NickName; else if (mineRoomMiniInfo.Player2UID == uid) mineRoomMiniInfo.Player2NickName = userdata.NickName; else if (mineRoomMiniInfo.Player3UID == uid) mineRoomMiniInfo.Player3NickName = userdata.NickName; else if (mineRoomMiniInfo.Player4UID == uid) mineRoomMiniInfo.Player4NickName = userdata.NickName; } } } public static class RoomEX { /// /// 获取房间空闲席位下标 (返回True表示由余位) /// /// /// /// public static bool GetFreeSlot(this Protobuf_Room_MiniInfo roomMiniInfo, out int[] freeSlots) { List temp = new List(); if (roomMiniInfo.Player1UID <= 0) temp.Add(0); if (roomMiniInfo.Player2UID <= 0) temp.Add(1); if (roomMiniInfo.Player3UID <= 0) temp.Add(2); if (roomMiniInfo.Player4UID <= 0) temp.Add(3); freeSlots = temp.ToArray(); return freeSlots.Length > 0; } /// /// 按照房间玩家下标获取昵称 /// /// /// /// /// public static bool GetPlayerNameByPlayerIdx(this Protobuf_Room_MiniInfo roomMiniInfo,uint PlayerIndex, out string PlayerName) { PlayerName = string.Empty; switch (PlayerIndex) { case 0: PlayerName = roomMiniInfo.Player1UID > 0 ? roomMiniInfo.Player1NickName : null; break; case 1: PlayerName = roomMiniInfo.Player2UID > 0 ? roomMiniInfo.Player2NickName : null; break; case 2: PlayerName = roomMiniInfo.Player3UID > 0 ? roomMiniInfo.Player3NickName : null; break; case 3: PlayerName = roomMiniInfo.Player4UID > 0 ? roomMiniInfo.Player4NickName : null; break; } return string.IsNullOrEmpty(PlayerName); } } }