Hello everyone,
I have been solo developing a networking solution for about six years, I hope this solution disrupts the current market selections we have today. As developers we are the ones under the gun and although some solutions are easy to use they come at a cost, others bring promise then let us down. As a community we have searched high and low for a decent product that can fill this void without breaking our pockets and/or time constraints. I have had an idea to make things easy, networking should not be a pain staking process but instead be fun. Thus Distrupt is what I have embarked on and here are the results.
- Source will be made available through a Proprietary license.
- Send data with networked instantiate (classes, structs, variables, (Unity3dās Vector3 and Quaternionās)
- Send as many variables through Sync params as needed.
- Views consist of instantiator, host or shared.
- Reliable / Sequenced type networking
- Each host can handle (100+ players).
- Relay Server handles room-based games, Stun, Turn and ICE calls.
- UPNP can be setup if it fails drops back to Relay Server.
- LAN based discovery.
- Relay Server is also setup to handle saving and loading of data.
- Packet headers are 2 bytes.
- Packet RDās remote deliveries are 8 bytes + Payload.
- 100 players each syncing 20 Game Object orientations constantly
- Easy to use Events.
- Easy learning curve, you should know how to use the whole system in about one hour.
- Once purchased its free for life (Per seat guys please be honest).
- Runs on potatoes BenchmarkNet test results a second (12% cpu, 50mb ram, 240mb transfer) 1k benchtest. https://github.com/nxrighthere/BenchmarkNet/wiki/Benchmark-Results
- RD attributes are a bit like magic but do not use Reflection during runtime. (1 million calls to RD takes 240ms) using store actions based off of Reflection during editor mode.
- Currently Disrupt uses boxing/unboxing for Sync params, I am searching for answers to find the fastest possible way to do this. For now 2k+ objects all moving in the scene is not bad at all. If I find away to avoid boxing/unboxing we can double that.
- Standalone RelayServer with instructions to setup on Digital Ocean or AWS.
- A Discord channel to stay in touch with me the developer or the community using Disrupt.
Cons?
- Must be compiled against 4.x
- Must allow unsafe code (why?)
āI dont use a BinaryWriter instead I have a custom solution to speed up the packing process.ā
csharp**_ <em>** public unsafe void GetBytes(Packet packet, short value) { fixed (byte* b = &packet.PayLoad[packet.Length]) *((short*)b) = *&value; packet.Length += 2; }**</em> _**
In depth look below.
Simple Messaging System (37 lines of code)
using RavelTek.Disrupt;
using UnityEngine;
using UnityEngine.UI;
public class Messenger : NetHelper
{
public Transform MessageHolder;
public Text Message;
private Peer[] peers = new Peer[4];
private int count;
public void Start()
{
Disrupt.Client.OnConnected += Client_OnConnected;
}
private void Client_OnConnected(Peer peer)
{
if(!View.IsServer) return;
peers[count] = peer;
Sync("NetMessage", peer, "Welcome to the server");
count++;
}
public void SendMessage(InputField field)
{
//Many ways to sync a message
Sync("NetMessageReceived")
.Add("Some Message")
.Send(SendTo.Others)
.Send(SendTo.All)
.Send(SendTo.Server)
.Send(SomePeer or Some Peers[])
}
[RD]
public void NetMessageReceived(string message)
{
var inMessage = Instantiate(Message, MessageHolder);
inMessage.text = message;
}
}
The RD stands for Remote Delivery (Thought it had a nice ring for an attribute).
Serializable Values
namespace RavelTek.Disrupt
{
[System.Serializable]
public enum ValueType
{
Boolean,
BooleanA,
SByte,
SByteA,
Byte,
ByteA,
Char,
CharA,
UInt16,
UInt16A,
Int16,
Int16A,
UInt32,
UInt32A,
Int32,
Int32A,
Single,
SingleA,
UInt64,
UInt64A,
Int64,
Int64A,
Decimal,
DecimalA,
Double,
DoubleA,
String,
StringA,
Object,
Vector3,
Vector3A,
Quaternion,
QuaternionA,
}
}
Vector3A and QuaternionA are just enums that can handle Vector3 arrays and Quaternion arrays. Quaternions are sent as 4 bytes each variable (āxyzwā) being 1 bytes each, Vector3ās are sent as 12 bytes (āxyzā) each currently 4 bytes as half math didnāt work as promised. There is a OrientationView component that only syncs the variables in positions or rotations that have changed. So if position X changes in the position you will only send one variable being 4 bytes Quaternion would have been 2 bytes.
Many types of Networking Instantiates
#region Default Instantiates
public static GameObject Instantiate(GameObject item)
{
return ProcessInstantiate(item.transform.position, item.transform.rotation, item);
}
public static GameObject Instantiate(GameObject item, Vector3 position, Quaternion rotation)
{
return ProcessInstantiate(position, rotation, item);
}
#endregion
#region Specialized Instantiates
public static GameObject Instantiate(GameObject item, params object[] data)
{
return ProcessInstantiate(item.transform.position, item.transform.rotation, item, null, data);
}
public static GameObject Instantiate(GameObject item, Vector3 position, Quaternion rotation, params object[] data)
{
return ProcessInstantiate(position, rotation, item, null, data);
}
public static T Instantiate<T>(T item, params object[] data) where T : Component
{
var outItem = ProcessInstantiate(item.transform.position, item.transform.rotation, item.gameObject, null, data);
return outItem.GetComponent(typeof(T)) as T;
}
public static T Instantiate<T>(T item, Vector3 position, Quaternion rotation, params object[] data) where T : Component
{
var outItem = ProcessInstantiate(position, rotation, item.gameObject, null, data);
return outItem.GetComponent(typeof(T)) as T;
}
#endregion
#region Default Single Send Instantiates
public static GameObject Instantiate(GameObject item, Peer peer)
{
return ProcessInstantiate(item.transform.position, item.transform.rotation, item, peer, null);
}
public static GameObject Instantiate(GameObject item, Vector3 position, Quaternion rotation, Peer peer)
{
return ProcessInstantiate(position, rotation, item, peer, null);
}
#endregion
#region Default Multi Send Instantiates
public static GameObject Instantiate(GameObject item, Peer[] peers)
{
return ProcessMultiInstantiate(item.transform.position, item.transform.rotation, item, peers, null);
}
public static GameObject Instantiate(GameObject item, Vector3 position, Quaternion rotation, Peer[] peers)
{
return ProcessMultiInstantiate(position, rotation, item, peers, null);
}
#endregion
#region Specialized Single Send Instantiates
public static GameObject Instantiate(GameObject item, Peer peer, params object[] data)
{
return ProcessInstantiate(item.transform.position, item.transform.rotation, item, peer, data);
}
public static GameObject Instantiate(GameObject item, Vector3 position, Quaternion rotation, Peer peer, params object[] data)
{
return ProcessInstantiate(position, rotation, item, peer, data);
}
#endregion
#region Specialized MultiSelect Send Instantiates
public static GameObject Instantiate(GameObject item, Peer[] peers, params object[] data)
{
return ProcessMultiInstantiate(item.transform.position, item.transform.rotation, item, peers, data);
}
public static GameObject Instantiate(GameObject item, Vector3 position, Quaternion rotation, Peer[] peers, params object[] data)
{
return ProcessMultiInstantiate(position, rotation, item, peers, data);
}
#endregion
Events can be extended through partial class using Client
public delegate void ConnectionRequest(Packet packet);
public delegate void Connected(Peer peer);
public delegate void Disconnected(EndPoint endPoint);
public delegate void Message(Packet packet);
public delegate void NatSuccess(Packet packet);
public delegate void Discovery(NatInfo natInfo);
public delegate void HostList(NatInfo[] hosts);
public delegate void HostSuccess();
public event ConnectionRequest OnConnectionRequest;
public event Connected OnConnected;
public event Disconnected OnDisconnected;
public event Message OnIncomingMessage;
public event Discovery OnDiscovery;
public event HostList OnHostList;
public event HostSuccess OnHostSuccess;
Those are only some of the highlights if there is anything else the community would like to know I am transparent with questions.Price aiming for $20 per seat this wont last for long I will not go any higher then $60 so get yours as soon as it comes out. -Levon