浏览代码

Consolidating and renaming for readability. This still represents the baseline Relay + UTP behavior, without removing existing Lobby behavior yet or handling edge cases.

/main/staging
nathaniel.buck@unity3d.com 3 年前
当前提交
d1773d39
共有 13 个文件被更改,包括 340 次插入327 次删除
  1. 7
      Assets/Prefabs/UI/RenamePopup.prefab
  2. 68
      Assets/Scripts/Entities/GameStateManager.cs
  3. 76
      Assets/Scripts/Entities/LobbyUser.cs
  4. 4
      Assets/Scripts/LobbyRelaySample.asmdef
  5. 28
      Assets/Scripts/Relay/RelayUtpSetup.cs
  6. 9
      Packages/packages-lock.json
  7. 188
      Assets/Scripts/Relay/RelayUtpClient.cs
  8. 44
      Assets/Scripts/Relay/RelayUtpHost.cs
  9. 51
      Assets/Scripts/Relay/RelayHost.cs
  10. 192
      Assets/Scripts/Relay/RelayUserWatcher.cs
  11. 0
      /Assets/Scripts/Relay/RelayUtpHost.cs.meta
  12. 0
      /Assets/Scripts/Relay/RelayUtpClient.cs.meta

7
Assets/Prefabs/UI/RenamePopup.prefab


m_CharacterValidation: 0
m_RegexValue:
m_GlobalPointSize: 30
m_CharacterLimit: 0
m_CharacterLimit: 32
m_OnEndEdit:
m_PersistentCalls:
m_Calls:

m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 28.6
m_fontSize: 24.15
m_fontSizeBase: 14
m_fontWeight: 400
m_enableAutoSizing: 1

m_Script: {fileID: 11500000, guid: 160dfc78f3641c94fbebe419be087996, type: 3}
m_Name:
m_EditorClassIdentifier:
m_onVisibilityChange:
m_PersistentCalls:
m_Calls: []
showing: 0
--- !u!1 &8624457953407905705
GameObject:

68
Assets/Scripts/Entities/GameStateManager.cs


using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Services.Relay.Models;
using UnityEngine;
namespace LobbyRelaySample

LocalLobby m_localLobby;
LobbyServiceData m_lobbyServiceData = new LobbyServiceData();
LocalGameState m_localGameState = new LocalGameState();
ReadyCheck m_ReadyCheck;
RelayUTPSetup m_RelaySetup;
ReadyCheck m_readyCheck;
RelayUtpSetup m_relaySetup;
RelayUtpClient m_relayClient;
public void Awake()
{

var unused = Locator.Get;
#pragma warning restore IDE0059 // Unnecessary assignment of a value
Locator.Get.Provide(new Auth.Identity(OnAuthSignIn));
m_ReadyCheck = new ReadyCheck(7);
m_readyCheck = new ReadyCheck(7);
Application.wantsToQuit += OnWantToQuit;
}

Dictionary<string, string> displayNameData = new Dictionary<string, string>();
displayNameData.Add("DisplayName", m_localUser.DisplayName);
LobbyAsyncRequests.Instance.UpdatePlayerDataAsync(displayNameData, null);
StartRelayConnection();
}
void StartRelayConnection()
{
{
m_RelaySetup = gameObject.AddComponent<RelayUtpSetup_Host>();
m_RelaySetup.BeginRelayJoin(m_localLobby, m_localUser);
}
m_relaySetup = gameObject.AddComponent<RelayUtpSetupHost>();
m_relaySetup = gameObject.AddComponent<RelayUtpSetupClient>();
m_relaySetup.BeginRelayJoin(m_localLobby, m_localUser, OnRelayConnected);
}
void OnRelayConnected(bool didSucceed, RelayUtpClient client)
{
Component.Destroy(m_relaySetup);
m_relaySetup = null;
if (!didSucceed)
m_RelaySetup = gameObject.AddComponent<RelayUtpSetup_Client>();
m_RelaySetup.BeginRelayJoin(m_localLobby, m_localUser);
Debug.LogError("Relay connection failed! Retrying in 5s...");
StartCoroutine(RetryRelayConnection());
return;
m_relayClient = client;
}
IEnumerator RetryRelayConnection()
{
yield return new WaitForSeconds(5);
StartRelayConnection();
}
void OnLeftLobby()

m_lobbyContentHeartbeat.EndTracking();
LobbyAsyncRequests.Instance.EndTracking();
if (m_RelaySetup != null)
{
Component.Destroy(m_RelaySetup);
m_RelaySetup = null;
if (m_relaySetup != null)
{ Component.Destroy(m_relaySetup);
m_relaySetup = null;
}
if (m_relayClient != null)
{ Component.Destroy(m_relayClient);
m_relayClient = null;
}
}

/// </summary>
IEnumerator CountDown()
{
m_ReadyCheck.EndCheckingForReady();
m_readyCheck.EndCheckingForReady();
while (m_localLobby.CountDownTime > 0)
{
yield return new WaitForSeconds(0.2f);

// TODO TRANSPORT: Move Relay Join to Pre-Countdown, and do connection and health checks before counting down for the game start.
//RelayInterface.JoinAsync(m_localLobby.RelayCode, OnJoinedRelay);
}
/// <summary>
/// Non Hosts Connect to server Here
/// </summary>
void OnJoinedRelay(JoinAllocation joinData)
{
m_localUser.UserStatus = UserStatus.Connected;
var ip = joinData.RelayServer.IpV4;
var port = joinData.RelayServer.Port;
m_localLobby.RelayServer = new ServerAddress(ip, port);
}
void ToLobby()
{

SetGameState(GameState.Lobby);
m_localUser.UserStatus = UserStatus.Lobby;
if (m_localUser.IsHost)
m_ReadyCheck.BeginCheckingForReady();
m_readyCheck.BeginCheckingForReady();
}
void ResetLocalLobby()

m_localLobby.RelayServer = null;
m_ReadyCheck.EndCheckingForReady();
m_readyCheck.EndCheckingForReady();
}
void OnDestroy()

76
Assets/Scripts/Entities/LobbyUser.cs


public LobbyUser(bool isHost = false, string displayName = null, string id = null, EmoteType emote = EmoteType.None, string userStatus = null)
{
m_isHost = isHost;
m_DisplayName = displayName;
m_ID = id;
m_Emote = emote;
m_displayName = displayName;
m_id = id;
m_emote = emote;
m_UserStatus = status;
m_userStatus = status;
bool m_isHost;
/// <summary>
/// Used for limiting costly OnChanged actions to just the members which actually changed.
/// </summary>
[Flags]
public enum UserMembers { IsHost = 1, DisplayName = 2, Emote = 4, ID = 8, UserStatus = 16 }
private UserMembers m_lastChanged;
public UserMembers LastChanged => m_lastChanged;
bool m_isHost;
public bool IsHost
{
get { return m_isHost; }

{
m_isHost = value;
m_lastChanged = UserMembers.IsHost;
string m_DisplayName = "";
string m_displayName = "";
get => m_DisplayName;
get => m_displayName;
if (m_DisplayName != value)
if (m_displayName != value)
m_DisplayName = value;
m_displayName = value;
m_lastChanged = UserMembers.DisplayName;
EmoteType m_Emote = EmoteType.None;
EmoteType m_emote = EmoteType.None;
get => m_Emote;
get => m_emote;
if (m_Emote != value)
if (m_emote != value)
m_Emote = value;
m_emote = value;
m_lastChanged = UserMembers.Emote;
string m_ID = "";
string m_id = "";
get => m_ID;
get => m_id;
if (m_ID != value)
if (m_id != value)
m_ID = value;
m_id = value;
m_lastChanged = UserMembers.ID;
UserStatus m_UserStatus = UserStatus.Menu;
UserStatus m_userStatus = UserStatus.Menu;
get => m_UserStatus;
get => m_userStatus;
m_UserStatus = value;
m_userStatus = value;
m_lastChanged = UserMembers.UserStatus;
OnChanged(this);
}
}

m_DisplayName = oldObserved.m_DisplayName;
m_Emote = oldObserved.m_Emote;
m_ID = oldObserved.m_ID;
int lastChanged = // Set flags just for the members that will be changed.
(m_displayName == oldObserved.m_displayName ? 0 : (int)UserMembers.DisplayName) |
(m_emote == oldObserved.m_emote ? 0 : (int)UserMembers.Emote) |
(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);
m_displayName = oldObserved.m_displayName;
m_emote = oldObserved.m_emote;
m_id = oldObserved.m_id;
m_UserStatus = oldObserved.m_UserStatus;
OnChanged(this);
m_userStatus = oldObserved.m_userStatus;
m_lastChanged = (UserMembers)lastChanged;
if (lastChanged != 0) // Ensure something actually changed.
OnChanged(this);
}
}
}

4
Assets/Scripts/LobbyRelaySample.asmdef


"GUID:5540e30183c82e84b954c033c388e06c",
"GUID:fe25561d224ed4743af4c60938a59d0b",
"GUID:4c3f49d89436d478ea78315c03159dcc",
"GUID:f2d49d9fa7e7eb3418e39723a7d3b92f",
"GUID:e0cd26848372d4e5c891c569017e11f1",
"GUID:8a2eafa29b15f444eb6d74f94a930e1d"
"GUID:f2d49d9fa7e7eb3418e39723a7d3b92f"
],
"includePlatforms": [],
"excludePlatforms": [],

28
Assets/Scripts/Relay/RelayUtpSetup.cs


using LobbyRelaySample;
using System;
using System;
using Unity.Collections;
using Unity.Jobs;
using Unity.Networking.Transport;
using Unity.Networking.Transport.Relay;

/// Responsible for setting up a connection with Relay using UTP, for the lobby host.
/// Must be a MonoBehaviour since the binding process doesn't have asynchronous callback options.
/// </summary>
public abstract class RelayUTPSetup : MonoBehaviour
public abstract class RelayUtpSetup : MonoBehaviour
{
protected bool m_isRelayConnected = false;
protected NetworkDriver m_networkDriver;

protected LocalLobby m_localLobby;
protected LobbyUser m_localUser;
protected Action<bool, string> m_onJoinComplete;
protected Action<bool, RelayUtpClient> m_onJoinComplete;
public void BeginRelayJoin(LocalLobby localLobby, LobbyUser localUser)//, Action<bool, string> onJoinComplete)
public void BeginRelayJoin(LocalLobby localLobby, LobbyUser localUser, Action<bool, RelayUtpClient> onJoinComplete)
// m_onJoinComplete = onJoinComplete;
m_onJoinComplete = onJoinComplete;
JoinRelay();
}
protected abstract void JoinRelay();

#endregion
}
public class RelayUtpSetup_Host : RelayUTPSetup
public class RelayUtpSetupHost : RelayUtpSetup
{
protected override void JoinRelay()
{

if (m_networkDriver.Listen() != 0)
{
Debug.LogError("Server failed to listen");
m_onJoinComplete(false, null);
// TODO: Be able to dispose.
RelayHost host = gameObject.AddComponent<RelayHost>();
RelayUtpHost host = gameObject.AddComponent<RelayUtpHost>();
m_onJoinComplete(true, host);
public class RelayUtpSetup_Client : RelayUTPSetup
public class RelayUtpSetupClient : RelayUtpSetup
{
protected override void JoinRelay()
{

yield return null;
}
if (m_networkDriver.GetConnectionState(m_connections[0]) != NetworkConnection.State.Connected)
{
m_onJoinComplete(false, null);
}
// TODO: Be able to dispose.
RelayUserWatcher watcher = gameObject.AddComponent<RelayUserWatcher>();
RelayUtpClient watcher = gameObject.AddComponent<RelayUtpClient>();
m_onJoinComplete(true, watcher);
}
}
}

9
Packages/packages-lock.json


"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.jobs": {
"version": "file:com.unity.jobs",
"depth": 0,
"source": "embedded",
"dependencies": {
"com.unity.collections": "0.17.0-preview.18",
"com.unity.mathematics": "1.2.1"
}
},
"com.unity.mathematics": {
"version": "1.2.1",
"depth": 1,

188
Assets/Scripts/Relay/RelayUtpClient.cs


using System.Collections.Generic;
using Unity.Networking.Transport;
using UnityEngine;
using MsgType = LobbyRelaySample.Relay.RelayUtpSetup.MsgType;
namespace LobbyRelaySample.Relay
{
/// <summary>
/// This will handle observing the local player and updating remote players over Relay when there are local changes.
/// Created after the connection to Relay has been confirmed.
/// </summary>
public class RelayUtpClient : MonoBehaviour // This is a MonoBehaviour merely to have access to Update.
{
protected LobbyUser m_localUser;
protected LocalLobby m_localLobby;
protected NetworkDriver m_networkDriver;
protected List<NetworkConnection> m_connections; // For clients, this has just one member, but for hosts it will have more.
private bool m_hasSentInitialMessage = false;
public void Initialize(NetworkDriver networkDriver, List<NetworkConnection> connections, LobbyUser localUser, LocalLobby localLobby)
{
m_localUser = localUser;
m_localLobby = localLobby;
m_localUser.onChanged += OnLocalChange;
m_networkDriver = networkDriver;
m_connections = connections;
if (this is RelayUtpHost) // The host will be alone in the lobby at first, so they need not send any messages right away.
m_hasSentInitialMessage = true;
}
public void OnDestroy()
{
m_localUser.onChanged -= OnLocalChange;
}
private void OnLocalChange(LobbyUser localUser)
{
if (m_connections.Count == 0) // This could be the case for the host alone in the lobby.
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.
}
public void Update()
{
OnUpdate();
}
protected virtual void OnUpdate()
{
m_networkDriver.ScheduleUpdate().Complete(); // This pumps all messages, which pings the Relay allocation and keeps it alive.
ReceiveNetworkEvents(m_networkDriver, m_connections);
if (!m_hasSentInitialMessage)
SendInitialMessage(m_networkDriver, m_connections[0]);
}
private void ReceiveNetworkEvents(NetworkDriver driver, List<NetworkConnection> connections) // TODO: Just the one connection. Also not NativeArray.
{
DataStreamReader strm;
NetworkEvent.Type cmd;
foreach (NetworkConnection connection in connections)
{
while ((cmd = connection.PopEvent(driver, out strm)) != NetworkEvent.Type.Empty)
{
ProcessNetworkEvent(strm, cmd);
}
}
}
private void ProcessNetworkEvent(DataStreamReader strm, NetworkEvent.Type cmd)
{
if (cmd == NetworkEvent.Type.Data)
{
MsgType msgType = (MsgType)strm.ReadByte();
string id = ReadLengthAndString(ref strm);
if (id == m_localUser.ID || !m_localLobby.LobbyUsers.ContainsKey(id))
return;
if (msgType == MsgType.PlayerName)
{
string name = ReadLengthAndString(ref strm);
m_localLobby.LobbyUsers[id].DisplayName = name;
Debug.LogError("User id " + id + " is named " + name);
}
else if (msgType == MsgType.Emote)
{
EmoteType emote = (EmoteType)strm.ReadByte();
m_localLobby.LobbyUsers[id].Emote = emote;
Debug.LogError("User id " + id + " has emote " + emote.ToString());
}
else if (msgType == MsgType.ReadyState)
{
UserStatus status = (UserStatus)strm.ReadByte();
m_localLobby.LobbyUsers[id].UserStatus = status;
Debug.LogError("User id " + id + " has state " + status.ToString());
}
ProcessNetworkEventDataAdditional(strm, cmd, msgType, id);
}
}
protected virtual void ProcessNetworkEventDataAdditional(DataStreamReader strm, NetworkEvent.Type cmd, MsgType msgType, string id) { }
unsafe private string ReadLengthAndString(ref DataStreamReader strm)
{
byte length = strm.ReadByte();
byte[] bytes = new byte[length];
fixed (byte* ptr = bytes)
{
strm.ReadBytes(ptr, length);
}
return System.Text.Encoding.UTF8.GetString(bytes);
}
private void SendInitialMessage(NetworkDriver driver, NetworkConnection connection)
{
DoUserUpdate(driver, connection); // Assuming this is only created after the Relay connection is successful.
m_hasSentInitialMessage = true;
}
private void DoUserUpdate(NetworkDriver driver, NetworkConnection connection)
{
// Only update with actual changes. (If multiple change at once, we send messages for each separately, but that shouldn't happen often.)
if (0 < (m_localUser.LastChanged & LobbyUser.UserMembers.DisplayName))
WriteString(driver, connection, MsgType.PlayerName, m_localUser.DisplayName);
if (0 < (m_localUser.LastChanged & LobbyUser.UserMembers.Emote))
WriteByte(driver, connection, MsgType.Emote, (byte)m_localUser.Emote);
if (0 < (m_localUser.LastChanged & LobbyUser.UserMembers.UserStatus))
WriteByte(driver, connection, MsgType.ReadyState, (byte)m_localUser.UserStatus);
}
/// <summary>
/// Write string data as: [1 byte: msgType][1 byte: id length N][N bytes: id][1 byte: string length M][M bytes: string]
/// </summary>
private void WriteString(NetworkDriver driver, NetworkConnection connection, MsgType msgType, string str)
{
byte[] idBytes = System.Text.Encoding.UTF8.GetBytes(m_localUser.ID);
byte[] strBytes = System.Text.Encoding.UTF8.GetBytes(str);
List<byte> message = new List<byte>(idBytes.Length + strBytes.Length + 3);
message.Add((byte)msgType);
message.Add((byte)idBytes.Length);
message.AddRange(idBytes);
message.Add((byte)strBytes.Length);
message.AddRange(strBytes);
if (driver.BeginSend(connection, out var dataStream) == 0) // Oh, should check this first?
{
byte[] bytes = message.ToArray();
unsafe
{
fixed (byte* bytesPtr = bytes)
{
dataStream.WriteBytes(bytesPtr, message.Count);
driver.EndSend(dataStream);
}
}
}
}
/// <summary>
/// Write byte data as: [1 byte: msgType][1 byte: id length N][N bytes: id][1 byte: data]
/// </summary>
private void WriteByte(NetworkDriver driver, NetworkConnection connection, MsgType msgType, byte value)
{
byte[] idBytes = System.Text.Encoding.UTF8.GetBytes(m_localUser.ID);
List<byte> message = new List<byte>(idBytes.Length + 3);
message.Add((byte)msgType);
message.Add((byte)idBytes.Length);
message.AddRange(idBytes);
message.Add(value);
if (driver.BeginSend(connection, out var dataStream) == 0) // Oh, should check this first?
{
byte[] bytes = message.ToArray();
unsafe
{
fixed (byte* bytesPtr = bytes)
{
dataStream.WriteBytes(bytesPtr, message.Count);
driver.EndSend(dataStream);
}
}
}
}
}
}

44
Assets/Scripts/Relay/RelayUtpHost.cs


using Unity.Networking.Transport;
using MsgType = LobbyRelaySample.Relay.RelayUtpSetup.MsgType;
namespace LobbyRelaySample.Relay
{
public class RelayUtpHost : RelayUtpClient
{
protected override void OnUpdate()
{
base.OnUpdate();
DoHeartbeat();
}
protected override void ProcessNetworkEventDataAdditional(DataStreamReader strm, NetworkEvent.Type cmd, MsgType msgType, string id)
{
// Note that the strm contents might have already been consumed, depending on the msgType.
if (msgType == MsgType.ReadyState)
{
// TODO: Check if all players have readied.
}
}
/// <summary>
/// Clean out destroyed connections, and accept all new ones.
/// </summary>
private void DoHeartbeat()
{
m_networkDriver.ScheduleUpdate().Complete();
for (int c = m_connections.Count - 1; c >= 0; c--)
{
if (!m_connections[c].IsCreated)
m_connections.RemoveAt(c);
}
while (true)
{
var con = m_networkDriver.Accept();
if (!con.IsCreated) // "Nothing more to accept" is signalled by returning an invalid connection from Accept.
break;
m_connections.Add(con);
}
}
}
}

51
Assets/Scripts/Relay/RelayHost.cs


using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Jobs;
using Unity.Networking.Transport;
using Unity.Networking.Transport.Relay;
using Unity.Services.Relay.Models;
using UnityEngine;
using MsgType = LobbyRelaySample.Relay.RelayUTPSetup.MsgType;
namespace LobbyRelaySample.Relay
{
public class RelayHost : RelayUserWatcher
{
protected override void OnUpdate()
{
base.OnUpdate();
DoHeartbeat();
}
protected override void ProcessNetworkEvent(DataStreamReader strm, NetworkEvent.Type cmd)
{
base.ProcessNetworkEvent(strm, cmd);
// TODO: The only thing this has to care about is if all players have readied up.
}
private void DoHeartbeat()
{
// Update the driver should be the first job in the chain
m_networkDriver.ScheduleUpdate().Complete();
// Remove connections which have been destroyed from the list of active connections
for (int c = m_connections.Count - 1; c >= 0; c--)
{
if (!m_connections[c].IsCreated)
m_connections.RemoveAtSwapBack(c);
}
// Accept all new connections
while (true)
{
var con = m_networkDriver.Accept();
// "Nothing more to accept" is signaled by returning an invalid connection from accept
if (!con.IsCreated)
break;
m_connections.Add(con);
}
}
}
}

192
Assets/Scripts/Relay/RelayUserWatcher.cs


using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Jobs;
using Unity.Networking.Transport;
using Unity.Networking.Transport.Relay;
using Unity.Services.Relay.Models;
using UnityEngine;
using MsgType = LobbyRelaySample.Relay.RelayUTPSetup.MsgType;
namespace LobbyRelaySample.Relay
{
/// <summary>
/// This will handle observing the local user and updating remote users over Relay when there are local changes.
/// Created after the connection to Relay has been confirmed.
/// </summary>
public class RelayUserWatcher : MonoBehaviour, IDisposable
{
protected LobbyUser m_localUser;
protected LocalLobby m_localLobby;
private bool m_hasDisposed = false;
protected NetworkDriver m_networkDriver;
protected List<NetworkConnection> m_connections; // TODO: Make it clearer that this is just the one member?
private bool m_hasSentInitialMessage = false;
public void Initialize(NetworkDriver networkDriver, List<NetworkConnection> connections, LobbyUser localUser, LocalLobby localLobby)
{
m_localUser = localUser;
m_localLobby = localLobby;
m_localUser.onChanged += OnLocalChange; // TODO: This should break up the state type?
m_networkDriver = networkDriver;
m_connections = connections;
}
public void Dispose()
{
if (!m_hasDisposed)
{
m_localUser.onChanged -= OnLocalChange;
m_hasDisposed = true;
}
}
~RelayUserWatcher() { Dispose(); } // TODO: Disposable or MonoBehaviour?
private void OnLocalChange(LobbyUser localUser)
{
if (m_connections.Count == 0) // Could be the case for the server, should probably actually break that out after all?
return;
m_networkDriver.ScheduleUpdate().Complete();
DoUserUpdate(m_networkDriver, m_connections[0]); // TODO: Hmm...I don't think this ends up working if the host has to manually transmit changes over all connections.
}
public void Update()
{
OnUpdate();
}
protected virtual void OnUpdate()
{
m_networkDriver.ScheduleUpdate().Complete();
ReceiveNetworkEvents(m_networkDriver, m_connections);
if (!m_hasSentInitialMessage && !(this is RelayHost))
SendInitialMessage(m_networkDriver, m_connections[0]);
}
private void ReceiveNetworkEvents(NetworkDriver driver, List<NetworkConnection> connections) // TODO: Just the one connection. Also not NativeArray.
{
DataStreamReader strm;
NetworkEvent.Type cmd;
foreach (NetworkConnection connection in connections)
{
while ((cmd = connection.PopEvent(driver, out strm)) != NetworkEvent.Type.Empty)
{
ProcessNetworkEvent(strm, cmd);
}
}
}
protected virtual void ProcessNetworkEvent(DataStreamReader strm, NetworkEvent.Type cmd)
{
if (cmd == NetworkEvent.Type.Data)
{
MsgType msgType = (MsgType)strm.ReadByte();
string id = ReadLengthAndString(ref strm);
if (id == m_localUser.ID || !m_localLobby.LobbyUsers.ContainsKey(id))
return;
if (msgType == MsgType.PlayerName)
{
string name = ReadLengthAndString(ref strm);
m_localLobby.LobbyUsers[id].DisplayName = name;
Debug.LogError("User id " + id + " is named " + name);
}
else if (msgType == MsgType.Emote)
{
EmoteType emote = (EmoteType)strm.ReadByte();
m_localLobby.LobbyUsers[id].Emote = emote;
Debug.LogError("User id " + id + " has emote " + emote.ToString());
}
else if (msgType == MsgType.ReadyState)
{
UserStatus status = (UserStatus)strm.ReadByte();
m_localLobby.LobbyUsers[id].UserStatus = status;
Debug.LogError("User id " + id + " has state " + status.ToString());
}
}
}
unsafe private string ReadLengthAndString(ref DataStreamReader strm)
{
byte length = strm.ReadByte();
byte[] bytes = new byte[length];
fixed (byte* ptr = bytes)
{
strm.ReadBytes(ptr, length);
}
return System.Text.Encoding.UTF8.GetString(bytes);
}
private void SendInitialMessage(NetworkDriver driver, NetworkConnection connection)
{
// Assuming this is only created after the Relay connection is successful.
// TODO: Retry logic for that?
DoUserUpdate(driver, connection);
m_hasSentInitialMessage = true;
}
private void DoUserUpdate(NetworkDriver driver, NetworkConnection connection)
{
// TODO: Combine these all into one message, if I'm just going to send them all each time anyway.
WriteString(driver, connection, MsgType.PlayerName, m_localUser.DisplayName);
WriteByte(driver, connection, MsgType.Emote, (byte)m_localUser.Emote);
WriteByte(driver, connection, MsgType.ReadyState, (byte)m_localUser.UserStatus);
}
// TODO: We do have a character limit on the name entry field, right?
// Msg type, ID length, ID, str length, str
// Not doing bit packing.
private void WriteString(NetworkDriver driver, NetworkConnection connection, MsgType msgType, string str)
{
byte[] idBytes = System.Text.Encoding.UTF8.GetBytes(m_localUser.ID);
byte[] strBytes = System.Text.Encoding.UTF8.GetBytes(str);
List<byte> message = new List<byte>(idBytes.Length + strBytes.Length + 3);
message.Add((byte)msgType);
message.Add((byte)idBytes.Length);
message.AddRange(idBytes);
message.Add((byte)strBytes.Length);
message.AddRange(strBytes);
if (driver.BeginSend(connection, out var dataStream) == 0) // Oh, should check this first?
{
byte[] bytes = message.ToArray();
unsafe
{
fixed (byte* bytesPtr = bytes)
{
dataStream.WriteBytes(bytesPtr, message.Count);
driver.EndSend(dataStream);
}
}
}
}
private void WriteByte(NetworkDriver driver, NetworkConnection connection, MsgType msgType, byte value)
{
byte[] idBytes = System.Text.Encoding.UTF8.GetBytes(m_localUser.ID);
List<byte> message = new List<byte>(idBytes.Length + 3);
message.Add((byte)msgType);
message.Add((byte)idBytes.Length);
message.AddRange(idBytes);
message.Add(value);
if (driver.BeginSend(connection, out var dataStream) == 0) // Oh, should check this first?
{
byte[] bytes = message.ToArray();
unsafe
{
fixed (byte* bytesPtr = bytes)
{
dataStream.WriteBytes(bytesPtr, message.Count);
driver.EndSend(dataStream);
}
}
}
}
}
}

/Assets/Scripts/Relay/RelayHost.cs.meta → /Assets/Scripts/Relay/RelayUtpHost.cs.meta

/Assets/Scripts/Relay/RelayUserWatcher.cs.meta → /Assets/Scripts/Relay/RelayUtpClient.cs.meta

正在加载...
取消
保存