ball 项目提交

This commit is contained in:
2026-04-20 12:06:34 +08:00
parent 4331ebba60
commit 99145facbd
6052 changed files with 576445 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: af3b822355b50854d85fb6b4fb58ba1b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,5 @@
org.gradle.jvmargs=-Xmx**JVM_HEAP_SIZE**M
org.gradle.parallel=true
android.enableR8=**MINIFY_WITH_R_EIGHT**
unityStreamingAssets=**STREAMING_ASSETS**
**ADDITIONAL_PROPERTIES**
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: dc96f3f48ea52c445af29f357b4ec42c
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,39 @@
apply plugin: 'com.android.library'
**APPLY_PLUGINS**
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
**DEPS**}
android {
compileSdkVersion **APIVERSION**
buildToolsVersion '**BUILDTOOLS**'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
minSdkVersion **MINSDKVERSION**
targetSdkVersion **TARGETSDKVERSION**
ndk {
abiFilters **ABIFILTERS**
}
versionCode **VERSIONCODE**
versionName '**VERSIONNAME**'
consumerProguardFiles 'proguard-unity.txt'**USER_PROGUARD**
}
lintOptions {
abortOnError false
}
aaptOptions {
noCompress = **BUILTIN_NOCOMPRESS** + unityStreamingAssets.tokenize(', ')
ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~"
}**PACKAGING_OPTIONS**
}**REPOSITORIES**
**IL_CPP_BUILD_SETUP**
**SOURCE_BUILD_SETUP**
**EXTERNAL_SOURCES**
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a66065698c9436344b3d18daccbdb027
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ff14fb2c30ffa6d41bc03ad58abc4f05
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -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:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 74883e5d446142e4f8d83cafa8d77f35
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,21 @@
fileFormatVersion: 2
guid: a50bd9a009c8dfc4ebd88cc8101225a7
labels:
- Tween
- Tweening
- Animation
- HOTween
- Paths
- iTween
- DFTween
- LeanTween
- Ease
- Easing
- Shake
- Punch
- 2DToolkit
- TextMeshPro
- Text
folderAsset: yes
DefaultImporter:
userData:
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,4 @@
fileFormatVersion: 2
guid: 34192c5e0d14aee43a0e86cc4823268a
TextScriptImporter:
userData:
Binary file not shown.
@@ -0,0 +1,4 @@
fileFormatVersion: 2
guid: 4f007001a22b3d24dae350342c4d19c8
DefaultImporter:
userData:
@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: a811bde74b26b53498b4f6d872b09b6d
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 1
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
Windows Store Apps: WindowsStoreApps
second:
enabled: 0
settings:
CPU: AnyCPU
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: b27f58ae5d5c33a4bb2d1f4f34bd036d
folderAsset: yes
DefaultImporter:
userData:
@@ -0,0 +1,107 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>DOTweenEditor</name>
</assembly>
<members>
<member name="M:DG.DOTweenEditor.DOTweenEditorPreview.Start(System.Action)">
<summary>
Starts the update loop of tween in the editor. Has no effect during playMode.
</summary>
<param name="onPreviewUpdated">Eventual callback to call after every update</param>
</member>
<member name="M:DG.DOTweenEditor.DOTweenEditorPreview.Stop(System.Boolean)">
<summary>
Stops the update loop and clears the onPreviewUpdated callback.
</summary>
<param name="resetTweenTargets">If TRUE also resets the tweened objects to their original state</param>
</member>
<member name="M:DG.DOTweenEditor.DOTweenEditorPreview.PrepareTweenForPreview(DG.Tweening.Tween,System.Boolean,System.Boolean,System.Boolean)">
<summary>
Readies the tween for editor preview by setting its UpdateType to Manual plus eventual extra settings.
</summary>
<param name="t">The tween to ready</param>
<param name="clearCallbacks">If TRUE (recommended) removes all callbacks (OnComplete/Rewind/etc)</param>
<param name="preventAutoKill">If TRUE prevents the tween from being auto-killed at completion</param>
<param name="andPlay">If TRUE starts playing the tween immediately</param>
</member>
<member name="F:DG.DOTweenEditor.EditorVersion.Version">
<summary>Full major version + first minor version (ex: 2018.1f)</summary>
</member>
<member name="F:DG.DOTweenEditor.EditorVersion.MajorVersion">
<summary>Major version</summary>
</member>
<member name="F:DG.DOTweenEditor.EditorVersion.MinorVersion">
<summary>First minor version (ex: in 2018.1 it would be 1)</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.SetEditorTexture(UnityEngine.Texture2D,UnityEngine.FilterMode,System.Int32)">
<summary>
Checks that the given editor texture use the correct import settings,
and applies them if they're incorrect.
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.DOTweenSetupRequired">
<summary>
Returns TRUE if setup is required
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.AssetExists(System.String)">
<summary>
Returns TRUE if the file/directory at the given path exists.
</summary>
<param name="adbPath">Path, relative to Unity's project folder</param>
<returns></returns>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.ADBPathToFullPath(System.String)">
<summary>
Converts the given project-relative path to a full path,
with backward (\) slashes).
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.FullPathToADBPath(System.String)">
<summary>
Converts the given full path to a path usable with AssetDatabase methods
(relative to Unity's project folder, and with the correct Unity forward (/) slashes).
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.ConnectToSourceAsset``1(System.String,System.Boolean)">
<summary>
Connects to a <see cref="T:UnityEngine.ScriptableObject"/> asset.
If the asset already exists at the given path, loads it and returns it.
Otherwise, either returns NULL or automatically creates it before loading and returning it
(depending on the given parameters).
</summary>
<typeparam name="T">Asset type</typeparam>
<param name="adbFilePath">File path (relative to Unity's project folder)</param>
<param name="createIfMissing">If TRUE and the requested asset doesn't exist, forces its creation</param>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.GetAssemblyFilePath(System.Reflection.Assembly)">
<summary>
Full path for the given loaded assembly, assembly file included
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.AddGlobalDefine(System.String)">
<summary>
Adds the given global define if it's not already present
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.RemoveGlobalDefine(System.String)">
<summary>
Removes the given global define if it's present
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.HasGlobalDefine(System.String,System.Nullable{UnityEditor.BuildTargetGroup})">
<summary>
Returns TRUE if the given global define is present in all the <see cref="T:UnityEditor.BuildTargetGroup"/>
or only in the given <see cref="T:UnityEditor.BuildTargetGroup"/>, depending on passed parameters.<para/>
</summary>
<param name="id"></param>
<param name="buildTargetGroup"><see cref="T:UnityEditor.BuildTargetGroup"/>to use. Leave NULL to check in all of them.</param>
</member>
<member name="T:DG.DOTweenEditor.DOTweenDefines">
<summary>
Not used as menu item anymore, but as a utiity function
</summary>
</member>
</members>
</doc>
@@ -0,0 +1,4 @@
fileFormatVersion: 2
guid: 2e2c6224d345d9249acfa6e8ef40bb2d
TextScriptImporter:
userData:
@@ -0,0 +1,4 @@
fileFormatVersion: 2
guid: 8f46310a8b0a8f04a92993c37c713243
DefaultImporter:
userData:
@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 45d5034162d6cf04dbe46da84fc7d074
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
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,5 @@
fileFormatVersion: 2
guid: 0034ebae0c2a9344e897db1160d71b6d
folderAsset: yes
DefaultImporter:
userData:
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,47 @@
fileFormatVersion: 2
guid: 8da095e39e9b4df488dfd436f81116d6
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 128
textureSettings:
filterMode: 1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

@@ -0,0 +1,47 @@
fileFormatVersion: 2
guid: 7051dba417b3d53409f2918f1ea4938d
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 256
textureSettings:
filterMode: 1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

@@ -0,0 +1,47 @@
fileFormatVersion: 2
guid: 519694efe2bb2914788b151fbd8c01f4
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 1
linearTexture: 0
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
seamlessCubemap: 0
textureFormat: -1
maxTextureSize: 1024
textureSettings:
filterMode: -1
aniso: -1
mipBias: -1
wrapMode: -1
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 0
textureType: -1
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:
Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

@@ -0,0 +1,47 @@
fileFormatVersion: 2
guid: 78a59ca99f8987941adb61f9e14a06a7
TextureImporter:
fileIDToRecycleName: {}
serializedVersion: 2
mipmaps:
mipMapMode: 0
enableMipMap: 0
linearTexture: 1
correctGamma: 0
fadeOut: 0
borderMipMap: 0
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: .25
normalMapFilter: 0
isReadable: 0
grayScaleToAlpha: 0
generateCubemap: 0
seamlessCubemap: 0
textureFormat: -3
maxTextureSize: 512
textureSettings:
filterMode: 1
aniso: 1
mipBias: -1
wrapMode: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: .5, y: .5}
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spritePixelsToUnits: 100
alphaIsTransparency: 1
textureType: 2
buildTargetSettings: []
spriteSheet:
sprites: []
spritePackingTag:
userData:
@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 143604b8bad857d47a6f7cc7a533e2dc
folderAsset: yes
DefaultImporter:
userData:
@@ -0,0 +1,3 @@
{
"name": "DOTween.Modules"
}
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1d85850b2bd2239408107d29ad53c78e
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,202 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if true // MODULE_MARKER
using System;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;
using UnityEngine;
#if UNITY_5 || UNITY_2017_1_OR_NEWER
using UnityEngine.Audio; // Required for AudioMixer
#endif
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModuleAudio
{
#region Shortcuts
#region Audio
/// <summary>Tweens an AudioSource's volume to the given value.
/// Also stores the AudioSource as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach (0 to 1)</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOFade(this AudioSource target, float endValue, float duration)
{
if (endValue < 0) endValue = 0;
else if (endValue > 1) endValue = 1;
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.volume, x => target.volume = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an AudioSource's pitch to the given value.
/// Also stores the AudioSource as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOPitch(this AudioSource target, float endValue, float duration)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.pitch, x => target.pitch = x, endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#if UNITY_5 || UNITY_2017_1_OR_NEWER
#region AudioMixer (Unity 5 or Newer)
/// <summary>Tweens an AudioMixer's exposed float to the given value.
/// Also stores the AudioMixer as the tween's target so it can be used for filtered operations.
/// Note that you need to manually expose a float in an AudioMixerGroup in order to be able to tween it from an AudioMixer.</summary>
/// <param name="floatName">Name given to the exposed float to set</param>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOSetFloat(this AudioMixer target, string floatName, float endValue, float duration)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(()=> {
float currVal;
target.GetFloat(floatName, out currVal);
return currVal;
}, x=> target.SetFloat(floatName, x), endValue, duration);
t.SetTarget(target);
return t;
}
#region Operation Shortcuts
/// <summary>
/// Completes all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens completed
/// (meaning the tweens that don't have infinite loops and were not already complete)
/// </summary>
/// <param name="withCallbacks">For Sequences only: if TRUE also internal Sequence callbacks will be fired,
/// otherwise they will be ignored</param>
public static int DOComplete(this AudioMixer target, bool withCallbacks = false)
{
return DOTween.Complete(target, withCallbacks);
}
/// <summary>
/// Kills all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens killed.
/// </summary>
/// <param name="complete">If TRUE completes the tween before killing it</param>
public static int DOKill(this AudioMixer target, bool complete = false)
{
return DOTween.Kill(target, complete);
}
/// <summary>
/// Flips the direction (backwards if it was going forward or viceversa) of all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens flipped.
/// </summary>
public static int DOFlip(this AudioMixer target)
{
return DOTween.Flip(target);
}
/// <summary>
/// Sends to the given position all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens involved.
/// </summary>
/// <param name="to">Time position to reach
/// (if higher than the whole tween duration the tween will simply reach its end)</param>
/// <param name="andPlay">If TRUE will play the tween after reaching the given position, otherwise it will pause it</param>
public static int DOGoto(this AudioMixer target, float to, bool andPlay = false)
{
return DOTween.Goto(target, to, andPlay);
}
/// <summary>
/// Pauses all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens paused.
/// </summary>
public static int DOPause(this AudioMixer target)
{
return DOTween.Pause(target);
}
/// <summary>
/// Plays all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens played.
/// </summary>
public static int DOPlay(this AudioMixer target)
{
return DOTween.Play(target);
}
/// <summary>
/// Plays backwards all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens played.
/// </summary>
public static int DOPlayBackwards(this AudioMixer target)
{
return DOTween.PlayBackwards(target);
}
/// <summary>
/// Plays forward all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens played.
/// </summary>
public static int DOPlayForward(this AudioMixer target)
{
return DOTween.PlayForward(target);
}
/// <summary>
/// Restarts all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens restarted.
/// </summary>
public static int DORestart(this AudioMixer target)
{
return DOTween.Restart(target);
}
/// <summary>
/// Rewinds all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens rewinded.
/// </summary>
public static int DORewind(this AudioMixer target)
{
return DOTween.Rewind(target);
}
/// <summary>
/// Smoothly rewinds all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens rewinded.
/// </summary>
public static int DOSmoothRewind(this AudioMixer target)
{
return DOTween.SmoothRewind(target);
}
/// <summary>
/// Toggles the paused state (plays if it was paused, pauses if it was playing) of all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens involved.
/// </summary>
public static int DOTogglePause(this AudioMixer target)
{
return DOTween.TogglePause(target);
}
#endregion
#endregion
#endif
#endregion
}
}
#endif
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b766d08851589514b97afb23c6f30a70
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,216 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if true // MODULE_MARKER
using System;
using DG.Tweening.Core;
using DG.Tweening.Core.Enums;
using DG.Tweening.Plugins;
using DG.Tweening.Plugins.Core.PathCore;
using DG.Tweening.Plugins.Options;
using UnityEngine;
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModulePhysics
{
#region Shortcuts
#region Rigidbody
/// <summary>Tweens a Rigidbody's position to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMove(this Rigidbody target, Vector3 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody's X position to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMoveX(this Rigidbody target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector3(endValue, 0, 0), duration);
t.SetOptions(AxisConstraint.X, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody's Y position to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMoveY(this Rigidbody target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector3(0, endValue, 0), duration);
t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody's Z position to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMoveZ(this Rigidbody target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector3(0, 0, endValue), duration);
t.SetOptions(AxisConstraint.Z, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody's rotation to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="mode">Rotation mode</param>
public static TweenerCore<Quaternion, Vector3, QuaternionOptions> DORotate(this Rigidbody target, Vector3 endValue, float duration, RotateMode mode = RotateMode.Fast)
{
TweenerCore<Quaternion, Vector3, QuaternionOptions> t = DOTween.To(() => target.rotation, target.MoveRotation, endValue, duration);
t.SetTarget(target);
t.plugOptions.rotateMode = mode;
return t;
}
/// <summary>Tweens a Rigidbody's rotation so that it will look towards the given position.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="towards">The position to look at</param><param name="duration">The duration of the tween</param>
/// <param name="axisConstraint">Eventual axis constraint for the rotation</param>
/// <param name="up">The vector that defines in which direction up is (default: Vector3.up)</param>
public static TweenerCore<Quaternion, Vector3, QuaternionOptions> DOLookAt(this Rigidbody target, Vector3 towards, float duration, AxisConstraint axisConstraint = AxisConstraint.None, Vector3? up = null)
{
TweenerCore<Quaternion, Vector3, QuaternionOptions> t = DOTween.To(() => target.rotation, target.MoveRotation, towards, duration)
.SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetLookAt);
t.plugOptions.axisConstraint = axisConstraint;
t.plugOptions.up = (up == null) ? Vector3.up : (Vector3)up;
return t;
}
#region Special
/// <summary>Tweens a Rigidbody's position to the given value, while also applying a jump effect along the Y axis.
/// Returns a Sequence instead of a Tweener.
/// Also stores the Rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param>
/// <param name="jumpPower">Power of the jump (the max height of the jump is represented by this plus the final Y offset)</param>
/// <param name="numJumps">Total number of jumps</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Sequence DOJump(this Rigidbody target, Vector3 endValue, float jumpPower, int numJumps, float duration, bool snapping = false)
{
if (numJumps < 1) numJumps = 1;
float startPosY = 0;
float offsetY = -1;
bool offsetYSet = false;
Sequence s = DOTween.Sequence();
Tween yTween = DOTween.To(() => target.position, target.MovePosition, new Vector3(0, jumpPower, 0), duration / (numJumps * 2))
.SetOptions(AxisConstraint.Y, snapping).SetEase(Ease.OutQuad).SetRelative()
.SetLoops(numJumps * 2, LoopType.Yoyo)
.OnStart(() => startPosY = target.position.y);
s.Append(DOTween.To(() => target.position, target.MovePosition, new Vector3(endValue.x, 0, 0), duration)
.SetOptions(AxisConstraint.X, snapping).SetEase(Ease.Linear)
).Join(DOTween.To(() => target.position, target.MovePosition, new Vector3(0, 0, endValue.z), duration)
.SetOptions(AxisConstraint.Z, snapping).SetEase(Ease.Linear)
).Join(yTween)
.SetTarget(target).SetEase(DOTween.defaultEaseType);
yTween.OnUpdate(() => {
if (!offsetYSet) {
offsetYSet = true;
offsetY = s.isRelative ? endValue.y : endValue.y - startPosY;
}
Vector3 pos = target.position;
pos.y += DOVirtual.EasedValue(0, offsetY, yTween.ElapsedPercentage(), Ease.OutQuad);
target.MovePosition(pos);
});
return s;
}
/// <summary>Tweens a Rigidbody's position through the given path waypoints, using the chosen path algorithm.
/// Also stores the Rigidbody as the tween's target so it can be used for filtered operations.
/// <para>NOTE: to tween a rigidbody correctly it should be set to kinematic at least while being tweened.</para>
/// <para>BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug).
/// If you plan to publish there you should use a regular transform.DOPath.</para></summary>
/// <param name="path">The waypoints to go through</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="pathType">The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points)</param>
/// <param name="pathMode">The path mode: 3D, side-scroller 2D, top-down 2D</param>
/// <param name="resolution">The resolution of the path (useless in case of Linear paths): higher resolutions make for more detailed curved paths but are more expensive.
/// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints</param>
/// <param name="gizmoColor">The color of the path (shown when gizmos are active in the Play panel and the tween is running)</param>
public static TweenerCore<Vector3, Path, PathOptions> DOPath(
this Rigidbody target, Vector3[] path, float duration, PathType pathType = PathType.Linear,
PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null
)
{
if (resolution < 1) resolution = 1;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => target.position, target.MovePosition, new Path(pathType, path, resolution, gizmoColor), duration)
.SetTarget(target).SetUpdate(UpdateType.Fixed);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
return t;
}
/// <summary>Tweens a Rigidbody's localPosition through the given path waypoints, using the chosen path algorithm.
/// Also stores the Rigidbody as the tween's target so it can be used for filtered operations
/// <para>NOTE: to tween a rigidbody correctly it should be set to kinematic at least while being tweened.</para>
/// <para>BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug).
/// If you plan to publish there you should use a regular transform.DOLocalPath.</para></summary>
/// <param name="path">The waypoint to go through</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="pathType">The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points)</param>
/// <param name="pathMode">The path mode: 3D, side-scroller 2D, top-down 2D</param>
/// <param name="resolution">The resolution of the path: higher resolutions make for more detailed curved paths but are more expensive.
/// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints</param>
/// <param name="gizmoColor">The color of the path (shown when gizmos are active in the Play panel and the tween is running)</param>
public static TweenerCore<Vector3, Path, PathOptions> DOLocalPath(
this Rigidbody target, Vector3[] path, float duration, PathType pathType = PathType.Linear,
PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null
)
{
if (resolution < 1) resolution = 1;
Transform trans = target.transform;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), new Path(pathType, path, resolution, gizmoColor), duration)
.SetTarget(target).SetUpdate(UpdateType.Fixed);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
t.plugOptions.useLocalPosition = true;
return t;
}
// Used by path editor when creating the actual tween, so it can pass a pre-compiled path
internal static TweenerCore<Vector3, Path, PathOptions> DOPath(
this Rigidbody target, Path path, float duration, PathMode pathMode = PathMode.Full3D
)
{
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => target.position, target.MovePosition, path, duration)
.SetTarget(target);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
return t;
}
internal static TweenerCore<Vector3, Path, PathOptions> DOLocalPath(
this Rigidbody target, Path path, float duration, PathMode pathMode = PathMode.Full3D
)
{
Transform trans = target.transform;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), path, duration)
.SetTarget(target);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
t.plugOptions.useLocalPosition = true;
return t;
}
#endregion
#endregion
#endregion
}
}
#endif
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dae9aa560b4242648a3affa2bfabc365
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,168 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if true && (UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_2017_1_OR_NEWER) // MODULE_MARKER
using System;
using DG.Tweening.Core;
using DG.Tweening.Plugins;
using DG.Tweening.Plugins.Core.PathCore;
using DG.Tweening.Plugins.Options;
using UnityEngine;
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModulePhysics2D
{
#region Shortcuts
#region Rigidbody2D Shortcuts
/// <summary>Tweens a Rigidbody2D's position to the given value.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOMove(this Rigidbody2D target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody2D's X position to the given value.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOMoveX(this Rigidbody2D target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector2(endValue, 0), duration);
t.SetOptions(AxisConstraint.X, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody2D's Y position to the given value.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOMoveY(this Rigidbody2D target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector2(0, endValue), duration);
t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody2D's rotation to the given value.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DORotate(this Rigidbody2D target, float endValue, float duration)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.rotation, target.MoveRotation, endValue, duration);
t.SetTarget(target);
return t;
}
#region Special
/// <summary>Tweens a Rigidbody2D's position to the given value, while also applying a jump effect along the Y axis.
/// Returns a Sequence instead of a Tweener.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations.
/// <para>IMPORTANT: a rigidbody2D can't be animated in a jump arc using MovePosition, so the tween will directly set the position</para></summary>
/// <param name="endValue">The end value to reach</param>
/// <param name="jumpPower">Power of the jump (the max height of the jump is represented by this plus the final Y offset)</param>
/// <param name="numJumps">Total number of jumps</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Sequence DOJump(this Rigidbody2D target, Vector2 endValue, float jumpPower, int numJumps, float duration, bool snapping = false)
{
if (numJumps < 1) numJumps = 1;
float startPosY = 0;
float offsetY = -1;
bool offsetYSet = false;
Sequence s = DOTween.Sequence();
Tween yTween = DOTween.To(() => target.position, x => target.position = x, new Vector2(0, jumpPower), duration / (numJumps * 2))
.SetOptions(AxisConstraint.Y, snapping).SetEase(Ease.OutQuad).SetRelative()
.SetLoops(numJumps * 2, LoopType.Yoyo)
.OnStart(() => startPosY = target.position.y);
s.Append(DOTween.To(() => target.position, x => target.position = x, new Vector2(endValue.x, 0), duration)
.SetOptions(AxisConstraint.X, snapping).SetEase(Ease.Linear)
).Join(yTween)
.SetTarget(target).SetEase(DOTween.defaultEaseType);
yTween.OnUpdate(() => {
if (!offsetYSet) {
offsetYSet = true;
offsetY = s.isRelative ? endValue.y : endValue.y - startPosY;
}
Vector3 pos = target.position;
pos.y += DOVirtual.EasedValue(0, offsetY, yTween.ElapsedPercentage(), Ease.OutQuad);
target.MovePosition(pos);
});
return s;
}
/// <summary>Tweens a Rigidbody2D's position through the given path waypoints, using the chosen path algorithm.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations.
/// <para>NOTE: to tween a Rigidbody2D correctly it should be set to kinematic at least while being tweened.</para>
/// <para>BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug).
/// If you plan to publish there you should use a regular transform.DOPath.</para></summary>
/// <param name="path">The waypoints to go through</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="pathType">The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points)</param>
/// <param name="pathMode">The path mode: 3D, side-scroller 2D, top-down 2D</param>
/// <param name="resolution">The resolution of the path (useless in case of Linear paths): higher resolutions make for more detailed curved paths but are more expensive.
/// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints</param>
/// <param name="gizmoColor">The color of the path (shown when gizmos are active in the Play panel and the tween is running)</param>
public static TweenerCore<Vector3, Path, PathOptions> DOPath(
this Rigidbody2D target, Vector2[] path, float duration, PathType pathType = PathType.Linear,
PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null
)
{
if (resolution < 1) resolution = 1;
int len = path.Length;
Vector3[] path3D = new Vector3[len];
for (int i = 0; i < len; ++i) path3D[i] = path[i];
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => target.position, x => target.MovePosition(x), new Path(pathType, path3D, resolution, gizmoColor), duration)
.SetTarget(target).SetUpdate(UpdateType.Fixed);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
return t;
}
/// <summary>Tweens a Rigidbody2D's localPosition through the given path waypoints, using the chosen path algorithm.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations
/// <para>NOTE: to tween a Rigidbody2D correctly it should be set to kinematic at least while being tweened.</para>
/// <para>BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug).
/// If you plan to publish there you should use a regular transform.DOLocalPath.</para></summary>
/// <param name="path">The waypoint to go through</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="pathType">The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points)</param>
/// <param name="pathMode">The path mode: 3D, side-scroller 2D, top-down 2D</param>
/// <param name="resolution">The resolution of the path: higher resolutions make for more detailed curved paths but are more expensive.
/// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints</param>
/// <param name="gizmoColor">The color of the path (shown when gizmos are active in the Play panel and the tween is running)</param>
public static TweenerCore<Vector3, Path, PathOptions> DOLocalPath(
this Rigidbody2D target, Vector2[] path, float duration, PathType pathType = PathType.Linear,
PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null
)
{
if (resolution < 1) resolution = 1;
int len = path.Length;
Vector3[] path3D = new Vector3[len];
for (int i = 0; i < len; ++i) path3D[i] = path[i];
Transform trans = target.transform;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), new Path(pathType, path3D, resolution, gizmoColor), duration)
.SetTarget(target).SetUpdate(UpdateType.Fixed);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
t.plugOptions.useLocalPosition = true;
return t;
}
#endregion
#endregion
#endregion
}
}
#endif
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 230fe34542e175245ba74b4659dae700
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,93 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if true && (UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_2017_1_OR_NEWER) // MODULE_MARKER
using System;
using UnityEngine;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModuleSprite
{
#region Shortcuts
#region SpriteRenderer
/// <summary>Tweens a SpriteRenderer's color to the given value.
/// Also stores the spriteRenderer as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this SpriteRenderer target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Material's alpha color to the given value.
/// Also stores the spriteRenderer as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this SpriteRenderer target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a SpriteRenderer's color using the given gradient
/// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener).
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="gradient">The gradient to use</param><param name="duration">The duration of the tween</param>
public static Sequence DOGradientColor(this SpriteRenderer target, Gradient gradient, float duration)
{
Sequence s = DOTween.Sequence();
GradientColorKey[] colors = gradient.colorKeys;
int len = colors.Length;
for (int i = 0; i < len; ++i) {
GradientColorKey c = colors[i];
if (i == 0 && c.time <= 0) {
target.color = c.color;
continue;
}
float colorDuration = i == len - 1
? duration - s.Duration(false) // Verifies that total duration is correct
: duration * (i == 0 ? c.time : c.time - colors[i - 1].time);
s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear));
}
s.SetTarget(target);
return s;
}
#endregion
#region Blendables
#region SpriteRenderer
/// <summary>Tweens a SpriteRenderer's color to the given value,
/// in a way that allows other DOBlendableColor tweens to work together on the same target,
/// instead than fight each other as multiple DOColor would do.
/// Also stores the SpriteRenderer as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The value to tween to</param><param name="duration">The duration of the tween</param>
public static Tweener DOBlendableColor(this SpriteRenderer target, Color endValue, float duration)
{
endValue = endValue - target.color;
Color to = new Color(0, 0, 0, 0);
return DOTween.To(() => to, x => {
Color diff = x - to;
to = x;
target.color += diff;
}, endValue, duration)
.Blendable().SetTarget(target);
}
#endregion
#endregion
#endregion
}
}
#endif
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 188918ab119d93148aa0de59ccf5286b
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
@@ -0,0 +1,634 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if true && (UNITY_4_6 || UNITY_5 || UNITY_2017_1_OR_NEWER) // MODULE_MARKER
using System;
using System.Globalization;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening.Core;
using DG.Tweening.Core.Enums;
using DG.Tweening.Plugins.Options;
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModuleUI
{
#region Shortcuts
#region CanvasGroup
/// <summary>Tweens a CanvasGroup's alpha color to the given value.
/// Also stores the canvasGroup as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOFade(this CanvasGroup target, float endValue, float duration)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.alpha, x => target.alpha = x, endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#region Graphic
/// <summary>Tweens an Graphic's color to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Graphic target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an Graphic's alpha color to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Graphic target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#region Image
/// <summary>Tweens an Image's color to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Image target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an Image's alpha color to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Image target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an Image's fillAmount to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach (0 to 1)</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOFillAmount(this Image target, float endValue, float duration)
{
if (endValue > 1) endValue = 1;
else if (endValue < 0) endValue = 0;
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.fillAmount, x => target.fillAmount = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an Image's colors using the given gradient
/// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener).
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="gradient">The gradient to use</param><param name="duration">The duration of the tween</param>
public static Sequence DOGradientColor(this Image target, Gradient gradient, float duration)
{
Sequence s = DOTween.Sequence();
GradientColorKey[] colors = gradient.colorKeys;
int len = colors.Length;
for (int i = 0; i < len; ++i) {
GradientColorKey c = colors[i];
if (i == 0 && c.time <= 0) {
target.color = c.color;
continue;
}
float colorDuration = i == len - 1
? duration - s.Duration(false) // Verifies that total duration is correct
: duration * (i == 0 ? c.time : c.time - colors[i - 1].time);
s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear));
}
s.SetTarget(target);
return s;
}
#endregion
#region LayoutElement
/// <summary>Tweens an LayoutElement's flexibleWidth/Height to the given value.
/// Also stores the LayoutElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOFlexibleSize(this LayoutElement target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => new Vector2(target.flexibleWidth, target.flexibleHeight), x => {
target.flexibleWidth = x.x;
target.flexibleHeight = x.y;
}, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens an LayoutElement's minWidth/Height to the given value.
/// Also stores the LayoutElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOMinSize(this LayoutElement target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => new Vector2(target.minWidth, target.minHeight), x => {
target.minWidth = x.x;
target.minHeight = x.y;
}, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens an LayoutElement's preferredWidth/Height to the given value.
/// Also stores the LayoutElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOPreferredSize(this LayoutElement target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => new Vector2(target.preferredWidth, target.preferredHeight), x => {
target.preferredWidth = x.x;
target.preferredHeight = x.y;
}, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
#endregion
#region Outline
/// <summary>Tweens a Outline's effectColor to the given value.
/// Also stores the Outline as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Outline target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.effectColor, x => target.effectColor = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Outline's effectColor alpha to the given value.
/// Also stores the Outline as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Outline target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.effectColor, x => target.effectColor = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Outline's effectDistance to the given value.
/// Also stores the Outline as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOScale(this Outline target, Vector2 endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.effectDistance, x => target.effectDistance = x, endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#region RectTransform
/// <summary>Tweens a RectTransform's anchoredPosition to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorPos(this RectTransform target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition X to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorPosX(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(endValue, 0), duration);
t.SetOptions(AxisConstraint.X, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition Y to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorPosY(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(0, endValue), duration);
t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition3D to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOAnchorPos3D(this RectTransform target, Vector3 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition3D X to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOAnchorPos3DX(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, new Vector3(endValue, 0, 0), duration);
t.SetOptions(AxisConstraint.X, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition3D Y to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOAnchorPos3DY(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, new Vector3(0, endValue, 0), duration);
t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition3D Z to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOAnchorPos3DZ(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, new Vector3(0, 0, endValue), duration);
t.SetOptions(AxisConstraint.Z, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchorMax to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorMax(this RectTransform target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchorMax, x => target.anchorMax = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchorMin to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorMin(this RectTransform target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchorMin, x => target.anchorMin = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's pivot to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOPivot(this RectTransform target, Vector2 endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.pivot, x => target.pivot = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's pivot X to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOPivotX(this RectTransform target, float endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.pivot, x => target.pivot = x, new Vector2(endValue, 0), duration);
t.SetOptions(AxisConstraint.X).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's pivot Y to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOPivotY(this RectTransform target, float endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.pivot, x => target.pivot = x, new Vector2(0, endValue), duration);
t.SetOptions(AxisConstraint.Y).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's sizeDelta to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOSizeDelta(this RectTransform target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.sizeDelta, x => target.sizeDelta = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Punches a RectTransform's anchoredPosition towards the given direction and then back to the starting one
/// as if it was connected to the starting position via an elastic.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="punch">The direction and strength of the punch (added to the RectTransform's current position)</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="vibrato">Indicates how much will the punch vibrate</param>
/// <param name="elasticity">Represents how much (0 to 1) the vector will go beyond the starting position when bouncing backwards.
/// 1 creates a full oscillation between the punch direction and the opposite direction,
/// while 0 oscillates only between the punch and the start position</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Tweener DOPunchAnchorPos(this RectTransform target, Vector2 punch, float duration, int vibrato = 10, float elasticity = 1, bool snapping = false)
{
return DOTween.Punch(() => target.anchoredPosition, x => target.anchoredPosition = x, punch, duration, vibrato, elasticity)
.SetTarget(target).SetOptions(snapping);
}
/// <summary>Shakes a RectTransform's anchoredPosition with the given values.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="duration">The duration of the tween</param>
/// <param name="strength">The shake strength</param>
/// <param name="vibrato">Indicates how much will the shake vibrate</param>
/// <param name="randomness">Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware).
/// Setting it to 0 will shake along a single direction.</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
/// <param name="fadeOut">If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not</param>
public static Tweener DOShakeAnchorPos(this RectTransform target, float duration, float strength = 100, int vibrato = 10, float randomness = 90, bool snapping = false, bool fadeOut = true)
{
return DOTween.Shake(() => target.anchoredPosition, x => target.anchoredPosition = x, duration, strength, vibrato, randomness, true, fadeOut)
.SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetShake).SetOptions(snapping);
}
/// <summary>Shakes a RectTransform's anchoredPosition with the given values.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="duration">The duration of the tween</param>
/// <param name="strength">The shake strength on each axis</param>
/// <param name="vibrato">Indicates how much will the shake vibrate</param>
/// <param name="randomness">Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware).
/// Setting it to 0 will shake along a single direction.</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
/// <param name="fadeOut">If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not</param>
public static Tweener DOShakeAnchorPos(this RectTransform target, float duration, Vector2 strength, int vibrato = 10, float randomness = 90, bool snapping = false, bool fadeOut = true)
{
return DOTween.Shake(() => target.anchoredPosition, x => target.anchoredPosition = x, duration, strength, vibrato, randomness, fadeOut)
.SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetShake).SetOptions(snapping);
}
#region Special
/// <summary>Tweens a RectTransform's anchoredPosition to the given value, while also applying a jump effect along the Y axis.
/// Returns a Sequence instead of a Tweener.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param>
/// <param name="jumpPower">Power of the jump (the max height of the jump is represented by this plus the final Y offset)</param>
/// <param name="numJumps">Total number of jumps</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Sequence DOJumpAnchorPos(this RectTransform target, Vector2 endValue, float jumpPower, int numJumps, float duration, bool snapping = false)
{
if (numJumps < 1) numJumps = 1;
float startPosY = 0;
float offsetY = -1;
bool offsetYSet = false;
// Separate Y Tween so we can elaborate elapsedPercentage on that insted of on the Sequence
// (in case users add a delay or other elements to the Sequence)
Sequence s = DOTween.Sequence();
Tween yTween = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(0, jumpPower), duration / (numJumps * 2))
.SetOptions(AxisConstraint.Y, snapping).SetEase(Ease.OutQuad).SetRelative()
.SetLoops(numJumps * 2, LoopType.Yoyo)
.OnStart(()=> startPosY = target.anchoredPosition.y);
s.Append(DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(endValue.x, 0), duration)
.SetOptions(AxisConstraint.X, snapping).SetEase(Ease.Linear)
).Join(yTween)
.SetTarget(target).SetEase(DOTween.defaultEaseType);
s.OnUpdate(() => {
if (!offsetYSet) {
offsetYSet = true;
offsetY = s.isRelative ? endValue.y : endValue.y - startPosY;
}
Vector2 pos = target.anchoredPosition;
pos.y += DOVirtual.EasedValue(0, offsetY, s.ElapsedDirectionalPercentage(), Ease.OutQuad);
target.anchoredPosition = pos;
});
return s;
}
#endregion
#endregion
#region ScrollRect
/// <summary>Tweens a ScrollRect's horizontal/verticalNormalizedPosition to the given value.
/// Also stores the ScrollRect as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Tweener DONormalizedPos(this ScrollRect target, Vector2 endValue, float duration, bool snapping = false)
{
return DOTween.To(() => new Vector2(target.horizontalNormalizedPosition, target.verticalNormalizedPosition),
x => {
target.horizontalNormalizedPosition = x.x;
target.verticalNormalizedPosition = x.y;
}, endValue, duration)
.SetOptions(snapping).SetTarget(target);
}
/// <summary>Tweens a ScrollRect's horizontalNormalizedPosition to the given value.
/// Also stores the ScrollRect as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Tweener DOHorizontalNormalizedPos(this ScrollRect target, float endValue, float duration, bool snapping = false)
{
return DOTween.To(() => target.horizontalNormalizedPosition, x => target.horizontalNormalizedPosition = x, endValue, duration)
.SetOptions(snapping).SetTarget(target);
}
/// <summary>Tweens a ScrollRect's verticalNormalizedPosition to the given value.
/// Also stores the ScrollRect as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Tweener DOVerticalNormalizedPos(this ScrollRect target, float endValue, float duration, bool snapping = false)
{
return DOTween.To(() => target.verticalNormalizedPosition, x => target.verticalNormalizedPosition = x, endValue, duration)
.SetOptions(snapping).SetTarget(target);
}
#endregion
#region Slider
/// <summary>Tweens a Slider's value to the given value.
/// Also stores the Slider as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<float, float, FloatOptions> DOValue(this Slider target, float endValue, float duration, bool snapping = false)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.value, x => target.value = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
#endregion
#region Text
/// <summary>Tweens a Text's color to the given value.
/// Also stores the Text as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Text target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>
/// Tweens a Text's text from one integer to another, with options for thousands separators
/// </summary>
/// <param name="fromValue">The value to start from</param>
/// <param name="endValue">The end value to reach</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="addThousandsSeparator">If TRUE (default) also adds thousands separators</param>
/// <param name="culture">The <see cref="CultureInfo"/> to use (InvariantCulture if NULL)</param>
public static TweenerCore<int, int, NoOptions> DOCounter(
this Text target, int fromValue, int endValue, float duration, bool addThousandsSeparator = true, CultureInfo culture = null
){
int v = fromValue;
CultureInfo cInfo = !addThousandsSeparator ? null : culture ?? CultureInfo.InvariantCulture;
TweenerCore<int, int, NoOptions> t = DOTween.To(() => v, x => {
v = x;
target.text = addThousandsSeparator
? v.ToString("N0", cInfo)
: v.ToString();
}, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Text's alpha color to the given value.
/// Also stores the Text as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Text target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Text's text to the given value.
/// Also stores the Text as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end string to tween to</param><param name="duration">The duration of the tween</param>
/// <param name="richTextEnabled">If TRUE (default), rich text will be interpreted correctly while animated,
/// otherwise all tags will be considered as normal text</param>
/// <param name="scrambleMode">The type of scramble mode to use, if any</param>
/// <param name="scrambleChars">A string containing the characters to use for scrambling.
/// Use as many characters as possible (minimum 10) because DOTween uses a fast scramble mode which gives better results with more characters.
/// Leave it to NULL (default) to use default ones</param>
public static TweenerCore<string, string, StringOptions> DOText(this Text target, string endValue, float duration, bool richTextEnabled = true, ScrambleMode scrambleMode = ScrambleMode.None, string scrambleChars = null)
{
if (endValue == null) {
if (Debugger.logPriority > 0) Debugger.LogWarning("You can't pass a NULL string to DOText: an empty string will be used instead to avoid errors");
endValue = "";
}
TweenerCore<string, string, StringOptions> t = DOTween.To(() => target.text, x => target.text = x, endValue, duration);
t.SetOptions(richTextEnabled, scrambleMode, scrambleChars)
.SetTarget(target);
return t;
}
#endregion
#region Blendables
#region Graphic
/// <summary>Tweens a Graphic's color to the given value,
/// in a way that allows other DOBlendableColor tweens to work together on the same target,
/// instead than fight each other as multiple DOColor would do.
/// Also stores the Graphic as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The value to tween to</param><param name="duration">The duration of the tween</param>
public static Tweener DOBlendableColor(this Graphic target, Color endValue, float duration)
{
endValue = endValue - target.color;
Color to = new Color(0, 0, 0, 0);
return DOTween.To(() => to, x => {
Color diff = x - to;
to = x;
target.color += diff;
}, endValue, duration)
.Blendable().SetTarget(target);
}
#endregion
#region Image
/// <summary>Tweens a Image's color to the given value,
/// in a way that allows other DOBlendableColor tweens to work together on the same target,
/// instead than fight each other as multiple DOColor would do.
/// Also stores the Image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The value to tween to</param><param name="duration">The duration of the tween</param>
public static Tweener DOBlendableColor(this Image target, Color endValue, float duration)
{
endValue = endValue - target.color;
Color to = new Color(0, 0, 0, 0);
return DOTween.To(() => to, x => {
Color diff = x - to;
to = x;
target.color += diff;
}, endValue, duration)
.Blendable().SetTarget(target);
}
#endregion
#region Text
/// <summary>Tweens a Text's color BY the given value,
/// in a way that allows other DOBlendableColor tweens to work together on the same target,
/// instead than fight each other as multiple DOColor would do.
/// Also stores the Text as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The value to tween to</param><param name="duration">The duration of the tween</param>
public static Tweener DOBlendableColor(this Text target, Color endValue, float duration)
{
endValue = endValue - target.color;
Color to = new Color(0, 0, 0, 0);
return DOTween.To(() => to, x => {
Color diff = x - to;
to = x;
target.color += diff;
}, endValue, duration)
.Blendable().SetTarget(target);
}
#endregion
#endregion
#endregion
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
// ███ INTERNAL CLASSES ████████████████████████████████████████████████████████████████████████████████████████████████
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
public static class Utils
{
/// <summary>
/// Converts the anchoredPosition of the first RectTransform to the second RectTransform,
/// taking into consideration offset, anchors and pivot, and returns the new anchoredPosition
/// </summary>
public static Vector2 SwitchToRectTransform(RectTransform from, RectTransform to)
{
Vector2 localPoint;
Vector2 fromPivotDerivedOffset = new Vector2(from.rect.width * 0.5f + from.rect.xMin, from.rect.height * 0.5f + from.rect.yMin);
Vector2 screenP = RectTransformUtility.WorldToScreenPoint(null, from.position);
screenP += fromPivotDerivedOffset;
RectTransformUtility.ScreenPointToLocalPointInRectangle(to, screenP, null, out localPoint);
Vector2 pivotDerivedOffset = new Vector2(to.rect.width * 0.5f + to.rect.xMin, to.rect.height * 0.5f + to.rect.yMin);
return to.anchoredPosition + localPoint - pivotDerivedOffset;
}
}
}
}
#endif
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a060394c03331a64392db53a10e7f2d1
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

Some files were not shown because too many files have changed in this diff Show More