Disrupt Networking

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

8 Likes

nice to see new network asset, havenā€™t seen good one since fholmā€™s days
in any case even if it can hold 100 players it will be impressiveā€¦

but it sounds like science fiction to be frankā€¦
1k players with 8% cpu usage? how many packets per second do you send ?
does it have delta compression ?
what kind of networking library do you use ? (ENet, NanoSockets, etcā€¦)
its only standalone ? (so not authoritative unless you have custom physics)
source code available ?
available platforms ?

also any videos and demos would be great

GCat, Your questions in order
how many packets per second do you send ?

  • Packets sent are based per frame, in my case I was doing 100 packets per frame at 60 frames a second it was about 6k packets a second from the server. All movement was tied into one update and then I looped the 2k Object positions and Rotations using a Orientation View that was driven in the networking loop. I have a list of Orientation Views in my networking loop and based off the ObjectsPerSync a for iteration is called and does that amount then the next frame increases the count etc, etc.(if you have a 4 player game you should not be sending that many in a frame)ā€¦

does it have delta compression ?

  • Yes, I take most values and do a few equations to reduce the bytes sent. Its an option because you wont get precise results for example.
  • Quaternionā€™s are 1 / -1 as a float thats 4 bytes so with this example I can reduce the bandwidth cost by multiplying the value by 100 lets say you have .99999 gives you 99.9 now we send that value over the wire as a short (2 bytes) being 99 once it arrives it will be 99 * .01 giving you .99 we miss a few values here but to the eye its not noticeable.
  • Little tricks here and there to reduce bandwidth are implemented, I got you guys.

what kind of networking library do you use ?

  • I used six years of my life to roll my own solution, Sequence packets were easy the Reliable layer was not I do not use an ACK / NACK type system. One layer for transport is all thatā€™s needed improving the performance on any application. There is no GC in my solution as packets are pooled/reused and essentials are placed on the stack. This is an image of Distrupt the reason im fast is because all of the RDā€™s are stored before the game is even compiled. Also I forgot I dont use a window slider for the reliable layer so there is thatā€¦ Happy figuring that one out to all networking developers :stuck_out_tongue:
  • Please note I am trying to figure out a way to make viewing the method info store as an option, I might be releasing it as hidden so there isnā€™t much clutter, but for those who would like to see the coolness I am working it out. All the Values seen here are the RD attributes gathered during Editor session then when you press play we essentially have a direct reference to all the methods.


its only standalone ? (so not authoritative unless you have custom physics)

  • No, A lot of time was spent in this area looking at all the other solutions on the AssetStore, I chose a different path for physics. The players will set their Ridged Bodies off the host / server will control all of the physics and or movement.Put your application into headless mode for the server/host not sure what its called now but I remember 4.6 if you know about Fholm more then sure you were around then.
  • If you make a build like one person as a host and one as a player then put your game into headless mode essentially you have a Server Auth type game just host that on the cloud.

source code available ?

  • This one is tough, I am in a toss up honestly I would love to release the sourceā€¦ Right now I am releasing the plugin source code. My back-end for Disrupt is RavelNet and that is what I am wondering about ā€œWith proper licensingā€ Yes.

available platforms ?

  • Any Platform will work with this solution, all calls are Mono friendly.

Videos are on the way, hope I was able to answer all your question properly (Fholm is who im trying to beat plus ENet with ease of use that RakNet days back in 4.x) Fohlmā€™s socket was in C++ though, I did everything in C# :slight_smile: . -Levon

I want to make a note in the features, to be fair you can have 2k players moving all at once but thats all they will do, so realistically 2000 / 100 players gives a very very fair game with each player having 20 Orientation views. I will update my features to read correctly, you can possibly squeeze in more that if you know exactly what your doing. If you just slapping updates everywhere in your game and not optimizing it sure thats not Disturbs fault, if your careful and manage the ms you could hit way more then 100 players. Depends on the developers skillset, if you have been developing for a few years and know what GC is and how ms effects the frame rate your looking at more connections.

2k Objects syncing from server to clients all clients look the sameā€¦ Sorry guys could not figure out how to post a gifā€¦ This was tested from California (USA) to India I had one server hosted on a Droplet and one client on my PC, The person in India recorded the results it matched my client so I am not sure exactly how you guys feel about it but I feel great. Here is the last one each round fired from the tank is still moving even though it cannot be seen on the screenā€¦ This has to be downloaded unfortunately to view. @ the end of that video 1.6k objects were syncing rotations and positions off the scene view. I will get more tests up on Youtube soon but these were some impressions that I captured with ShareX.

Let me know if you think I was being obtuse about the results I was projecting through my post from the above information. I do not think I was but who knows? Guess what im getting at is none of the objects in those gifs would be in a real world application. 2K all at once? Even if we did a Battle Royal type game the chance for everyone to be all in one area at one time is not that great, so you can optimize for off scene calls :slight_smile: -Levon

3 Likes

you should consider granting source access (in github) for ones with invoices
canā€™t think of a reason why notā€¦ just write some none sharing license

specially this day and age when networking assets are abandoned
it will boost confidence in this asset and let people do customization for their own needs

Wow, I thought it was an imageā€¦ you really should upload to YouTube
its an amazing system if it works like in the GIF,
Boltā€™s Achilles heel is syncing many statesā€¦ let alone 2k

looking forward for this asset to be on the store!

1 Like

Thank you I am currently documenting everything and making videos shortly I was very sick over the weekend.

I am making the source available through a Proprietary License.

2 Likes

thatā€™s great news! very excited for this system

I wanted to ask if its possible to send custom byte[ ] into your low level network library (RavelNet)

btw an idea for future updates is to use C# Job System and Burst Compiler within Disrupt/RavelNet
should also consider replacing locks if you have any with lockless queue ringbuffer

although disrupt seems very fast from the start and thatā€™s a good sign
I hope you will take different approach, first maximize performance then add new features

I wanted to ask if its possible to send custom byte[ ] into your low level network library (RavelNet)

  • You may send almost anything you can think of as long as its serializable

btw an idea for future updates is to use C# Job System and Burst Compiler within Disrupt/RavelNet

  • I use unsafe code to convert to bytes, not sure how the Unity.Mathmatics will help in that area.

I hope you will take different approach, first maximize performance then add new features

  • I have maximize as much as possible, there could be room for improvement for now I am releasing the package so everyone can take a look then possibly let me know where or what could be optimized.

should also consider replacing locks if you have any with lockless queue ringbuffer

  • I do use a few locks on the Networking thread for the Queue but they are strictly in and out
  • lock(objectLock) var packet = SendQueue.Dequeue(); ā† negligible

Also Unity3d will not be blocked by Distrupt as it is a Consumer Producer pattern. -Levon

Finally got around to making the banner for the Asset Store check it out in the first post. -Levon

you donā€™t use Mathf anywhere else in your code ? what do you use to compress the data ?

No Mathf in the code, as for compression take a look at the unsafe in first post (search for) ā€œI dont use a BinaryWriter instead I have a custom solution to speed up the packing process.ā€ :wink:ā€¦ When you do Sync(ā€œMethodā€, SendTo.Blah, (byte) 1, new byte[2]{1, 2}) my backend does this.

var packet = client.CreatePacket(); ("Creates a packet from a pool)
packet.Protocol = Protocol.Reliable;
packet.Flag = Flags.Dat;
packet.SendType = YourSendType;
var writer = new Writer(); (I dont create a new Writer every time but for example im doing it here)
writer.PushByte(params[0]);
writer.PushByteA(params[1]);
lock(sendQueue) SendQueue.Push(packet); (lock is negligible)

its a very fast process 1 million of these calls takes about 2ms -Levon

I want to reply to all the likes and let you guys know I am fixing a few bugs that have popped up during testing. I am at about 90% bug free based off of many tests I and beta testers are throwing at it. I promise without a shadow of a doubt upon release improvements and maintenance will be in a timely manner. This is for those who know how hard networking is and seeing my results. ā€œIt has taken 6 years with a family of five day in day out to make what is coming shortly.ā€ So without further adieu my gratitude for those who are paying attention to the thread. (No particular order just a recognition and my thanks to you as I do watch the forum every day. I also want to do something special for those who comment I am adding your names with links to your profile in blue. If you have assets or contributed to Unity3d if they click your name developers will see your references.-Levon)

  • Mikael-H

  • GCat - Developement testing and code optimizations (Thank you)

  • Neviah

  • LostPanda

  • MrArcher

  • ElroyUnity

  • Tiny-Tree

  • Giovanni (Lead Developer on EonWar, development fixes and testing)

  • Mario (Owner of Eonwar)

  • Sabaresh (Owner of FlipSetter)

  • Dario Ortega (Development testing)

  • xVergilx

  • Player7

  • jmjd

  • Also to those who are looking but are hesitant to reply or like I still want to thank you. "I know seeing is believing and Disrupt Networking is very hard to believe in. As a developer I donā€™t rely on assets from the store as there are very few assets that say ā€œwhat is promised do as promised". I am skeptical just as you are, I will do my best to show you through comments and reviews that this is the real deal hopefully one day I can make a believer out of you.ā€

I also would like to mention, the videos you might have seen with cubes falling or moving could let you down. With Disrupt Networking I have distributed beta APIā€™s for testing in projects that have been growing for many years. To developers amazement, the ease of use and performance over anything in the Asset Store has surpassed many expectationā€™s. "Do not take my word for this, I donā€™t expect you to." I am gathering the developers of such said projects to comment here on the forum.

Thank you everyone for your time and support, from the bottom of my heart. -Levon

2 Likes

Update, I am tight in development getting past a few bugs. Honestly I can say its almost ready for release there is a short hiccup with mixture of server auth and peer to peer. I know this is going to happen with a lot of developers so I am doing my best to make sure if and when it does happen its not an issue.-Levon

Thereā€™s no sources right now, I can only assume Sync looks similar to this:

public void Sync(string methodName, ... destination, params object[] objects);

The only way of unwrapping that would be to create specific overloads for the method to avoid boxing value types + creating object array.

UNet used an automatic weaver for that kind of things by using attributes.
But since networking is mostly per project, I think its best to make separate base methods for basic value types up to 3 parameters. This can be done via code autogen swizzling.

Rest of overloads should be possible to re-implement on the customersā€™ end.
But anyhow params must go, as its pretty nasty.

Also, looking at OP, it seems like params arrays also used for the Instantiates. That might hinder the performance as well. Personally Iā€™d rather use custom messages for instantiations. Then again, it might be useful for quick prototyping.

Other than that, looks promising, even though I donā€™t make network games anymore, I might check this one out.

1 Like

I had done something similar to this before instead I created a DomCompilerUnit and just looked through all the Attributes and created a new class that referenced all of the methods. I might go back to that example but yes your right params object[ ] currently is being used, also thank you for your time and interest. -Levon

1 Like

Interesting, though I think getting your networking solution supported by some of the other networking related assets is what will sell it for someā€¦ like dissonance-voice-chat , simple-network-sync etc maybe provide code early to some of them to see if they will implement support?

1 Like

Most of the plugins your mentioning are already implemented as components in Disrupt, I am going to release more as time passes but for now the main solution is what I am trying to pack down. Maybe later I can investigate assets that have been tried and tested with very low bandwidth consumption and optimized techniques to plug into Disrupt.-Levon