-
-
Save Deathwing/8c8a5c1ed68c87e6ee31b67fd8aa8db0 to your computer and use it in GitHub Desktop.
Initialization Code supporting Relay for Unity 2022.2.0f1 with NetCode for Entities 1.0.0-pre.15
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Unity.Assertions; | |
using Unity.Entities; | |
using Unity.NetCode; | |
using Unity.Networking.Transport; | |
using Unity.Networking.Transport.Relay; | |
using UnityEngine.Scripting; | |
namespace NetCode | |
{ | |
[Preserve] | |
public sealed class NetCodeBootstrap : ClientServerBootstrap | |
{ | |
public override bool Initialize(string defaultWorldName) => false; | |
public static void Prepare(PlayType requestedPlayType, RelayServerData? relayData = null) | |
{ | |
EnsureRequestedPlayTypeIsSupported(requestedPlayType); | |
EnsureNoNetCodeWorldExists(); | |
if (requestedPlayType != PlayType.Client) | |
{ | |
EnsureCorrectDriverConstructorIsSelected(requestedPlayType, relayData, WorldFlags.GameServer); | |
CreateServerWorld("ServerWorld"); | |
} | |
if (requestedPlayType != PlayType.Server) | |
{ | |
EnsureCorrectDriverConstructorIsSelected(requestedPlayType, relayData, WorldFlags.GameClient); | |
CreateClientWorld("ClientWorld"); | |
#if UNITY_EDITOR | |
EnsureCorrectDriverConstructorIsSelected(requestedPlayType, relayData, WorldFlags.GameThinClient); | |
var requestedNumThinClients = RequestedNumThinClients; | |
for (var i = 0; i < requestedNumThinClients; i++) | |
CreateThinClientWorld(); | |
#endif | |
} | |
} | |
static void EnsureRequestedPlayTypeIsSupported(PlayType requestedPlayType) | |
{ | |
switch (ClientServerBootstrap.RequestedPlayType) | |
{ | |
case PlayType.Client: | |
if (requestedPlayType == PlayType.ClientAndServer || requestedPlayType == PlayType.Server) | |
throw new System.NotSupportedException("Cannot run a server on a client-only process"); | |
return; | |
case PlayType.Server: | |
if (requestedPlayType == PlayType.ClientAndServer || requestedPlayType == PlayType.Client) | |
throw new System.NotSupportedException("Cannot run a client on a server-only process"); | |
return; | |
} | |
} | |
static void EnsureNoNetCodeWorldExists() | |
{ | |
for (var i = World.All.Count - 1; i >= 0; --i) | |
if (World.All[i].IsClient() || World.All[i].IsServer() || World.All[i].IsThinClient()) | |
World.All[i].Dispose(); | |
} | |
static void EnsureCorrectDriverConstructorIsSelected(PlayType requestedPlayType, RelayServerData? relayData, WorldFlags flags) | |
{ | |
if (relayData.HasValue && (requestedPlayType != PlayType.ClientAndServer || flags == WorldFlags.GameServer)) | |
NetworkStreamReceiveSystem.DriverConstructor = new RelayIPCAndSocketDriverConstructor(relayData.Value); | |
else | |
NetworkStreamReceiveSystem.DriverConstructor = DefaultDriverBuilder.DefaultDriverConstructor; | |
} | |
struct RelayIPCAndSocketDriverConstructor : INetworkStreamDriverConstructor | |
{ | |
RelayServerData relayData; | |
public RelayIPCAndSocketDriverConstructor(RelayServerData relayData) | |
{ | |
this.relayData = relayData; | |
} | |
public void CreateClientDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug) | |
{ | |
// TODO: Check after NetCode update | |
var settings = DefaultDriverBuilder.GetNetworkSettings(); | |
settings = settings.WithRelayParameters(ref relayData); | |
Assert.IsTrue(ClientServerBootstrap.RequestedPlayType != ClientServerBootstrap.PlayType.Server); | |
Assert.IsTrue(world.IsClient()); | |
netDebug.DebugLog("Create client relay socket network interface driver"); | |
var driverInstance = DefaultDriverBuilder.CreateClientNetworkDriver(new UDPNetworkInterface(), settings); | |
driverStore.RegisterDriver(TransportType.Socket, driverInstance); | |
} | |
public void CreateServerDriver(World world, ref NetworkDriverStore driverStore, NetDebug netDebug) | |
{ | |
// TODO: Check after NetCode update | |
{ | |
var settings = DefaultDriverBuilder.GetNetworkServerSettings(playerCount: 0); | |
settings = settings.WithRelayParameters(ref relayData); | |
Assert.IsTrue(world.IsServer()); | |
netDebug.DebugLog("Create server relay socket network interface driver"); | |
var socketDriver = DefaultDriverBuilder.CreateServerNetworkDriver(new UDPNetworkInterface(), settings); | |
driverStore.RegisterDriver(TransportType.Socket, socketDriver); | |
} | |
{ | |
var settings = DefaultDriverBuilder.GetNetworkServerSettings(playerCount: 0); | |
Assert.IsTrue(world.IsServer()); | |
netDebug.DebugLog("Create server relay IPC network interface driver"); | |
var ipcDriver = DefaultDriverBuilder.CreateServerNetworkDriver(new IPCNetworkInterface(), settings); | |
driverStore.RegisterDriver(TransportType.IPC, ipcDriver); | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using static Unity.NetCode.ClientServerBootstrap; | |
using Unity.Entities; | |
using Unity.NetCode; | |
using Unity.Networking.Transport; | |
using Unity.Networking.Transport.Relay; | |
using UnityEngine; | |
namespace NetCode | |
{ | |
public static partial class NetCodeUtility | |
{ | |
public static void RequestHost(RelayServerData relayData) | |
{ | |
// TODO: Check after NetCode update | |
var port = (ushort)(UnityEngine.Random.Range(ushort.MinValue, ushort.MaxValue) + 1); | |
NetCodeBootstrap.Prepare(PlayType.ClientAndServer, relayData); | |
RequestServerListen(NetworkEndpoint.AnyIpv4.WithPort(port)); | |
RequestClientConnect(NetworkEndpoint.LoopbackIpv4.WithPort(port)); | |
} | |
public static void RequestHost(string listenAddress, string connectAddress, ushort port, NetworkFamily family) | |
{ | |
if (!NetworkEndpoint.TryParse(listenAddress, port, out var listenEndpoint, family)) | |
throw new InvalidOperationException($"Invalid network endpoint: {family}::{listenAddress}:{port}."); | |
if (!NetworkEndpoint.TryParse(connectAddress, port, out var connectEndpoint, family)) | |
throw new InvalidOperationException($"Invalid network endpoint: {family}::{connectAddress}:{port}."); | |
NetCodeBootstrap.Prepare(PlayType.ClientAndServer); | |
RequestServerListen(listenEndpoint); | |
RequestClientConnect(connectEndpoint); | |
} | |
public static void RequestServer(RelayServerData relayData) | |
{ | |
NetCodeBootstrap.Prepare(PlayType.Server, relayData); | |
RequestServerListen(NetworkEndpoint.AnyIpv4); | |
} | |
public static void RequestServer(string listenAddress, ushort port, NetworkFamily family) | |
{ | |
if (!NetworkEndpoint.TryParse(listenAddress, port, out var listenEndpoint, family)) | |
throw new InvalidOperationException($"Invalid network endpoint: {family}::{listenAddress}:{port}."); | |
NetCodeBootstrap.Prepare(PlayType.Server); | |
RequestServerListen(listenEndpoint); | |
} | |
public static void RequestClient(RelayServerData relayData) | |
{ | |
NetCodeBootstrap.Prepare(PlayType.Client, relayData); | |
RequestClientConnect(default(NetworkEndpoint)); | |
} | |
public static void RequestClient(string connectAddress, ushort port, NetworkFamily family) | |
{ | |
if (!NetworkEndpoint.TryParse(connectAddress, port, out var connectEndpoint, family)) | |
throw new InvalidOperationException($"Invalid network endpoint: {family}::{connectAddress}:{port}."); | |
NetCodeBootstrap.Prepare(PlayType.Client); | |
RequestClientConnect(connectEndpoint); | |
} | |
static void RequestServerListen(NetworkEndpoint endpoint) | |
{ | |
EntityManager entityManager = default; | |
foreach (var world in World.All) | |
if (world.Flags == WorldFlags.GameServer) | |
entityManager = world.EntityManager; | |
if (entityManager == default) | |
throw new InvalidOperationException("No server world found."); | |
// TODO: Check after NetCode update | |
var listenRequest = entityManager.CreateEntity(typeof(ServerListenRequest)); | |
entityManager.SetComponentData(listenRequest, new ServerListenRequest { Endpoint = endpoint }); | |
Debug.Log($"Listening on {endpoint}"); | |
} | |
static void RequestClientConnect(NetworkEndpoint endpoint) | |
{ | |
EntityManager entityManager = default; | |
foreach (var world in World.All) | |
if (world.Flags == WorldFlags.GameClient) | |
entityManager = world.EntityManager; | |
if (entityManager == default) | |
throw new InvalidOperationException("No client world found."); | |
// TODO: Check after NetCode update | |
var connectRequest = entityManager.CreateEntity(typeof(ClientConnectRequest)); | |
entityManager.SetComponentData(connectRequest, new ClientConnectRequest { Endpoint = endpoint }); | |
Debug.Log($"Connecting on {endpoint}"); | |
} | |
struct ServerListenRequest : IComponentData | |
{ | |
public NetworkEndpoint Endpoint; | |
} | |
[WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] | |
[CreateAfter(typeof(NetworkStreamReceiveSystem))] | |
partial struct ServerListenSystem : ISystem | |
{ | |
public void OnCreate(ref SystemState state) | |
{ | |
state.RequireForUpdate<ServerListenRequest>(); | |
} | |
public void OnDestroy(ref SystemState state) | |
{ | |
} | |
public void OnUpdate(ref SystemState state) | |
{ | |
var listenRequest = SystemAPI.GetSingleton<ServerListenRequest>(); | |
var entity = SystemAPI.GetSingletonEntity<ServerListenRequest>(); | |
SystemAPI.GetSingletonRW<NetworkStreamDriver>().ValueRW.Listen(listenRequest.Endpoint); | |
state.EntityManager.RemoveComponent<ServerListenRequest>(entity); | |
} | |
} | |
struct ClientConnectRequest : IComponentData | |
{ | |
public NetworkEndpoint Endpoint; | |
} | |
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation | WorldSystemFilterFlags.ThinClientSimulation)] | |
[CreateAfter(typeof(NetworkStreamReceiveSystem))] | |
partial struct ClientConnectSystem : ISystem | |
{ | |
public void OnCreate(ref SystemState state) | |
{ | |
state.RequireForUpdate<ClientConnectRequest>(); | |
} | |
public void OnDestroy(ref SystemState state) | |
{ | |
} | |
public void OnUpdate(ref SystemState state) | |
{ | |
var connectRequest = SystemAPI.GetSingleton<ClientConnectRequest>(); | |
var entity = SystemAPI.GetSingletonEntity<ClientConnectRequest>(); | |
SystemAPI.GetSingletonRW<NetworkStreamDriver>().ValueRW.Connect(state.EntityManager, connectRequest.Endpoint); | |
state.EntityManager.RemoveComponent<ClientConnectRequest>(entity); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment