提交工程

This commit is contained in:
2026-05-20 12:01:19 +08:00
commit e0ddde0393
5502 changed files with 596320 additions and 0 deletions
@@ -0,0 +1,99 @@
using UnityEngine;
using System;
#if UNITY_EDITOR
using System.Reflection;
#endif
public static class ConsoleProDebug
{
// Clear the console and the native console
public static void Clear()
{
#if UNITY_EDITOR
if(ConsoleClearMethod != null)
{
ConsoleClearMethod.Invoke(null, null);
}
#endif
}
// Send a log to a specific filter regardless of contents
// Ex: ConsoleProDebug.LogToFilter("Hi", "CustomFilter");
public static void LogToFilter(string inLog, string inFilterName)
{
Debug.Log(inLog + "\nCPAPI:{\"cmd\":\"Filter\" \"name\":\"" + inFilterName + "\"}");
}
// Send a log as a regular log but change its type in ConsolePro
// Ex: ConsoleProDebug.LogAsType("Hi", "Error");
public static void LogAsType(string inLog, string inTypeName)
{
Debug.Log(inLog + "\nCPAPI:{\"cmd\":\"LogType\" \"name\":\"" + inTypeName + "\"}");
}
// Watch a variable. This will only produce one log entry regardless of how many times it is logged, allowing you to track variables without spam.
// Ex:
// void Update() {
// ConsoleProDebug.Watch("Player X Position", transform.position.x);
// }
public static void Watch(string inName, string inValue)
{
Debug.Log(inName + " : " + inValue + "\nCPAPI:{\"cmd\":\"Watch\" \"name\":\"" + inName + "\"}");
}
public static void Search(string inText)
{
Debug.Log("\nCPAPI:{\"cmd\":\"Search\" \"text\":\"" + inText + "\"}");
}
#if UNITY_EDITOR
// Reflection calls to access Console Pro from runtime
private static bool _checkedConsoleClearMethod = false;
private static MethodInfo _consoleClearMethod = null;
private static MethodInfo ConsoleClearMethod
{
get
{
if(_consoleClearMethod == null || !_checkedConsoleClearMethod)
{
_checkedConsoleClearMethod = true;
if(ConsoleWindowType == null)
{
return null;
}
_consoleClearMethod = ConsoleWindowType.GetMethod("ClearEntries", BindingFlags.Static | BindingFlags.Public);
}
return _consoleClearMethod;
}
}
private static bool _checkedConsoleWindowType = false;
private static Type _consoleWindowType = null;
private static Type ConsoleWindowType
{
get
{
if(_consoleWindowType == null || !_checkedConsoleWindowType)
{
_checkedConsoleWindowType = true;
Assembly[] assemblies = System.AppDomain.CurrentDomain.GetAssemblies();
for(int iAssembly = 0; iAssembly < assemblies.Length; iAssembly++)
{
Type[] types = assemblies[iAssembly].GetTypes();
for(int iType = 0; iType < types.Length; iType++)
{
if(types[iType].Name == "ConsolePro3Window")
{
_consoleWindowType = types[iType];
}
}
}
}
return _consoleWindowType;
}
}
#endif
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 30f42e8a12eb842acbe9a63057fb00e4
timeCreated: 1469329295
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5de782a9528f04b41a8ba70afba32a61
timeCreated: 1498113024
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: be7aee03972b847e4a8b81ef8ce46a8e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,30 @@
fileFormatVersion: 2
guid: a2284c517ee274c19a6ba4c1a8c96fb6
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
isPreloaded: 0
isOverridable: 0
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 1
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a1d51a9b386eb4992af4cb193629d854
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,237 @@
// Uncomment to use in Editor
// #define USECONSOLEPROREMOTESERVERINEDITOR
#if (!UNITY_EDITOR && DEBUG) || (UNITY_EDITOR && USECONSOLEPROREMOTESERVERINEDITOR)
#define USECONSOLEPROREMOTESERVER
#endif
#if (UNITY_WP_8_1 || UNITY_WSA)
#define UNSUPPORTEDCONSOLEPROREMOTESERVER
#endif
#if UNITY_EDITOR && !USECONSOLEPROREMOTESERVER
#elif UNSUPPORTEDCONSOLEPROREMOTESERVER
#elif !USECONSOLEPROREMOTESERVER
#else
using System;
using System.Collections.Generic;
#endif
using UnityEngine;
#if USECONSOLEPROREMOTESERVER
using FlyingWormConsole3.LiteNetLib;
using FlyingWormConsole3.LiteNetLib.Utils;
#endif
namespace FlyingWormConsole3
{
#if USECONSOLEPROREMOTESERVER
public class ConsoleProRemoteServer : MonoBehaviour, INetEventListener
#else
public class ConsoleProRemoteServer : MonoBehaviour
#endif
{
public bool useNATPunch = false;
public int port = 51000;
#if UNITY_EDITOR && !USECONSOLEPROREMOTESERVER
#elif UNSUPPORTEDCONSOLEPROREMOTESERVER
public void Awake()
{
Debug.Log("Console Pro Remote Server is not supported on this platform");
}
#elif !USECONSOLEPROREMOTESERVER
public void Awake()
{
Debug.Log("Console Pro Remote Server is disabled in release mode, please use a Development build or define DEBUG to use it");
}
#else
private NetManager _netServer;
private NetPeer _ourPeer;
private NetDataWriter _dataWriter;
[System.SerializableAttribute]
public class QueuedLog
{
public string message;
public string stackTrace;
public LogType type;
}
[NonSerializedAttribute]
public List<QueuedLog> logs = new List<QueuedLog>();
private static ConsoleProRemoteServer instance = null;
void Awake()
{
if(instance != null)
{
Destroy(gameObject);
}
instance = this;
DontDestroyOnLoad(gameObject);
Debug.Log("Starting Console Pro Server on port : " + port);
_dataWriter = new NetDataWriter();
_netServer = new NetManager(this, 100, "ConsolePro");
_netServer.Start(port);
_netServer.DiscoveryEnabled = true;
_netServer.UpdateTime = 15;
_netServer.MergeEnabled = true;
_netServer.NatPunchEnabled = useNATPunch;
}
void OnDestroy()
{
if(_netServer != null)
{
_netServer.Stop();
}
}
public void OnPeerConnected(NetPeer peer)
{
Debug.Log("Connected to " + peer.EndPoint);
_ourPeer = peer;
}
public void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo)
{
Debug.Log("Disconnected from " + peer.EndPoint + ", info: " + disconnectInfo.Reason);
if (peer == _ourPeer)
{
_ourPeer = null;
}
}
public void OnNetworkReceive(NetPeer peer, NetDataReader reader)
{
}
public void OnPeerDisconnected(NetPeer peer, DisconnectReason reason, int socketErrorCode)
{
}
public void OnNetworkError(NetEndPoint endPoint, int socketErrorCode)
{
}
public void OnNetworkReceiveUnconnected(NetEndPoint remoteEndPoint, NetDataReader reader, UnconnectedMessageType messageType)
{
if (messageType == UnconnectedMessageType.DiscoveryRequest)
{
// Debug.Log("[SERVER] Received discovery request. Send discovery response");
_netServer.SendDiscoveryResponse(new byte[] {1}, remoteEndPoint);
}
}
public void OnNetworkLatencyUpdate(NetPeer peer, int latency)
{
}
#if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9
void OnEnable()
{
Application.RegisterLogCallback(LogCallback);
}
void Update()
{
Application.RegisterLogCallback(LogCallback);
}
void OnDisable()
{
Application.RegisterLogCallback(null);
}
#else
void OnEnable()
{
Application.logMessageReceived += LogCallback;
}
void OnDisable()
{
Application.logMessageReceived -= LogCallback;
}
#endif
public void LogCallback(string logString, string stackTrace, LogType type)
{
if(!logString.StartsWith("CPIGNORE"))
{
QueueLog(logString, stackTrace, type);
}
}
void QueueLog(string logString, string stackTrace, LogType type)
{
if(logs.Count > 200)
{
while(logs.Count > 200)
{
logs.RemoveAt(0);
}
}
logs.Add(new QueuedLog() { message = logString, stackTrace = stackTrace, type = type } );
}
void LateUpdate()
{
if(_netServer == null)
{
return;
}
_netServer.PollEvents();
if(_ourPeer == null)
{
return;
}
if(logs.Count <= 0)
{
return;
}
string cMessage = "";
for(int i = 0; i < logs.Count; i++)
{
cMessage = "";
QueuedLog cLog = logs[i];
cMessage = "::::" + cLog.type + "::::" + cLog.message + "\n" + cLog.stackTrace;
_dataWriter.Reset();
_dataWriter.Put(cMessage);
_ourPeer.Send(_dataWriter, SendOptions.ReliableOrdered);
}
logs.Clear();
}
#endif
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d6bcfaced529e418bb75980b297fda2a
timeCreated: 1437614101
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 2c6bd635eeaa04c228b6d342c4758ad7
folderAsset: yes
timeCreated: 1494014730
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,120 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System.Runtime.InteropServices;
namespace FlyingWormConsole3.LiteNetLib.Utils
{
public static class FastBitConverter
{
[StructLayout(LayoutKind.Explicit)]
private struct ConverterHelperDouble
{
[FieldOffset(0)]
public ulong Along;
[FieldOffset(0)]
public double Adouble;
}
[StructLayout(LayoutKind.Explicit)]
private struct ConverterHelperFloat
{
[FieldOffset(0)]
public int Aint;
[FieldOffset(0)]
public float Afloat;
}
private static void WriteLittleEndian(byte[] buffer, int offset, ulong data)
{
#if BIGENDIAN
buffer[offset + 7] = (byte)(data);
buffer[offset + 6] = (byte)(data >> 8);
buffer[offset + 5] = (byte)(data >> 16);
buffer[offset + 4] = (byte)(data >> 24);
buffer[offset + 3] = (byte)(data >> 32);
buffer[offset + 2] = (byte)(data >> 40);
buffer[offset + 1] = (byte)(data >> 48);
buffer[offset ] = (byte)(data >> 56);
#else
buffer[offset] = (byte)(data);
buffer[offset + 1] = (byte)(data >> 8);
buffer[offset + 2] = (byte)(data >> 16);
buffer[offset + 3] = (byte)(data >> 24);
buffer[offset + 4] = (byte)(data >> 32);
buffer[offset + 5] = (byte)(data >> 40);
buffer[offset + 6] = (byte)(data >> 48);
buffer[offset + 7] = (byte)(data >> 56);
#endif
}
private static void WriteLittleEndian(byte[] buffer, int offset, int data)
{
#if BIGENDIAN
buffer[offset + 3] = (byte)(data);
buffer[offset + 2] = (byte)(data >> 8);
buffer[offset + 1] = (byte)(data >> 16);
buffer[offset ] = (byte)(data >> 24);
#else
buffer[offset] = (byte)(data);
buffer[offset + 1] = (byte)(data >> 8);
buffer[offset + 2] = (byte)(data >> 16);
buffer[offset + 3] = (byte)(data >> 24);
#endif
}
public static void WriteLittleEndian(byte[] buffer, int offset, short data)
{
#if BIGENDIAN
buffer[offset + 1] = (byte)(data);
buffer[offset ] = (byte)(data >> 8);
#else
buffer[offset] = (byte)(data);
buffer[offset + 1] = (byte)(data >> 8);
#endif
}
public static void GetBytes(byte[] bytes, int startIndex, double value)
{
ConverterHelperDouble ch = new ConverterHelperDouble { Adouble = value };
WriteLittleEndian(bytes, startIndex, ch.Along);
}
public static void GetBytes(byte[] bytes, int startIndex, float value)
{
ConverterHelperFloat ch = new ConverterHelperFloat { Afloat = value };
WriteLittleEndian(bytes, startIndex, ch.Aint);
}
public static void GetBytes(byte[] bytes, int startIndex, short value)
{
WriteLittleEndian(bytes, startIndex, value);
}
public static void GetBytes(byte[] bytes, int startIndex, ushort value)
{
WriteLittleEndian(bytes, startIndex, (short)value);
}
public static void GetBytes(byte[] bytes, int startIndex, int value)
{
WriteLittleEndian(bytes, startIndex, value);
}
public static void GetBytes(byte[] bytes, int startIndex, uint value)
{
WriteLittleEndian(bytes, startIndex, (int)value);
}
public static void GetBytes(byte[] bytes, int startIndex, long value)
{
WriteLittleEndian(bytes, startIndex, (ulong)value);
}
public static void GetBytes(byte[] bytes, int startIndex, ulong value)
{
WriteLittleEndian(bytes, startIndex, value);
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 55df0de9a58e74c9395dfe5ffdab9a5a
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,128 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using FlyingWormConsole3.LiteNetLib.Utils;
namespace FlyingWormConsole3.LiteNetLib
{
public enum UnconnectedMessageType
{
Default,
DiscoveryRequest,
DiscoveryResponse
}
public enum DisconnectReason
{
SocketReceiveError,
ConnectionFailed,
Timeout,
SocketSendError,
RemoteConnectionClose,
DisconnectPeerCalled
}
public struct DisconnectInfo
{
public DisconnectReason Reason;
public int SocketErrorCode;
public NetDataReader AdditionalData;
}
public interface INetEventListener
{
/// <summary>
/// New remote peer connected to host, or client connected to remote host
/// </summary>
/// <param name="peer">Connected peer object</param>
void OnPeerConnected(NetPeer peer);
/// <summary>
/// Peer disconnected
/// </summary>
/// <param name="peer">disconnected peer</param>
/// <param name="disconnectInfo">additional info about reason, errorCode or data received with disconnect message</param>
void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo);
/// <summary>
/// Network error (on send or receive)
/// </summary>
/// <param name="endPoint">From endPoint (can be null)</param>
/// <param name="socketErrorCode">Socket error code</param>
void OnNetworkError(NetEndPoint endPoint, int socketErrorCode);
/// <summary>
/// Received some data
/// </summary>
/// <param name="peer">From peer</param>
/// <param name="reader">DataReader containing all received data</param>
void OnNetworkReceive(NetPeer peer, NetDataReader reader);
/// <summary>
/// Received unconnected message
/// </summary>
/// <param name="remoteEndPoint">From address (IP and Port)</param>
/// <param name="reader">Message data</param>
/// <param name="messageType">Message type (simple, discovery request or responce)</param>
void OnNetworkReceiveUnconnected(NetEndPoint remoteEndPoint, NetDataReader reader, UnconnectedMessageType messageType);
/// <summary>
/// Latency information updated
/// </summary>
/// <param name="peer">Peer with updated latency</param>
/// <param name="latency">latency value in milliseconds</param>
void OnNetworkLatencyUpdate(NetPeer peer, int latency);
}
public class EventBasedNetListener : INetEventListener
{
public delegate void OnPeerConnected(NetPeer peer);
public delegate void OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo);
public delegate void OnNetworkError(NetEndPoint endPoint, int socketErrorCode);
public delegate void OnNetworkReceive(NetPeer peer, NetDataReader reader);
public delegate void OnNetworkReceiveUnconnected(NetEndPoint remoteEndPoint, NetDataReader reader, UnconnectedMessageType messageType);
public delegate void OnNetworkLatencyUpdate(NetPeer peer, int latency);
public event OnPeerConnected PeerConnectedEvent;
public event OnPeerDisconnected PeerDisconnectedEvent;
public event OnNetworkError NetworkErrorEvent;
public event OnNetworkReceive NetworkReceiveEvent;
public event OnNetworkReceiveUnconnected NetworkReceiveUnconnectedEvent;
public event OnNetworkLatencyUpdate NetworkLatencyUpdateEvent;
void INetEventListener.OnPeerConnected(NetPeer peer)
{
if (PeerConnectedEvent != null)
PeerConnectedEvent(peer);
}
void INetEventListener.OnPeerDisconnected(NetPeer peer, DisconnectInfo disconnectInfo)
{
if (PeerDisconnectedEvent != null)
PeerDisconnectedEvent(peer, disconnectInfo);
}
void INetEventListener.OnNetworkError(NetEndPoint endPoint, int socketErrorCode)
{
if (NetworkErrorEvent != null)
NetworkErrorEvent(endPoint, socketErrorCode);
}
void INetEventListener.OnNetworkReceive(NetPeer peer, NetDataReader reader)
{
if (NetworkReceiveEvent != null)
NetworkReceiveEvent(peer, reader);
}
void INetEventListener.OnNetworkReceiveUnconnected(NetEndPoint remoteEndPoint, NetDataReader reader, UnconnectedMessageType messageType)
{
if (NetworkReceiveUnconnectedEvent != null)
NetworkReceiveUnconnectedEvent(remoteEndPoint, reader, messageType);
}
void INetEventListener.OnNetworkLatencyUpdate(NetPeer peer, int latency)
{
if (NetworkLatencyUpdateEvent != null)
NetworkLatencyUpdateEvent(peer, latency);
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d391f9565d58e44a798d680ec5c11906
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,231 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System;
using System.Collections.Generic;
using FlyingWormConsole3.LiteNetLib.Utils;
//Some code parts taked from lidgren-network-gen3
namespace FlyingWormConsole3.LiteNetLib
{
public interface INatPunchListener
{
void OnNatIntroductionRequest(NetEndPoint localEndPoint, NetEndPoint remoteEndPoint, string token);
void OnNatIntroductionSuccess(NetEndPoint targetEndPoint, string token);
}
public class EventBasedNatPunchListener : INatPunchListener
{
public delegate void OnNatIntroductionRequest(NetEndPoint localEndPoint, NetEndPoint remoteEndPoint, string token);
public delegate void OnNatIntroductionSuccess(NetEndPoint targetEndPoint, string token);
public event OnNatIntroductionRequest NatIntroductionRequest;
public event OnNatIntroductionSuccess NatIntroductionSuccess;
void INatPunchListener.OnNatIntroductionRequest(NetEndPoint localEndPoint, NetEndPoint remoteEndPoint, string token)
{
if(NatIntroductionRequest != null)
NatIntroductionRequest(localEndPoint, remoteEndPoint, token);
}
void INatPunchListener.OnNatIntroductionSuccess(NetEndPoint targetEndPoint, string token)
{
if (NatIntroductionSuccess != null)
NatIntroductionSuccess(targetEndPoint, token);
}
}
public sealed class NatPunchModule
{
struct RequestEventData
{
public NetEndPoint LocalEndPoint;
public NetEndPoint RemoteEndPoint;
public string Token;
}
struct SuccessEventData
{
public NetEndPoint TargetEndPoint;
public string Token;
}
private readonly NetManager _netBase;
private readonly Queue<RequestEventData> _requestEvents;
private readonly Queue<SuccessEventData> _successEvents;
private const byte HostByte = 1;
private const byte ClientByte = 0;
public const int MaxTokenLength = 256;
private INatPunchListener _natPunchListener;
internal NatPunchModule(NetManager netBase)
{
_netBase = netBase;
_requestEvents = new Queue<RequestEventData>();
_successEvents = new Queue<SuccessEventData>();
}
public void Init(INatPunchListener listener)
{
_natPunchListener = listener;
}
public void NatIntroduce(
NetEndPoint hostInternal,
NetEndPoint hostExternal,
NetEndPoint clientInternal,
NetEndPoint clientExternal,
string additionalInfo)
{
NetDataWriter dw = new NetDataWriter();
//First packet (server)
//send to client
dw.Put(ClientByte);
dw.Put(hostInternal);
dw.Put(hostExternal);
dw.Put(additionalInfo, MaxTokenLength);
var packet = _netBase.PacketPool.GetWithData(PacketProperty.NatIntroduction, dw);
_netBase.SendRawAndRecycle(packet, clientExternal);
//Second packet (client)
//send to server
dw.Reset();
dw.Put(HostByte);
dw.Put(clientInternal);
dw.Put(clientExternal);
dw.Put(additionalInfo, MaxTokenLength);
packet = _netBase.PacketPool.GetWithData(PacketProperty.NatIntroduction, dw);
_netBase.SendRawAndRecycle(packet, hostExternal);
}
public void PollEvents()
{
if (_natPunchListener == null)
return;
lock (_successEvents)
{
while (_successEvents.Count > 0)
{
var evt = _successEvents.Dequeue();
_natPunchListener.OnNatIntroductionSuccess(evt.TargetEndPoint, evt.Token);
}
}
lock (_requestEvents)
{
while (_requestEvents.Count > 0)
{
var evt = _requestEvents.Dequeue();
_natPunchListener.OnNatIntroductionRequest(evt.LocalEndPoint, evt.RemoteEndPoint, evt.Token);
}
}
}
public void SendNatIntroduceRequest(NetEndPoint masterServerEndPoint, string additionalInfo)
{
if (!_netBase.IsRunning)
return;
//prepare outgoing data
NetDataWriter dw = new NetDataWriter();
string networkIp = NetUtils.GetLocalIp(LocalAddrType.IPv4);
if (string.IsNullOrEmpty(networkIp))
{
networkIp = NetUtils.GetLocalIp(LocalAddrType.IPv6);
}
int networkPort = _netBase.LocalEndPoint.Port;
NetEndPoint localEndPoint = new NetEndPoint(networkIp, networkPort);
dw.Put(localEndPoint);
dw.Put(additionalInfo, MaxTokenLength);
//prepare packet
var packet = _netBase.PacketPool.GetWithData(PacketProperty.NatIntroductionRequest, dw);
_netBase.SendRawAndRecycle(packet, masterServerEndPoint);
}
private void HandleNatPunch(NetEndPoint senderEndPoint, NetDataReader dr)
{
byte fromHostByte = dr.GetByte();
if (fromHostByte != HostByte && fromHostByte != ClientByte)
{
//garbage
return;
}
//Read info
string additionalInfo = dr.GetString(MaxTokenLength);
NetUtils.DebugWrite(ConsoleColor.Green, "[NAT] punch received from {0} - additional info: {1}", senderEndPoint, additionalInfo);
//Release punch success to client; enabling him to Connect() to msg.Sender if token is ok
lock (_successEvents)
{
_successEvents.Enqueue(new SuccessEventData { TargetEndPoint = senderEndPoint, Token = additionalInfo });
}
}
private void HandleNatIntroduction(NetDataReader dr)
{
// read intro
byte hostByte = dr.GetByte();
NetEndPoint remoteInternal = dr.GetNetEndPoint();
NetEndPoint remoteExternal = dr.GetNetEndPoint();
string token = dr.GetString(MaxTokenLength);
NetUtils.DebugWrite(ConsoleColor.Cyan, "[NAT] introduction received; we are designated " + (hostByte == HostByte ? "host" : "client"));
NetDataWriter writer = new NetDataWriter();
// send internal punch
writer.Put(hostByte);
writer.Put(token);
var packet = _netBase.PacketPool.GetWithData(PacketProperty.NatPunchMessage, writer);
_netBase.SendRawAndRecycle(packet, remoteInternal);
NetUtils.DebugWrite(ConsoleColor.Cyan, "[NAT] internal punch sent to " + remoteInternal);
// send external punch
writer.Reset();
writer.Put(hostByte);
writer.Put(token);
packet = _netBase.PacketPool.GetWithData(PacketProperty.NatPunchMessage, writer);
_netBase.SendRawAndRecycle(packet, remoteExternal);
NetUtils.DebugWrite(ConsoleColor.Cyan, "[NAT] external punch sent to " + remoteExternal);
}
private void HandleNatIntroductionRequest(NetEndPoint senderEndPoint, NetDataReader dr)
{
NetEndPoint localEp = dr.GetNetEndPoint();
string token = dr.GetString(MaxTokenLength);
lock (_requestEvents)
{
_requestEvents.Enqueue(new RequestEventData
{
LocalEndPoint = localEp,
RemoteEndPoint = senderEndPoint,
Token = token
});
}
}
internal void ProcessMessage(NetEndPoint senderEndPoint, NetPacket packet)
{
var dr = new NetDataReader(packet.RawData, NetConstants.HeaderSize, packet.Size);
switch (packet.Property)
{
case PacketProperty.NatIntroductionRequest:
//We got request and must introduce
HandleNatIntroductionRequest(senderEndPoint, dr);
break;
case PacketProperty.NatIntroduction:
//We got introduce and must punch
HandleNatIntroduction(dr);
break;
case PacketProperty.NatPunchMessage:
//We got punch and can connect
HandleNatPunch(senderEndPoint, dr);
break;
}
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 11f3508667cc14e3797a49d4695ffdd8
timeCreated: 1497976517
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,53 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
namespace FlyingWormConsole3.LiteNetLib
{
public enum SendOptions
{
Unreliable,
ReliableUnordered,
Sequenced,
ReliableOrdered
}
public static class NetConstants
{
public const int HeaderSize = 1;
public const int SequencedHeaderSize = 3;
public const int FragmentHeaderSize = 6;
public const int DefaultWindowSize = 64;
public const ushort MaxSequence = 32768;
public const ushort HalfMaxSequence = MaxSequence / 2;
//socket
public const string MulticastGroupIPv4 = "224.0.0.1";
public const string MulticastGroupIPv6 = "FF02:0:0:0:0:0:0:1";
public const int SocketBufferSize = 1024*1024; //2mb
public const int SocketTTL = 255;
//protocol
public const int ProtocolId = 1;
public const int MaxUdpHeaderSize = 68;
public const int PacketSizeLimit = ushort.MaxValue - MaxUdpHeaderSize;
public const int MinPacketSize = 576 - MaxUdpHeaderSize;
public const int MinPacketDataSize = MinPacketSize - HeaderSize;
public const int MinSequencedPacketDataSize = MinPacketSize - SequencedHeaderSize;
public static readonly int[] PossibleMtu =
{
576 - MaxUdpHeaderSize, //Internet Path MTU for X.25 (RFC 879)
1492 - MaxUdpHeaderSize, //Ethernet with LLC and SNAP, PPPoE (RFC 1042)
1500 - MaxUdpHeaderSize, //Ethernet II (RFC 1191)
4352 - MaxUdpHeaderSize, //FDDI
4464 - MaxUdpHeaderSize, //Token ring
7981 - MaxUdpHeaderSize //WLAN
};
public static int MaxPacketSize = PossibleMtu[PossibleMtu.Length - 1];
//peer specific
public const int FlowUpdateTime = 1000;
public const int FlowIncreaseThreshold = 4;
public const int DefaultPingInterval = 1000;
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 02abb4740bff94f28bdd538839339932
timeCreated: 1497976517
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,444 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System;
using System.Text;
namespace FlyingWormConsole3.LiteNetLib.Utils
{
public class NetDataReader
{
protected byte[] _data;
protected int _position;
protected int _dataSize;
public byte[] Data
{
get { return _data; }
}
public int Position
{
get { return _position; }
}
public bool EndOfData
{
get { return _position == _dataSize; }
}
public int AvailableBytes
{
get { return _dataSize - _position; }
}
public void SetSource(NetDataWriter dataWriter)
{
_data = dataWriter.Data;
_position = 0;
_dataSize = dataWriter.Length;
}
public void SetSource(byte[] source)
{
_data = source;
_position = 0;
_dataSize = source.Length;
}
public void SetSource(byte[] source, int offset)
{
_data = source;
_position = offset;
_dataSize = source.Length;
}
public void SetSource(byte[] source, int offset, int dataSize)
{
_data = source;
_position = offset;
_dataSize = dataSize;
}
public NetDataReader()
{
}
public NetDataReader(byte[] source)
{
SetSource(source);
}
public NetDataReader(byte[] source, int offset)
{
SetSource(source, offset);
}
public NetDataReader(byte[] source, int offset, int maxSize)
{
SetSource(source, offset, maxSize);
}
#region GetMethods
public NetEndPoint GetNetEndPoint()
{
string host = GetString(1000);
int port = GetInt();
return new NetEndPoint(host, port);
}
public byte GetByte()
{
byte res = _data[_position];
_position += 1;
return res;
}
public sbyte GetSByte()
{
var b = (sbyte)_data[_position];
_position++;
return b;
}
public bool[] GetBoolArray()
{
ushort size = BitConverter.ToUInt16(_data, _position);
_position += 2;
var arr = new bool[size];
for (int i = 0; i < size; i++)
{
arr[i] = GetBool();
}
return arr;
}
public ushort[] GetUShortArray()
{
ushort size = BitConverter.ToUInt16(_data, _position);
_position += 2;
var arr = new ushort[size];
for (int i = 0; i < size; i++)
{
arr[i] = GetUShort();
}
return arr;
}
public short[] GetShortArray()
{
ushort size = BitConverter.ToUInt16(_data, _position);
_position += 2;
var arr = new short[size];
for (int i = 0; i < size; i++)
{
arr[i] = GetShort();
}
return arr;
}
public long[] GetLongArray()
{
ushort size = BitConverter.ToUInt16(_data, _position);
_position += 2;
var arr = new long[size];
for (int i = 0; i < size; i++)
{
arr[i] = GetLong();
}
return arr;
}
public ulong[] GetULongArray()
{
ushort size = BitConverter.ToUInt16(_data, _position);
_position += 2;
var arr = new ulong[size];
for (int i = 0; i < size; i++)
{
arr[i] = GetULong();
}
return arr;
}
public int[] GetIntArray()
{
ushort size = BitConverter.ToUInt16(_data, _position);
_position += 2;
var arr = new int[size];
for (int i = 0; i < size; i++)
{
arr[i] = GetInt();
}
return arr;
}
public uint[] GetUIntArray()
{
ushort size = BitConverter.ToUInt16(_data, _position);
_position += 2;
var arr = new uint[size];
for (int i = 0; i < size; i++)
{
arr[i] = GetUInt();
}
return arr;
}
public float[] GetFloatArray()
{
ushort size = BitConverter.ToUInt16(_data, _position);
_position += 2;
var arr = new float[size];
for (int i = 0; i < size; i++)
{
arr[i] = GetFloat();
}
return arr;
}
public double[] GetDoubleArray()
{
ushort size = BitConverter.ToUInt16(_data, _position);
_position += 2;
var arr = new double[size];
for (int i = 0; i < size; i++)
{
arr[i] = GetDouble();
}
return arr;
}
public string[] GetStringArray(int maxLength)
{
ushort size = BitConverter.ToUInt16(_data, _position);
_position += 2;
var arr = new string[size];
for (int i = 0; i < size; i++)
{
arr[i] = GetString(maxLength);
}
return arr;
}
public bool GetBool()
{
bool res = _data[_position] > 0;
_position += 1;
return res;
}
public ushort GetUShort()
{
ushort result = BitConverter.ToUInt16(_data, _position);
_position += 2;
return result;
}
public short GetShort()
{
short result = BitConverter.ToInt16(_data, _position);
_position += 2;
return result;
}
public long GetLong()
{
long result = BitConverter.ToInt64(_data, _position);
_position += 8;
return result;
}
public ulong GetULong()
{
ulong result = BitConverter.ToUInt64(_data, _position);
_position += 8;
return result;
}
public int GetInt()
{
int result = BitConverter.ToInt32(_data, _position);
_position += 4;
return result;
}
public uint GetUInt()
{
uint result = BitConverter.ToUInt32(_data, _position);
_position += 4;
return result;
}
public float GetFloat()
{
float result = BitConverter.ToSingle(_data, _position);
_position += 4;
return result;
}
public double GetDouble()
{
double result = BitConverter.ToDouble(_data, _position);
_position += 8;
return result;
}
public string GetString(int maxLength)
{
int bytesCount = GetInt();
if (bytesCount <= 0 || bytesCount > maxLength*2)
{
return string.Empty;
}
int charCount = Encoding.UTF8.GetCharCount(_data, _position, bytesCount);
if (charCount > maxLength)
{
return string.Empty;
}
string result = Encoding.UTF8.GetString(_data, _position, bytesCount);
_position += bytesCount;
return result;
}
public string GetString()
{
int bytesCount = GetInt();
if (bytesCount <= 0)
{
return string.Empty;
}
string result = Encoding.UTF8.GetString(_data, _position, bytesCount);
_position += bytesCount;
return result;
}
public byte[] GetRemainingBytes()
{
byte[] outgoingData = new byte[AvailableBytes];
Buffer.BlockCopy(_data, _position, outgoingData, 0, AvailableBytes);
_position = _data.Length;
return outgoingData;
}
public void GetRemainingBytes(byte[] destination)
{
Buffer.BlockCopy(_data, _position, destination, 0, AvailableBytes);
_position = _data.Length;
}
public void GetBytes(byte[] destination, int lenght)
{
Buffer.BlockCopy(_data, _position, destination, 0, lenght);
_position += lenght;
}
public byte[] GetBytesWithLength()
{
int length = GetInt();
byte[] outgoingData = new byte[length];
Buffer.BlockCopy(_data, _position, outgoingData, 0, length);
_position += length;
return outgoingData;
}
#endregion
#region PeekMethods
public byte PeekByte()
{
return _data[_position];
}
public sbyte PeekSByte()
{
return (sbyte)_data[_position];
}
public bool PeekBool()
{
return _data[_position] > 0;
}
public ushort PeekUShort()
{
return BitConverter.ToUInt16(_data, _position);
}
public short PeekShort()
{
return BitConverter.ToInt16(_data, _position);
}
public long PeekLong()
{
return BitConverter.ToInt64(_data, _position);
}
public ulong PeekULong()
{
return BitConverter.ToUInt64(_data, _position);
}
public int PeekInt()
{
return BitConverter.ToInt32(_data, _position);
}
public uint PeekUInt()
{
return BitConverter.ToUInt32(_data, _position);
}
public float PeekFloat()
{
return BitConverter.ToSingle(_data, _position);
}
public double PeekDouble()
{
return BitConverter.ToDouble(_data, _position);
}
public string PeekString(int maxLength)
{
int bytesCount = BitConverter.ToInt32(_data, _position);
if (bytesCount <= 0 || bytesCount > maxLength * 2)
{
return string.Empty;
}
int charCount = Encoding.UTF8.GetCharCount(_data, _position + 4, bytesCount);
if (charCount > maxLength)
{
return string.Empty;
}
string result = Encoding.UTF8.GetString(_data, _position + 4, bytesCount);
return result;
}
public string PeekString()
{
int bytesCount = BitConverter.ToInt32(_data, _position);
if (bytesCount <= 0)
{
return string.Empty;
}
string result = Encoding.UTF8.GetString(_data, _position + 4, bytesCount);
return result;
}
#endregion
public void Clear()
{
_position = 0;
_dataSize = 0;
_data = null;
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 37bb0204fc22b499690c4032caf14811
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,375 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System;
using System.Text;
namespace FlyingWormConsole3.LiteNetLib.Utils
{
public class NetDataWriter
{
protected byte[] _data;
protected int _position;
private int _maxLength;
private readonly bool _autoResize;
public NetDataWriter()
{
_maxLength = 64;
_data = new byte[_maxLength];
_autoResize = true;
}
public NetDataWriter(bool autoResize)
{
_maxLength = 64;
_data = new byte[_maxLength];
_autoResize = autoResize;
}
public NetDataWriter(bool autoResize, int initialSize)
{
_maxLength = initialSize;
_data = new byte[_maxLength];
_autoResize = autoResize;
}
public void ResizeIfNeed(int newSize)
{
if (_maxLength < newSize)
{
while (_maxLength < newSize)
{
_maxLength *= 2;
}
Array.Resize(ref _data, _maxLength);
}
}
public void Reset(int size)
{
ResizeIfNeed(size);
_position = 0;
}
public void Reset()
{
_position = 0;
}
public byte[] CopyData()
{
byte[] resultData = new byte[_position];
Buffer.BlockCopy(_data, 0, resultData, 0, _position);
return resultData;
}
public byte[] Data
{
get { return _data; }
}
public int Length
{
get { return _position; }
}
public void Put(float value)
{
if (_autoResize)
ResizeIfNeed(_position + 4);
FastBitConverter.GetBytes(_data, _position, value);
_position += 4;
}
public void Put(double value)
{
if (_autoResize)
ResizeIfNeed(_position + 8);
FastBitConverter.GetBytes(_data, _position, value);
_position += 8;
}
public void Put(long value)
{
if (_autoResize)
ResizeIfNeed(_position + 8);
FastBitConverter.GetBytes(_data, _position, value);
_position += 8;
}
public void Put(ulong value)
{
if (_autoResize)
ResizeIfNeed(_position + 8);
FastBitConverter.GetBytes(_data, _position, value);
_position += 8;
}
public void Put(int value)
{
if (_autoResize)
ResizeIfNeed(_position + 4);
FastBitConverter.GetBytes(_data, _position, value);
_position += 4;
}
public void Put(uint value)
{
if (_autoResize)
ResizeIfNeed(_position + 4);
FastBitConverter.GetBytes(_data, _position, value);
_position += 4;
}
public void Put(ushort value)
{
if (_autoResize)
ResizeIfNeed(_position + 2);
FastBitConverter.GetBytes(_data, _position, value);
_position += 2;
}
public void Put(short value)
{
if (_autoResize)
ResizeIfNeed(_position + 2);
FastBitConverter.GetBytes(_data, _position, value);
_position += 2;
}
public void Put(sbyte value)
{
if (_autoResize)
ResizeIfNeed(_position + 1);
_data[_position] = (byte)value;
_position++;
}
public void Put(byte value)
{
if (_autoResize)
ResizeIfNeed(_position + 1);
_data[_position] = value;
_position++;
}
public void Put(byte[] data, int offset, int length)
{
if (_autoResize)
ResizeIfNeed(_position + length);
Buffer.BlockCopy(data, offset, _data, _position, length);
_position += length;
}
public void Put(byte[] data)
{
if (_autoResize)
ResizeIfNeed(_position + data.Length);
Buffer.BlockCopy(data, 0, _data, _position, data.Length);
_position += data.Length;
}
public void PutBytesWithLength(byte[] data, int offset, int length)
{
if (_autoResize)
ResizeIfNeed(_position + length);
Put(length);
Buffer.BlockCopy(data, offset, _data, _position, length);
_position += length;
}
public void PutBytesWithLength(byte[] data)
{
if (_autoResize)
ResizeIfNeed(_position + data.Length);
Put(data.Length);
Buffer.BlockCopy(data, 0, _data, _position, data.Length);
_position += data.Length;
}
public void Put(bool value)
{
if (_autoResize)
ResizeIfNeed(_position + 1);
_data[_position] = (byte)(value ? 1 : 0);
_position++;
}
public void PutArray(float[] value)
{
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
if (_autoResize)
ResizeIfNeed(_position + len * 4 + 2);
Put(len);
for (int i = 0; i < len; i++)
{
Put(value[i]);
}
}
public void PutArray(double[] value)
{
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
if (_autoResize)
ResizeIfNeed(_position + len * 8 + 2);
Put(len);
for (int i = 0; i < len; i++)
{
Put(value[i]);
}
}
public void PutArray(long[] value)
{
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
if (_autoResize)
ResizeIfNeed(_position + len * 8 + 2);
Put(len);
for (int i = 0; i < len; i++)
{
Put(value[i]);
}
}
public void PutArray(ulong[] value)
{
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
if (_autoResize)
ResizeIfNeed(_position + len * 8 + 2);
Put(len);
for (int i = 0; i < len; i++)
{
Put(value[i]);
}
}
public void PutArray(int[] value)
{
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
if (_autoResize)
ResizeIfNeed(_position + len * 4 + 2);
Put(len);
for (int i = 0; i < len; i++)
{
Put(value[i]);
}
}
public void PutArray(uint[] value)
{
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
if (_autoResize)
ResizeIfNeed(_position + len * 4 + 2);
Put(len);
for (int i = 0; i < len; i++)
{
Put(value[i]);
}
}
public void PutArray(ushort[] value)
{
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
if (_autoResize)
ResizeIfNeed(_position + len * 2 + 2);
Put(len);
for (int i = 0; i < len; i++)
{
Put(value[i]);
}
}
public void PutArray(short[] value)
{
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
if (_autoResize)
ResizeIfNeed(_position + len * 2 + 2);
Put(len);
for (int i = 0; i < len; i++)
{
Put(value[i]);
}
}
public void PutArray(bool[] value)
{
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
if (_autoResize)
ResizeIfNeed(_position + len + 2);
Put(len);
for (int i = 0; i < len; i++)
{
Put(value[i]);
}
}
public void PutArray(string[] value)
{
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
Put(len);
for (int i = 0; i < value.Length; i++)
{
Put(value[i]);
}
}
public void PutArray(string[] value, int maxLength)
{
ushort len = value == null ? (ushort)0 : (ushort)value.Length;
Put(len);
for (int i = 0; i < len; i++)
{
Put(value[i], maxLength);
}
}
public void Put(NetEndPoint endPoint)
{
Put(endPoint.Host);
Put(endPoint.Port);
}
public void Put(string value)
{
if (string.IsNullOrEmpty(value))
{
Put(0);
return;
}
//put bytes count
int bytesCount = Encoding.UTF8.GetByteCount(value);
if (_autoResize)
ResizeIfNeed(_position + bytesCount + 4);
Put(bytesCount);
//put string
Encoding.UTF8.GetBytes(value, 0, value.Length, _data, _position);
_position += bytesCount;
}
public void Put(string value, int maxLength)
{
if (string.IsNullOrEmpty(value))
{
Put(0);
return;
}
int length = value.Length > maxLength ? maxLength : value.Length;
//calculate max count
int bytesCount = Encoding.UTF8.GetByteCount(value);
if (_autoResize)
ResizeIfNeed(_position + bytesCount + 4);
//put bytes count
Put(bytesCount);
//put string
Encoding.UTF8.GetBytes(value, 0, length, _data, _position);
_position += bytesCount;
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 81ecf42c9cc394fc395942030e71bddd
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,16 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System;
namespace FlyingWormConsole3.LiteNetLib
{
public interface INetLogger
{
void WriteNet(ConsoleColor color, string str, params object[] args);
}
public static class NetDebug
{
public static INetLogger Logger = null;
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 78dc00ceb66ac4fdfa8c3957763522ba
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,221 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
#if !WINRT || UNITY_EDITOR
using System;
using System.Net;
using System.Net.Sockets;
namespace FlyingWormConsole3.LiteNetLib
{
public sealed class NetEndPoint
{
public string Host { get { return EndPoint.Address.ToString(); } }
public int Port { get { return EndPoint.Port; } }
internal readonly IPEndPoint EndPoint;
internal NetEndPoint(IPEndPoint ipEndPoint)
{
EndPoint = ipEndPoint;
}
public override bool Equals(object obj)
{
if (!(obj is NetEndPoint))
{
return false;
}
return EndPoint.Equals(((NetEndPoint)obj).EndPoint);
}
public override string ToString()
{
return EndPoint.ToString();
}
public override int GetHashCode()
{
return EndPoint.GetHashCode();
}
public NetEndPoint(string hostStr, int port)
{
IPAddress ipAddress;
if (!IPAddress.TryParse(hostStr, out ipAddress))
{
if (Socket.OSSupportsIPv6)
{
if (hostStr == "localhost")
{
ipAddress = IPAddress.IPv6Loopback;
}
else
{
ipAddress = ResolveAddress(hostStr, AddressFamily.InterNetworkV6);
}
}
if (ipAddress == null)
{
ipAddress = ResolveAddress(hostStr, AddressFamily.InterNetwork);
}
}
if (ipAddress == null)
{
throw new Exception("Invalid address: " + hostStr);
}
EndPoint = new IPEndPoint(ipAddress, port);
}
private IPAddress ResolveAddress(string hostStr, AddressFamily addressFamily)
{
#if NETCORE
var hostTask = Dns.GetHostEntryAsync(hostStr);
hostTask.Wait();
var host = hostTask.Result;
#else
var host = Dns.GetHostEntry(hostStr);
#endif
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == addressFamily)
{
return ip;
}
}
return null;
}
internal long GetId()
{
byte[] addr = EndPoint.Address.GetAddressBytes();
long id = 0;
if (addr.Length == 4) //IPv4
{
id = addr[0];
id |= (long)addr[1] << 8;
id |= (long)addr[2] << 16;
id |= (long)addr[3] << 24;
id |= (long)EndPoint.Port << 32;
}
else if (addr.Length == 16) //IPv6
{
id = addr[0] ^ addr[8];
id |= (long)(addr[1] ^ addr[9]) << 8;
id |= (long)(addr[2] ^ addr[10]) << 16;
id |= (long)(addr[3] ^ addr[11]) << 24;
id |= (long)(addr[4] ^ addr[12]) << 32;
id |= (long)(addr[5] ^ addr[13]) << 40;
id |= (long)(addr[6] ^ addr[14]) << 48;
id |= (long)(Port ^ addr[7] ^ addr[15]) << 56;
}
return id;
}
}
}
#else
using System;
using Windows.Networking;
using Windows.Networking.Sockets;
namespace FlyingWormConsole3.LiteNetLib
{
public sealed class NetEndPoint
{
public string Host { get { return HostName.DisplayName; } }
public int Port { get; private set; }
internal readonly HostName HostName;
internal readonly string PortStr;
internal NetEndPoint(int port)
{
HostName = null;
PortStr = port.ToString();
Port = port;
}
public override bool Equals(object obj)
{
if (!(obj is NetEndPoint))
{
return false;
}
NetEndPoint other = (NetEndPoint) obj;
return HostName.IsEqual(other.HostName) && PortStr.Equals(other.PortStr);
}
public override int GetHashCode()
{
return HostName.CanonicalName.GetHashCode() ^ PortStr.GetHashCode();
}
internal long GetId()
{
//Check locals
if (HostName == null)
{
return ParseIpToId("0.0.0.0");
}
if (HostName.DisplayName == "localhost")
{
return ParseIpToId("127.0.0.1");
}
//Check remote
string hostIp = string.Empty;
var task = DatagramSocket.GetEndpointPairsAsync(HostName, "0").AsTask();
task.Wait();
//IPv4
foreach (var endpointPair in task.Result)
{
hostIp = endpointPair.RemoteHostName.CanonicalName;
if (endpointPair.RemoteHostName.Type == HostNameType.Ipv4)
{
return ParseIpToId(hostIp);
}
}
//Else
return hostIp.GetHashCode() ^ Port;
}
private long ParseIpToId(string hostIp)
{
long id = 0;
string[] ip = hostIp.Split('.');
id |= long.Parse(ip[0]);
id |= long.Parse(ip[1]) << 8;
id |= long.Parse(ip[2]) << 16;
id |= long.Parse(ip[3]) << 24;
id |= (long)Port << 32;
return id;
}
public override string ToString()
{
return HostName.CanonicalName + ":" + PortStr;
}
public NetEndPoint(string hostName, int port)
{
var task = DatagramSocket.GetEndpointPairsAsync(new HostName(hostName), port.ToString()).AsTask();
task.Wait();
HostName = task.Result[0].RemoteHostName;
Port = port;
PortStr = port.ToString();
}
internal NetEndPoint(HostName hostName, string port)
{
HostName = hostName;
Port = int.Parse(port);
PortStr = port;
}
}
}
#endif
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 33fb66c3ba5b8429fbbb0a2f5e7ceb57
timeCreated: 1497976517
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a0197124da84847d8855d5f690b8c653
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,163 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System;
using FlyingWormConsole3.LiteNetLib.Utils;
namespace FlyingWormConsole3.LiteNetLib
{
internal enum PacketProperty : byte
{
Unreliable, //0
Reliable, //1
Sequenced, //2
ReliableOrdered, //3
AckReliable, //4
AckReliableOrdered, //5
Ping, //6
Pong, //7
ConnectRequest, //8
ConnectAccept, //9
Disconnect, //10
UnconnectedMessage, //11
NatIntroductionRequest, //12
NatIntroduction, //13
NatPunchMessage, //14
MtuCheck, //15
MtuOk, //16
DiscoveryRequest, //17
DiscoveryResponse, //18
Merged //19
}
internal sealed class NetPacket
{
private const int LastProperty = 19;
//Header
public PacketProperty Property
{
get { return (PacketProperty)(RawData[0] & 0x7F); }
set { RawData[0] = (byte)((RawData[0] & 0x80) | ((byte)value & 0x7F)); }
}
public ushort Sequence
{
get { return BitConverter.ToUInt16(RawData, 1); }
set { FastBitConverter.GetBytes(RawData, 1, value); }
}
public bool IsFragmented
{
get { return (RawData[0] & 0x80) != 0; }
set
{
if (value)
RawData[0] |= 0x80; //set first bit
else
RawData[0] &= 0x7F; //unset first bit
}
}
public ushort FragmentId
{
get { return BitConverter.ToUInt16(RawData, 3); }
set { FastBitConverter.GetBytes(RawData, 3, value); }
}
public ushort FragmentPart
{
get { return BitConverter.ToUInt16(RawData, 5); }
set { FastBitConverter.GetBytes(RawData, 5, value); }
}
public ushort FragmentsTotal
{
get { return BitConverter.ToUInt16(RawData, 7); }
set { FastBitConverter.GetBytes(RawData, 7, value); }
}
//Data
public readonly byte[] RawData;
public int Size;
public NetPacket(int size)
{
RawData = new byte[size];
Size = 0;
}
public static bool GetPacketProperty(byte[] data, out PacketProperty property)
{
byte properyByte = (byte)(data[0] & 0x7F);
if (properyByte > LastProperty)
{
property = PacketProperty.Unreliable;
return false;
}
property = (PacketProperty)properyByte;
return true;
}
public static int GetHeaderSize(PacketProperty property)
{
return IsSequenced(property)
? NetConstants.SequencedHeaderSize
: NetConstants.HeaderSize;
}
public int GetHeaderSize()
{
return GetHeaderSize(Property);
}
public byte[] GetPacketData()
{
int headerSize = GetHeaderSize(Property);
int dataSize = Size - headerSize;
byte[] data = new byte[dataSize];
Buffer.BlockCopy(RawData, headerSize, data, 0, dataSize);
return data;
}
public bool IsClientData()
{
var property = Property;
return property == PacketProperty.Reliable ||
property == PacketProperty.ReliableOrdered ||
property == PacketProperty.Unreliable ||
property == PacketProperty.Sequenced;
}
public static bool IsSequenced(PacketProperty property)
{
return property == PacketProperty.ReliableOrdered ||
property == PacketProperty.Reliable ||
property == PacketProperty.Sequenced ||
property == PacketProperty.Ping ||
property == PacketProperty.Pong ||
property == PacketProperty.AckReliable ||
property == PacketProperty.AckReliableOrdered;
}
//Packet contstructor from byte array
public bool FromBytes(byte[] data, int start, int packetSize)
{
//Reading property
byte property = (byte)(data[start] & 0x7F);
bool fragmented = (data[start] & 0x80) != 0;
int headerSize = GetHeaderSize((PacketProperty) property);
if (property > LastProperty ||
packetSize > NetConstants.PacketSizeLimit ||
packetSize < headerSize ||
(fragmented && packetSize < headerSize + NetConstants.FragmentHeaderSize))
{
return false;
}
Buffer.BlockCopy(data, start, RawData, 0, packetSize);
Size = packetSize;
return true;
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7aa9ed55f53fa48569ccd0963c50d8da
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,101 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System;
using System.Collections.Generic;
using FlyingWormConsole3.LiteNetLib.Utils;
namespace FlyingWormConsole3.LiteNetLib
{
internal class NetPacketPool
{
private readonly Stack<NetPacket> _pool;
public NetPacketPool()
{
_pool = new Stack<NetPacket>();
}
public NetPacket GetWithData(PacketProperty property, NetDataWriter writer)
{
var packet = Get(property, writer.Length);
Buffer.BlockCopy(writer.Data, 0, packet.RawData, NetPacket.GetHeaderSize(property), writer.Length);
return packet;
}
public NetPacket GetWithData(PacketProperty property, byte[] data, int start, int length)
{
var packet = Get(property, length);
Buffer.BlockCopy(data, start, packet.RawData, NetPacket.GetHeaderSize(property), length);
return packet;
}
//Get packet just for read
public NetPacket GetAndRead(byte[] data, int start, int count)
{
NetPacket packet = null;
lock (_pool)
{
if (_pool.Count > 0)
{
packet = _pool.Pop();
}
}
if (packet == null)
{
//allocate new packet of max size or bigger
packet = new NetPacket(NetConstants.MaxPacketSize);
}
if (!packet.FromBytes(data, start, count))
{
Recycle(packet);
return null;
}
return packet;
}
//Get packet with size
public NetPacket Get(PacketProperty property, int size)
{
NetPacket packet = null;
size += NetPacket.GetHeaderSize(property);
if (size <= NetConstants.MaxPacketSize)
{
lock (_pool)
{
if (_pool.Count > 0)
{
packet = _pool.Pop();
}
}
}
if (packet == null)
{
//allocate new packet of max size or bigger
packet = new NetPacket(size > NetConstants.MaxPacketSize ? size : NetConstants.MaxPacketSize);
}
else
{
Array.Clear(packet.RawData, 0, size);
}
packet.Property = property;
packet.Size = size;
return packet;
}
public void Recycle(NetPacket packet)
{
if (packet.Size > NetConstants.MaxPacketSize)
{
//Dont pool big packets. Save memory
return;
}
//Clean fragmented flag
packet.IsFragmented = false;
lock (_pool)
{
_pool.Push(packet);
}
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3637381933a4745b996d4dd48cd71efe
timeCreated: 1497976517
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,857 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System;
using System.Collections.Generic;
using System.Text;
using FlyingWormConsole3.LiteNetLib.Utils;
namespace FlyingWormConsole3.LiteNetLib
{
public enum ConnectionState
{
InProgress,
Connected,
Disconnected
}
public sealed class NetPeer
{
//Flow control
private int _currentFlowMode;
private int _sendedPacketsCount;
private int _flowTimer;
//Ping and RTT
private int _ping;
private int _rtt;
private int _avgRtt;
private int _rttCount;
private int _goodRttCount;
private ushort _pingSequence;
private ushort _remotePingSequence;
private double _resendDelay = 27.0;
private int _pingSendTimer;
private const int RttResetDelay = 1000;
private int _rttResetTimer;
private DateTime _pingTimeStart;
private int _timeSinceLastPacket;
//Common
private readonly NetEndPoint _remoteEndPoint;
private readonly NetManager _peerListener;
private readonly NetPacketPool _packetPool;
private readonly object _flushLock = new object();
//Channels
private readonly ReliableChannel _reliableOrderedChannel;
private readonly ReliableChannel _reliableUnorderedChannel;
private readonly SequencedChannel _sequencedChannel;
private readonly SimpleChannel _simpleChannel;
private int _windowSize = NetConstants.DefaultWindowSize;
//MTU
private int _mtu = NetConstants.PossibleMtu[0];
private int _mtuIdx;
private bool _finishMtu;
private int _mtuCheckTimer;
private int _mtuCheckAttempts;
private const int MtuCheckDelay = 1000;
private const int MaxMtuCheckAttempts = 4;
private readonly object _mtuMutex = new object();
//Fragment
private class IncomingFragments
{
public NetPacket[] Fragments;
public int ReceivedCount;
public int TotalSize;
}
private ushort _fragmentId;
private readonly Dictionary<ushort, IncomingFragments> _holdedFragments;
//Merging
private readonly NetPacket _mergeData;
private int _mergePos;
private int _mergeCount;
//Connection
private int _connectAttempts;
private int _connectTimer;
private long _connectId;
private ConnectionState _connectionState;
public ConnectionState ConnectionState
{
get { return _connectionState; }
}
public long ConnectId
{
get { return _connectId; }
}
public NetEndPoint EndPoint
{
get { return _remoteEndPoint; }
}
public int Ping
{
get { return _ping; }
}
public int CurrentFlowMode
{
get { return _currentFlowMode; }
}
public int Mtu
{
get { return _mtu; }
}
public int TimeSinceLastPacket
{
get { return _timeSinceLastPacket; }
}
public NetManager NetManager
{
get { return _peerListener; }
}
public int PacketsCountInReliableQueue
{
get { return _reliableUnorderedChannel.PacketsInQueue; }
}
public int PacketsCountInReliableOrderedQueue
{
get { return _reliableOrderedChannel.PacketsInQueue; }
}
internal double ResendDelay
{
get { return _resendDelay; }
}
/// <summary>
/// Application defined object containing data about the connection
/// </summary>
public object Tag;
internal NetPeer(NetManager peerListener, NetEndPoint remoteEndPoint, long connectId)
{
_packetPool = peerListener.PacketPool;
_peerListener = peerListener;
_remoteEndPoint = remoteEndPoint;
_avgRtt = 0;
_rtt = 0;
_pingSendTimer = 0;
_reliableOrderedChannel = new ReliableChannel(this, true, _windowSize);
_reliableUnorderedChannel = new ReliableChannel(this, false, _windowSize);
_sequencedChannel = new SequencedChannel(this);
_simpleChannel = new SimpleChannel(this);
_holdedFragments = new Dictionary<ushort, IncomingFragments>();
_mergeData = _packetPool.Get(PacketProperty.Merged, NetConstants.MaxPacketSize);
//if ID != 0 then we already connected
_connectAttempts = 0;
if (connectId == 0)
{
_connectId = DateTime.UtcNow.Ticks;
SendConnectRequest();
}
else
{
_connectId = connectId;
_connectionState = ConnectionState.Connected;
SendConnectAccept();
}
NetUtils.DebugWrite(ConsoleColor.Cyan, "[CC] ConnectId: {0}", _connectId);
}
private void SendConnectRequest()
{
//Get connect key bytes
byte[] keyData = Encoding.UTF8.GetBytes(_peerListener.ConnectKey);
//Make initial packet
var connectPacket = _packetPool.Get(PacketProperty.ConnectRequest, 12 + keyData.Length);
//Add data
FastBitConverter.GetBytes(connectPacket.RawData, 1, NetConstants.ProtocolId);
FastBitConverter.GetBytes(connectPacket.RawData, 5, _connectId);
Buffer.BlockCopy(keyData, 0, connectPacket.RawData, 13, keyData.Length);
//Send raw
_peerListener.SendRawAndRecycle(connectPacket, _remoteEndPoint);
}
private void SendConnectAccept()
{
//Reset connection timer
_timeSinceLastPacket = 0;
//Make initial packet
var connectPacket = _packetPool.Get(PacketProperty.ConnectAccept, 8);
//Add data
FastBitConverter.GetBytes(connectPacket.RawData, 1, _connectId);
//Send raw
_peerListener.SendRawAndRecycle(connectPacket, _remoteEndPoint);
}
internal bool ProcessConnectAccept(NetPacket packet)
{
if (_connectionState != ConnectionState.InProgress)
return false;
//check connection id
if (BitConverter.ToInt64(packet.RawData, 1) != _connectId)
{
return false;
}
NetUtils.DebugWrite(ConsoleColor.Cyan, "[NC] Received connection accept");
_timeSinceLastPacket = 0;
_connectionState = ConnectionState.Connected;
return true;
}
private static PacketProperty SendOptionsToProperty(SendOptions options)
{
switch (options)
{
case SendOptions.ReliableUnordered:
return PacketProperty.Reliable;
case SendOptions.Sequenced:
return PacketProperty.Sequenced;
case SendOptions.ReliableOrdered:
return PacketProperty.ReliableOrdered;
default:
return PacketProperty.Unreliable;
}
}
public int GetMaxSinglePacketSize(SendOptions options)
{
return _mtu - NetPacket.GetHeaderSize(SendOptionsToProperty(options));
}
public void Send(byte[] data, SendOptions options)
{
Send(data, 0, data.Length, options);
}
public void Send(NetDataWriter dataWriter, SendOptions options)
{
Send(dataWriter.Data, 0, dataWriter.Length, options);
}
public void Send(byte[] data, int start, int length, SendOptions options)
{
//Prepare
PacketProperty property = SendOptionsToProperty(options);
int headerSize = NetPacket.GetHeaderSize(property);
//Check fragmentation
if (length + headerSize > _mtu)
{
if (options == SendOptions.Sequenced || options == SendOptions.Unreliable)
{
throw new Exception("Unreliable packet size > allowed (" + (_mtu - headerSize) + ")");
}
int packetFullSize = _mtu - headerSize;
int packetDataSize = packetFullSize - NetConstants.FragmentHeaderSize;
int fullPacketsCount = length / packetDataSize;
int lastPacketSize = length % packetDataSize;
int totalPackets = fullPacketsCount + (lastPacketSize == 0 ? 0 : 1);
NetUtils.DebugWrite("FragmentSend:\n" +
" MTU: {0}\n" +
" headerSize: {1}\n" +
" packetFullSize: {2}\n" +
" packetDataSize: {3}\n" +
" fullPacketsCount: {4}\n" +
" lastPacketSize: {5}\n" +
" totalPackets: {6}",
_mtu, headerSize, packetFullSize, packetDataSize, fullPacketsCount, lastPacketSize, totalPackets);
if (totalPackets > ushort.MaxValue)
{
throw new Exception("Too many fragments: " + totalPackets + " > " + ushort.MaxValue);
}
int dataOffset = headerSize + NetConstants.FragmentHeaderSize;
for (ushort i = 0; i < fullPacketsCount; i++)
{
NetPacket p = _packetPool.Get(property, packetFullSize);
p.FragmentId = _fragmentId;
p.FragmentPart = i;
p.FragmentsTotal = (ushort)totalPackets;
p.IsFragmented = true;
Buffer.BlockCopy(data, i * packetDataSize, p.RawData, dataOffset, packetDataSize);
SendPacket(p);
}
if (lastPacketSize > 0)
{
NetPacket p = _packetPool.Get(property, lastPacketSize + NetConstants.FragmentHeaderSize);
p.FragmentId = _fragmentId;
p.FragmentPart = (ushort)fullPacketsCount; //last
p.FragmentsTotal = (ushort)totalPackets;
p.IsFragmented = true;
Buffer.BlockCopy(data, fullPacketsCount * packetDataSize, p.RawData, dataOffset, lastPacketSize);
SendPacket(p);
}
_fragmentId++;
return;
}
//Else just send
NetPacket packet = _packetPool.GetWithData(property, data, start, length);
SendPacket(packet);
}
private void CreateAndSend(PacketProperty property, ushort sequence)
{
NetPacket packet = _packetPool.Get(property, 0);
packet.Sequence = sequence;
SendPacket(packet);
}
//from user thread, our thread, or recv?
private void SendPacket(NetPacket packet)
{
NetUtils.DebugWrite("[RS]Packet: " + packet.Property);
switch (packet.Property)
{
case PacketProperty.Reliable:
_reliableUnorderedChannel.AddToQueue(packet);
break;
case PacketProperty.Sequenced:
_sequencedChannel.AddToQueue(packet);
break;
case PacketProperty.ReliableOrdered:
_reliableOrderedChannel.AddToQueue(packet);
break;
case PacketProperty.Unreliable:
_simpleChannel.AddToQueue(packet);
break;
case PacketProperty.MtuCheck:
//Must check result for MTU fix
if (!_peerListener.SendRawAndRecycle(packet, _remoteEndPoint))
{
_finishMtu = true;
}
break;
case PacketProperty.AckReliable:
case PacketProperty.AckReliableOrdered:
case PacketProperty.Ping:
case PacketProperty.Pong:
case PacketProperty.Disconnect:
case PacketProperty.MtuOk:
SendRawData(packet);
_packetPool.Recycle(packet);
break;
default:
throw new Exception("Unknown packet property: " + packet.Property);
}
}
private void UpdateRoundTripTime(int roundTripTime)
{
//Calc average round trip time
_rtt += roundTripTime;
_rttCount++;
_avgRtt = _rtt/_rttCount;
//flowmode 0 = fastest
//flowmode max = lowest
if (_avgRtt < _peerListener.GetStartRtt(_currentFlowMode - 1))
{
if (_currentFlowMode <= 0)
{
//Already maxed
return;
}
_goodRttCount++;
if (_goodRttCount > NetConstants.FlowIncreaseThreshold)
{
_goodRttCount = 0;
_currentFlowMode--;
NetUtils.DebugWrite("[PA]Increased flow speed, RTT: {0}, PPS: {1}", _avgRtt, _peerListener.GetPacketsPerSecond(_currentFlowMode));
}
}
else if(_avgRtt > _peerListener.GetStartRtt(_currentFlowMode))
{
_goodRttCount = 0;
if (_currentFlowMode < _peerListener.GetMaxFlowMode())
{
_currentFlowMode++;
NetUtils.DebugWrite("[PA]Decreased flow speed, RTT: {0}, PPS: {1}", _avgRtt, _peerListener.GetPacketsPerSecond(_currentFlowMode));
}
}
//recalc resend delay
double avgRtt = _avgRtt;
if (avgRtt <= 0.0)
avgRtt = 0.1;
_resendDelay = 25 + (avgRtt * 2.1); // 25 ms + double rtt
}
internal void AddIncomingPacket(NetPacket p)
{
if (p.IsFragmented)
{
NetUtils.DebugWrite("Fragment. Id: {0}, Part: {1}, Total: {2}", p.FragmentId, p.FragmentPart, p.FragmentsTotal);
//Get needed array from dictionary
ushort packetFragId = p.FragmentId;
IncomingFragments incomingFragments;
if (!_holdedFragments.TryGetValue(packetFragId, out incomingFragments))
{
incomingFragments = new IncomingFragments
{
Fragments = new NetPacket[p.FragmentsTotal]
};
_holdedFragments.Add(packetFragId, incomingFragments);
}
//Cache
var fragments = incomingFragments.Fragments;
//Error check
if (p.FragmentPart >= fragments.Length || fragments[p.FragmentPart] != null)
{
_packetPool.Recycle(p);
NetUtils.DebugWriteError("Invalid fragment packet");
return;
}
//Fill array
fragments[p.FragmentPart] = p;
//Increase received fragments count
incomingFragments.ReceivedCount++;
//Increase total size
int dataOffset = p.GetHeaderSize() + NetConstants.FragmentHeaderSize;
incomingFragments.TotalSize += p.Size - dataOffset;
//Check for finish
if (incomingFragments.ReceivedCount != fragments.Length)
{
return;
}
NetUtils.DebugWrite("Received all fragments!");
NetPacket resultingPacket = _packetPool.Get( p.Property, incomingFragments.TotalSize );
int resultingPacketOffset = resultingPacket.GetHeaderSize();
int firstFragmentSize = fragments[0].Size - dataOffset;
for (int i = 0; i < incomingFragments.ReceivedCount; i++)
{
//Create resulting big packet
int fragmentSize = fragments[i].Size - dataOffset;
Buffer.BlockCopy(
fragments[i].RawData,
dataOffset,
resultingPacket.RawData,
resultingPacketOffset + firstFragmentSize * i,
fragmentSize);
//Free memory
_packetPool.Recycle(fragments[i]);
fragments[i] = null;
}
//Send to process
_peerListener.ReceiveFromPeer(resultingPacket, _remoteEndPoint);
//Clear memory
_packetPool.Recycle(resultingPacket);
_holdedFragments.Remove(packetFragId);
}
else //Just simple packet
{
_peerListener.ReceiveFromPeer(p, _remoteEndPoint);
_packetPool.Recycle(p);
}
}
private void ProcessMtuPacket(NetPacket packet)
{
if (packet.Size == 1 ||
packet.RawData[1] >= NetConstants.PossibleMtu.Length)
return;
//MTU auto increase
if (packet.Property == PacketProperty.MtuCheck)
{
if (packet.Size != NetConstants.PossibleMtu[packet.RawData[1]])
{
return;
}
_mtuCheckAttempts = 0;
NetUtils.DebugWrite("MTU check. Resend: " + packet.RawData[1]);
var mtuOkPacket = _packetPool.Get(PacketProperty.MtuOk, 1);
mtuOkPacket.RawData[1] = packet.RawData[1];
SendPacket(mtuOkPacket);
}
else if(packet.RawData[1] > _mtuIdx) //MtuOk
{
lock (_mtuMutex)
{
_mtuIdx = packet.RawData[1];
_mtu = NetConstants.PossibleMtu[_mtuIdx];
}
//if maxed - finish.
if (_mtuIdx == NetConstants.PossibleMtu.Length - 1)
{
_finishMtu = true;
}
NetUtils.DebugWrite("MTU ok. Increase to: " + _mtu);
}
}
//Process incoming packet
internal void ProcessPacket(NetPacket packet)
{
_timeSinceLastPacket = 0;
NetUtils.DebugWrite("[RR]PacketProperty: {0}", packet.Property);
switch (packet.Property)
{
case PacketProperty.ConnectRequest:
//response with connect
long newId = BitConverter.ToInt64(packet.RawData, 1);
if (newId > _connectId)
{
_connectId = newId;
}
NetUtils.DebugWrite("ConnectRequest LastId: {0}, NewId: {1}, EP: {2}", ConnectId, newId, _remoteEndPoint);
SendConnectAccept();
_packetPool.Recycle(packet);
break;
case PacketProperty.Merged:
int pos = NetConstants.HeaderSize;
while (pos < packet.Size)
{
ushort size = BitConverter.ToUInt16(packet.RawData, pos);
pos += 2;
NetPacket mergedPacket = _packetPool.GetAndRead(packet.RawData, pos, size);
if (mergedPacket == null)
{
_packetPool.Recycle(packet);
break;
}
pos += size;
ProcessPacket(mergedPacket);
}
break;
//If we get ping, send pong
case PacketProperty.Ping:
if (NetUtils.RelativeSequenceNumber(packet.Sequence, _remotePingSequence) < 0)
{
_packetPool.Recycle(packet);
break;
}
NetUtils.DebugWrite("[PP]Ping receive, send pong");
_remotePingSequence = packet.Sequence;
_packetPool.Recycle(packet);
//send
CreateAndSend(PacketProperty.Pong, _remotePingSequence);
break;
//If we get pong, calculate ping time and rtt
case PacketProperty.Pong:
if (NetUtils.RelativeSequenceNumber(packet.Sequence, _pingSequence) < 0)
{
_packetPool.Recycle(packet);
break;
}
_pingSequence = packet.Sequence;
int rtt = (int)(DateTime.UtcNow - _pingTimeStart).TotalMilliseconds;
UpdateRoundTripTime(rtt);
NetUtils.DebugWrite("[PP]Ping: {0}", rtt);
_packetPool.Recycle(packet);
break;
//Process ack
case PacketProperty.AckReliable:
_reliableUnorderedChannel.ProcessAck(packet);
_packetPool.Recycle(packet);
break;
case PacketProperty.AckReliableOrdered:
_reliableOrderedChannel.ProcessAck(packet);
_packetPool.Recycle(packet);
break;
//Process in order packets
case PacketProperty.Sequenced:
_sequencedChannel.ProcessPacket(packet);
break;
case PacketProperty.Reliable:
_reliableUnorderedChannel.ProcessPacket(packet);
break;
case PacketProperty.ReliableOrdered:
_reliableOrderedChannel.ProcessPacket(packet);
break;
//Simple packet without acks
case PacketProperty.Unreliable:
AddIncomingPacket(packet);
return;
case PacketProperty.MtuCheck:
case PacketProperty.MtuOk:
ProcessMtuPacket(packet);
break;
default:
NetUtils.DebugWriteError("Error! Unexpected packet type: " + packet.Property);
break;
}
}
private static bool CanMerge(PacketProperty property)
{
switch (property)
{
case PacketProperty.ConnectAccept:
case PacketProperty.ConnectRequest:
case PacketProperty.MtuOk:
case PacketProperty.Pong:
case PacketProperty.Disconnect:
return false;
default:
return true;
}
}
internal void SendRawData(NetPacket packet)
{
//2 - merge byte + minimal packet size + datalen(ushort)
if (_peerListener.MergeEnabled &&
CanMerge(packet.Property) &&
_mergePos + packet.Size + NetConstants.HeaderSize*2 + 2 < _mtu)
{
FastBitConverter.GetBytes(_mergeData.RawData, _mergePos + NetConstants.HeaderSize, (ushort)packet.Size);
Buffer.BlockCopy(packet.RawData, 0, _mergeData.RawData, _mergePos + NetConstants.HeaderSize + 2, packet.Size);
_mergePos += packet.Size + 2;
_mergeCount++;
//DebugWriteForce("Merged: " + _mergePos + "/" + (_mtu - 2) + ", count: " + _mergeCount);
return;
}
NetUtils.DebugWrite(ConsoleColor.DarkYellow, "[P]SendingPacket: " + packet.Property);
_peerListener.SendRaw(packet.RawData, 0, packet.Size, _remoteEndPoint);
}
private void SendQueuedPackets(int currentMaxSend)
{
int currentSended = 0;
while (currentSended < currentMaxSend)
{
//Get one of packets
if (_reliableOrderedChannel.SendNextPacket() ||
_reliableUnorderedChannel.SendNextPacket() ||
_sequencedChannel.SendNextPacket() ||
_simpleChannel.SendNextPacket())
{
currentSended++;
}
else
{
//no outgoing packets
break;
}
}
//Increase counter
_sendedPacketsCount += currentSended;
//If merging enabled
if (_mergePos > 0)
{
if (_mergeCount > 1)
{
NetUtils.DebugWrite("Send merged: " + _mergePos + ", count: " + _mergeCount);
_peerListener.SendRaw(_mergeData.RawData, 0, NetConstants.HeaderSize + _mergePos, _remoteEndPoint);
}
else
{
//Send without length information and merging
_peerListener.SendRaw(_mergeData.RawData, NetConstants.HeaderSize + 2, _mergePos - 2, _remoteEndPoint);
}
_mergePos = 0;
_mergeCount = 0;
}
}
/// <summary>
/// Flush all queued packets
/// </summary>
public void Flush()
{
lock (_flushLock)
{
SendQueuedPackets(int.MaxValue);
}
}
internal void Update(int deltaTime)
{
if (_connectionState == ConnectionState.Disconnected)
{
return;
}
_timeSinceLastPacket += deltaTime;
if (_connectionState == ConnectionState.InProgress)
{
_connectTimer += deltaTime;
if (_connectTimer > _peerListener.ReconnectDelay)
{
_connectTimer = 0;
_connectAttempts++;
if (_connectAttempts > _peerListener.MaxConnectAttempts)
{
_connectionState = ConnectionState.Disconnected;
return;
}
//else send connect again
SendConnectRequest();
}
return;
}
//Get current flow mode
int maxSendPacketsCount = _peerListener.GetPacketsPerSecond(_currentFlowMode);
int currentMaxSend;
if (maxSendPacketsCount > 0)
{
int availableSendPacketsCount = maxSendPacketsCount - _sendedPacketsCount;
currentMaxSend = Math.Min(availableSendPacketsCount, (maxSendPacketsCount*deltaTime)/NetConstants.FlowUpdateTime);
}
else
{
currentMaxSend = int.MaxValue;
}
//DebugWrite("[UPDATE]Delta: {0}ms, MaxSend: {1}", deltaTime, currentMaxSend);
//Pending acks
_reliableOrderedChannel.SendAcks();
_reliableUnorderedChannel.SendAcks();
//ResetFlowTimer
_flowTimer += deltaTime;
if (_flowTimer >= NetConstants.FlowUpdateTime)
{
NetUtils.DebugWrite("[UPDATE]Reset flow timer, _sendedPackets - {0}", _sendedPacketsCount);
_sendedPacketsCount = 0;
_flowTimer = 0;
}
//Send ping
_pingSendTimer += deltaTime;
if (_pingSendTimer >= _peerListener.PingInterval)
{
NetUtils.DebugWrite("[PP] Send ping...");
//reset timer
_pingSendTimer = 0;
//send ping
CreateAndSend(PacketProperty.Ping, _pingSequence);
//reset timer
_pingTimeStart = DateTime.UtcNow;
}
//RTT - round trip time
_rttResetTimer += deltaTime;
if (_rttResetTimer >= RttResetDelay)
{
_rttResetTimer = 0;
//Rtt update
_rtt = _avgRtt;
_ping = _avgRtt;
_peerListener.ConnectionLatencyUpdated(this, _ping);
_rttCount = 1;
}
//MTU - Maximum transmission unit
if (!_finishMtu)
{
_mtuCheckTimer += deltaTime;
if (_mtuCheckTimer >= MtuCheckDelay)
{
_mtuCheckTimer = 0;
_mtuCheckAttempts++;
if (_mtuCheckAttempts >= MaxMtuCheckAttempts)
{
_finishMtu = true;
}
else
{
lock (_mtuMutex)
{
//Send increased packet
if (_mtuIdx < NetConstants.PossibleMtu.Length - 1)
{
int newMtu = NetConstants.PossibleMtu[_mtuIdx + 1] - NetConstants.HeaderSize;
var p = _packetPool.Get(PacketProperty.MtuCheck, newMtu);
p.RawData[1] = (byte)(_mtuIdx + 1);
SendPacket(p);
}
}
}
}
}
//MTU - end
//Pending send
lock (_flushLock)
{
SendQueuedPackets(currentMaxSend);
}
}
//For channels
internal void Recycle(NetPacket packet)
{
_packetPool.Recycle(packet);
}
internal NetPacket GetPacketFromPool(PacketProperty property, int bytesCount)
{
return _packetPool.Get(property, bytesCount);
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 39ca2e83856ea4ba0a0100a00089e695
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,81 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System;
using System.Collections.Generic;
namespace FlyingWormConsole3.LiteNetLib
{
internal sealed class NetPeerCollection
{
private readonly Dictionary<NetEndPoint, NetPeer> _peersDict;
private readonly NetPeer[] _peersArray;
private int _count;
public int Count
{
get { return _count; }
}
public NetPeer this[int index]
{
get { return _peersArray[index]; }
}
public NetPeerCollection(int maxPeers)
{
_peersArray = new NetPeer[maxPeers];
_peersDict = new Dictionary<NetEndPoint, NetPeer>();
}
public bool TryGetValue(NetEndPoint endPoint, out NetPeer peer)
{
return _peersDict.TryGetValue(endPoint, out peer);
}
public void Clear()
{
Array.Clear(_peersArray, 0, _count);
_peersDict.Clear();
_count = 0;
}
public void Add(NetEndPoint endPoint, NetPeer peer)
{
_peersArray[_count] = peer;
_peersDict.Add(endPoint, peer);
_count++;
}
public bool ContainsAddress(NetEndPoint endPoint)
{
return _peersDict.ContainsKey(endPoint);
}
public NetPeer[] ToArray()
{
NetPeer[] result = new NetPeer[_count];
Array.Copy(_peersArray, 0, result, 0, _count);
return result;
}
public void RemoveAt(int idx)
{
_peersDict.Remove(_peersArray[idx].EndPoint);
_peersArray[idx] = _peersArray[_count - 1];
_peersArray[_count - 1] = null;
_count--;
}
public void Remove(NetEndPoint endPoint)
{
for (int i = 0; i < _count; i++)
{
if (_peersArray[i].EndPoint.Equals(endPoint))
{
RemoveAt(i);
break;
}
}
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ca9b271291848481a86c9b3cb7f07451
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,709 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System;
using System.Reflection;
using System.Collections.Generic;
#if WINRT || NETCORE
using System.Linq;
#endif
namespace FlyingWormConsole3.LiteNetLib.Utils
{
public interface INetSerializable
{
void Serialize(NetDataWriter writer);
void Desereialize(NetDataReader reader);
}
public abstract class NetSerializerHasher
{
public abstract ulong GetHash(string type);
public abstract void WriteHash(ulong hash, NetDataWriter writer);
public abstract ulong ReadHash(NetDataReader reader);
}
public sealed class FNVHasher : NetSerializerHasher
{
private readonly Dictionary<string, ulong> _hashCache = new Dictionary<string, ulong>();
private readonly char[] _hashBuffer = new char[1024];
public override ulong GetHash(string type)
{
ulong hash;
if (_hashCache.TryGetValue(type, out hash))
{
return hash;
}
hash = 14695981039346656037UL; //offset
int len = type.Length;
type.CopyTo(0, _hashBuffer, 0, len);
for (var i = 0; i < len; i++)
{
hash = hash ^ _hashBuffer[i];
hash *= 1099511628211UL; //prime
}
_hashCache.Add(type, hash);
return hash;
}
public override ulong ReadHash(NetDataReader reader)
{
return reader.GetULong();
}
public override void WriteHash(ulong hash, NetDataWriter writer)
{
writer.Put(hash);
}
}
public sealed class NetSerializer
{
private sealed class CustomType
{
public readonly CustomTypeWrite WriteDelegate;
public readonly CustomTypeRead ReadDelegate;
public CustomType(CustomTypeWrite writeDelegate, CustomTypeRead readDelegate)
{
WriteDelegate = writeDelegate;
ReadDelegate = readDelegate;
}
}
private delegate void CustomTypeWrite(NetDataWriter writer, object customObj);
private delegate object CustomTypeRead(NetDataReader reader);
private sealed class StructInfo
{
public readonly Action<NetDataWriter>[] WriteDelegate;
public readonly Action<NetDataReader>[] ReadDelegate;
public readonly Type[] FieldTypes;
public object Reference;
public Func<object> CreatorFunc;
public Action<object, object> OnReceive;
public readonly ulong Hash;
public readonly int MembersCount;
public StructInfo(ulong hash, int membersCount)
{
Hash = hash;
MembersCount = membersCount;
WriteDelegate = new Action<NetDataWriter>[membersCount];
ReadDelegate = new Action<NetDataReader>[membersCount];
FieldTypes = new Type[membersCount];
}
public void Write(NetDataWriter writer, object obj)
{
Reference = obj;
for (int i = 0; i < MembersCount; i++)
{
WriteDelegate[i](writer);
}
}
public void Read(NetDataReader reader)
{
for (int i = 0; i < MembersCount; i++)
{
ReadDelegate[i](reader);
}
}
}
private readonly Dictionary<ulong, StructInfo> _cache;
private readonly Dictionary<Type, CustomType> _registeredCustomTypes;
private static readonly HashSet<Type> BasicTypes = new HashSet<Type>
{
typeof(int),
typeof(uint),
typeof(byte),
typeof(sbyte),
typeof(short),
typeof(ushort),
typeof(long),
typeof(ulong),
typeof(string),
typeof(float),
typeof(double),
typeof(bool)
};
private readonly NetDataWriter _writer;
private readonly NetSerializerHasher _hasher;
private const int MaxStringLenght = 1024;
public NetSerializer() : this(new FNVHasher())
{
}
public NetSerializer(NetSerializerHasher hasher)
{
_hasher = hasher;
_cache = new Dictionary<ulong, StructInfo>();
_registeredCustomTypes = new Dictionary<Type, CustomType>();
_writer = new NetDataWriter();
}
private bool RegisterCustomTypeInternal<T>(Func<T> constructor) where T : INetSerializable
{
var t = typeof(T);
if (_registeredCustomTypes.ContainsKey(t))
{
return false;
}
var rwDelegates = new CustomType(
(writer, obj) =>
{
((T)obj).Serialize(writer);
},
reader =>
{
var instance = constructor();
instance.Desereialize(reader);
return instance;
});
_registeredCustomTypes.Add(t, rwDelegates);
return true;
}
/// <summary>
/// Register custom property type
/// </summary>
/// <typeparam name="T">INetSerializable structure</typeparam>
/// <returns>True - if register successful, false - if type already registered</returns>
public bool RegisterCustomType<T>() where T : struct, INetSerializable
{
return RegisterCustomTypeInternal(() => new T());
}
/// <summary>
/// Register custom property type
/// </summary>
/// <typeparam name="T">INetSerializable class</typeparam>
/// <returns>True - if register successful, false - if type already registered</returns>
public bool RegisterCustomType<T>(Func<T> constructor) where T : class, INetSerializable
{
return RegisterCustomTypeInternal(constructor);
}
/// <summary>
/// Register custom property type
/// </summary>
/// <param name="writeDelegate"></param>
/// <param name="readDelegate"></param>
/// <returns>True - if register successful, false - if type already registered</returns>
public bool RegisterCustomType<T>(Action<NetDataWriter, T> writeDelegate, Func<NetDataReader, T> readDelegate)
{
var t = typeof(T);
if (BasicTypes.Contains(t) || _registeredCustomTypes.ContainsKey(t))
{
return false;
}
var rwDelegates = new CustomType(
(writer, obj) => writeDelegate(writer, (T)obj),
reader => readDelegate(reader));
_registeredCustomTypes.Add(t, rwDelegates);
return true;
}
private static Delegate CreateDelegate(Type type, MethodInfo info)
{
#if WINRT || NETCORE
return info.CreateDelegate(type);
#else
return Delegate.CreateDelegate(type, info);
#endif
}
private static Func<TClass, TProperty> ExtractGetDelegate<TClass, TProperty>(MethodInfo info)
{
return (Func<TClass, TProperty>)CreateDelegate(typeof(Func<TClass, TProperty>), info);
}
private static Action<TClass, TProperty> ExtractSetDelegate<TClass, TProperty>(MethodInfo info)
{
return (Action<TClass, TProperty>)CreateDelegate(typeof(Action<TClass, TProperty>), info);
}
private StructInfo RegisterInternal<T>() where T : class
{
Type t = typeof(T);
ulong nameHash = _hasher.GetHash(t.Name);
StructInfo info;
if (_cache.TryGetValue(nameHash, out info))
{
return info;
}
#if WINRT || NETCORE
var props = t.GetRuntimeProperties().ToArray();
int propsCount = props.Count();
#else
var props = t.GetProperties(
BindingFlags.Instance |
BindingFlags.Public |
BindingFlags.GetProperty |
BindingFlags.SetProperty);
int propsCount = props.Length;
#endif
if (props == null || propsCount < 0)
{
throw new ArgumentException("Type does not contain acceptable fields");
}
info = new StructInfo(nameHash, propsCount);
for (int i = 0; i < props.Length; i++)
{
var property = props[i];
var propertyType = property.PropertyType;
//Set field type
info.FieldTypes[i] = propertyType.IsArray ? propertyType.GetElementType() : propertyType;
#if WINRT || NETCORE
bool isEnum = propertyType.GetTypeInfo().IsEnum;
var getMethod = property.GetMethod;
var setMethod = property.SetMethod;
#else
bool isEnum = propertyType.IsEnum;
var getMethod = property.GetGetMethod();
var setMethod = property.GetSetMethod();
#endif
if (isEnum)
{
var underlyingType = Enum.GetUnderlyingType(propertyType);
if (underlyingType == typeof(byte))
{
info.ReadDelegate[i] = reader =>
{
property.SetValue(info.Reference, Enum.ToObject(propertyType, reader.GetByte()), null);
};
info.WriteDelegate[i] = writer =>
{
writer.Put((byte)property.GetValue(info.Reference, null));
};
}
else if (underlyingType == typeof(int))
{
info.ReadDelegate[i] = reader =>
{
property.SetValue(info.Reference, Enum.ToObject(propertyType, reader.GetInt()), null);
};
info.WriteDelegate[i] = writer =>
{
writer.Put((int)property.GetValue(info.Reference, null));
};
}
else
{
throw new Exception("Not supported enum underlying type: " + underlyingType.Name);
}
}
else if (propertyType == typeof(string))
{
var setDelegate = ExtractSetDelegate<T, string>(setMethod);
var getDelegate = ExtractGetDelegate<T, string>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetString(MaxStringLenght));
info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference), MaxStringLenght);
}
else if (propertyType == typeof(bool))
{
var setDelegate = ExtractSetDelegate<T, bool>(setMethod);
var getDelegate = ExtractGetDelegate<T, bool>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetBool());
info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(byte))
{
var setDelegate = ExtractSetDelegate<T, byte>(setMethod);
var getDelegate = ExtractGetDelegate<T, byte>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetByte());
info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(sbyte))
{
var setDelegate = ExtractSetDelegate<T, sbyte>(setMethod);
var getDelegate = ExtractGetDelegate<T, sbyte>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetSByte());
info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(short))
{
var setDelegate = ExtractSetDelegate<T, short>(setMethod);
var getDelegate = ExtractGetDelegate<T, short>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetShort());
info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(ushort))
{
var setDelegate = ExtractSetDelegate<T, ushort>(setMethod);
var getDelegate = ExtractGetDelegate<T, ushort>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetUShort());
info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(int))
{
var setDelegate = ExtractSetDelegate<T, int>(setMethod);
var getDelegate = ExtractGetDelegate<T, int>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetInt());
info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(uint))
{
var setDelegate = ExtractSetDelegate<T, uint>(setMethod);
var getDelegate = ExtractGetDelegate<T, uint>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetUInt());
info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(long))
{
var setDelegate = ExtractSetDelegate<T, long>(setMethod);
var getDelegate = ExtractGetDelegate<T, long>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetLong());
info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(ulong))
{
var setDelegate = ExtractSetDelegate<T, ulong>(setMethod);
var getDelegate = ExtractGetDelegate<T, ulong>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetULong());
info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(float))
{
var setDelegate = ExtractSetDelegate<T, float>(setMethod);
var getDelegate = ExtractGetDelegate<T, float>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetFloat());
info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(double))
{
var setDelegate = ExtractSetDelegate<T, double>(setMethod);
var getDelegate = ExtractGetDelegate<T, double>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetDouble());
info.WriteDelegate[i] = writer => writer.Put(getDelegate((T)info.Reference));
}
// Array types
else if (propertyType == typeof(string[]))
{
var setDelegate = ExtractSetDelegate<T, string[]>(setMethod);
var getDelegate = ExtractGetDelegate<T, string[]>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetStringArray(MaxStringLenght));
info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference), MaxStringLenght);
}
else if (propertyType == typeof(byte[]))
{
var setDelegate = ExtractSetDelegate<T, byte[]>(setMethod);
var getDelegate = ExtractGetDelegate<T, byte[]>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetBytesWithLength());
info.WriteDelegate[i] = writer => writer.PutBytesWithLength(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(short[]))
{
var setDelegate = ExtractSetDelegate<T, short[]>(setMethod);
var getDelegate = ExtractGetDelegate<T, short[]>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetShortArray());
info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(ushort[]))
{
var setDelegate = ExtractSetDelegate<T, ushort[]>(setMethod);
var getDelegate = ExtractGetDelegate<T, ushort[]>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetUShortArray());
info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(int[]))
{
var setDelegate = ExtractSetDelegate<T, int[]>(setMethod);
var getDelegate = ExtractGetDelegate<T, int[]>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetIntArray());
info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(uint[]))
{
var setDelegate = ExtractSetDelegate<T, uint[]>(setMethod);
var getDelegate = ExtractGetDelegate<T, uint[]>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetUIntArray());
info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(long[]))
{
var setDelegate = ExtractSetDelegate<T, long[]>(setMethod);
var getDelegate = ExtractGetDelegate<T, long[]>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetLongArray());
info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(ulong[]))
{
var setDelegate = ExtractSetDelegate<T, ulong[]>(setMethod);
var getDelegate = ExtractGetDelegate<T, ulong[]>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetULongArray());
info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(float[]))
{
var setDelegate = ExtractSetDelegate<T, float[]>(setMethod);
var getDelegate = ExtractGetDelegate<T, float[]>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetFloatArray());
info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
}
else if (propertyType == typeof(double[]))
{
var setDelegate = ExtractSetDelegate<T, double[]>(setMethod);
var getDelegate = ExtractGetDelegate<T, double[]>(getMethod);
info.ReadDelegate[i] = reader => setDelegate((T)info.Reference, reader.GetDoubleArray());
info.WriteDelegate[i] = writer => writer.PutArray(getDelegate((T)info.Reference));
}
else
{
CustomType registeredCustomType;
bool array = false;
if (propertyType.IsArray)
{
array = true;
propertyType = propertyType.GetElementType();
}
if (_registeredCustomTypes.TryGetValue(propertyType, out registeredCustomType))
{
if (array) //Array type serialize/deserialize
{
info.ReadDelegate[i] = reader =>
{
ushort arrLength = reader.GetUShort();
Array arr = Array.CreateInstance(propertyType, arrLength);
for (int k = 0; k < arrLength; k++)
{
arr.SetValue(registeredCustomType.ReadDelegate(reader), k);
}
property.SetValue(info.Reference, arr, null);
};
info.WriteDelegate[i] = writer =>
{
Array arr = (Array)property.GetValue(info.Reference, null);
writer.Put((ushort)arr.Length);
for (int k = 0; k < arr.Length; k++)
{
registeredCustomType.WriteDelegate(writer, arr.GetValue(k));
}
};
}
else //Simple
{
info.ReadDelegate[i] = reader =>
{
property.SetValue(info.Reference, registeredCustomType.ReadDelegate(reader), null);
};
info.WriteDelegate[i] = writer =>
{
registeredCustomType.WriteDelegate(writer, property.GetValue(info.Reference, null));
};
}
}
else
{
throw new Exception("Unknown property type: " + propertyType.Name);
}
}
}
_cache.Add(nameHash, info);
return info;
}
/// <summary>
/// Reads all available data from NetDataReader and calls OnReceive delegates
/// </summary>
/// <param name="reader">NetDataReader with packets data</param>
public void ReadAllPackets(NetDataReader reader)
{
while (reader.AvailableBytes > 0)
{
ReadPacket(reader);
}
}
/// <summary>
/// Reads all available data from NetDataReader and calls OnReceive delegates
/// </summary>
/// <param name="reader">NetDataReader with packets data</param>
/// <param name="userData">Argument that passed to OnReceivedEvent</param>
public void ReadAllPackets<T>(NetDataReader reader, T userData)
{
while (reader.AvailableBytes > 0)
{
ReadPacket(reader, userData);
}
}
/// <summary>
/// Reads one packet from NetDataReader and calls OnReceive delegate
/// </summary>
/// <param name="reader">NetDataReader with packet</param>
public void ReadPacket(NetDataReader reader)
{
ReadPacket(reader, null);
}
private StructInfo ReadInfo(NetDataReader reader)
{
ulong hash = _hasher.ReadHash(reader);
StructInfo info;
if (!_cache.TryGetValue(hash, out info))
{
throw new Exception("Undefined packet received");
}
return info;
}
/// <summary>
/// Reads packet with known type
/// </summary>
/// <param name="reader">NetDataReader with packet</param>
/// <returns>Returns packet if packet in reader is matched type</returns>
public T ReadKnownPacket<T>(NetDataReader reader) where T : class, new()
{
var info = ReadInfo(reader);
ulong typeHash = _hasher.GetHash(typeof(T).Name);
if (typeHash != info.Hash)
{
return null;
}
info.Reference = info.CreatorFunc != null ? info.CreatorFunc() : Activator.CreateInstance<T>();
info.Read(reader);
return (T)info.Reference;
}
/// <summary>
/// Reads packet with known type (non alloc variant)
/// </summary>
/// <param name="reader">NetDataReader with packet</param>
/// <param name="target">Deserialization target</param>
/// <returns>Returns true if packet in reader is matched type</returns>
public bool ReadKnownPacket<T>(NetDataReader reader, T target) where T : class, new()
{
var info = ReadInfo(reader);
ulong typeHash = _hasher.GetHash(typeof(T).Name);
if (typeHash != info.Hash)
{
return false;
}
info.Reference = target;
info.Read(reader);
return true;
}
/// <summary>
/// Reads one packet from NetDataReader and calls OnReceive delegate
/// </summary>
/// <param name="reader">NetDataReader with packet</param>
/// <param name="userData">Argument that passed to OnReceivedEvent</param>
public void ReadPacket(NetDataReader reader, object userData)
{
var info = ReadInfo(reader);
if (info.CreatorFunc != null)
{
info.Reference = info.CreatorFunc();
}
info.Read(reader);
info.OnReceive(info.Reference, userData);
}
/// <summary>
/// Register and subscribe to packet receive event
/// </summary>
/// <param name="onReceive">event that will be called when packet deserialized with ReadPacket method</param>
/// <param name="packetConstructor">Method that constructs packet intead of slow Activator.CreateInstance</param>
public void Subscribe<T>(Action<T> onReceive, Func<T> packetConstructor) where T : class, new()
{
var info = RegisterInternal<T>();
info.CreatorFunc = () => packetConstructor();
info.OnReceive = (o, userData) => { onReceive((T)o); };
}
/// <summary>
/// Register packet type for direct reading (ReadKnownPacket)
/// </summary>
/// <param name="packetConstructor">Method that constructs packet intead of slow Activator.CreateInstance</param>
public void Register<T>(Func<T> packetConstructor = null) where T : class, new()
{
var info = RegisterInternal<T>();
if (packetConstructor != null)
{
info.CreatorFunc = () => packetConstructor();
}
info.OnReceive = (o, userData) => { };
}
/// <summary>
/// Register and subscribe to packet receive event (with userData)
/// </summary>
/// <param name="onReceive">event that will be called when packet deserialized with ReadPacket method</param>
/// <param name="packetConstructor">Method that constructs packet intead of slow Activator.CreateInstance</param>
public void Subscribe<T, TUserData>(Action<T, TUserData> onReceive, Func<T> packetConstructor) where T : class, new()
{
var info = RegisterInternal<T>();
info.CreatorFunc = () => packetConstructor();
info.OnReceive = (o, userData) => { onReceive((T)o, (TUserData)userData); };
}
/// <summary>
/// Register and subscribe to packet receive event
/// This metod will overwrite last received packet class on receive (less garbage)
/// </summary>
/// <param name="onReceive">event that will be called when packet deserialized with ReadPacket method</param>
public void SubscribeReusable<T>(Action<T> onReceive) where T : class, new()
{
var info = RegisterInternal<T>();
info.Reference = new T();
info.OnReceive = (o, userData) => { onReceive((T)o); };
}
/// <summary>
/// Register and subscribe to packet receive event
/// This metod will overwrite last received packet class on receive (less garbage)
/// </summary>
/// <param name="onReceive">event that will be called when packet deserialized with ReadPacket method</param>
public void SubscribeReusable<T, TUserData>(Action<T, TUserData> onReceive) where T : class, new()
{
var info = RegisterInternal<T>();
info.Reference = new T();
info.OnReceive = (o, userData) => { onReceive((T)o, (TUserData)userData); };
}
/// <summary>
/// Serialize struct to NetDataWriter (fast)
/// </summary>
/// <param name="writer">Serialization target NetDataWriter</param>
/// <param name="obj">Struct to serialize</param>
public void Serialize<T>(NetDataWriter writer, T obj) where T : class, new()
{
var info = RegisterInternal<T>();
_hasher.WriteHash(info.Hash, writer);
info.Write(writer, obj);
}
/// <summary>
/// Serialize struct to byte array
/// </summary>
/// <param name="obj">Struct to serialize</param>
/// <returns>byte array with serialized data</returns>
public byte[] Serialize<T>(T obj) where T : class, new()
{
_writer.Reset();
Serialize(_writer, obj);
return _writer.CopyData();
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e26db3a8188754e07b42db31f32e20f7
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,455 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
#if !WINRT || UNITY_EDITOR
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace FlyingWormConsole3.LiteNetLib
{
internal sealed class NetSocket
{
private Socket _udpSocketv4;
private Socket _udpSocketv6;
private NetEndPoint _localEndPoint;
private Thread _threadv4;
private Thread _threadv6;
private bool _running;
private readonly NetManager.OnMessageReceived _onMessageReceived;
private static readonly IPAddress MulticastAddressV6 = IPAddress.Parse (NetConstants.MulticastGroupIPv6);
private static readonly bool IPv6Support;
private const int SocketReceivePollTime = 100000;
private const int SocketSendPollTime = 5000;
public NetEndPoint LocalEndPoint
{
get { return _localEndPoint; }
}
static NetSocket()
{
try
{
//Unity3d .NET 2.0 throws exception.
// IPv6Support = Socket.OSSupportsIPv6;
IPv6Support = false;
}
catch
{
IPv6Support = false;
}
}
public NetSocket(NetManager.OnMessageReceived onMessageReceived)
{
_onMessageReceived = onMessageReceived;
}
private void ReceiveLogic(object state)
{
Socket socket = (Socket)state;
EndPoint bufferEndPoint = new IPEndPoint(socket.AddressFamily == AddressFamily.InterNetwork ? IPAddress.Any : IPAddress.IPv6Any, 0);
NetEndPoint bufferNetEndPoint = new NetEndPoint((IPEndPoint)bufferEndPoint);
byte[] receiveBuffer = new byte[NetConstants.PacketSizeLimit];
while (_running)
{
//wait for data
if (!socket.Poll(SocketReceivePollTime, SelectMode.SelectRead))
{
continue;
}
int result;
//Reading data
try
{
result = socket.ReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ref bufferEndPoint);
if (!bufferNetEndPoint.EndPoint.Equals(bufferEndPoint))
{
bufferNetEndPoint = new NetEndPoint((IPEndPoint)bufferEndPoint);
}
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.ConnectionReset ||
ex.SocketErrorCode == SocketError.MessageSize)
{
//10040 - message too long
//10054 - remote close (not error)
//Just UDP
NetUtils.DebugWrite(ConsoleColor.DarkRed, "[R] Ingored error: {0} - {1}", (int)ex.SocketErrorCode, ex.ToString() );
continue;
}
NetUtils.DebugWriteError("[R]Error code: {0} - {1}", (int)ex.SocketErrorCode, ex.ToString());
_onMessageReceived(null, 0, (int)ex.SocketErrorCode, bufferNetEndPoint);
continue;
}
//All ok!
NetUtils.DebugWrite(ConsoleColor.Blue, "[R]Recieved data from {0}, result: {1}", bufferNetEndPoint.ToString(), result);
_onMessageReceived(receiveBuffer, result, 0, bufferNetEndPoint);
}
}
public bool Bind(int port, bool reuseAddress)
{
_udpSocketv4 = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
_udpSocketv4.Blocking = false;
_udpSocketv4.ReceiveBufferSize = NetConstants.SocketBufferSize;
_udpSocketv4.SendBufferSize = NetConstants.SocketBufferSize;
_udpSocketv4.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, NetConstants.SocketTTL);
if(reuseAddress)
_udpSocketv4.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
#if !NETCORE
_udpSocketv4.DontFragment = true;
#endif
try
{
_udpSocketv4.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
}
catch (SocketException e)
{
NetUtils.DebugWriteError("Broadcast error: {0}", e.ToString());
}
if (!BindSocket(_udpSocketv4, new IPEndPoint(IPAddress.Any, port)))
{
return false;
}
_localEndPoint = new NetEndPoint((IPEndPoint)_udpSocketv4.LocalEndPoint);
_running = true;
_threadv4 = new Thread(ReceiveLogic);
_threadv4.Name = "SocketThreadv4(" + port + ")";
_threadv4.IsBackground = true;
_threadv4.Start(_udpSocketv4);
//Check IPv6 support
if (!IPv6Support)
return true;
//Use one port for two sockets
port = _localEndPoint.Port;
_udpSocketv6 = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp);
_udpSocketv6.Blocking = false;
_udpSocketv6.ReceiveBufferSize = NetConstants.SocketBufferSize;
_udpSocketv6.SendBufferSize = NetConstants.SocketBufferSize;
if (reuseAddress)
_udpSocketv6.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
if (BindSocket(_udpSocketv6, new IPEndPoint(IPAddress.IPv6Any, port)))
{
_localEndPoint = new NetEndPoint((IPEndPoint)_udpSocketv6.LocalEndPoint);
try
{
_udpSocketv6.SetSocketOption(
SocketOptionLevel.IPv6,
SocketOptionName.AddMembership,
new IPv6MulticastOption(MulticastAddressV6));
}
catch(Exception)
{
// Unity3d throws exception - ignored
}
_threadv6 = new Thread(ReceiveLogic);
_threadv6.Name = "SocketThreadv6(" + port + ")";
_threadv6.IsBackground = true;
_threadv6.Start(_udpSocketv6);
}
return true;
}
private bool BindSocket(Socket socket, IPEndPoint ep)
{
try
{
socket.Bind(ep);
NetUtils.DebugWrite(ConsoleColor.Blue, "[B]Succesfully binded to port: {0}", ((IPEndPoint)socket.LocalEndPoint).Port);
}
catch (SocketException ex)
{
NetUtils.DebugWriteError("[B]Bind exception: {0}", ex.ToString());
//ODO: very temporary hack for iOS (Unity3D)
if (ex.SocketErrorCode == SocketError.AddressFamilyNotSupported)
{
return true;
}
return false;
}
return true;
}
public bool SendBroadcast(byte[] data, int offset, int size, int port)
{
try
{
int result = _udpSocketv4.SendTo(data, offset, size, SocketFlags.None, new IPEndPoint(IPAddress.Broadcast, port));
if (result <= 0)
return false;
if (IPv6Support)
{
result = _udpSocketv6.SendTo(data, offset, size, SocketFlags.None, new IPEndPoint(MulticastAddressV6, port));
if (result <= 0)
return false;
}
}
catch (Exception ex)
{
NetUtils.DebugWriteError("[S][MCAST]" + ex);
return false;
}
return true;
}
public int SendTo(byte[] data, int offset, int size, NetEndPoint remoteEndPoint, ref int errorCode)
{
try
{
int result = 0;
if (remoteEndPoint.EndPoint.AddressFamily == AddressFamily.InterNetwork)
{
if (!_udpSocketv4.Poll(SocketSendPollTime, SelectMode.SelectWrite))
return -1;
result = _udpSocketv4.SendTo(data, offset, size, SocketFlags.None, remoteEndPoint.EndPoint);
}
else if(IPv6Support)
{
if (!_udpSocketv6.Poll(SocketSendPollTime, SelectMode.SelectWrite))
return -1;
result = _udpSocketv6.SendTo(data, offset, size, SocketFlags.None, remoteEndPoint.EndPoint);
}
NetUtils.DebugWrite(ConsoleColor.Blue, "[S]Send packet to {0}, result: {1}", remoteEndPoint.EndPoint, result);
return result;
}
catch (SocketException ex)
{
if (ex.SocketErrorCode != SocketError.MessageSize)
{
NetUtils.DebugWriteError("[S]" + ex);
}
errorCode = (int)ex.SocketErrorCode;
return -1;
}
catch (Exception ex)
{
NetUtils.DebugWriteError("[S]" + ex);
return -1;
}
}
private void CloseSocket(Socket s)
{
#if NETCORE
s.Dispose();
#else
s.Close();
#endif
}
public void Close()
{
_running = false;
//Close IPv4
if (Thread.CurrentThread != _threadv4)
{
_threadv4.Join();
}
_threadv4 = null;
if (_udpSocketv4 != null)
{
CloseSocket(_udpSocketv4);
_udpSocketv4 = null;
}
//No ipv6
if (_udpSocketv6 == null)
return;
//Close IPv6
if (Thread.CurrentThread != _threadv6)
{
_threadv6.Join();
}
_threadv6 = null;
if (_udpSocketv6 != null)
{
CloseSocket(_udpSocketv6);
_udpSocketv6 = null;
}
}
}
}
#else
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using System.Threading.Tasks;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
namespace FlyingWormConsole3.LiteNetLib
{
internal sealed class NetSocket
{
private DatagramSocket _datagramSocket;
private readonly Dictionary<NetEndPoint, IOutputStream> _peers = new Dictionary<NetEndPoint, IOutputStream>();
private readonly NetManager.OnMessageReceived _onMessageReceived;
private readonly byte[] _byteBuffer = new byte[NetConstants.PacketSizeLimit];
private readonly IBuffer _buffer;
private NetEndPoint _bufferEndPoint;
private NetEndPoint _localEndPoint;
private static readonly HostName BroadcastAddress = new HostName("255.255.255.255");
private static readonly HostName MulticastAddressV6 = new HostName(NetConstants.MulticastGroupIPv6);
public NetEndPoint LocalEndPoint
{
get { return _localEndPoint; }
}
public NetSocket(NetManager.OnMessageReceived onMessageReceived)
{
_onMessageReceived = onMessageReceived;
_buffer = _byteBuffer.AsBuffer();
}
private void OnMessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
var result = args.GetDataStream().ReadAsync(_buffer, _buffer.Capacity, InputStreamOptions.None).AsTask().Result;
int length = (int)result.Length;
if (length <= 0)
return;
if (_bufferEndPoint == null ||
!_bufferEndPoint.HostName.IsEqual(args.RemoteAddress) ||
!_bufferEndPoint.PortStr.Equals(args.RemotePort))
{
_bufferEndPoint = new NetEndPoint(args.RemoteAddress, args.RemotePort);
}
_onMessageReceived(_byteBuffer, length, 0, _bufferEndPoint);
}
public bool Bind(int port, bool reuseAddress)
{
_datagramSocket = new DatagramSocket();
_datagramSocket.Control.InboundBufferSizeInBytes = NetConstants.SocketBufferSize;
_datagramSocket.Control.DontFragment = true;
_datagramSocket.Control.OutboundUnicastHopLimit = NetConstants.SocketTTL;
_datagramSocket.MessageReceived += OnMessageReceived;
try
{
_datagramSocket.BindServiceNameAsync(port.ToString()).AsTask().Wait();
_datagramSocket.JoinMulticastGroup(MulticastAddressV6);
_localEndPoint = new NetEndPoint(_datagramSocket.Information.LocalAddress, _datagramSocket.Information.LocalPort);
}
catch (Exception ex)
{
NetUtils.DebugWriteError("[B]Bind exception: {0}", ex.ToString());
return false;
}
return true;
}
public bool SendBroadcast(byte[] data, int offset, int size, int port)
{
var portString = port.ToString();
try
{
var outputStream =
_datagramSocket.GetOutputStreamAsync(BroadcastAddress, portString)
.AsTask()
.Result;
var writer = outputStream.AsStreamForWrite();
writer.Write(data, offset, size);
writer.Flush();
outputStream =
_datagramSocket.GetOutputStreamAsync(MulticastAddressV6, portString)
.AsTask()
.Result;
writer = outputStream.AsStreamForWrite();
writer.Write(data, offset, size);
writer.Flush();
}
catch (Exception ex)
{
NetUtils.DebugWriteError("[S][MCAST]" + ex);
return false;
}
return true;
}
public int SendTo(byte[] data, int offset, int length, NetEndPoint remoteEndPoint, ref int errorCode)
{
Task<uint> task = null;
try
{
IOutputStream writer;
if (!_peers.TryGetValue(remoteEndPoint, out writer))
{
writer =
_datagramSocket.GetOutputStreamAsync(remoteEndPoint.HostName, remoteEndPoint.PortStr)
.AsTask()
.Result;
_peers.Add(remoteEndPoint, writer);
}
task = writer.WriteAsync(data.AsBuffer(offset, length)).AsTask();
return (int)task.Result;
}
catch (Exception ex)
{
if (task?.Exception?.InnerExceptions != null)
{
ex = task.Exception.InnerException;
}
var errorStatus = SocketError.GetStatus(ex.HResult);
switch (errorStatus)
{
case SocketErrorStatus.MessageTooLong:
errorCode = 10040;
break;
default:
errorCode = (int)errorStatus;
NetUtils.DebugWriteError("[S " + errorStatus + "(" + errorCode + ")]" + ex);
break;
}
return -1;
}
}
internal void RemovePeer(NetEndPoint ep)
{
_peers.Remove(ep);
}
public void Close()
{
_datagramSocket.Dispose();
_datagramSocket = null;
ClearPeers();
}
internal void ClearPeers()
{
_peers.Clear();
}
}
}
#endif
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c517b909a8c704eae91d4eccf06bc8a1
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,97 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
#if WINRT && !UNITY_EDITOR
#define USE_WINRT
#endif
using System;
using System.Threading;
#if USE_WINRT
using Windows.Foundation;
using Windows.System.Threading;
using Windows.System.Threading.Core;
#endif
namespace FlyingWormConsole3.LiteNetLib
{
public sealed class NetThread
{
#if USE_WINRT
private readonly ManualResetEvent _updateWaiter = new ManualResetEvent(false);
private readonly ManualResetEvent _joinWaiter = new ManualResetEvent(false);
#else
private Thread _thread;
#endif
private readonly Action _callback;
public int SleepTime;
private bool _running;
private readonly string _name;
public bool IsRunning
{
get { return _running; }
}
public NetThread(string name, int sleepTime, Action callback)
{
_callback = callback;
SleepTime = sleepTime;
_name = name;
}
public void Start()
{
if (_running)
return;
_running = true;
#if USE_WINRT
var thread = new PreallocatedWorkItem(ThreadLogic, WorkItemPriority.Normal, WorkItemOptions.TimeSliced);
thread.RunAsync().AsTask();
#else
_thread = new Thread(ThreadLogic)
{
Name = _name,
IsBackground = true
};
_thread.Start();
#endif
}
public void Stop()
{
if (!_running)
return;
_running = false;
#if USE_WINRT
_joinWaiter.WaitOne();
#else
_thread.Join();
#endif
}
#if USE_WINRT
private void ThreadLogic(IAsyncAction action)
{
while (_running)
{
_callback();
_updateWaiter.WaitOne(SleepTime);
}
_joinWaiter.Set();
}
#else
private void ThreadLogic()
{
while (_running)
{
_callback();
Thread.Sleep(SleepTime);
}
}
#endif
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d1928476aac6242d29fab6849f102494
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,219 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
#define UNITY
using System;
using System.Collections.Generic;
using System.Diagnostics;
#if WINRT && !UNITY_EDITOR
using Windows.Networking;
using Windows.Networking.Connectivity;
#else
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
#endif
namespace FlyingWormConsole3.LiteNetLib
{
#if WINRT && !UNITY_EDITOR
public enum ConsoleColor
{
Gray,
Yellow,
Cyan,
DarkCyan,
DarkGreen,
Blue,
DarkRed,
Red,
Green,
DarkYellow
}
#endif
[Flags]
public enum LocalAddrType
{
IPv4 = 1,
IPv6 = 2,
All = 3
}
public static class NetUtils
{
internal static int RelativeSequenceNumber(int number, int expected)
{
return (number - expected + NetConstants.MaxSequence + NetConstants.HalfMaxSequence) % NetConstants.MaxSequence - NetConstants.HalfMaxSequence;
}
internal static int GetDividedPacketsCount(int size, int mtu)
{
return (size / mtu) + (size % mtu == 0 ? 0 : 1);
}
public static void PrintInterfaceInfos()
{
#if !WINRT || UNITY_EDITOR
DebugWriteForce(ConsoleColor.Green, "IPv6Support: {0}", Socket.OSSupportsIPv6);
try
{
foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
{
foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
{
if (ip.Address.AddressFamily == AddressFamily.InterNetwork ||
ip.Address.AddressFamily == AddressFamily.InterNetworkV6)
{
DebugWriteForce(
ConsoleColor.Green,
"Interface: {0}, Type: {1}, Ip: {2}, OpStatus: {3}",
ni.Name,
ni.NetworkInterfaceType.ToString(),
ip.Address.ToString(),
ni.OperationalStatus.ToString());
}
}
}
}
catch (Exception e)
{
DebugWriteForce(ConsoleColor.Red, "Error while getting interface infos: {0}", e.ToString());
}
#endif
}
public static void GetLocalIpList(List<string> targetList, LocalAddrType addrType)
{
bool ipv4 = (addrType & LocalAddrType.IPv4) == LocalAddrType.IPv4;
bool ipv6 = (addrType & LocalAddrType.IPv6) == LocalAddrType.IPv6;
#if WINRT && !UNITY_EDITOR
foreach (HostName localHostName in NetworkInformation.GetHostNames())
{
if (localHostName.IPInformation != null &&
((ipv4 && localHostName.Type == HostNameType.Ipv4) ||
(ipv6 && localHostName.Type == HostNameType.Ipv6)))
{
targetList.Add(localHostName.ToString());
}
}
#else
try
{
foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
{
//Skip loopback
if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback)
continue;
var ipProps = ni.GetIPProperties();
//Skip address without gateway
if (ipProps.GatewayAddresses.Count == 0)
continue;
foreach (UnicastIPAddressInformation ip in ipProps.UnicastAddresses)
{
var address = ip.Address;
if ((ipv4 && address.AddressFamily == AddressFamily.InterNetwork) ||
(ipv6 && address.AddressFamily == AddressFamily.InterNetworkV6))
targetList.Add(address.ToString());
}
}
}
catch
{
//ignored
}
//Fallback mode (unity android)
if (targetList.Count == 0)
{
#if NETCORE
var hostTask = Dns.GetHostEntryAsync(Dns.GetHostName());
hostTask.Wait();
var host = hostTask.Result;
#else
var host = Dns.GetHostEntry(Dns.GetHostName());
#endif
foreach (IPAddress ip in host.AddressList)
{
if((ipv4 && ip.AddressFamily == AddressFamily.InterNetwork) ||
(ipv6 && ip.AddressFamily == AddressFamily.InterNetworkV6))
targetList.Add(ip.ToString());
}
}
#endif
if (targetList.Count == 0)
{
if(ipv4)
targetList.Add("127.0.0.1");
if(ipv6)
targetList.Add("::1");
}
}
private static readonly List<string> IpList = new List<string>();
public static string GetLocalIp(LocalAddrType addrType)
{
lock (IpList)
{
IpList.Clear();
GetLocalIpList(IpList, addrType);
return IpList.Count == 0 ? string.Empty : IpList[0];
}
}
private static readonly object DebugLogLock = new object();
private static void DebugWriteLogic(ConsoleColor color, string str, params object[] args)
{
lock (DebugLogLock)
{
if (NetDebug.Logger == null)
{
#if UNITY
#if !UNITY_4_0
UnityEngine.Debug.LogFormat(str, args);
#endif
#elif WINRT
Debug.WriteLine(str, args);
#else
Console.ForegroundColor = color;
Console.WriteLine(str, args);
Console.ForegroundColor = ConsoleColor.Gray;
#endif
}
else
{
NetDebug.Logger.WriteNet(color, str, args);
}
}
}
[Conditional("DEBUG_MESSAGES")]
internal static void DebugWrite(string str, params object[] args)
{
DebugWriteLogic(ConsoleColor.DarkGreen, str, args);
}
[Conditional("DEBUG_MESSAGES")]
internal static void DebugWrite(ConsoleColor color, string str, params object[] args)
{
DebugWriteLogic(color, str, args);
}
[Conditional("DEBUG_MESSAGES"), Conditional("DEBUG")]
internal static void DebugWriteForce(ConsoleColor color, string str, params object[] args)
{
DebugWriteLogic(color, str, args);
}
[Conditional("DEBUG_MESSAGES"), Conditional("DEBUG")]
internal static void DebugWriteError(string str, params object[] args)
{
DebugWriteLogic(ConsoleColor.Red, str, args);
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0b27974b2b4714973a8f5a3ea4036677
timeCreated: 1497976517
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,59 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System;
using System.Threading;
namespace FlyingWormConsole3.LiteNetLib
{
public class NtpSyncModule
{
public DateTime? SyncedTime { get; private set; }
private readonly NetSocket _socket;
private readonly NetEndPoint _ntpEndPoint;
private readonly ManualResetEvent _waiter = new ManualResetEvent(false);
public NtpSyncModule(string ntpServer)
{
_ntpEndPoint = new NetEndPoint(ntpServer, 123);
_socket = new NetSocket(OnMessageReceived);
_socket.Bind(0, false);
SyncedTime = null;
}
private void OnMessageReceived(byte[] data, int length, int errorCode, NetEndPoint remoteEndPoint)
{
if (errorCode != 0)
{
_waiter.Set();
return;
}
ulong intPart = (ulong)data[40] << 24 | (ulong)data[41] << 16 | (ulong)data[42] << 8 | (ulong)data[43];
ulong fractPart = (ulong)data[44] << 24 | (ulong)data[45] << 16 | (ulong)data[46] << 8 | (ulong)data[47];
var milliseconds = (intPart * 1000) + ((fractPart * 1000) / 0x100000000L);
SyncedTime = (new DateTime(1900, 1, 1)).AddMilliseconds((long)milliseconds);
_waiter.Set();
}
public void GetNetworkTime()
{
if (SyncedTime != null)
return;
var ntpData = new byte[48];
//LeapIndicator = 0 (no warning)
//VersionNum = 3
//Mode = 3 (Client Mode)
ntpData[0] = 0x1B;
//send
int errorCode = 0;
_socket.SendTo(ntpData, 0, ntpData.Length, _ntpEndPoint, ref errorCode);
if(errorCode == 0)
_waiter.WaitOne(1000);
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 91e481bf657774228854ba5923470b26
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,375 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System;
using System.Collections.Generic;
using System.Threading;
namespace FlyingWormConsole3.LiteNetLib
{
internal sealed class ReliableChannel
{
private class PendingPacket
{
public NetPacket Packet;
public DateTime? TimeStamp;
public NetPacket GetAndClear()
{
var packet = Packet;
Packet = null;
TimeStamp = null;
return packet;
}
}
private readonly Queue<NetPacket> _outgoingPackets;
private readonly bool[] _outgoingAcks; //for send acks
private readonly PendingPacket[] _pendingPackets; //for unacked packets and duplicates
private readonly NetPacket[] _receivedPackets; //for order
private readonly bool[] _earlyReceived; //for unordered
private int _localSeqence;
private int _remoteSequence;
private int _localWindowStart;
private int _remoteWindowStart;
private readonly NetPeer _peer;
private bool _mustSendAcks;
private readonly bool _ordered;
private readonly int _windowSize;
private const int BitsInByte = 8;
private int _queueIndex;
public int PacketsInQueue
{
get { return _outgoingPackets.Count; }
}
public ReliableChannel(NetPeer peer, bool ordered, int windowSize)
{
_windowSize = windowSize;
_peer = peer;
_ordered = ordered;
_outgoingPackets = new Queue<NetPacket>(_windowSize);
_outgoingAcks = new bool[_windowSize];
_pendingPackets = new PendingPacket[_windowSize];
for (int i = 0; i < _pendingPackets.Length; i++)
{
_pendingPackets[i] = new PendingPacket();
}
if (_ordered)
_receivedPackets = new NetPacket[_windowSize];
else
_earlyReceived = new bool[_windowSize];
_localWindowStart = 0;
_localSeqence = 0;
_remoteSequence = 0;
_remoteWindowStart = 0;
}
//ProcessAck in packet
public void ProcessAck(NetPacket packet)
{
int validPacketSize = (_windowSize - 1) / BitsInByte + 1 + NetConstants.SequencedHeaderSize;
if (packet.Size != validPacketSize)
{
NetUtils.DebugWrite("[PA]Invalid acks packet size");
return;
}
ushort ackWindowStart = packet.Sequence;
if (ackWindowStart > NetConstants.MaxSequence)
{
NetUtils.DebugWrite("[PA]Bad window start");
return;
}
//check relevance
if (NetUtils.RelativeSequenceNumber(ackWindowStart, _localWindowStart) <= -_windowSize)
{
NetUtils.DebugWrite("[PA]Old acks");
return;
}
byte[] acksData = packet.RawData;
NetUtils.DebugWrite("[PA]AcksStart: {0}", ackWindowStart);
int startByte = NetConstants.SequencedHeaderSize;
Monitor.Enter(_pendingPackets);
for (int i = 0; i < _windowSize; i++)
{
int ackSequence = (ackWindowStart + i) % NetConstants.MaxSequence;
if (NetUtils.RelativeSequenceNumber(ackSequence, _localWindowStart) < 0)
{
//NetUtils.DebugWrite(ConsoleColor.Cyan, "[PA] SKIP OLD: " + ackSequence);
//Skip old ack
continue;
}
int currentByte = startByte + i / BitsInByte;
int currentBit = i % BitsInByte;
if ((acksData[currentByte] & (1 << currentBit)) == 0)
{
//NetUtils.DebugWrite(ConsoleColor.Cyan, "[PA] SKIP FALSE: " + ackSequence);
//Skip false ack
continue;
}
if (ackSequence == _localWindowStart)
{
//Move window
_localWindowStart = (_localWindowStart + 1) % NetConstants.MaxSequence;
}
NetPacket removed = _pendingPackets[ackSequence % _windowSize].GetAndClear();
if (removed != null)
{
_peer.Recycle(removed);
NetUtils.DebugWrite("[PA]Removing reliableInOrder ack: {0} - true", ackSequence);
}
else
{
NetUtils.DebugWrite("[PA]Removing reliableInOrder ack: {0} - false", ackSequence);
}
}
Monitor.Exit(_pendingPackets);
}
public void AddToQueue(NetPacket packet)
{
lock (_outgoingPackets)
{
_outgoingPackets.Enqueue(packet);
}
}
private void ProcessQueuedPackets()
{
//get packets from queue
while (_outgoingPackets.Count > 0)
{
int relate = NetUtils.RelativeSequenceNumber(_localSeqence, _localWindowStart);
if (relate < _windowSize)
{
NetPacket packet;
lock (_outgoingPackets)
{
packet = _outgoingPackets.Dequeue();
}
packet.Sequence = (ushort)_localSeqence;
_pendingPackets[_localSeqence % _windowSize].Packet = packet;
_localSeqence = (_localSeqence + 1) % NetConstants.MaxSequence;
}
else //Queue filled
{
break;
}
}
}
public bool SendNextPacket()
{
//check sending acks
DateTime currentTime = DateTime.UtcNow;
Monitor.Enter(_pendingPackets);
ProcessQueuedPackets();
//send
PendingPacket currentPacket;
bool packetFound = false;
int startQueueIndex = _queueIndex;
do
{
currentPacket = _pendingPackets[_queueIndex];
if (currentPacket.Packet != null)
{
//check send time
if(currentPacket.TimeStamp.HasValue)
{
double packetHoldTime = (currentTime - currentPacket.TimeStamp.Value).TotalMilliseconds;
if (packetHoldTime > _peer.ResendDelay)
{
NetUtils.DebugWrite("[RC]Resend: {0} > {1}", (int)packetHoldTime, _peer.ResendDelay);
packetFound = true;
}
}
else //Never sended
{
packetFound = true;
}
}
_queueIndex = (_queueIndex + 1) % _windowSize;
} while (!packetFound && _queueIndex != startQueueIndex);
if (packetFound)
{
currentPacket.TimeStamp = DateTime.UtcNow;
_peer.SendRawData(currentPacket.Packet);
NetUtils.DebugWrite("[RR]Sended");
}
Monitor.Exit(_pendingPackets);
return packetFound;
}
public void SendAcks()
{
if (!_mustSendAcks)
return;
_mustSendAcks = false;
NetUtils.DebugWrite("[RR]SendAcks");
//Init packet
int bytesCount = (_windowSize - 1) / BitsInByte + 1;
PacketProperty property = _ordered ? PacketProperty.AckReliableOrdered : PacketProperty.AckReliable;
var acksPacket = _peer.GetPacketFromPool(property, bytesCount);
//For quick access
byte[] data = acksPacket.RawData; //window start + acks size
//Put window start
Monitor.Enter(_outgoingAcks);
acksPacket.Sequence = (ushort)_remoteWindowStart;
//Put acks
int startAckIndex = _remoteWindowStart % _windowSize;
int currentAckIndex = startAckIndex;
int currentBit = 0;
int currentByte = NetConstants.SequencedHeaderSize;
do
{
if (_outgoingAcks[currentAckIndex])
{
data[currentByte] |= (byte)(1 << currentBit);
}
currentBit++;
if (currentBit == BitsInByte)
{
currentByte++;
currentBit = 0;
}
currentAckIndex = (currentAckIndex + 1) % _windowSize;
} while (currentAckIndex != startAckIndex);
Monitor.Exit(_outgoingAcks);
_peer.SendRawData(acksPacket);
_peer.Recycle(acksPacket);
}
//Process incoming packet
public void ProcessPacket(NetPacket packet)
{
if (packet.Sequence >= NetConstants.MaxSequence)
{
NetUtils.DebugWrite("[RR]Bad sequence");
return;
}
int relate = NetUtils.RelativeSequenceNumber(packet.Sequence, _remoteWindowStart);
int relateSeq = NetUtils.RelativeSequenceNumber(packet.Sequence, _remoteSequence);
if (relateSeq > _windowSize)
{
NetUtils.DebugWrite("[RR]Bad sequence");
return;
}
//Drop bad packets
if(relate < 0)
{
//Too old packet doesn't ack
NetUtils.DebugWrite("[RR]ReliableInOrder too old");
return;
}
if (relate >= _windowSize * 2)
{
//Some very new packet
NetUtils.DebugWrite("[RR]ReliableInOrder too new");
return;
}
//If very new - move window
Monitor.Enter(_outgoingAcks);
if (relate >= _windowSize)
{
//New window position
int newWindowStart = (_remoteWindowStart + relate - _windowSize + 1) % NetConstants.MaxSequence;
//Clean old data
while (_remoteWindowStart != newWindowStart)
{
_outgoingAcks[_remoteWindowStart % _windowSize] = false;
_remoteWindowStart = (_remoteWindowStart + 1) % NetConstants.MaxSequence;
}
}
//Final stage - process valid packet
//trigger acks send
_mustSendAcks = true;
if (_outgoingAcks[packet.Sequence % _windowSize])
{
NetUtils.DebugWrite("[RR]ReliableInOrder duplicate");
Monitor.Exit(_outgoingAcks);
return;
}
//save ack
_outgoingAcks[packet.Sequence % _windowSize] = true;
Monitor.Exit(_outgoingAcks);
//detailed check
if (packet.Sequence == _remoteSequence)
{
NetUtils.DebugWrite("[RR]ReliableInOrder packet succes");
_peer.AddIncomingPacket(packet);
_remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence;
if (_ordered)
{
NetPacket p;
while ( (p = _receivedPackets[_remoteSequence % _windowSize]) != null)
{
//process holded packet
_receivedPackets[_remoteSequence % _windowSize] = null;
_peer.AddIncomingPacket(p);
_remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence;
}
}
else
{
while (_earlyReceived[_remoteSequence % _windowSize])
{
//process early packet
_earlyReceived[_remoteSequence % _windowSize] = false;
_remoteSequence = (_remoteSequence + 1) % NetConstants.MaxSequence;
}
}
return;
}
//holded packet
if (_ordered)
{
_receivedPackets[packet.Sequence % _windowSize] = packet;
}
else
{
_earlyReceived[packet.Sequence % _windowSize] = true;
_peer.AddIncomingPacket(packet);
}
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 516bd901eb62f4bb391ef541f9effdec
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,4 @@
for file in *.cs; do
echo "#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA" | cat - $file > tempfile && mv tempfile $file
echo '#endif' >> "$file"
done
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a9f1f24482ff84a25a1188dd49ec4d86
timeCreated: 1498001160
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,53 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System.Collections.Generic;
namespace FlyingWormConsole3.LiteNetLib
{
internal sealed class SequencedChannel
{
private ushort _localSequence;
private ushort _remoteSequence;
private readonly Queue<NetPacket> _outgoingPackets;
private readonly NetPeer _peer;
public SequencedChannel(NetPeer peer)
{
_outgoingPackets = new Queue<NetPacket>();
_peer = peer;
}
public void AddToQueue(NetPacket packet)
{
lock (_outgoingPackets)
{
_outgoingPackets.Enqueue(packet);
}
}
public bool SendNextPacket()
{
NetPacket packet;
lock (_outgoingPackets)
{
if (_outgoingPackets.Count == 0)
return false;
packet = _outgoingPackets.Dequeue();
}
_localSequence++;
packet.Sequence = _localSequence;
_peer.SendRawData(packet);
_peer.Recycle(packet);
return true;
}
public void ProcessPacket(NetPacket packet)
{
if (NetUtils.RelativeSequenceNumber(packet.Sequence, _remoteSequence) > 0)
{
_remoteSequence = packet.Sequence;
_peer.AddIncomingPacket(packet);
}
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 84bbbc6c6e45c4287917fc944650e4af
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,40 @@
#if DEBUG && !UNITY_WP_8_1 && !UNITY_WSA
using System.Collections.Generic;
namespace FlyingWormConsole3.LiteNetLib
{
internal sealed class SimpleChannel
{
private readonly Queue<NetPacket> _outgoingPackets;
private readonly NetPeer _peer;
public SimpleChannel(NetPeer peer)
{
_outgoingPackets = new Queue<NetPacket>();
_peer = peer;
}
public void AddToQueue(NetPacket packet)
{
lock (_outgoingPackets)
{
_outgoingPackets.Enqueue(packet);
}
}
public bool SendNextPacket()
{
NetPacket packet;
lock (_outgoingPackets)
{
if (_outgoingPackets.Count == 0)
return false;
packet = _outgoingPackets.Dequeue();
}
_peer.SendRawData(packet);
_peer.Recycle(packet);
return true;
}
}
}
#endif
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6b4cdb673a0094d438a802844a8cc794
timeCreated: 1497976518
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 90979fd73276eab448e2785362667c6a
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: