Added more core features & object / player spawning
This commit is contained in:
parent
c102935df1
commit
4a280c08e3
10
MLAPI/Data/NetworkedClient.cs
Normal file
10
MLAPI/Data/NetworkedClient.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MLAPI
|
||||||
|
{
|
||||||
|
public class NetworkedClient
|
||||||
|
{
|
||||||
|
public int ClientId;
|
||||||
|
public GameObject PlayerObject;
|
||||||
|
}
|
||||||
|
}
|
74
MLAPI/Data/NetworkingConfiguration.cs
Normal file
74
MLAPI/Data/NetworkingConfiguration.cs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using UnityEngine.Networking;
|
||||||
|
|
||||||
|
namespace MLAPI
|
||||||
|
{
|
||||||
|
public class NetworkingConfiguration
|
||||||
|
{
|
||||||
|
public ushort ProtocolVersion = 0;
|
||||||
|
public Dictionary<string, QosType> Channels = new Dictionary<string, QosType>();
|
||||||
|
public List<string> MessageTypes = new List<string>();
|
||||||
|
public int MessageBufferSize = 65536;
|
||||||
|
public int MaxMessagesPerFrame = 150;
|
||||||
|
public int MaxConnections = 100;
|
||||||
|
public int Port = 7777;
|
||||||
|
public string Address;
|
||||||
|
public int ClientConnectionBufferTimeout = 10;
|
||||||
|
public bool ConnectionApproval = false;
|
||||||
|
public Action<byte[], int, Action<int, bool>> ConnectionApprovalCallback;
|
||||||
|
public byte[] ConnectionData;
|
||||||
|
public bool HandleObjectSpawning = true;
|
||||||
|
//TODO
|
||||||
|
public bool CompressMessages = false;
|
||||||
|
//Should only be used for dedicated servers and will require the servers RSA keypair being hard coded into clients in order to exchange a AES key
|
||||||
|
//TODO
|
||||||
|
public bool EncryptMessages = false;
|
||||||
|
|
||||||
|
|
||||||
|
//Cached config hash
|
||||||
|
private byte[] ConfigHash = null;
|
||||||
|
public byte[] GetConfig(bool cache = true)
|
||||||
|
{
|
||||||
|
if (ConfigHash != null && cache)
|
||||||
|
return ConfigHash;
|
||||||
|
|
||||||
|
using(MemoryStream writeStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using(BinaryWriter writer = new BinaryWriter(writeStream))
|
||||||
|
{
|
||||||
|
writer.Write(ProtocolVersion);
|
||||||
|
foreach (KeyValuePair<string, QosType> pair in Channels)
|
||||||
|
{
|
||||||
|
writer.Write(pair.Key);
|
||||||
|
writer.Write((int)pair.Value);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < MessageTypes.Count; i++)
|
||||||
|
{
|
||||||
|
writer.Write(MessageTypes[i]);
|
||||||
|
}
|
||||||
|
writer.Write(HandleObjectSpawning);
|
||||||
|
writer.Write(CompressMessages);
|
||||||
|
writer.Write(EncryptMessages);
|
||||||
|
}
|
||||||
|
using(SHA256Managed sha256 = new SHA256Managed())
|
||||||
|
{
|
||||||
|
//Returns a 256 bit / 32 byte long checksum of the config
|
||||||
|
if (cache)
|
||||||
|
{
|
||||||
|
ConfigHash = sha256.ComputeHash(writeStream);
|
||||||
|
return ConfigHash;
|
||||||
|
}
|
||||||
|
return sha256.ComputeHash(writeStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CompareConfig(byte[] hash)
|
||||||
|
{
|
||||||
|
return hash == GetConfig();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -35,20 +35,18 @@
|
|||||||
<Reference Include="System.Core" />
|
<Reference Include="System.Core" />
|
||||||
<Reference Include="System.Xml.Linq" />
|
<Reference Include="System.Xml.Linq" />
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
<Reference Include="Microsoft.CSharp" />
|
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Net.Http" />
|
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
<Reference Include="UnityEngine">
|
<Reference Include="UnityEngine">
|
||||||
<HintPath>..\..\..\..\..\..\Program Files\Unity\Editor\Data\Managed\UnityEngine.dll</HintPath>
|
<HintPath>..\..\..\..\..\..\Program Files\Unity\Editor\Data\Managed\UnityEngine.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="NetworkedBehaviour.cs" />
|
<Compile Include="MonoBehaviours\Core\NetworkedBehaviour.cs" />
|
||||||
<Compile Include="NetworkedClient.cs" />
|
<Compile Include="Data\NetworkedClient.cs" />
|
||||||
<Compile Include="NetworkedObject.cs" />
|
<Compile Include="MonoBehaviours\Core\NetworkedObject.cs" />
|
||||||
<Compile Include="NetworkingConfiguration.cs" />
|
<Compile Include="Data\NetworkingConfiguration.cs" />
|
||||||
<Compile Include="NetworkingManager.cs" />
|
<Compile Include="MonoBehaviours\Core\NetworkingManager.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
82
MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs
Normal file
82
MLAPI/MonoBehaviours/Core/NetworkedBehaviour.cs
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MLAPI
|
||||||
|
{
|
||||||
|
public abstract class NetworkedBehaviour : MonoBehaviour
|
||||||
|
{
|
||||||
|
protected bool isLocalPlayer
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return networkedObject.isLocalPlayer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected bool isServer = NetworkingManager.singleton.isServer;
|
||||||
|
protected NetworkedObject networkedObject
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(_networkedObject == null)
|
||||||
|
{
|
||||||
|
_networkedObject = GetComponentInParent<NetworkedObject>();
|
||||||
|
}
|
||||||
|
return _networkedObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private NetworkedObject _networkedObject = null;
|
||||||
|
protected uint netId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return networkedObject.NetworkId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Change data type
|
||||||
|
private Dictionary<string, int> registeredMessageHandlers = new Dictionary<string, int>();
|
||||||
|
|
||||||
|
public int RegisterMessageHandler(string name, Action<int, byte[]> action)
|
||||||
|
{
|
||||||
|
int counter = NetworkingManager.singleton.AddIncomingMessageHandler(name, action);
|
||||||
|
registeredMessageHandlers.Add(name, counter);
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeregisterMessageHandler(string name, int counter)
|
||||||
|
{
|
||||||
|
NetworkingManager.singleton.RemoveIncomingMessageHandler(name, counter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<string, int> pair in registeredMessageHandlers)
|
||||||
|
{
|
||||||
|
DeregisterMessageHandler(pair.Key, pair.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Send(int connectionId, string messageType, string channelName, byte[] data)
|
||||||
|
{
|
||||||
|
Send(connectionId, messageType, channelName, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Send(int[] connectonIds, string messageType, string channelName, byte[] data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < connectonIds.Length; i++)
|
||||||
|
{
|
||||||
|
Send(connectonIds[i], messageType, channelName, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Send(List<int> connectonIds, string messageType, string channelName, byte[] data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < connectonIds.Count; i++)
|
||||||
|
{
|
||||||
|
Send(connectonIds[i], messageType, channelName, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
MLAPI/MonoBehaviours/Core/NetworkedObject.cs
Normal file
26
MLAPI/MonoBehaviours/Core/NetworkedObject.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace MLAPI
|
||||||
|
{
|
||||||
|
//TODO
|
||||||
|
//Will be used for objects which will be spawned automatically across clients
|
||||||
|
public class NetworkedObject : MonoBehaviour
|
||||||
|
{
|
||||||
|
public uint NetworkId;
|
||||||
|
public int OwnerClientId = -1;
|
||||||
|
public int SpawnablePrefabId;
|
||||||
|
internal bool IsPlayerObject = false;
|
||||||
|
public bool isLocalPlayer
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return OwnerClientId == NetworkingManager.singleton.MyClientId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
NetworkingManager.OnDestroyObject(NetworkId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
565
MLAPI/MonoBehaviours/Core/NetworkingManager.cs
Normal file
565
MLAPI/MonoBehaviours/Core/NetworkingManager.cs
Normal file
@ -0,0 +1,565 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.Networking;
|
||||||
|
using UnityEngine.SceneManagement;
|
||||||
|
|
||||||
|
namespace MLAPI
|
||||||
|
{
|
||||||
|
public class NetworkingManager : MonoBehaviour
|
||||||
|
{
|
||||||
|
public List<GameObject> SpawnablePrefabs;
|
||||||
|
public GameObject DefaultPlayerPrefab;
|
||||||
|
public static NetworkingManager singleton;
|
||||||
|
//Client only, what my connectionId is on the server
|
||||||
|
public int MyClientId;
|
||||||
|
private Dictionary<int, NetworkedClient> connectedClients;
|
||||||
|
private HashSet<int> pendingClients;
|
||||||
|
internal bool isServer;
|
||||||
|
internal bool isClient;
|
||||||
|
internal bool isHost
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return isServer && isClient;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool isListening;
|
||||||
|
private byte[] messageBuffer;
|
||||||
|
private Dictionary<string, int> channels;
|
||||||
|
private Dictionary<string, ushort> messageTypes;
|
||||||
|
private Dictionary<ushort, Dictionary<int, Action<int, byte[]>>> messageCallbacks;
|
||||||
|
private Dictionary<ushort, int> messageHandlerCounter;
|
||||||
|
private Dictionary<ushort, Stack<int>> releasedMessageHandlerCounters;
|
||||||
|
private int localConnectionId;
|
||||||
|
public Scene PlayScene;
|
||||||
|
public Scene MenuScene;
|
||||||
|
private Dictionary<uint, NetworkedObject> spawnedObjects;
|
||||||
|
private List<uint> spawnedObjectIds;
|
||||||
|
private Stack<uint> releasedNetworkObjectIds;
|
||||||
|
private uint networkObjectIdCounter;
|
||||||
|
private uint GetNetworkObjectId()
|
||||||
|
{
|
||||||
|
if (releasedNetworkObjectIds.Count > 0)
|
||||||
|
{
|
||||||
|
return releasedNetworkObjectIds.Pop();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
networkObjectIdCounter++;
|
||||||
|
return networkObjectIdCounter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public NetworkingConfiguration NetworkConfig;
|
||||||
|
|
||||||
|
private void OnValidate()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < SpawnablePrefabs.Count; i++)
|
||||||
|
{
|
||||||
|
if(SpawnablePrefabs[i].GetComponentInChildren<NetworkedObject>() == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: All SpawnablePrefabs need a NetworkedObject component. Please add one to the prefab " + SpawnablePrefabs[i].gameObject.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal GameObject SpawnObject(int spawnablePrefabIndex, uint networkId, int ownerId)
|
||||||
|
{
|
||||||
|
GameObject go = Instantiate(singleton.SpawnablePrefabs[spawnablePrefabIndex]);
|
||||||
|
NetworkedObject netObject = go.GetComponent<NetworkedObject>();
|
||||||
|
if(netObject == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: Please add a NetworkedObject component to the root of all spawnable objects");
|
||||||
|
netObject = go.AddComponent<NetworkedObject>();
|
||||||
|
}
|
||||||
|
netObject.SpawnablePrefabId = spawnablePrefabIndex;
|
||||||
|
if(singleton.isServer)
|
||||||
|
{
|
||||||
|
netObject.NetworkId = singleton.GetNetworkObjectId();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
netObject.NetworkId = networkId;
|
||||||
|
}
|
||||||
|
netObject.OwnerClientId = ownerId;
|
||||||
|
|
||||||
|
singleton.spawnedObjectIds.Add(netObject.NetworkId);
|
||||||
|
singleton.spawnedObjects.Add(netObject.NetworkId, netObject);
|
||||||
|
return go;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal GameObject SpawnPlayerObject(int connectionId, uint networkId)
|
||||||
|
{
|
||||||
|
GameObject go = Instantiate(DefaultPlayerPrefab);
|
||||||
|
NetworkedObject netObject = go.GetComponent<NetworkedObject>();
|
||||||
|
if (netObject == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: Please add a NetworkedObject component to the root of the player prefab");
|
||||||
|
netObject = go.AddComponent<NetworkedObject>();
|
||||||
|
}
|
||||||
|
netObject.OwnerClientId = connectionId;
|
||||||
|
if(isServer)
|
||||||
|
{
|
||||||
|
netObject.NetworkId = singleton.GetNetworkObjectId();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
netObject.NetworkId = networkId;
|
||||||
|
}
|
||||||
|
netObject.IsPlayerObject = true;
|
||||||
|
connectedClients[connectionId].PlayerObject = go;
|
||||||
|
singleton.spawnedObjectIds.Add(netObject.NetworkId);
|
||||||
|
singleton.spawnedObjects.Add(netObject.NetworkId, netObject);
|
||||||
|
return go;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void OnDestroyObject(uint networkId)
|
||||||
|
{
|
||||||
|
if (!singleton.isServer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NetworkedObject netObject = singleton.spawnedObjects[networkId];
|
||||||
|
singleton.releasedNetworkObjectIds.Push(networkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal int AddIncomingMessageHandler(string name, Action<int, byte[]> action)
|
||||||
|
{
|
||||||
|
if(messageTypes.ContainsKey(name))
|
||||||
|
{
|
||||||
|
if(messageCallbacks.ContainsKey(messageTypes[name]))
|
||||||
|
{
|
||||||
|
int handlerId = 0;
|
||||||
|
if (messageHandlerCounter.ContainsKey(messageTypes[name]))
|
||||||
|
{
|
||||||
|
if (!releasedMessageHandlerCounters.ContainsKey(messageTypes[name]))
|
||||||
|
releasedMessageHandlerCounters.Add(messageTypes[name], new Stack<int>());
|
||||||
|
|
||||||
|
if(releasedMessageHandlerCounters[messageTypes[name]].Count == 0)
|
||||||
|
{
|
||||||
|
handlerId = messageHandlerCounter[messageTypes[name]];
|
||||||
|
messageHandlerCounter[messageTypes[name]]++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handlerId = releasedMessageHandlerCounters[messageTypes[name]].Pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
messageHandlerCounter.Add(messageTypes[name], handlerId + 1);
|
||||||
|
}
|
||||||
|
messageCallbacks[messageTypes[name]].Add(handlerId, action);
|
||||||
|
return handlerId;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
messageCallbacks.Add(messageTypes[name], new Dictionary<int, Action<int, byte[]>>());
|
||||||
|
messageHandlerCounter.Add(messageTypes[name], 1);
|
||||||
|
messageCallbacks[messageTypes[name]].Add(0, action);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: The message type " + name + " has not been registered. Please define it in the netConfig");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void RemoveIncomingMessageHandler(string name, int counter)
|
||||||
|
{
|
||||||
|
if (counter == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (messageTypes.ContainsKey(name) && messageCallbacks.ContainsKey(messageTypes[name]) && messageCallbacks[messageTypes[name]].ContainsKey(counter))
|
||||||
|
{
|
||||||
|
messageCallbacks[messageTypes[name]].Remove(counter);
|
||||||
|
releasedMessageHandlerCounters[messageTypes[name]].Push(counter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConnectionConfig Init(NetworkingConfiguration netConfig)
|
||||||
|
{
|
||||||
|
NetworkConfig = netConfig;
|
||||||
|
|
||||||
|
pendingClients = new HashSet<int>();
|
||||||
|
connectedClients = new Dictionary<int, NetworkedClient>();
|
||||||
|
messageBuffer = new byte[NetworkConfig.MessageBufferSize];
|
||||||
|
channels = new Dictionary<string, int>();
|
||||||
|
messageTypes = new Dictionary<string, ushort>();
|
||||||
|
messageCallbacks = new Dictionary<ushort, Dictionary<int, Action<int, byte[]>>>();
|
||||||
|
messageHandlerCounter = new Dictionary<ushort, int>();
|
||||||
|
releasedMessageHandlerCounters = new Dictionary<ushort, Stack<int>>();
|
||||||
|
spawnedObjects = new Dictionary<uint, NetworkedObject>();
|
||||||
|
spawnedObjectIds = new List<uint>();
|
||||||
|
releasedNetworkObjectIds = new Stack<uint>();
|
||||||
|
if(NetworkConfig.HandleObjectSpawning)
|
||||||
|
{
|
||||||
|
NetworkedObject[] sceneObjects = FindObjectsOfType<NetworkedObject>();
|
||||||
|
for (int i = 0; i < sceneObjects.Length; i++)
|
||||||
|
{
|
||||||
|
uint networkId = GetNetworkObjectId();
|
||||||
|
spawnedObjects.Add(networkId, sceneObjects[i]);
|
||||||
|
spawnedObjectIds.Add(networkId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NetworkConfig.ConnectionApproval)
|
||||||
|
{
|
||||||
|
if(NetworkConfig.ConnectionApprovalCallback == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: No ConnectionApproval callback defined. Connection aproval will timeout");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NetworkTransport.Init();
|
||||||
|
ConnectionConfig cConfig = new ConnectionConfig();
|
||||||
|
|
||||||
|
//MLAPI channels and messageTypes
|
||||||
|
NetworkConfig.Channels.Add("MLAPI_RELIABLE_FRAGMENTED", QosType.ReliableFragmented);
|
||||||
|
messageTypes.Add("MLAPI_CONNECTION_REQUEST", 0);
|
||||||
|
messageTypes.Add("MLAPI_CLIENT_LIST", 1);
|
||||||
|
//messageTypes.Add("")
|
||||||
|
|
||||||
|
|
||||||
|
HashSet<string> channelNames = new HashSet<string>();
|
||||||
|
foreach (KeyValuePair<string, QosType> pair in NetworkConfig.Channels)
|
||||||
|
{
|
||||||
|
if(pair.Key.StartsWith("MLAPI_"))
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: Channel names are not allowed to start with MLAPI_. This is to prevent name conflicts");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(channelNames.Contains(pair.Key))
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: Duplicate channel name: " + pair.Key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
channels.Add(pair.Key, cConfig.AddChannel(pair.Value));
|
||||||
|
}
|
||||||
|
//0-32 are reserved for MLAPI messages
|
||||||
|
for (ushort i = 32; i < NetworkConfig.MessageTypes.Count; i++)
|
||||||
|
{
|
||||||
|
messageTypes.Add(NetworkConfig.MessageTypes[i], i);
|
||||||
|
}
|
||||||
|
return cConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void StartServer(NetworkingConfiguration netConfig)
|
||||||
|
{
|
||||||
|
ConnectionConfig cConfig = Init(netConfig);
|
||||||
|
HostTopology hostTopology = new HostTopology(cConfig, NetworkConfig.MaxConnections);
|
||||||
|
hostId = NetworkTransport.AddHost(hostTopology, NetworkConfig.Port, null);
|
||||||
|
isServer = true;
|
||||||
|
isClient = false;
|
||||||
|
isListening = true;
|
||||||
|
SceneManager.LoadScene(PlayScene.buildIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartClient(NetworkingConfiguration netConfig)
|
||||||
|
{
|
||||||
|
ConnectionConfig cConfig = Init(netConfig);
|
||||||
|
HostTopology hostTopology = new HostTopology(cConfig, NetworkConfig.MaxConnections);
|
||||||
|
hostId = NetworkTransport.AddHost(hostTopology, 0);
|
||||||
|
|
||||||
|
localConnectionId = NetworkTransport.Connect(hostId, NetworkConfig.Address, NetworkConfig.Port, 0, out error);
|
||||||
|
isServer = false;
|
||||||
|
isClient = true;
|
||||||
|
isListening = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartHost(NetworkingConfiguration netConfig)
|
||||||
|
{
|
||||||
|
ConnectionConfig cConfig = Init(netConfig);
|
||||||
|
HostTopology hostTopology = new HostTopology(cConfig, NetworkConfig.MaxConnections);
|
||||||
|
hostId = NetworkTransport.AddHost(hostTopology, NetworkConfig.Port, null);
|
||||||
|
isServer = true;
|
||||||
|
isClient = true;
|
||||||
|
isListening = true;
|
||||||
|
connectedClients.Add(-1, new NetworkedClient() { ClientId = -1 });
|
||||||
|
SceneManager.LoadScene(PlayScene.buildIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
if (singleton != null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: Multiple NetworkingManagers");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
singleton = this;
|
||||||
|
DontDestroyOnLoad(gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDisable()
|
||||||
|
{
|
||||||
|
singleton = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Receive stuff
|
||||||
|
int hostId;
|
||||||
|
int connectionId;
|
||||||
|
int channelId;
|
||||||
|
int receivedSize;
|
||||||
|
byte error;
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
if(isListening)
|
||||||
|
{
|
||||||
|
NetworkEventType eventType;
|
||||||
|
int messagesProcessed = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
messagesProcessed++;
|
||||||
|
eventType = NetworkTransport.Receive(out hostId, out connectionId, out channelId, messageBuffer, NetworkConfig.MessageBufferSize, out receivedSize, out error);
|
||||||
|
NetworkError networkError = (NetworkError)error;
|
||||||
|
if (networkError != NetworkError.Ok)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: NetworkTransport receive error: " + networkError.ToString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (eventType)
|
||||||
|
{
|
||||||
|
case NetworkEventType.ConnectEvent:
|
||||||
|
if (isServer)
|
||||||
|
{
|
||||||
|
pendingClients.Add(connectionId);
|
||||||
|
StartCoroutine(ApprovalTimeout(connectionId));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using (MemoryStream writeStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(writeStream))
|
||||||
|
{
|
||||||
|
writer.Write(NetworkConfig.GetConfig());
|
||||||
|
if(NetworkConfig.ConnectionApproval)
|
||||||
|
{
|
||||||
|
writer.Write(NetworkConfig.ConnectionData);
|
||||||
|
}
|
||||||
|
Send(connectionId, "MLAPI_CONNECTION_REQUEST", "MLAPI_RELIABLE_FRAGMENTED", writeStream.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NetworkEventType.DataEvent:
|
||||||
|
HandleIncomingData(connectionId, ref messageBuffer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (eventType != NetworkEventType.Nothing &&
|
||||||
|
(messagesProcessed < NetworkConfig.MaxMessagesPerFrame || NetworkConfig.MaxMessagesPerFrame < 0));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator ApprovalTimeout(int connectionId)
|
||||||
|
{
|
||||||
|
float timeStarted = Time.time;
|
||||||
|
//We yield every frame incase a pending client disconnects and someone else gets its connection id
|
||||||
|
while (Time.time - timeStarted < NetworkConfig.ClientConnectionBufferTimeout && pendingClients.Contains(connectionId))
|
||||||
|
{
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
if(pendingClients.Contains(connectionId))
|
||||||
|
{
|
||||||
|
//Timeout
|
||||||
|
DisconnectClient(connectionId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleIncomingData(int connectonId, ref byte[] data)
|
||||||
|
{
|
||||||
|
using(MemoryStream readStream = new MemoryStream(data))
|
||||||
|
{
|
||||||
|
using (BinaryReader reader = new BinaryReader(readStream))
|
||||||
|
{
|
||||||
|
ushort messageType = reader.ReadUInt16();
|
||||||
|
|
||||||
|
//Client tried to send a network message that was not the connection request before he was accepted.
|
||||||
|
if (pendingClients.Contains(connectionId) && messageType != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (messageType >= 32)
|
||||||
|
{
|
||||||
|
//Custom message, invoke all message handlers
|
||||||
|
foreach (KeyValuePair<int, Action<int, byte[]>> pair in messageCallbacks[messageType])
|
||||||
|
{
|
||||||
|
pair.Value(connectionId, reader.ReadBytes(int.MaxValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//MLAPI message
|
||||||
|
switch (messageType)
|
||||||
|
{
|
||||||
|
case 0: //Client to server > sends connection buffer
|
||||||
|
if (isServer)
|
||||||
|
{
|
||||||
|
using (MemoryStream messageReadStream = new MemoryStream(reader.ReadBytes(int.MaxValue)))
|
||||||
|
{
|
||||||
|
using (BinaryReader messageReader = new BinaryReader(messageReadStream))
|
||||||
|
{
|
||||||
|
byte[] configHash = messageReader.ReadBytes(32);
|
||||||
|
if (NetworkConfig.CompareConfig(configHash) == false)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("MLAPI: NetworkConfiguration missmatch. The configuration between the server and client does not match.");
|
||||||
|
DisconnectClient(connectionId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (NetworkConfig.ConnectionApproval)
|
||||||
|
{
|
||||||
|
byte[] connectionBuffer = messageReader.ReadBytes(int.MaxValue);
|
||||||
|
NetworkConfig.ConnectionApprovalCallback(connectionBuffer, connectionId, HandleApproval);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HandleApproval(connectionId, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 1: //Server informs client it has been approved:
|
||||||
|
if (isClient)
|
||||||
|
{
|
||||||
|
SceneManager.LoadScene(PlayScene.buildIndex);
|
||||||
|
using (MemoryStream messageReadStream = new MemoryStream(reader.ReadBytes(int.MaxValue)))
|
||||||
|
{
|
||||||
|
using (BinaryReader messageReader = new BinaryReader(messageReadStream))
|
||||||
|
{
|
||||||
|
MyClientId = messageReader.ReadInt32();
|
||||||
|
connectedClients.Add(MyClientId, new NetworkedClient() { ClientId = MyClientId });
|
||||||
|
int clientCount = messageReader.ReadInt32();
|
||||||
|
for (int i = 0; i < clientCount; i++)
|
||||||
|
{
|
||||||
|
int conId = messageReader.ReadInt32();
|
||||||
|
connectedClients.Add(conId, new NetworkedClient() { ClientId = conId });
|
||||||
|
}
|
||||||
|
if(NetworkConfig.HandleObjectSpawning)
|
||||||
|
{
|
||||||
|
int objectCount = messageReader.ReadInt32();
|
||||||
|
for (int i = 0; i < objectCount; i++)
|
||||||
|
{
|
||||||
|
bool isPlayerObject = messageReader.ReadBoolean();
|
||||||
|
uint networkId = messageReader.ReadUInt32();
|
||||||
|
int ownerId = messageReader.ReadInt32();
|
||||||
|
int prefabId = messageReader.ReadInt32();
|
||||||
|
if(isPlayerObject)
|
||||||
|
{
|
||||||
|
SpawnPlayerObject(ownerId, networkId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SpawnObject(prefabId, networkId, ownerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Send(int connectionId, string messageType, string channelName, byte[] data)
|
||||||
|
{
|
||||||
|
using (MemoryStream stream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||||
|
{
|
||||||
|
writer.Write(messageTypes[messageType]);
|
||||||
|
writer.Write(data);
|
||||||
|
NetworkTransport.Send(hostId, connectionId, channels[channelName], data, data.Length, out error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Send(int[] connectonIds, string messageType, string channelName, byte[] data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < connectonIds.Length; i++)
|
||||||
|
{
|
||||||
|
Send(connectonIds[i], messageType, channelName, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void Send(List<int> connectonIds, string messageType, string channelName, byte[] data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < connectonIds.Count; i++)
|
||||||
|
{
|
||||||
|
Send(connectonIds[i], messageType, channelName, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void DisconnectClient(int connectionId)
|
||||||
|
{
|
||||||
|
if (!isServer)
|
||||||
|
return;
|
||||||
|
if (pendingClients.Contains(connectionId))
|
||||||
|
pendingClients.Remove(connectionId);
|
||||||
|
if (connectedClients.ContainsKey(connectionId))
|
||||||
|
connectedClients.Remove(connectionId);
|
||||||
|
NetworkTransport.Disconnect(hostId, connectionId, out error);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleApproval(int connectionId, bool approved)
|
||||||
|
{
|
||||||
|
if(approved)
|
||||||
|
{
|
||||||
|
NetworkedClient client = new NetworkedClient()
|
||||||
|
{
|
||||||
|
ClientId = connectionId
|
||||||
|
};
|
||||||
|
connectedClients.Add(connectionId, client);
|
||||||
|
if(NetworkConfig.HandleObjectSpawning)
|
||||||
|
{
|
||||||
|
uint networkId = GetNetworkObjectId();
|
||||||
|
GameObject go = SpawnPlayerObject(connectionId, networkId);
|
||||||
|
connectedClients[connectionId].PlayerObject = go;
|
||||||
|
}
|
||||||
|
using (MemoryStream writeStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(writeStream))
|
||||||
|
{
|
||||||
|
writer.Write(connectionId);
|
||||||
|
writer.Write(connectedClients.Count - 1);
|
||||||
|
foreach (KeyValuePair<int, NetworkedClient> item in connectedClients)
|
||||||
|
{
|
||||||
|
//Our own ID. Already added as the first one above
|
||||||
|
if (item.Key == connectionId)
|
||||||
|
continue;
|
||||||
|
writer.Write(item.Key); //Connection id
|
||||||
|
}
|
||||||
|
if (NetworkConfig.HandleObjectSpawning)
|
||||||
|
{
|
||||||
|
writer.Write(spawnedObjectIds.Count);
|
||||||
|
for (int i = 0; i < spawnedObjectIds.Count; i++)
|
||||||
|
{
|
||||||
|
writer.Write(spawnedObjects[spawnedObjectIds[i]].IsPlayerObject);
|
||||||
|
writer.Write(spawnedObjects[spawnedObjectIds[i]].NetworkId);
|
||||||
|
writer.Write(spawnedObjects[spawnedObjectIds[i]].OwnerClientId);
|
||||||
|
writer.Write(spawnedObjects[spawnedObjectIds[i]].SpawnablePrefabId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Send(connectionId, "MLAPI_CLIENT_LIST", "MLAPI_RELIABLE_FRAGMENTED", writeStream.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (pendingClients.Contains(connectionId))
|
||||||
|
pendingClients.Remove(connectionId);
|
||||||
|
NetworkTransport.Disconnect(hostId, connectionId, out error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,35 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MLAPI
|
|
||||||
{
|
|
||||||
public abstract class NetworkedBehaviour : MonoBehaviour
|
|
||||||
{
|
|
||||||
protected bool isLocalPlayer;
|
|
||||||
protected bool isServer = NetworkingManager.singleton.isServer;
|
|
||||||
|
|
||||||
//Change data type
|
|
||||||
private Dictionary<string, int> registeredMessageHandlers = new Dictionary<string, int>();
|
|
||||||
|
|
||||||
public int RegisterMessageHandler(string name, Action<int, byte[]> action)
|
|
||||||
{
|
|
||||||
int counter = NetworkingManager.singleton.AddIncomingMessageHandler(name, action);
|
|
||||||
registeredMessageHandlers.Add(name, counter);
|
|
||||||
return counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DeregisterMessageHandler(string name, int counter)
|
|
||||||
{
|
|
||||||
NetworkingManager.singleton.RemoveIncomingMessageHandler(name, counter);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDestroy()
|
|
||||||
{
|
|
||||||
foreach(KeyValuePair<string, int> pair in registeredMessageHandlers)
|
|
||||||
{
|
|
||||||
DeregisterMessageHandler(pair.Key, pair.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
namespace MLAPI
|
|
||||||
{
|
|
||||||
public class NetworkedClient
|
|
||||||
{
|
|
||||||
public int ClientId;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MLAPI
|
|
||||||
{
|
|
||||||
//TODO
|
|
||||||
//Will be used for objects which will be spawned automatically across clients
|
|
||||||
public class NetworkedObject : MonoBehaviour
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,21 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using UnityEngine.Networking;
|
|
||||||
|
|
||||||
namespace MLAPI
|
|
||||||
{
|
|
||||||
public class NetworkingConfiguration
|
|
||||||
{
|
|
||||||
public ushort ProtocolVersion = 0;
|
|
||||||
public Dictionary<string, QosType> Channels = new Dictionary<string, QosType>();
|
|
||||||
public List<string> MessageTypes = new List<string>();
|
|
||||||
public int MessageBufferSize = 65536;
|
|
||||||
public int MaxMessagesPerFrame = 150;
|
|
||||||
public int MaxConnections = 100;
|
|
||||||
public int Port = 7777;
|
|
||||||
public int ClientConnectionBufferTimeout = 10;
|
|
||||||
public bool ConnectionApproval = false;
|
|
||||||
public Action<byte[], int, Action<int, bool>> ConnectionApprovalCallback;
|
|
||||||
public byte[] ConnectionData;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,320 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.Networking;
|
|
||||||
|
|
||||||
namespace MLAPI
|
|
||||||
{
|
|
||||||
public class NetworkingManager : MonoBehaviour
|
|
||||||
{
|
|
||||||
public static NetworkingManager singleton;
|
|
||||||
//Client only, what my connectionId is on the server
|
|
||||||
public int MyClientId;
|
|
||||||
//Server only
|
|
||||||
private Dictionary<int, NetworkedClient> connectedClients;
|
|
||||||
private HashSet<int> pendingClients;
|
|
||||||
internal bool isServer;
|
|
||||||
private bool isListening;
|
|
||||||
private byte[] messageBuffer;
|
|
||||||
private Dictionary<string, int> channels;
|
|
||||||
private Dictionary<string, ushort> messageTypes;
|
|
||||||
private Dictionary<ushort, Dictionary<int, Action<int, byte[]>>> messageCallbacks;
|
|
||||||
private Dictionary<ushort, int> messageHandlerCounter;
|
|
||||||
private Dictionary<ushort, Stack<int>> releasedMessageHandlerCounters;
|
|
||||||
|
|
||||||
public NetworkingConfiguration NetworkConfig;
|
|
||||||
|
|
||||||
internal int AddIncomingMessageHandler(string name, Action<int, byte[]> action)
|
|
||||||
{
|
|
||||||
if(messageTypes.ContainsKey(name))
|
|
||||||
{
|
|
||||||
if(messageCallbacks.ContainsKey(messageTypes[name]))
|
|
||||||
{
|
|
||||||
int handlerId = 0;
|
|
||||||
if (messageHandlerCounter.ContainsKey(messageTypes[name]))
|
|
||||||
{
|
|
||||||
if (!releasedMessageHandlerCounters.ContainsKey(messageTypes[name]))
|
|
||||||
releasedMessageHandlerCounters.Add(messageTypes[name], new Stack<int>());
|
|
||||||
|
|
||||||
if(releasedMessageHandlerCounters[messageTypes[name]].Count == 0)
|
|
||||||
{
|
|
||||||
handlerId = messageHandlerCounter[messageTypes[name]];
|
|
||||||
messageHandlerCounter[messageTypes[name]]++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
handlerId = releasedMessageHandlerCounters[messageTypes[name]].Pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
messageHandlerCounter.Add(messageTypes[name], handlerId + 1);
|
|
||||||
}
|
|
||||||
messageCallbacks[messageTypes[name]].Add(handlerId, action);
|
|
||||||
return handlerId;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
messageCallbacks.Add(messageTypes[name], new Dictionary<int, Action<int, byte[]>>());
|
|
||||||
messageHandlerCounter.Add(messageTypes[name], 1);
|
|
||||||
messageCallbacks[messageTypes[name]].Add(0, action);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogWarning("MLAPI: The message type " + name + " has not been registered. Please define it in the netConfig");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void RemoveIncomingMessageHandler(string name, int counter)
|
|
||||||
{
|
|
||||||
if (counter == -1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (messageTypes.ContainsKey(name) && messageCallbacks.ContainsKey(messageTypes[name]) && messageCallbacks[messageTypes[name]].ContainsKey(counter))
|
|
||||||
{
|
|
||||||
messageCallbacks[messageTypes[name]].Remove(counter);
|
|
||||||
releasedMessageHandlerCounters[messageTypes[name]].Push(counter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ConnectionConfig Init(NetworkingConfiguration netConfig)
|
|
||||||
{
|
|
||||||
NetworkConfig = netConfig;
|
|
||||||
|
|
||||||
pendingClients = new HashSet<int>();
|
|
||||||
connectedClients = new Dictionary<int, NetworkedClient>();
|
|
||||||
messageBuffer = new byte[NetworkConfig.MessageBufferSize];
|
|
||||||
channels = new Dictionary<string, int>();
|
|
||||||
messageTypes = new Dictionary<string, ushort>();
|
|
||||||
messageCallbacks = new Dictionary<ushort, Dictionary<int, Action<int, byte[]>>>();
|
|
||||||
messageHandlerCounter = new Dictionary<ushort, int>();
|
|
||||||
releasedMessageHandlerCounters = new Dictionary<ushort, Stack<int>>();
|
|
||||||
|
|
||||||
if (NetworkConfig.ConnectionApproval)
|
|
||||||
{
|
|
||||||
if(NetworkConfig.ConnectionApprovalCallback == null)
|
|
||||||
{
|
|
||||||
Debug.LogWarning("MLAPI: No ConnectionAproval callback defined. Connection aproval will timeout");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NetworkTransport.Init();
|
|
||||||
ConnectionConfig cConfig = new ConnectionConfig();
|
|
||||||
|
|
||||||
//MLAPI channels and messageTypes
|
|
||||||
NetworkConfig.Channels.Add("MLAPI_RELIABLE_FRAGMENTED", QosType.ReliableFragmented);
|
|
||||||
messageTypes.Add("CONNECTION_REQUEST", 0);
|
|
||||||
|
|
||||||
|
|
||||||
foreach (KeyValuePair<string, QosType> pair in NetworkConfig.Channels)
|
|
||||||
{
|
|
||||||
channels.Add(pair.Key, cConfig.AddChannel(pair.Value));
|
|
||||||
}
|
|
||||||
//0-32 are reserved for MLAPI messages
|
|
||||||
for (ushort i = 32; i < NetworkConfig.MessageTypes.Count; i++)
|
|
||||||
{
|
|
||||||
messageTypes.Add(NetworkConfig.MessageTypes[i], i);
|
|
||||||
}
|
|
||||||
return cConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void StartServer(NetworkingConfiguration netConfig)
|
|
||||||
{
|
|
||||||
ConnectionConfig cConfig = Init(netConfig);
|
|
||||||
HostTopology hostTopology = new HostTopology(cConfig, NetworkConfig.MaxConnections);
|
|
||||||
NetworkTransport.AddHost(hostTopology, NetworkConfig.Port);
|
|
||||||
isServer = true;
|
|
||||||
isListening = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnEnable()
|
|
||||||
{
|
|
||||||
if (singleton != null)
|
|
||||||
{
|
|
||||||
Debug.LogWarning("MLAPI: Multiple NetworkingManagers");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
singleton = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDisable()
|
|
||||||
{
|
|
||||||
singleton = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Receive stuff
|
|
||||||
int hostId;
|
|
||||||
int connectionId;
|
|
||||||
int channelId;
|
|
||||||
int receivedSize;
|
|
||||||
byte error;
|
|
||||||
private void Update()
|
|
||||||
{
|
|
||||||
if(isListening)
|
|
||||||
{
|
|
||||||
NetworkEventType eventType;
|
|
||||||
int messagesProcessed = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
messagesProcessed++;
|
|
||||||
eventType = NetworkTransport.Receive(out hostId, out connectionId, out channelId, messageBuffer, NetworkConfig.MessageBufferSize, out receivedSize, out error);
|
|
||||||
NetworkError networkError = (NetworkError)error;
|
|
||||||
if (networkError != NetworkError.Ok)
|
|
||||||
{
|
|
||||||
Debug.LogWarning("MLAPI: NetworkTransport receive error: " + networkError.ToString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (eventType)
|
|
||||||
{
|
|
||||||
case NetworkEventType.ConnectEvent:
|
|
||||||
if(isServer)
|
|
||||||
{
|
|
||||||
if (NetworkConfig.ConnectionApproval)
|
|
||||||
{
|
|
||||||
pendingClients.Add(connectionId);
|
|
||||||
StartCoroutine(ApprovalTimeout(connectionId));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Connect
|
|
||||||
HandleApproval(connectionId, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (NetworkConfig.ConnectionApproval)
|
|
||||||
Send(connectionId, "CONNECTION_REQUEST", "MLAPI_RELIABLE_FRAGMENTED", NetworkConfig.ConnectionData);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case NetworkEventType.DataEvent:
|
|
||||||
HandleIncomingData(connectionId, ref messageBuffer);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (eventType != NetworkEventType.Nothing &&
|
|
||||||
(messagesProcessed < NetworkConfig.MaxMessagesPerFrame || NetworkConfig.MaxMessagesPerFrame < 0));
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator ApprovalTimeout(int connectionId)
|
|
||||||
{
|
|
||||||
float timeStarted = Time.time;
|
|
||||||
//We yield every frame incase a pending client disconnects and someone else gets its connection id
|
|
||||||
while (Time.time - timeStarted < NetworkConfig.ClientConnectionBufferTimeout && pendingClients.Contains(connectionId))
|
|
||||||
{
|
|
||||||
yield return null;
|
|
||||||
}
|
|
||||||
if(pendingClients.Contains(connectionId))
|
|
||||||
{
|
|
||||||
//Timeout
|
|
||||||
DisconnectClient(connectionId);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//If the key nolonger exist in pending and not in connected, they disconnected
|
|
||||||
if(!connectedClients.ContainsKey(connectionId))
|
|
||||||
{
|
|
||||||
pendingClients.Remove(connectionId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleIncomingData(int connectonId, ref byte[] data)
|
|
||||||
{
|
|
||||||
using(MemoryStream stream = new MemoryStream(data))
|
|
||||||
{
|
|
||||||
BinaryReader reader = new BinaryReader(stream);
|
|
||||||
ushort protocolVersion = reader.ReadUInt16();
|
|
||||||
ushort messageType = reader.ReadUInt16();
|
|
||||||
if(messageType >= 32)
|
|
||||||
{
|
|
||||||
//Custom message
|
|
||||||
if(protocolVersion != NetworkConfig.ProtocolVersion)
|
|
||||||
{
|
|
||||||
Debug.LogWarning("MLAPI: Protocol version not matching");
|
|
||||||
DisconnectClient(connectionId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//MLAPI message
|
|
||||||
switch(messageType)
|
|
||||||
{
|
|
||||||
case 0: //Client to server > sends connection buffer
|
|
||||||
byte[] connectionBuffer = reader.ReadBytes(int.MaxValue);
|
|
||||||
NetworkConfig.ConnectionApprovalCallback(connectionBuffer, connectionId, HandleApproval);
|
|
||||||
break;
|
|
||||||
case 1: //Server gives client it's connectionId
|
|
||||||
break;
|
|
||||||
case 2: //Server informs client of spawned objects
|
|
||||||
break;
|
|
||||||
case 3: //Server informs client of spawned players
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void Send(int connectionId, string messageType, string channelName, byte[] data)
|
|
||||||
{
|
|
||||||
using (MemoryStream stream = new MemoryStream())
|
|
||||||
{
|
|
||||||
BinaryWriter writer = new BinaryWriter(stream);
|
|
||||||
writer.Write(NetworkConfig.ProtocolVersion);
|
|
||||||
writer.Write(messageTypes[messageType]);
|
|
||||||
writer.Write(data);
|
|
||||||
NetworkTransport.Send(hostId, connectionId, channels[channelName], data, data.Length, out error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void Send(int[] connectonIds, string messageType, string channelName, byte[] data)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < connectonIds.Length; i++)
|
|
||||||
{
|
|
||||||
Send(connectonIds[i], messageType, channelName, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void Send(List<int> connectonIds, string messageType, string channelName, byte[] data)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < connectonIds.Count; i++)
|
|
||||||
{
|
|
||||||
Send(connectonIds[i], messageType, channelName, data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void DisconnectClient(int connectionId)
|
|
||||||
{
|
|
||||||
if (pendingClients.Contains(connectionId))
|
|
||||||
pendingClients.Remove(connectionId);
|
|
||||||
if (connectedClients.ContainsKey(connectionId))
|
|
||||||
connectedClients.Remove(connectionId);
|
|
||||||
NetworkTransport.Disconnect(hostId, connectionId, out error);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleApproval(int connectionId, bool approved)
|
|
||||||
{
|
|
||||||
if(approved)
|
|
||||||
{
|
|
||||||
NetworkedClient client = new NetworkedClient()
|
|
||||||
{
|
|
||||||
ClientId = connectionId
|
|
||||||
};
|
|
||||||
connectedClients.Add(connectionId, client);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (pendingClients.Contains(connectionId))
|
|
||||||
pendingClients.Remove(connectionId);
|
|
||||||
NetworkTransport.Disconnect(hostId, connectionId, out error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user