服务器重构玩家位置管理,使其可以一对多手柄位联机,以及切换位置等协议

This commit is contained in:
sin365 2024-12-20 01:04:40 +08:00
parent 417390227c
commit abddf3c0b5
4 changed files with 1214 additions and 1038 deletions

View File

@ -34,20 +34,17 @@ namespace AxibugEmuOnline.Server.Manager
public class UserRoomState public class UserRoomState
{ {
public int RoomID { get; private set; } public int RoomID { get; private set; }
public int PlayerIdx { get; private set; }
public UserRoomState() public UserRoomState()
{ {
ClearRoomData(); ClearRoomData();
} }
public void SetRoomData(int roomID, int playerIdx) public void SetRoomData(int roomID)
{ {
RoomID = roomID; RoomID = roomID;
PlayerIdx = playerIdx;
} }
public void ClearRoomData() public void ClearRoomData()
{ {
RoomID = -1; RoomID = -1;
PlayerIdx = -1;
} }
} }

View File

@ -3,6 +3,8 @@ using AxibugEmuOnline.Server.Manager;
using AxibugEmuOnline.Server.NetWork; using AxibugEmuOnline.Server.NetWork;
using AxibugProtobuf; using AxibugProtobuf;
using MySql.Data.MySqlClient; using MySql.Data.MySqlClient;
using Org.BouncyCastle.Crypto.Parameters;
using System.Data;
using System.Net.Sockets; using System.Net.Sockets;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Security.Policy; using System.Security.Policy;
@ -25,6 +27,7 @@ namespace AxibugEmuOnline.Server
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomCreate, OnCmdRoomCreate); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomCreate, OnCmdRoomCreate);
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomJoin, OnCmdRoomJoin); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomJoin, OnCmdRoomJoin);
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomLeave, OnCmdRoomLeave); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomLeave, OnCmdRoomLeave);
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomChangePlayerWithJoy, OnCmdRoomChangePlayerWithJoy);
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomHostPlayerUpdateStateRaw, OnHostPlayerUpdateStateRaw); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomHostPlayerUpdateStateRaw, OnHostPlayerUpdateStateRaw);
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomPlayerReady, OnRoomPlayerReady); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomPlayerReady, OnRoomPlayerReady);
NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomSingelPlayerInput, OnSingelPlayerInput); NetMsg.Instance.RegNetMsgEvent((int)CommandID.CmdRoomSingelPlayerInput, OnSingelPlayerInput);
@ -148,23 +151,21 @@ namespace AxibugEmuOnline.Server
HostPlayerUID = room.HostUID, HostPlayerUID = room.HostUID,
GameState = room.GameState, GameState = room.GameState,
ObsUserCount = 0,//TODO ObsUserCount = 0,//TODO
Player1UID = room.Player1_UID,
Player2UID = room.Player2_UID,
Player3UID = room.Player3_UID,
Player4UID = room.Player4_UID,
}; };
if (result.Player1UID >= 0 && AppSrv.g_ClientMgr.GetClientByUID(result.Player1UID, out ClientInfo _c1)) for (byte i = 0; i < room.PlayerSlot.Count(); i++)
result.Player1NickName = _c1.NickName; {
Protobuf_Room_GamePlaySlot pbSlot = new Protobuf_Room_GamePlaySlot();
if (result.Player2UID >= 0 && AppSrv.g_ClientMgr.GetClientByUID(result.Player2UID, out ClientInfo _c2)) Data_RoomSlot slot = room.PlayerSlot[i];
result.Player2NickName = _c2.NickName; if (slot.UID > 0)
{
if (result.Player3UID >= 0 && AppSrv.g_ClientMgr.GetClientByUID(result.Player1UID, out ClientInfo _c3)) pbSlot.PlayerUID = slot.UID;
result.Player3NickName = _c3.NickName; pbSlot.PlayerLocalJoyIdx = (int)slot.LocalJoyIdx;
if (AppSrv.g_ClientMgr.GetClientByUID(pbSlot.PlayerUID, out ClientInfo _client))
if (result.Player4UID >= 0 && AppSrv.g_ClientMgr.GetClientByUID(result.Player2UID, out ClientInfo _c4)) pbSlot.PlayerNickName = _client.NickName;
result.Player4NickName = _c4.NickName; }
result.GamePlaySlotList.Add(pbSlot);
}
return result; return result;
} }
@ -234,7 +235,7 @@ namespace AxibugEmuOnline.Server
AddRoom(newRoom); AddRoom(newRoom);
ErrorCode joinErrcode = ErrorCode.ErrorOk; ErrorCode joinErrcode = ErrorCode.ErrorOk;
//加入 //加入
if (newRoom.Join(msg.JoinPlayerIdx, _c, out joinErrcode, out bool bHadRoomStateChange)) if (newRoom.Join((uint)msg.PlayerSlotIdx, (uint)msg.PlayerLocalJoyIdx, _c, out joinErrcode, out bool bHadRoomStateChange))
{ {
//创建成功下行 //创建成功下行
resp.RoomMiniInfo = GetProtoDataRoom(newRoom); resp.RoomMiniInfo = GetProtoDataRoom(newRoom);
@ -254,7 +255,7 @@ namespace AxibugEmuOnline.Server
AppSrv.g_Log.DebugCmd($"OnCmdRoomJoin"); AppSrv.g_Log.DebugCmd($"OnCmdRoomJoin");
ClientInfo _c = AppSrv.g_ClientMgr.GetClientForSocket(sk); ClientInfo _c = AppSrv.g_ClientMgr.GetClientForSocket(sk);
Protobuf_Room_Join msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_Join>(reqData); Protobuf_Room_Join msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_Join>(reqData);
Protobuf_Room_Create_RESP resp = new Protobuf_Room_Create_RESP(); Protobuf_Room_Join_RESP resp = new Protobuf_Room_Join_RESP();
ErrorCode joinErrcode; ErrorCode joinErrcode;
Data_RoomData room = GetRoomData(msg.RoomID); Data_RoomData room = GetRoomData(msg.RoomID);
bool bHadRoomStateChange = false; bool bHadRoomStateChange = false;
@ -268,7 +269,7 @@ namespace AxibugEmuOnline.Server
lock (room) lock (room)
{ {
//加入 //加入
if (room.Join(msg.PlayerNum, _c, out joinErrcode, out bHadRoomStateChange)) if (room.Join((uint)msg.PlayerSlotIdx, (uint)msg.PlayerLocalJoyIdx, _c, out joinErrcode, out bHadRoomStateChange))
{ {
Data_RoomData roomData = GetRoomData(msg.RoomID); Data_RoomData roomData = GetRoomData(msg.RoomID);
resp.RoomMiniInfo = GetProtoDataRoom(roomData); resp.RoomMiniInfo = GetProtoDataRoom(roomData);
@ -316,7 +317,6 @@ namespace AxibugEmuOnline.Server
//if (room.GetPlayerCount() < 1) //if (room.GetPlayerCount() < 1)
// RemoveRoom(room.RoomID); // RemoveRoom(room.RoomID);
} }
public void LeaveRoom(ClientInfo _c, int RoomID) public void LeaveRoom(ClientInfo _c, int RoomID)
{ {
AppSrv.g_Log.Debug($"LeaveRoom"); AppSrv.g_Log.Debug($"LeaveRoom");
@ -354,6 +354,40 @@ namespace AxibugEmuOnline.Server
RoomLog(_c.UID, 1, room.RoomID, room.GameRomID, RoomLogType.Leave); RoomLog(_c.UID, 1, room.RoomID, room.GameRomID, RoomLogType.Leave);
} }
public void OnCmdRoomChangePlayerWithJoy(Socket sk, byte[] reqData)
{
AppSrv.g_Log.DebugCmd($"OnCmdRoomChangePlayerjoySlot");
ClientInfo _c = AppSrv.g_ClientMgr.GetClientForSocket(sk);
Protobuf_Room_Change_PlaySlotWithJoy msg = ProtoBufHelper.DeSerizlize<Protobuf_Room_Change_PlaySlotWithJoy>(reqData);
Protobuf_Room_Change_PlaySlotWithJoy_RESP resp = new Protobuf_Room_Change_PlaySlotWithJoy_RESP();
ErrorCode errcode = ErrorCode.ErrorOk;
Data_RoomData room = GetRoomData(_c.RoomState.RoomID);
if (room == null)
errcode = ErrorCode.ErrorRoomNotFound;
if (errcode == ErrorCode.ErrorOk)
{
Dictionary<uint, uint> newSlotIdx2JoyIdx = new Dictionary<uint, uint>();
foreach (var slotinfo in msg.SlotWithJoy)
{
//如果有任意一个槽位有人
if (room.GetPlayerUIDByIdx((uint)slotinfo.PlayerSlotIdx, out long UID))
{
//且人不是自己,则不允许换位
if(UID != _c.UID)
errcode = ErrorCode.ErrorRoomSlotAlreadlyHadPlayer; break;
}
newSlotIdx2JoyIdx[(uint)slotinfo.PlayerSlotIdx] = (uint)slotinfo.PlayerLocalJoyIdx;
}
room.SetPlayerSlotData(_c,ref newSlotIdx2JoyIdx);
}
AppSrv.g_ClientMgr.ClientSend(_c, (int)CommandID.CmdRoomMyRoomStateChanged, (int)errcode, ProtoBufHelper.Serizlize(resp));
}
public void OnHostPlayerUpdateStateRaw(Socket sk, byte[] reqData) public void OnHostPlayerUpdateStateRaw(Socket sk, byte[] reqData)
{ {
ClientInfo _c = AppSrv.g_ClientMgr.GetClientForSocket(sk); ClientInfo _c = AppSrv.g_ClientMgr.GetClientForSocket(sk);
@ -388,8 +422,8 @@ namespace AxibugEmuOnline.Server
return; return;
lock (room) lock (room)
{ {
AppSrv.g_Log.Debug($"SetRePlayerReady RoomID->{room.RoomID},UID->{_c.UID}, PlayerIdx->{_c.RoomState.PlayerIdx}"); AppSrv.g_Log.Debug($"SetRePlayerReady RoomID->{room.RoomID},UID->{_c.UID}");
room.SetRePlayerReady(_c.RoomState.PlayerIdx, out errcode, out bool bHadRoomStateChange); room.SetRePlayerReady(_c.UID, out errcode, out bool bHadRoomStateChange);
if (bHadRoomStateChange) if (bHadRoomStateChange)
{ {
SendRoomStepChange(room); SendRoomStepChange(room);
@ -422,7 +456,7 @@ namespace AxibugEmuOnline.Server
// room.SynInputData(); // room.SynInputData();
//推帧过程中,最后一帧才写入操作 //推帧过程中,最后一帧才写入操作
room.SetPlayerInput(_c.RoomState.PlayerIdx, msg.FrameID, temp); room.SetPlayerInput(_c.UID, msg.FrameID, temp);
} }
//推帧 //推帧
room.TakeFrame(); room.TakeFrame();
@ -431,7 +465,7 @@ namespace AxibugEmuOnline.Server
else//不需要推帧 else//不需要推帧
{ {
//虽然不推帧但是存入Input //虽然不推帧但是存入Input
room.SetPlayerInput(_c.RoomState.PlayerIdx, msg.FrameID, temp); room.SetPlayerInput(_c.UID, msg.FrameID, temp);
} }
if (room.LastTestRecv != room.mCurrInputData.all) if (room.LastTestRecv != room.mCurrInputData.all)
@ -550,13 +584,14 @@ namespace AxibugEmuOnline.Server
public string RomHash { get; private set; } public string RomHash { get; private set; }
public long HostUID { get; private set; } public long HostUID { get; private set; }
public long ScreenProviderUID { get; private set; } public long ScreenProviderUID { get; private set; }
public long Player1_UID { get; private set; } public Data_RoomSlot[] PlayerSlot;
public long Player2_UID { get; private set; } public long Player1_UID => PlayerSlot[0].UID;
public long Player3_UID { get; private set; } public long Player2_UID => PlayerSlot[1].UID;
public long Player4_UID { get; private set; } public long Player3_UID => PlayerSlot[2].UID;
public long Player4_UID => PlayerSlot[3].UID;
public Google.Protobuf.ByteString? NextStateRaw { get; private set; } public Google.Protobuf.ByteString? NextStateRaw { get; private set; }
public Google.Protobuf.ByteString? ScreenRaw { get; private set; } public Google.Protobuf.ByteString? ScreenRaw { get; private set; }
public bool[] PlayerReadyState { get; private set; } //public bool[] PlayerReadyState { get; private set; }
public List<long> SynUIDs; public List<long> SynUIDs;
//public RoomPlayerState PlayerState => getPlayerState(); //public RoomPlayerState PlayerState => getPlayerState();
private RoomGameState mGameState; private RoomGameState mGameState;
@ -580,7 +615,7 @@ namespace AxibugEmuOnline.Server
NextStateRaw = null; NextStateRaw = null;
break; break;
case RoomGameState.WaitReady: case RoomGameState.WaitReady:
Array.Fill<bool>(PlayerReadyState, false); ClearAllSlotReadyState();//清理玩家所有准备状态
break; break;
} }
} }
@ -590,23 +625,6 @@ namespace AxibugEmuOnline.Server
/// 服务器提前帧数 /// 服务器提前帧数
/// </summary> /// </summary>
public uint SrvForwardFrames { get; set; } public uint SrvForwardFrames { get; set; }
bool IsAllReady()
{
bool Ready = true;
if (
(Player1_UID > 0 && !PlayerReadyState[0])
||
(Player2_UID > 0 && !PlayerReadyState[1])
||
(Player3_UID > 0 && !PlayerReadyState[2])
||
(Player4_UID > 0 && !PlayerReadyState[3])
)
{
Ready = false;
}
return Ready;
}
public void Init(int roomID, int gameRomID, string roomHash, long hostUId, bool bloadState = false) public void Init(int roomID, int gameRomID, string roomHash, long hostUId, bool bloadState = false)
{ {
RoomID = roomID; RoomID = roomID;
@ -614,54 +632,193 @@ namespace AxibugEmuOnline.Server
RomHash = roomHash; RomHash = roomHash;
HostUID = hostUId; HostUID = hostUId;
ScreenProviderUID = hostUId; ScreenProviderUID = hostUId;
Player1_UID = -1;
Player2_UID = -1; if (PlayerSlot == null)
Player3_UID = -1; PlayerSlot = new Data_RoomSlot[4];
Player4_UID = -1;
PlayerReadyState = new bool[4]; for (uint i = 0; i < PlayerSlot.Length; i++)
PlayerSlot[i].Init(i);
//PlayerReadyState = new bool[4];
SynUIDs = new List<long>();//广播角色列表 SynUIDs = new List<long>();//广播角色列表
GameState = RoomGameState.NoneGameState; GameState = RoomGameState.NoneGameState;
mCurrInputData = new ServerInputSnapShot(); mCurrInputData = new ServerInputSnapShot();
mInputQueue = new Queue<(uint, ServerInputSnapShot)>(); mInputQueue = new Queue<(uint, ServerInputSnapShot)>();
mDictPlayerIdx2SendQueue = new Dictionary<int, Queue<byte[]>>(); mDictPlayerIdx2SendQueue = new Dictionary<int, Queue<byte[]>>();
} }
public void SetPlayerUID(int PlayerIdx, ClientInfo _c) public Dictionary<uint, uint> GetSlotDataByUID(long uid)
{ {
long oldUID = -1; Dictionary<uint, uint> slotIdx2JoyIdx = new Dictionary<uint, uint>();
switch (PlayerIdx) var dataarr = PlayerSlot.Where(w => w.UID == uid).ToArray();
{ foreach (var slot in dataarr)
case 0: oldUID = Player1_UID; Player1_UID = _c.UID; break; slotIdx2JoyIdx[slot.SlotIdx] = slot.LocalJoyIdx;
case 1: oldUID = Player2_UID; Player2_UID = _c.UID; break; return slotIdx2JoyIdx;
case 2: oldUID = Player3_UID; Player3_UID = _c.UID; break;
case 3: oldUID = Player4_UID; Player4_UID = _c.UID; break;
} }
if (oldUID >= 0) /// <summary>
SynUIDs.Remove(oldUID); /// 按照SlotIdx设置Input
SynUIDs.Add(_c.UID); /// </summary>
AppSrv.g_Log.Debug($"SetPlayerUID RoomID->{RoomID} _c.UID->{_c.UID} PlayerIdx->{PlayerIdx}"); /// <param name="slotIdx"></param>
_c.RoomState.SetRoomData(this.RoomID, PlayerIdx); void SetInputDataBySlotIdx(uint slotIdx, byte val)
{
switch (slotIdx)
{
case 0: mCurrInputData.p1_byte = val; break;
case 1: mCurrInputData.p2_byte = val; break;
case 2: mCurrInputData.p3_byte = val; break;
case 4: mCurrInputData.p3_byte = val; break;
}
}
/// <summary>
/// 按照UID清理SlotData
/// </summary>
/// <param name="uid"></param>
void ClearSlotDataByUid(long uid)
{
var dataarr = PlayerSlot.Where(w => w.UID == uid).ToArray();
foreach (var slot in dataarr)
{
dataarr[slot.SlotIdx].Init(slot.SlotIdx);
ClearInputDataBySlotIdx(slot.SlotIdx);
}
}
/// <summary>
/// 按照SlotIdx清理SlotData
/// </summary>
/// <param name="slotIdx"></param>
void ClearSlotDataBySlotIdx(uint slotIdx)
{
PlayerSlot[slotIdx].Init(slotIdx);
ClearInputDataBySlotIdx(slotIdx);
}
/// <summary>
/// 按照SlotIdx清理Input
/// </summary>
/// <param name="slotIdx"></param>
void ClearInputDataBySlotIdx(uint slotIdx)
{
switch (slotIdx)
{
case 0: mCurrInputData.p1_byte = 0; break;
case 1: mCurrInputData.p2_byte = 0; break;
case 2: mCurrInputData.p3_byte = 0; break;
case 4: mCurrInputData.p3_byte = 0; break;
}
}
/// <summary>
/// 更新同步名单
/// </summary>
void UpdateSynUIDs()
{
for (int i = SynUIDs.Count - 1; i >= 0; i--)
{
long uid = SynUIDs[i];
bool bHad = false;
if (Player1_UID == uid) bHad = true;
else if (Player2_UID == uid) bHad = true;
else if (Player3_UID == uid) bHad = true;
else if (Player4_UID == uid) bHad = true;
if (bHad)
SynUIDs.RemoveAt(i);
}
if (!SynUIDs.Contains(Player1_UID)) SynUIDs.Add(Player1_UID);
if (!SynUIDs.Contains(Player2_UID)) SynUIDs.Add(Player2_UID);
if (!SynUIDs.Contains(Player3_UID)) SynUIDs.Add(Player3_UID);
if (!SynUIDs.Contains(Player4_UID)) SynUIDs.Add(Player4_UID);
}
#region
bool IsAllReady()
{
bool Ready = true;
if (
(Player1_UID > 0 && !PlayerSlot[0].Ready)
||
(Player2_UID > 0 && !PlayerSlot[1].Ready)
||
(Player3_UID > 0 && !PlayerSlot[2].Ready)
||
(Player4_UID > 0 && !PlayerSlot[3].Ready)
)
{
Ready = false;
}
return Ready;
}
/// <summary>
/// 清除所有槽位准备状态
/// </summary>
void ClearAllSlotReadyState()
{
for (var i = 0; i < PlayerSlot.Length; i++)
{
PlayerSlot[i].Ready = false;
}
}
/// <summary>
/// 按照UID设置Ready信息
/// </summary>
/// <param name="uid"></param>
void SetReadyByUid(long uid)
{
for (var i = 0; i < PlayerSlot.Length; i++)
{
if (PlayerSlot[i].UID == uid)
PlayerSlot[i].Ready = true;
}
}
#endregion
public void SetPlayerSlotData(ClientInfo _c, ref readonly Dictionary<uint, uint> newSlotIdx2JoyIdx)
{
Dictionary<uint, uint> oldSlotIdx2JoyIdx = GetSlotDataByUID(_c.UID);
HashSet<uint> diffSlotIdxs = new HashSet<uint>();
foreach (var old in oldSlotIdx2JoyIdx)
{
uint old_slotIdx = old.Key;
//如果旧位置已经不存在于新位置则需要算作diff
if (!newSlotIdx2JoyIdx.ContainsKey(old_slotIdx))
{
diffSlotIdxs.Add(old_slotIdx); continue;
}
uint old_slotjoyIdx = old.Value;
//如果旧位置不变但客户端本地JoyIdx变化则算作diff
if (old_slotjoyIdx != newSlotIdx2JoyIdx[old_slotIdx])
{
diffSlotIdxs.Add(old_slotIdx); continue;
}
}
//如果是在旧数据中不存在的位置则算作diff
foreach (var newdata in newSlotIdx2JoyIdx)
{
uint new_slotIdx = newdata.Key;
if (!oldSlotIdx2JoyIdx.ContainsKey(new_slotIdx))
{
diffSlotIdxs.Add(new_slotIdx); continue;
}
}
//必要的diff slot 清理键值数据
foreach (var diffSlotIdx in diffSlotIdxs)
{
ClearSlotDataBySlotIdx(diffSlotIdx);
}
//设置新的槽位
foreach (var slotdata in newSlotIdx2JoyIdx)
{
PlayerSlot[slotdata.Key].LocalJoyIdx = slotdata.Value;
AppSrv.g_Log.Debug($"SetPlayerUID RoomID->{RoomID} _c.UID->{_c.UID} PlayerSlotIdx->{slotdata.Key} LocalJoyIdx->{slotdata.Value}");
}
//更新需要同步的UID
UpdateSynUIDs();
_c.RoomState.SetRoomData(this.RoomID);
} }
public void RemovePlayer(ClientInfo _c) public void RemovePlayer(ClientInfo _c)
{ {
int PlayerIdx = GetPlayerIdx(_c); ClearSlotDataByUid(_c.UID);
switch (PlayerIdx) UpdateSynUIDs();
{
case 0: Player1_UID = -1; SynUIDs.Remove(_c.UID); break;
case 1: Player2_UID = -1; SynUIDs.Remove(_c.UID); break;
case 2: Player3_UID = -1; SynUIDs.Remove(_c.UID); break;
case 3: Player4_UID = -1; SynUIDs.Remove(_c.UID); break;
}
_c.RoomState.ClearRoomData(); _c.RoomState.ClearRoomData();
} }
int GetPlayerIdx(ClientInfo _c) public bool GetPlayerUIDByIdx(uint Idx, out long UID)
{
if (Player1_UID == _c.UID) return 0;
if (Player2_UID == _c.UID) return 1;
if (Player3_UID == _c.UID) return 2;
if (Player4_UID == _c.UID) return 3;
return -1;
}
public bool GetPlayerUIDByIdx(int Idx, out long UID)
{ {
switch (Idx) switch (Idx)
{ {
@ -673,7 +830,7 @@ namespace AxibugEmuOnline.Server
} }
return UID > 0; return UID > 0;
} }
public bool GetPlayerClientByIdx(int Idx, out ClientInfo _c) public bool GetPlayerClientByIdx(uint Idx, out ClientInfo _c)
{ {
_c = null; _c = null;
if (!GetPlayerUIDByIdx(Idx, out long UID)) if (!GetPlayerUIDByIdx(Idx, out long UID))
@ -684,61 +841,50 @@ namespace AxibugEmuOnline.Server
return true; return true;
} }
public List<long> GetAllPlayerUIDs()
{
List<long> list = new List<long>();
if (Player1_UID > 0) list.Add(Player1_UID);
if (Player2_UID > 0) list.Add(Player2_UID);
if (Player3_UID > 0) list.Add(Player3_UID);
if (Player4_UID > 0) list.Add(Player4_UID);
return list;
}
public List<ClientInfo> GetAllPlayerClientList() public List<ClientInfo> GetAllPlayerClientList()
{ {
List<ClientInfo> list = new List<ClientInfo>(); List<ClientInfo> list = new List<ClientInfo>();
List<long> Uids = SynUIDs;
List<long> Uids = GetAllPlayerUIDs();
foreach (long uid in Uids) foreach (long uid in Uids)
{ {
if (!AppSrv.g_ClientMgr.GetClientByUID(uid, out ClientInfo _c, true)) if (!AppSrv.g_ClientMgr.GetClientByUID(uid, out ClientInfo _c, true))
continue; continue;
list.Add(_c); list.Add(_c);
} }
return list; return list;
} }
public void SetPlayerInput(int PlayerIdx, long mFrameID, ServerInputSnapShot allinput)
void SetInputBySlotIdxJoyIdx(uint SlotIdx, uint LocalJoyIdx, ServerInputSnapShot clieninput)
{ {
switch (PlayerIdx) switch (LocalJoyIdx)
{ {
case 0: mCurrInputData.p1_byte = allinput.p1_byte; break; case 0: SetInputDataBySlotIdx(SlotIdx, clieninput.p1_byte); break;
case 1: mCurrInputData.p2_byte = allinput.p1_byte; break; case 1: SetInputDataBySlotIdx(SlotIdx, clieninput.p2_byte); break;
case 2: mCurrInputData.p3_byte = allinput.p1_byte; break; case 2: SetInputDataBySlotIdx(SlotIdx, clieninput.p3_byte); break;
case 3: mCurrInputData.p4_byte = allinput.p1_byte; break; case 3: SetInputDataBySlotIdx(SlotIdx, clieninput.p4_byte); break;
}
}
public void ClearPlayerInput(ClientInfo _c)
{
int PlayerIdx = GetPlayerIdx(_c);
switch (PlayerIdx)
{
case 0: mCurrInputData.p1_byte = 0; break;
case 1: mCurrInputData.p2_byte = 0; break;
case 2: mCurrInputData.p3_byte = 0; break;
case 3: mCurrInputData.p4_byte = 0; break;
} }
} }
public int GetPlayerCount() public int GetPlayerCount()
{ {
int count = 0; return SynUIDs.Count;
if (Player1_UID > 0) count++;
if (Player2_UID > 0) count++;
if (Player3_UID > 0) count++;
if (Player4_UID > 0) count++;
return count;
} }
public void UpdateRoomForwardNum()
{
List<ClientInfo> playerlist = GetAllPlayerClientList();
double maxNetDelay = 0;
for (int i = 0; i < playerlist.Count; i++)
{
ClientInfo player = playerlist[i];
maxNetDelay = Math.Max(maxNetDelay, player.AveNetDelay);
}
float MustTaskFrame = 1;
SrvForwardFrames = (uint)((maxNetDelay / 0.016f) + MustTaskFrame);
if (SrvForwardFrames < 2)
SrvForwardFrames = 2;
//AppSrv.g_Log.Debug($"服务器提前跑帧数Max(2,({maxNetDelay} / {0.016f}) + {MustTaskFrame}) = {SrvForwardFrames}");
}
#region
void StartNewTick() void StartNewTick()
{ {
mInputQueue.Clear(); mInputQueue.Clear();
@ -756,23 +902,6 @@ namespace AxibugEmuOnline.Server
TakeFrame(); TakeFrame();
AppSrv.g_Log.Info($"房间初始提前量=>{StartForwardFrames},当前延迟提前量=>{SrvForwardFrames}"); AppSrv.g_Log.Info($"房间初始提前量=>{StartForwardFrames},当前延迟提前量=>{SrvForwardFrames}");
} }
public void UpdateRoomForwardNum()
{
List<ClientInfo> playerlist = GetAllPlayerClientList();
double maxNetDelay = 0;
for (int i = 0; i < playerlist.Count; i++)
{
ClientInfo player = playerlist[i];
maxNetDelay = Math.Max(maxNetDelay, player.AveNetDelay);
}
float MustTaskFrame = 1;
SrvForwardFrames = (uint)((maxNetDelay / 0.016f) + MustTaskFrame);
if (SrvForwardFrames < 2)
SrvForwardFrames = 2;
//AppSrv.g_Log.Debug($"服务器提前跑帧数Max(2,({maxNetDelay} / {0.016f}) + {MustTaskFrame}) = {SrvForwardFrames}");
}
public void TakeFrame() public void TakeFrame()
{ {
lock (synInputLock) lock (synInputLock)
@ -785,6 +914,7 @@ namespace AxibugEmuOnline.Server
} }
} }
} }
#endregion
ulong LastTestSend = 0; ulong LastTestSend = 0;
internal ulong LastTestRecv; internal ulong LastTestRecv;
@ -850,62 +980,6 @@ namespace AxibugEmuOnline.Server
} }
} }
#region
/// <summary>
/// 进入房间
/// </summary>
/// <param name="RoomID"></param>
/// <param name="PlayerNum"></param>
/// <param name="_c"></param>
/// <param name="errcode"></param>
/// <returns></returns>
public bool Join(int PlayerNum, ClientInfo _c, out ErrorCode errcode, out bool bHadRoomStateChange)
{
bHadRoomStateChange = false;
int oldPlayerCount = GetPlayerCount();
if (GetPlayerUIDByIdx(PlayerNum, out long hadUID))
{
errcode = ErrorCode.ErrorRoomSlotAlreadlyHadPlayer;
return false;
}
AppSrv.g_Log.Debug($"Join _c.UID->{_c.UID} RoomID->{RoomID}");
SetPlayerUID(PlayerNum, _c);
int newPlayerCount = GetPlayerCount();
errcode = ErrorCode.ErrorOk;
bHadRoomStateChange = CheckRoomStateChange(oldPlayerCount, newPlayerCount);
return true;
}
/// <summary>
/// 离开房间
/// </summary>
/// <param name="RoomID"></param>
/// <param name="_c"></param>
/// <param name="errcode"></param>
/// <returns></returns>
public bool Leave(ClientInfo _c, out ErrorCode errcode, out bool bHadRoomStateChange)
{
int oldPlayerCount = GetPlayerCount();
RemovePlayer(_c);
ClearPlayerInput(_c);
int newPlayerCount = GetPlayerCount();
errcode = ErrorCode.ErrorOk;
bHadRoomStateChange = CheckRoomStateChange(oldPlayerCount, newPlayerCount);
return true;
}
#endregion
public bool SetRePlayerReady(int PlayerIdx, out ErrorCode errcode, out bool bHadRoomStateChange)
{
int oldPlayerCount = GetPlayerCount();
PlayerReadyState[PlayerIdx] = true;
int newPlayerCount = GetPlayerCount();
errcode = ErrorCode.ErrorOk;
bHadRoomStateChange = CheckRoomStateChange(oldPlayerCount, newPlayerCount);
return true;
}
bool CheckRoomStateChange(int oldPlayerCount, int newPlayerCount) bool CheckRoomStateChange(int oldPlayerCount, int newPlayerCount)
{ {
bool bChanged = false; bool bChanged = false;
@ -980,6 +1054,73 @@ namespace AxibugEmuOnline.Server
return bChanged; return bChanged;
} }
#region
#region
/// <summary>
/// 进入房间
/// </summary>
/// <param name="RoomID"></param>
/// <param name="PlayerNum"></param>
/// <param name="_c"></param>
/// <param name="errcode"></param>
/// <returns></returns>
public bool Join(uint slotIdx, uint joyIdx, ClientInfo _c, out ErrorCode errcode, out bool bHadRoomStateChange)
{
bHadRoomStateChange = false;
int oldPlayerCount = GetPlayerCount();
if (GetPlayerUIDByIdx(slotIdx, out long hadUID))
{
errcode = ErrorCode.ErrorRoomSlotAlreadlyHadPlayer;
return false;
}
AppSrv.g_Log.Debug($"Join _c.UID->{_c.UID} RoomID->{RoomID}");
Dictionary<uint, uint> slotInfo = new Dictionary<uint, uint>();
slotInfo[slotIdx] = joyIdx;
SetPlayerSlotData(_c, ref slotInfo);
int newPlayerCount = GetPlayerCount();
errcode = ErrorCode.ErrorOk;
bHadRoomStateChange = CheckRoomStateChange(oldPlayerCount, newPlayerCount);
return true;
}
/// <summary>
/// 离开房间
/// </summary>
/// <param name="RoomID"></param>
/// <param name="_c"></param>
/// <param name="errcode"></param>
/// <returns></returns>
public bool Leave(ClientInfo _c, out ErrorCode errcode, out bool bHadRoomStateChange)
{
int oldPlayerCount = GetPlayerCount();
RemovePlayer(_c);
int newPlayerCount = GetPlayerCount();
errcode = ErrorCode.ErrorOk;
bHadRoomStateChange = CheckRoomStateChange(oldPlayerCount, newPlayerCount);
return true;
}
#endregion
public void SetPlayerInput(long UID, uint LocalJoyIdx, ServerInputSnapShot clieninput)
{
for (uint i = 0; i < PlayerSlot.Count(); i++)
{
Data_RoomSlot slotData = PlayerSlot[i];
if (slotData.UID != UID)
continue;
SetInputBySlotIdxJoyIdx(slotData.SlotIdx, slotData.LocalJoyIdx, clieninput);
}
}
public bool SetRePlayerReady(long UID, out ErrorCode errcode, out bool bHadRoomStateChange)
{
int oldPlayerCount = GetPlayerCount();
SetReadyByUid(UID);
int newPlayerCount = GetPlayerCount();
errcode = ErrorCode.ErrorOk;
bHadRoomStateChange = CheckRoomStateChange(oldPlayerCount, newPlayerCount);
return true;
}
public void SetLoadRaw(Google.Protobuf.ByteString NextStateRaw, out bool bHadRoomStateChange) public void SetLoadRaw(Google.Protobuf.ByteString NextStateRaw, out bool bHadRoomStateChange)
{ {
int oldPlayerCount = GetPlayerCount(); int oldPlayerCount = GetPlayerCount();
@ -988,12 +1129,10 @@ namespace AxibugEmuOnline.Server
int newPlayerCount = GetPlayerCount(); int newPlayerCount = GetPlayerCount();
bHadRoomStateChange = CheckRoomStateChange(oldPlayerCount, newPlayerCount); bHadRoomStateChange = CheckRoomStateChange(oldPlayerCount, newPlayerCount);
} }
public void InputScreenData(Google.Protobuf.ByteString screenRaw) public void InputScreenData(Google.Protobuf.ByteString screenRaw)
{ {
this.ScreenRaw = NextStateRaw; this.ScreenRaw = NextStateRaw;
} }
public bool GetNeedForwardTick(uint clientFrame, out long forwaFrame) public bool GetNeedForwardTick(uint clientFrame, out long forwaFrame)
{ {
forwaFrame = 0; forwaFrame = 0;
@ -1003,6 +1142,22 @@ namespace AxibugEmuOnline.Server
forwaFrame = targetFrame - mCurrServerFrameId; forwaFrame = targetFrame - mCurrServerFrameId;
return forwaFrame > 0; return forwaFrame > 0;
} }
#endregion
}
public class Data_RoomSlot
{
public uint SlotIdx { get; set; }
public long UID { get; set; }
public uint LocalJoyIdx { get; set; }
public bool Ready = false;
public void Init(uint SlotIdx)
{
this.SlotIdx = SlotIdx;
UID = -1;
LocalJoyIdx = 0;
Ready = false;
}
} }
[StructLayout(LayoutKind.Explicit, Size = 8)] [StructLayout(LayoutKind.Explicit, Size = 8)]

View File

@ -38,14 +38,16 @@ namespace AxibugEmuOnline.Server
AppSrv.g_Log.Info($"input p3:{room.mCurrInputData.p3_byte}"); AppSrv.g_Log.Info($"input p3:{room.mCurrInputData.p3_byte}");
AppSrv.g_Log.Info($"input p4:{room.mCurrInputData.p4_byte}"); AppSrv.g_Log.Info($"input p4:{room.mCurrInputData.p4_byte}");
AppSrv.g_Log.Info($"GetPlayerCount:{room.GetPlayerCount()}"); AppSrv.g_Log.Info($"GetPlayerCount:{room.GetPlayerCount()}");
for (int i = 0; i < 4; i++) for (int i = 0; i < room.PlayerSlot.Length; i++)
{ {
AppSrv.g_Log.Info($" P{i}"); AppSrv.g_Log.Info($" P{i}");
if (room.GetPlayerClientByIdx(i, out ClientInfo _c))
if (AppSrv.g_ClientMgr.GetClientByUID(room.PlayerSlot[i].UID, out ClientInfo _c))
{ {
AppSrv.g_Log.Info($" UID->{_c.UID}"); AppSrv.g_Log.Info($" UID->{room.PlayerSlot[i].UID}");
AppSrv.g_Log.Info($" NickName->{_c.NickName}"); AppSrv.g_Log.Info($" NickName->{_c.NickName}");
AppSrv.g_Log.Info($" AveNetDelay->{_c.AveNetDelay}"); AppSrv.g_Log.Info($" AveNetDelay->{_c.AveNetDelay}");
AppSrv.g_Log.Info($" LocalJoyIdx->{room.PlayerSlot[i].LocalJoyIdx}");
} }
else else
{ {

View File

@ -33,6 +33,7 @@ enum CommandID
CMD_Room_Join = 5105; // Protobuf_Room_Join | Protobuf_Room_Join_RESP //Join之前按照房间信息Rom CMD_Room_Join = 5105; // Protobuf_Room_Join | Protobuf_Room_Join_RESP //Join之前按照房间信息Rom
CMD_Room_Leave = 5106; // Protobuf_Room_Leave | Protobuf_Room_Leave_RESP CMD_Room_Leave = 5106; // Protobuf_Room_Leave | Protobuf_Room_Leave_RESP
CMD_Room_MyRoom_State_Changed = 5110; // Protobuf_Room_MyRoom_State_Change CMD_Room_MyRoom_State_Changed = 5110; // Protobuf_Room_MyRoom_State_Change
CMD_Room_ChangePlayerWithJoy = 5130; // Protobuf_Room_Change_PlaySlotWithJoy | Protobuf_Room_Change_PlaySlotWithJoy_RESP
//5201 ~ 5204 ~ 5208 //5201 ~ 5204 ~ 5208
// //
@ -257,15 +258,15 @@ message Protobuf_Room_MiniInfo
int64 HostPlayerUID = 4;//ID int64 HostPlayerUID = 4;//ID
RoomGameState GameState = 5;// RoomGameState GameState = 5;//
int32 ObsUserCount = 6;// int32 ObsUserCount = 6;//
int64 Player1_UID = 7;//1 UID int64 ScreenProviderUID = 7;//
string Player1_NickName = 8;//1 repeated Protobuf_Room_GamePlaySlot GamePlaySlotList = 8;//P1~P4 4
int64 Player2_UID = 9;//2 UID }
string Player2_NickName = 10;//2
int64 Player3_UID = 11;//3 UID message Protobuf_Room_GamePlaySlot
string Player3_NickName = 12;//3 {
int64 Player4_UID = 13;//4 UID int64 Player_UID = 1;// UID
string Player4_NickName = 14;//4 string Player_NickName = 2;//
int64 ScreenProviderUID = 15;// int32 PlayerLocalJoyIdx = 3;//JoyIdx
} }
message Protobuf_Room_Update_RESP message Protobuf_Room_Update_RESP
@ -299,7 +300,8 @@ message Protobuf_Room_Create
{ {
int32 GameRomID = 1; int32 GameRomID = 1;
string GameRomHash = 2; string GameRomHash = 2;
int32 JoinPlayerIdx = 3;//P1~P4[0~3] int32 PlayerSlotIdx = 3;//P1~P4编号
int32 PlayerLocalJoyIdx = 4;//Joy编号
} }
message Protobuf_Room_Create_RESP message Protobuf_Room_Create_RESP
@ -310,7 +312,8 @@ message Protobuf_Room_Create_RESP
message Protobuf_Room_Join message Protobuf_Room_Join
{ {
int32 RoomID = 1;//ID int32 RoomID = 1;//ID
int32 PlayerNum = 2;// [0]1 [1]2 int32 PlayerSlotIdx = 2;//P1~P4编号
int32 PlayerLocalJoyIdx = 3;//Joy编号
} }
message Protobuf_Room_Join_RESP message Protobuf_Room_Join_RESP
@ -333,6 +336,21 @@ message Protobuf_Room_MyRoom_State_Change
Protobuf_Room_MiniInfo RoomMiniInfo = 1;// Protobuf_Room_MiniInfo RoomMiniInfo = 1;//
} }
message Protobuf_Room_Change_PlaySlotWithJoy
{
repeated Protobuf_PlaySlotIdxWithJoyIdx SlotWithJoy = 1;//P1~P4编号
}
message Protobuf_PlaySlotIdxWithJoyIdx
{
int32 PlayerSlotIdx = 1;//P1~P4编号
int32 PlayerLocalJoyIdx = 2;//Joy编号
}
message Protobuf_Room_Change_PlaySlotWithJoy_RESP
{
}
message Protobuf_Room_WaitStep_RESP message Protobuf_Room_WaitStep_RESP
{ {
int32 WaitStep = 1;// [0] [1] [2] int32 WaitStep = 1;// [0] [1] [2]
@ -352,6 +370,10 @@ message Protobuf_Room_HostPlayer_UpdateStateRaw_RESP
message Protobuf_Room_Player_Ready message Protobuf_Room_Player_Ready
{ {
float PushFrameNeedTimeUs = 1;//push帧所需平均时间
float LoadStateNeedTimeUs = 2;//
float VideoFrameShowNeedTimeUs = 3;//
float AudioFramePlayNeedTimeUs = 4;//
} }
message Protobuf_Room_Get_Screen message Protobuf_Room_Get_Screen