浏览代码

Transitioning data handling to Relay, so Lobby will only be responsible for the data useful for getting players into the lobby. I'm also fixing a bug where the lobby list heartbeat would never stop.

/main/staging
nathaniel.buck@unity3d.com 3 年前
当前提交
5a114974
共有 7 个文件被更改,包括 67 次插入46 次删除
  1. 7
      Assets/Scripts/Entities/LobbyUser.cs
  2. 24
      Assets/Scripts/Lobby/LobbyContentHeartbeat.cs
  3. 1
      Assets/Scripts/Lobby/LobbyListHeartbeat.cs
  4. 20
      Assets/Scripts/Lobby/ToLocalLobby.cs
  5. 30
      Assets/Scripts/Relay/RelayUtpClient.cs
  6. 17
      Assets/Scripts/Relay/RelayUtpHost.cs
  7. 14
      Assets/Scripts/UI/UIPanelBase.cs

7
Assets/Scripts/Entities/LobbyUser.cs


/// </summary>
[Flags]
public enum UserMembers { IsHost = 1, DisplayName = 2, Emote = 4, ID = 8, UserStatus = 16 }
private UserMembers m_lastChanged;// TODO: Is the following necessary to prompt an initial update, or do I need to adjust RelayUtpClient.DoUserUpdate to force all messages on the first go? (Or maybe just have some separate call to send full state as one message to start with? Although it should only be name...) = (UserMembers)(-1); // All values are set as changed to begin with, for initial updates.
private UserMembers m_lastChanged;
public UserMembers LastChanged => m_lastChanged;
bool m_isHost;

(m_id == oldObserved.m_id ? 0 : (int)UserMembers.ID) |
(m_isHost == oldObserved.m_isHost ? 0 : (int)UserMembers.IsHost) |
(m_userStatus == oldObserved.m_userStatus ? 0 : (int)UserMembers.UserStatus);
if (lastChanged == 0) // Ensure something actually changed.
return;
m_displayName = oldObserved.m_displayName;
m_emote = oldObserved.m_emote;

m_lastChanged = (UserMembers)lastChanged;
if (lastChanged != 0) // Ensure something actually changed.
OnChanged(this);
OnChanged(this);
}
}
}

24
Assets/Scripts/Lobby/LobbyContentHeartbeat.cs


using System;
using System.Collections.Generic;
using LobbyRemote = Unity.Services.Lobbies.Models.Lobby;
namespace LobbyRelaySample

void DoLobbyDataPush()
{
LobbyAsyncRequests.Instance.UpdateLobbyDataAsync(lobby.ToLocalLobby.RetrieveLobbyData(m_localLobby), () => { DoPlayerDataPush(); });
LobbyAsyncRequests.Instance.UpdateLobbyDataAsync(RetrieveLobbyData(m_localLobby), () => { DoPlayerDataPush(); });
LobbyAsyncRequests.Instance.UpdatePlayerDataAsync(lobby.ToLocalLobby.RetrieveUserData(m_localUser), () => { m_isAwaitingQuery = false; });
LobbyAsyncRequests.Instance.UpdatePlayerDataAsync(RetrieveUserData(m_localUser), () => { m_isAwaitingQuery = false; });
}
void OnRetrieve()

Locator.Get.Messenger.OnReceiveMessage(MessageType.Client_EndReadyCountdownAt, targetTime); // Note that this could be called multiple times.
}
}
}
public static Dictionary<string, string> RetrieveLobbyData(LocalLobby lobby)
{
Dictionary<string, string> data = new Dictionary<string, string>();
data.Add("RelayCode", lobby.RelayCode);
data.Add("State", ((int)lobby.State).ToString());
// We only want the ArePlayersReadyTime to be set when we actually are ready for it, and it's null otherwise. So, don't set that here.
return data;
}
public static Dictionary<string, string> RetrieveUserData(LobbyUser user)
{
Dictionary<string, string> data = new Dictionary<string, string>();
if (user == null || string.IsNullOrEmpty(user.ID))
return data;
data.Add("DisplayName", user.DisplayName); // The lobby doesn't need to know any data beyond the name and state; Relay will handle the rest.
data.Add("UserStatus", ((int)user.UserStatus).ToString());
return data;
}
}
}

1
Assets/Scripts/Lobby/LobbyListHeartbeat.cs


/// </summary>
public class LobbyListHeartbeat : MonoBehaviour
{
// This is called in-editor via events.
public void SetActive(bool isActive)
{
if (isActive)

20
Assets/Scripts/Lobby/ToLocalLobby.cs


Convert(lobby, data);
return data;
}
public static Dictionary<string, string> RetrieveLobbyData(LocalLobby lobby)
{
Dictionary<string, string> data = new Dictionary<string, string>();
data.Add("RelayCode", lobby.RelayCode);
data.Add("State", ((int)lobby.State).ToString());
// We only want the ArePlayersReadyTime to be set when we actually are ready for it, and it's null otherwise. So, don't set that here.
return data;
}
public static Dictionary<string, string> RetrieveUserData(LobbyUser user)
{
Dictionary<string, string> data = new Dictionary<string, string>();
if (user == null || string.IsNullOrEmpty(user.ID))
return data;
data.Add("DisplayName", user.DisplayName);
data.Add("Emote", ((int)user.Emote).ToString());
data.Add("UserStatus", ((int)user.UserStatus).ToString());
return data;
}
}
}

30
Assets/Scripts/Relay/RelayUtpClient.cs


return;
m_networkDriver.ScheduleUpdate().Complete();
foreach (NetworkConnection conn in m_connections)
DoUserUpdate(m_networkDriver, conn); // TODO: Hmm...I don't think this ends up working if the host has to manually transmit changes over all connections.
DoUserUpdate(m_networkDriver, conn, m_localUser);
}
public void Update()

SendInitialMessage(m_networkDriver, m_connections[0]);
}
private void ReceiveNetworkEvents(NetworkDriver driver, List<NetworkConnection> connections) // TODO: Just the one connection. Also not NativeArray.
private void ReceiveNetworkEvents(NetworkDriver driver, List<NetworkConnection> connections)
{
DataStreamReader strm;
NetworkEvent.Type cmd;

}
ProcessNetworkEventDataAdditional(conn, strm, msgType, id);
}
ProcessNetworkEventAdditional(strm, cmd);
protected virtual void ProcessNetworkEventAdditional(DataStreamReader strm, NetworkEvent.Type cmd) { }
protected virtual void ProcessNetworkEventDataAdditional(NetworkConnection conn, DataStreamReader strm, MsgType msgType, string id) { }

private void SendInitialMessage(NetworkDriver driver, NetworkConnection connection)
{
DoUserUpdate(driver, connection); // Assuming this is only created after the Relay connection is successful.
ForceFullUserUpdate(driver, connection, m_localUser); // Assuming this is only created after the Relay connection is successful.
private void DoUserUpdate(NetworkDriver driver, NetworkConnection connection)
private void DoUserUpdate(NetworkDriver driver, NetworkConnection connection, LobbyUser user)
if (0 < (m_localUser.LastChanged & LobbyUser.UserMembers.DisplayName))
WriteString(driver, connection, m_localUser.ID, MsgType.PlayerName, m_localUser.DisplayName);
if (0 < (m_localUser.LastChanged & LobbyUser.UserMembers.Emote))
WriteByte(driver, connection, m_localUser.ID, MsgType.Emote, (byte)m_localUser.Emote);
if (0 < (m_localUser.LastChanged & LobbyUser.UserMembers.UserStatus))
WriteByte(driver, connection, m_localUser.ID, MsgType.ReadyState, (byte)m_localUser.UserStatus);
if (0 < (user.LastChanged & LobbyUser.UserMembers.DisplayName))
WriteString(driver, connection, user.ID, MsgType.PlayerName, user.DisplayName);
if (0 < (user.LastChanged & LobbyUser.UserMembers.Emote))
WriteByte(driver, connection, user.ID, MsgType.Emote, (byte)user.Emote);
if (0 < (user.LastChanged & LobbyUser.UserMembers.UserStatus))
WriteByte(driver, connection, user.ID, MsgType.ReadyState, (byte)user.UserStatus);
}
protected void ForceFullUserUpdate(NetworkDriver driver, NetworkConnection connection, LobbyUser user)
{
// TODO: Write full state in one message?
WriteString(driver, connection, user.ID, MsgType.PlayerName, user.DisplayName);
WriteByte(driver, connection, user.ID, MsgType.Emote, (byte)user.Emote);
WriteByte(driver, connection, user.ID, MsgType.ReadyState, (byte)user.UserStatus);
}
/// <summary>

17
Assets/Scripts/Relay/RelayUtpHost.cs


/// <summary>
/// When a new client connects, they need to be given all up-to-date info.
/// </summary>
protected override void ProcessNetworkEventAdditional(DataStreamReader strm, NetworkEvent.Type cmd)
private void OnNewConnection(NetworkConnection conn)
if (cmd == NetworkEvent.Type.Connect)
{
}
// When a new client connects, they need to be updated with the current state of everyone else.
// (We can't exclude this client from the events we send to it, since we don't have its ID in strm, but it will ignore messages about itself on arrival.)
foreach (var user in m_localLobby.LobbyUsers)
ForceFullUserUpdate(m_networkDriver, conn, user.Value);
}
protected override void ProcessNetworkEventDataAdditional(NetworkConnection conn, DataStreamReader strm, MsgType msgType, string id)

}
while (true)
{
var con = m_networkDriver.Accept();
if (!con.IsCreated) // "Nothing more to accept" is signalled by returning an invalid connection from Accept.
var conn = m_networkDriver.Accept();
if (!conn.IsCreated) // "Nothing more to accept" is signalled by returning an invalid connection from Accept.
m_connections.Add(con);
m_connections.Add(conn);
OnNewConnection(conn);
}
}
}

14
Assets/Scripts/UI/UIPanelBase.cs


using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

bool showing;
CanvasGroup m_canvasGroup;
List<UIPanelBase> m_uiPanelsInChildren = new List<UIPanelBase>(); // Otherwise, when this Shows/Hides, the children won't know to update their own visibility.
public void Start()
{
var children = GetComponentsInChildren<UIPanelBase>(true); // Note that this won't detect children in GameObjects added during gameplay, if there were any.
foreach (var child in children)
if (child != this)
m_uiPanelsInChildren.Add(child);
}
protected CanvasGroup MyCanvasGroup
{

MyCanvasGroup.blocksRaycasts = true;
showing = true;
m_onVisibilityChange?.Invoke(true);
foreach (UIPanelBase child in m_uiPanelsInChildren)
child.m_onVisibilityChange?.Invoke(true);
}
public void Hide()

MyCanvasGroup.blocksRaycasts = false;
showing = false;
m_onVisibilityChange?.Invoke(false);
foreach (UIPanelBase child in m_uiPanelsInChildren)
child.m_onVisibilityChange?.Invoke(false);
}
}
}
正在加载...
取消
保存