Search Unity

Showcase Mirror - Open Source Networking for Unity

Discussion in 'Multiplayer' started by mischa2k, Aug 11, 2016.

  1. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    Sadly had to edit the above post. If you're going to attack you can't write about other people's intelligence - it's an insult. You can attack only the data though :)

    Peace, all.
     
    mischa2k and goldbug like this.
  2. goldbug

    goldbug

    Joined:
    Oct 12, 2011
    Posts:
    769
    That pull request is a clear improvement over the previous code we inherited from HLAPI. I am not sure why you find it ridiculous that we are trying to improve it.

    Notice the date of that PR, it is a month old, it is obviously dead. The only reason that PR has not been merged (and probably never will be) is because we already have a better implementation of area of interest that does no allocation and does it in just a few milliseconds by using a grid spatial index. That is already in place in ummorpg and my own game. We will probably eventually add it to mirror itself if we can make it easy to use. In other words, just like yourself, we don't think that code is good enough.

    Area of interest as it was written in HLAPI was showing as a clear bottleneck. In general we try to optimize stuff that shows in the profiler. If it does not show in the profiler as an issue we try to keep the code as simple as possible. For example, allocations in Update() are treated much different than allocations when a user connects.
     
    Last edited: Feb 20, 2019
    Padilha and mischa2k like this.
  3. jjobby

    jjobby

    Joined:
    Nov 28, 2009
    Posts:
    161
    Yes, I can confirm that they really tested many methods. I was there reading in Mirror discord when they were testing TCP transport in Unity (this is just a CCU test, not real world test). They said that they could easily reach 10k CCU using SocketAsyncEventArgs outside of Unity. But when they used it inside Unity then it could only reach 1,200 CCU. Even fholm tried to help investigating this issue using his old SocketAsyncEventArgs TCP transport. He could get it to 3,000 CCU which was still far less than outside of Unity. They had the conclusion that SocketAsyncEventArgs was implemented poorly in Unity mono. Days later, fholm said that he saw new PR in Unity mono which should fix this issue. But we will never know when this fix will come in Unity.

    Saying that Mirror is a trap or unusable or regress from HLAPI is over-criticize. The biggest trap here is actually UNET. I've tested Mirror and yes it's a lot better than UNET. Well, some people may still said that making something better than UNET shouldn't be hard because the standard is very low. ECS looks very good and should be a better choice for performance but not all people can just easily switch to use it. Many people have already invested their time developing their game using Monobehaviour. Not to mention that Unity themselves said that ECS is not production ready.
     
    jolix, nirvanajie, Player7 and 2 others like this.
  4. Deleted User

    Deleted User

    Guest

    @vis2k thanks for the answer, nice to hear.
    I was talking about the HLAPI, did a quick search and found you answering a Forum post related to this. I think that solves it for Mirror.
    To recap: it was usually sufficient to do a minor change to a networkbehaviour only to receive differently assigned netIDs when building a scene compared to before. Server and Client went constantly out of sync and you had to be careful to build out both with the exact same code.
     
    mischa2k likes this.
  5. hottabych

    hottabych

    Joined:
    Apr 18, 2015
    Posts:
    107
    Hi everyone. Seems like after UNet deprecation, Unity removed Multiplayer tutorial from its "Learn" section. Where to find it now? It was convenient to check that tutorial, creating my own multiplayer game from scratch (especially if I forgot a workflow).
     
  6. bingofly

    bingofly

    Joined:
    Sep 15, 2018
    Posts:
    27
    Hello guys.
    No matter what others say about Mirror, after a few days of testing, I wanna say that I like it. Many thanks for your effort.
    I have some questions here. The NetworkManager contains two variables such as OnlineScene and OfflineScene. Dose that mean I can have only one onlineScene?
    In order to test, I keep OnlineScene and OfflineScene null and use my own code to load scenes.Firstly I start a host, then I start a client and connect it to the host. I find that the remote(host) player is synchronized in the offlineScene of client automatically. After that, client load onlineScene use my code and destory remote player by default.So errors emerge.
    Maybe it's a stupid question, I wanna know how can I synchronize players from one scene to another. Dose Mirror support more onlineScenes or just one?
     
    Last edited: Feb 24, 2019
  7. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    https://vis2k.github.io/Mirror/
     
  8. GuiTeK

    GuiTeK

    Joined:
    Apr 28, 2017
    Posts:
    12
    Hi @vis2k,

    Thank you for developing Mirror!

    I'm starting a new turn by turn MMORPG project and I need a networking solution with Unity. The official networking solution, UNet, has been deprecated, and the official replacement hasn't been released yet. So it seems like Mirror is my only choice left (and it seems pretty good so I'm glad)!

    However, I have a few questions:
    • Does Mirror allow to make an Authoritative Server? By authoritative, I mean that everything is managed by the server, including all the players. I'm asking because I read Unity User Manual - Network Authority, and it seems that for UNet, "Server Authoritative" means "everything but the players": "This means - for example - the server would manage control of all collectable items, moving platforms, NPCs - and any other parts of your game that players can interac and player GameObjects have authority on their owner’s client (meaning the client manages their behavior)."
    • If the answer to the previous question is yes: is it the "default behaviour" or does it require extra work to build an authoritative server?
    • Does Mirror depend on any external service (e.g. matchmaking service)?
    • Is deploying an online game server as easy as running the game in server mode and distributing the IP to the clients?

    Thank you!
     
  9. goldbug

    goldbug

    Joined:
    Oct 12, 2011
    Posts:
    769
    Yes, Mirror is designed for authoritative server. A client cannot change any data on the server. As you say, everything is managed by the server including all the players. Suppose a user wants to buy an item from the store. The client cannot just add the item to your inventory. You can try, but all it would do is add it to your client inventory, the inventory as seen by the server and other clients would still be unmodified. The only way for a client to make a purchase would be to send a [Command] call to the server. Your Command method would check if the player has enough money, deduct the amount and add the item to the inventory.

    Keep in mind that you have to design your game correctly. If you have a CmdPay and CmdAddToInventory and you expect that people will call pay before adding to inventory then you messed up. Someone could hack the client and call CmdAddToInventory without paying. If instead you make a CmdPurchase that does both operations, then it can't be hacked.

    Yes, this is the default and only behavior. Clients cannot modify data on the server period. The only way to do it is to call a [Command] or send a Message. Your server is always the one that changes things.

    No. We have a Lobby class that does it. If it does not work for your needs, you can just extend it or write your own with ease.

    Yes, that is all it takes. You can try it with some of the provided examples.
     
    GuiTeK likes this.
  10. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    Progress: stress testing 0gc branch: https://github.com/vis2k/Mirror/pull/443 with uMMORPG and a 16 core server.



    Found a giant bottleneck while stepping through main loop to minimize GC. NetworkServer.SendToAll/Ready/Observers previously constructed the message for each connection (420 x 420 players). Now it only constructs it once and sends it to all connections (1 x 420 players). This combined with some NetworkWriter caching results in:
    * half the CPU% at 200 CCU
    * 1/3 the latency at 420 CCU
    * 165 ms instead of 450 ms latency at 420 CCU

    Pretty sure this just doubled CCU again.
     
  11. NoobDoAAA

    NoobDoAAA

    Joined:
    May 7, 2018
    Posts:
    11
    I think that we all agree that ECS is great.
    But it is not ready for production yet. When? With Unity 2019 LTS maybe?
    For those who can't wait Mirror is a great UNET replacement.
    My short article about Unity networking in the beginning of 2019 - http://noobdoaaa.com/read=9
     
    goldbug likes this.
  12. Roamer79

    Roamer79

    Joined:
    Oct 25, 2016
    Posts:
    45
    Ahhh E-net. Error error error error error error. Screw that. I'm not picking apart that S*** to get it to work. I don't care about ticks. Mirror is fast enough for me and it imports perfectly. Can't even find any video documentation other than some circle jerk video showing some cylinders moving around. Before mirror I couldn't run my game without it crashing. Now I have had 6 months with zero problems. Its not just about code. Its about support and implementation which you have a lot to learn about.
     
  13. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
  14. bingofly

    bingofly

    Joined:
    Sep 15, 2018
    Posts:
    27
  15. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    I recommend to use Unity 2018.3.6.
    • We had to upgrade from 2017.4 because of a deadlock bug where Unity would freeze on OSX within 5-15 minutes while the network was active. This disappeared in 2018.2 version with .NET 4.X.
    • We had to upgrade from 2018.2 to 2018.3.6 because of a memory leak in Unity 2018.2, which disappeared in 2018.3.6.
    So for multiplayer games, 2018.3.6 is the only stable version at the moment.
     
  16. goldbug

    goldbug

    Joined:
    Oct 12, 2011
    Posts:
    769
    Mirror just got the biggest change since the SyncList rewrite. You can now send messages without worrying about ids. Since HLAPI, when you sent a message, you provided an ID that was unique and a Message object that provided the associated data.

    Before
    Code (CSharp):
    1.  
    2. // you needed a unique id and pray nobody else
    3. // was using it
    4. const ushort MyMessageId = 55;
    5.  
    6. // then you declare your message data
    7. class MyMessage
    8. {
    9.     public string name;
    10.     public string lastname;
    11.     // and whatever other variable
    12. }
    13.  
    14. // this is how you send it
    15. conn.Send(MyMessageId,   new MyMessage(...));
    16.  
    After
    Code (CSharp):
    1. [B][/B]
    2. // Declare your message data
    3. class MyMessage
    4. {
    5.     public string name;
    6.     public string lastname;
    7.     // and whatever other variable
    8. }
    9.  
    10. // send it with no id.  Mirror figures out an unique id for MyMessage
    11. conn.Send(new MyMessage(...));
    12.  
    Receiving is now much simpler too.

    Before
    Code (CSharp):
    1.  
    2. conn.RegisterHandler(MyMessageId,  myHandler);
    3.  
    4. public void myHandler(NetworkMessage netMsg) {
    5.    // ewwwwwww
    6.    MyMessage msg  = netMsg.ReadMessage<MyMessage>();
    7.     ...
    8. }
    9.  
    After
    Code (CSharp):
    1.  
    2. // the class itself is the id
    3. conn.RegisterHandler<MyMessage>(myHandler);
    4.  
    5. public void myHandler(NetworkConnection conn, MyMessage msg) {
    6.     ...
    7. }
    8.  
    To make it easier for you we kept the old API, but we have [Obsoleted] it. If you upgrade and you start getting warnings, your app will still work, but you should be migrating to the new Message API as soon as you can.

    Note this does not affect [Commands] and [*Rpc] (which is what you should be using the most) those work the same as before.
     
    sky_haihai, NoobDoAAA and hopeful like this.
  17. Player7

    Player7

    Joined:
    Oct 21, 2015
    Posts:
    1,533
    Can you update/expand the example scene with some of these new features and changes thanks
     
  18. hottabych

    hottabych

    Joined:
    Apr 18, 2015
    Posts:
    107
  19. Roamer79

    Roamer79

    Joined:
    Oct 25, 2016
    Posts:
    45
    Would it be difficult to allow the Network Transform and Network Transform child to select between syncing localposition and localrotation?
     
  20. Roamer79

    Roamer79

    Joined:
    Oct 25, 2016
    Posts:
    45

    Ok I have modded an independent Network Transform script that does this if anyone wants it message me. Would be nice to enable this feature as part of mirror as standard though.
     
  21. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    Can you explain why this would be necessary?
     
  22. iSleepzZz

    iSleepzZz

    Joined:
    Dec 23, 2012
    Posts:
    206
    Hi vis2k, just had a quick question. Mirror is supposed to be a replacement for UNET, which btw I am loving mirror:)
    However, I see in one of the classes for Telepathy (that comes in mirror folder), it uses UnityEngine.Networking;
    When unity delete UNET, this will be gone correct? So how can you keep mirror going if it is using UnityEngine.Networking?
     
  23. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    You probably saw the LLAPITransport - which is our Transport for Unity's old low level networking that came with UNET.
    Unity plans to support that until 2020 I believe, so we'll keep our Transport to support it. This way people can migrate to Mirror more easily.

    Mirror doesn't rely on UnityEngine.Networking though - we can remove that transport any day and Mirror will still function.
     
    iSleepzZz likes this.
  24. antsonthetree

    antsonthetree

    Joined:
    May 15, 2015
    Posts:
    102
    @vis2k, @goldbug

    Messaging Is Broken (or will be soon) - Message Id Deprecated

    Can you please NOT remove the Message Id parameter from the long established messaging interface that we have all been using for several years now? By removing the message Id you are adding a lot of overhead for people who use messages extensively. I have upwards of 20 message handler functions. Many of my messages pass the same message header class back and forth among them. Your new version basically makes this impossible since it seems to lock a message class into a 1-1 relationship with a single message handler function.

    FYI - It is FAR easier to maintain a simple list of integer message Id's than to maintain a list of pointlessly duplicate message header classes that all contain the same data.

    - ants
     
    vexe and Vincenzo like this.
  25. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    We can change/revert features easily, so don't panic :)
    You should try the new automated message ids though. It did make the code more simple when applying it to my assets. And we will be able to remove a whole 300 lines of useless Mirror code because of that soon.
    Another upside is that using third party assets/addons will be a lot easier. You won't have to worry about addon's message ids clashing with each other.

    But if you tried it and still think that it sucks then please let us know.
     
  26. bingofly

    bingofly

    Joined:
    Sep 15, 2018
    Posts:
    27
    Thank you, Vis2K, I've fixed it by myself.
     
    mischa2k likes this.
  27. iSleepzZz

    iSleepzZz

    Joined:
    Dec 23, 2012
    Posts:
    206
    Hey vis2k, a quick question.
    So I am using the latest version of mirror on unity 2018.3.6f1

    Currently what I've been doing is keeping a SyncVar of my position as a Vector3 and then whenever it moves, just have all the clients smoothly lerp to the new position.
    Do you believe it will be more network efficient to instead just use mirror's network transform component?

    P.S. my game is a multiplayer survival fps
     
  28. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    Try it :)
     
  29. Roamer79

    Roamer79

    Joined:
    Oct 25, 2016
    Posts:
    45
    Sure! Lets say you want to allow players to all get in the same non-controllable movable network object such as a boat or car (that isn't a player object) you will have a jerky player due to lag or compensation between the two networked objects in world space. If you do the same thing as local positions and rotations no jerky jerk as it is only concerned about the local co-ordinates and ignores the parent (being the car or whatever). If you sync an object as local position that isn't parented to anything it just becomes world position anyway and automatically switches from world to local from what I can work out. I just sync everything as local space and I can parent and unapparent without any fuss. Does this make sense? If you have any other ideas on how to get around this I am all ears!!
     
  30. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    A custom NetworkTransform is probably the best solution for those who need it.
    Will have to think about that one. Using localPosition by default might introduce other issues for other users.
    If you use a custom NetworkTransform then that should be fine for now. You can find our NetworkTransform code on Github.
     
  31. Vencarii

    Vencarii

    Joined:
    May 19, 2016
    Posts:
    9
    I began a personal game project. The small prototype I have so far works fine with UNet.
    I tried to switch to Mirror, but when I start the game as Host outside of Unity I get the error "NullReferenceException: Object reference not set to an instance of an object". I looks like it has something to do with LocalPlayerAuthority on a non-player GameObject.
    What would be the easiest way to get support for this?
     
    Last edited: Mar 6, 2019
  32. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    Post the full error message including stack trace
     
  33. TwoTen

    TwoTen

    Joined:
    May 25, 2016
    Posts:
    1,168
    ~130 lines of code were removed. Not 300
     
  34. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    Yes. And we 'will be able to remove a whole 300 lines of useless Mirror code because of that soon.'

    See the link in the PR that we didn't merge yet.
     
  35. TwoTen

    TwoTen

    Joined:
    May 25, 2016
    Posts:
    1,168
    Ye that's ~130 lines. The rest is line changes, not removals, empty lines, comments and such.

    Even then it's generous as code attributes, and enum declarations which are not logic are counted.

    Only reason I'm saying it is because it's the metric you used to justify and argue a feature change which someone was unhappy with.
     
    Last edited: Mar 7, 2019
    Vincenzo likes this.
  36. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    Ok, thanks for counting.
     
  37. Vencarii

    Vencarii

    Joined:
    May 19, 2016
    Posts:
    9
    The code below the stack trace is on the Player object. The object that is requested and is the reason for the NullReferenceException is MasterList, a non-player GameObject that has "Server only" checked in the NetworkIdentity.
    Here is the full stack trace from the output_log.txt:

    NullReferenceException: Object reference not set to an instance of an object
    at Player.CmdGetRandomData (System.Int32 count, System.String reason) [0x0000c] in D:\Unity\Projects\MyGame\Assets\Scripts\Player.cs:127
    at Player.CallCmdGetRandomData (System.Int32 count, System.String reason) [0x0000b] in <860fb0ddc13e4b6f9ecc7c13c1e9ec71>:0
    at Player.OnStartLocalPlayer () [0x00024] in D:\Unity\Projects\MyGame\Assets\Scripts\Player.cs:44
    at Mirror.NetworkIdentity.SetLocalPlayer () [0x00032] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkIdentity.cs:596
    at Mirror.NetworkServer.SetupLocalPlayerForConnection (Mirror.NetworkConnection conn, Mirror.NetworkIdentity identity) [0x00093] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkServer.cs:570
    at Mirror.NetworkServer.InternalAddPlayerForConnection (Mirror.NetworkConnection conn, UnityEngine.GameObject playerGameObject) [0x0006d] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkServer.cs:529
    at Mirror.NetworkServer.AddPlayerForConnection (Mirror.NetworkConnection conn, UnityEngine.GameObject player) [0x00001] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkServer.cs:502
    at Mirror.NetworkManager.OnServerAddPlayerInternal (Mirror.NetworkConnection conn) [0x000a4] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkManager.cs:704
    at Mirror.NetworkManager.OnServerAddPlayer (Mirror.NetworkConnection conn) [0x00001] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkManager.cs:676
    at Mirror.NetworkManager.OnServerAddPlayerMessageInternal (Mirror.NetworkMessage netMsg) [0x00075] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkManager.cs:568
    at Mirror.NetworkConnection.InvokeHandler (System.Int16 msgType, Mirror.NetworkReader reader) [0x00036] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkConnection.cs:206
    at Mirror.NetworkConnection.TransportReceive (System.Byte[] buffer) [0x000db] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkConnection.cs:241
    at Mirror.ULocalConnectionToServer.SendBytes (System.Byte[] bytes, System.Int32 channelId) [0x0001a] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\LocalConnections.cs:41
    at Mirror.NetworkConnection.Send (System.Int16 msgType, Mirror.MessageBase msg, System.Int32 channelId) [0x0000a] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkConnection.cs:132
    at Mirror.ClientScene.AddPlayer (Mirror.NetworkConnection readyConn, Mirror.MessageBase extraMessage) [0x000b4] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\ClientScene.cs:97
    at Mirror.ClientScene.AddPlayer (Mirror.NetworkConnection readyConn) [0x00000] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\ClientScene.cs:63
    at Mirror.ClientScene.AddPlayer () [0x00000] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\ClientScene.cs:60
    at Mirror.NetworkManager.OnClientConnect (Mirror.NetworkConnection conn) [0x00021] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkManager.cs:758
    at Mirror.NetworkManager.OnClientConnectInternal (Mirror.NetworkMessage netMsg) [0x00060] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkManager.cs:601
    at Mirror.NetworkConnection.InvokeHandler (System.Int16 msgType, Mirror.NetworkReader reader) [0x00036] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkConnection.cs:206
    at Mirror.NetworkConnection.TransportReceive (System.Byte[] buffer) [0x000db] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkConnection.cs:241
    at Mirror.NetworkClient.OnDataReceived (System.Byte[] data) [0x0000f] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkClient.cs:98
    at Mirror.LocalClient.Update () [0x00010] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\LocalClient.cs:43
    at Mirror.NetworkClient.UpdateClient () [0x00001] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkClient.cs:281
    at Mirror.NetworkManager.LateUpdate () [0x00007] in D:\Unity\Projects\MyGame\Assets\Mirror\Runtime\NetworkManager.cs:152

    (Filename: <860fb0ddc13e4b6f9ecc7c13c1e9ec71> Line: 0)

    And the corresponding code is this. (line 127 is "if (masterList.AllDataList.Count == 0) {")

    Code (CSharp):
    1. [Command]
    2.     void CmdGetRandomData(int count, string reason)
    3.     {
    4.         masterList = FindObjectOfType<MasterList>();
    5.  
    6.         if (masterList.AllDataList.Count == 0) {
    7.             masterList.LoadDataAtGameStart();
    8.         }
    9.  
    10.         string dataString = masterList.GetRandomDataIdsForRpcCall(count);
    11.  
    12.         TargetReceiveData(connectionToClient, dataString, reason);
    13.     }
     
  38. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    If masterList.AllDataList.Count throws a NullReferenceException then probably a part of that is null?
    If server-only is checked then the object won't exist on the client by the way.
     
  39. Vencarii

    Vencarii

    Joined:
    May 19, 2016
    Posts:
    9
    Okay fair enough. So I changed MasterList and didn't check any box in NetworkIdentity.
    It then works as expected when I run the Host in the Unity Editor and connect to that with a Standalone Client.
    But when I start the Standalone Build as Host, I get the NullReferenceException. :\ Any ideas about that?

    (masterList is null in that case, but I don't know why. Client works as Standalone, Host doesn't)
     
    Last edited: Mar 7, 2019
  40. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    upload_2019-3-8_20-57-48.png

    Update:
    very happy to announce that the Persistent SceneId fix is live [ https://github.com/vis2k/Mirror/pull/563 ].

    This bug caused me tremendous amounts of pain during the last three years. In fact, I was the one who originally reported it to the UNET team back then.

    Original UNET used FindObjectsOfType<NetworkIdentity> to assign sceneIds with a simple counter. The problem was that the FindObjectsOfType order was not deterministic. In other words, the result was often scrambled. So when building a game and connecting to it with the Editor, everything worked fine until we restarted the Editor and got a completely different FindObjectsOfType order, at which point the Editor and the Build would get out of sync. This resulted in situations where sometimes a player's move on the server would actually move a monster on the client, which is a complete nightmare to deal with.

    Later on when starting HLAPI Community Edition, we found a workaround where FindObjectsOfType was sorted by the actual order in the Hierarchy (by the sibling path to be exact). This worked perfectly fine for one scene, and in fact the UNET team even ported the fix to UNET. Instead of using the sibling path, they used only the root index though, which would still result in the same type of errors if the scene object was a child object of something else.

    Eventually people started switching scenes at runtime, which exposed a flaw in my original fix. When loading a scene for the second time, it's possible (in fact, likely) that objects like the NetworkManager were moved into the DontDestroyOnLoad scene, hence offseting the sibling path by -1 and getting the client and the server out of sync again.

    The next approach was to use Unity's fileID. Unity stores a fileID value for each object and each component in the Scene. It's persistent across restarts, and can be found in the Scene.unity files. The fileID itself is not directly available in Unity. There is however a workaround where a script is used to set the Inspector to debug view, at which point the LocalIdentifierInFile could be read. This was the perfect solution, except that it didn't work all the time. the LocalIdentifierInFile is sometimes 0 if Play wasn't pressed yet, and it even changes at runtime occasionally. There is no documentation on this field either, but it seems like this is not the true fileID at all times, only sometimes.

    The final solution was to generate a random sceneID of the format 0x00FFFFFF in Edit time, whenever OnValidate is called. Generating the sceneID sets the scene as dirty, which adds a '*' behind the scene name to indicate the user that it needs to be resaved. In other words, each NetworkIdentity gets a random sceneID that is stored on disk and never changed again afterwards.

    This alone was not enough yet though. If a user duplicates SceneA.unity to SceneB.unity, then ObjectA from SceneA will have the same sceneID as ObjectA in SceneB. This second problem was solved by shifting the scene's build index into the SceneID when the scene is first loaded. The previous sceneId of 0x00FFFFFF would then change to 0x01FFFFFF for the scene at index = 1. As result, we get a unique sceneId that even works if the user duplicates a scene.

    The third critical problem were unopened scenes. A lot of people will upgrade to the latest Mirror version for the fix, and there is a small chance that a user with SceneA and SceneB might only open SceneA, get all sceneIDs for SceneA assigned and then build the project without ever actually opening SceneB again, leaving all the SceneB sceneIDs still empty. In that case, Unity would call OnValidate for each object in SceneB, Mirror would generate a sceneID, but the scene would never get saved because the modifications happened at build time. This issue would not affect new Mirror users (because they always opened each of their new scenes with the latest Mirror version), but even if we were to add a huge "PLEASE RESAVE ALL SCENES ONCE" warning, someone upgrading to the latest Mirror version would still miss it and run into strange missing sceneID errors.

    This third problem was solved by a simple isBuilding check to never assign sceneIDs in OnValidate. Instead, users with yet unopened scenes will receive an Error message that even cancels the build process, notifying them to resave the unopened scene once.

    In the end, we get perfectly persistent sceneIds that work across multiple scenes in (so far) all possible scenarios. This fix will allow you to implemented advanced features like zones, instanced dungeons, player housing and (possibly) additive scene loading.

    I believe this was the last critical bug in Mirror. Enjoy!
     
    Last edited: Mar 8, 2019
    Player7, LostPanda and hopeful like this.
  41. goldbug

    goldbug

    Joined:
    Oct 12, 2011
    Posts:
    769
    you don't have to duplicate anything. for example:

    Code (CSharp):
    1. abstract class MyMessageHeader : MessageBase
    2. {
    3.       int foo;
    4.       string bar;
    5.      // whatever is common with all your messages
    6. }
    7.  
    8. class MyMessage1 : MyMessageHeader {};
    9.  
    10. class MyMessage2 : MyMessageHeader {};
    11.  
    12. class MyMessage3 : MyMessageHeader {};
    13.  
    Another cool thing with this change is that once we remove the old api, we can even start converting some of the messages to value types, and eliminate those allocations. But the old API needs to die for that.
     
    Last edited: Mar 9, 2019
    antsonthetree and mischa2k like this.
  42. antsonthetree

    antsonthetree

    Joined:
    May 15, 2015
    Posts:
    102
    Thanks - yup I found the workaround for duplicates in your source. Very helpful. So far all is working fine and it does not suck as much as I thought it would. :)
     
    goldbug and mischa2k like this.
  43. MwGfyzzo

    MwGfyzzo

    Joined:
    Jul 10, 2018
    Posts:
    7
    Your Migration Link in the First Post isn't working - you should fix that.

    Thanks for the free Network HLAPI. The new Unity Documentation around Networking is a mess. So I'm glad someone did the work to provide what Unity is lacking.

    edit: I got errors because of some old C# version or something. I used the recommended option to just change the target version or so and after that messed with the player settings maybe a bit too much because I thought it has to do something with that... Can someone tell me what the recommended player settings for Scripting Runtime Version and API Compatibility Level are?
     
    Last edited: Mar 13, 2019
    hopeful likes this.
  44. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    Use Unity 2018.3.6 with .NET 4.X
     
  45. Vancete

    Vancete

    Joined:
    May 3, 2010
    Posts:
    198
    It looks reaaally good.

    Only two decisive questions for me:
    - Is WebGL supported?
    - Anything to work with channels? Something to work with rooms or regions in the same server.

    Thanks in advance ;)
     
  46. goldbug

    goldbug

    Joined:
    Oct 12, 2011
    Posts:
    769
    Yes, WebGL works great. You can use the WebsocketTransport, or you can use MultiplexTransport if you want your server to support both webgl and standalone clients. We are considering making the MultiplexTransport the default.

    Channels work with [Command], and [*Rpc]. But you need to use a transport that take advantage of channels such as litenetlib, ignorance or steam. Channels don't really do anything with websocketransport, because there is no way to have unreliable messages in websockets. Join our discord server to get help on those other transports.

    To work with rooms or regions, we have interest management, you can easily write your logic of who can see whom, and have people divided by room/region.
     
  47. mischa2k

    mischa2k

    Joined:
    Sep 4, 2015
    Posts:
    4,347
    Important: if you downloaded Mirror from Github after 2019-03-08 (persistent sceneids), then please redownload. There was a bug where sceneIDs would get out of sync if the scene was not added to build settings, because in that case Unity's gameObject.scene.buildIndex would be '-1' when building, but '0' when pressing Play in the Editor.
     
    Last edited: Mar 14, 2019
  48. MwGfyzzo

    MwGfyzzo

    Joined:
    Jul 10, 2018
    Posts:
    7
    I didn't ask the Unity version :D So just to be sure:
    So ".NET 4.x Equivalent" as Scripting Runtme Version
    and ".NET 4.x" as Api Compatibility Level ?

    I also have some other basic questions now. Since I built a small Lobby UI I think I want to use the Network Lobby Manager. I'm not really sure how I use it with my own UI. Do I have to derive from the Network Lobby Manager? I skimmed through your code and I don't really know which methods I would need to override and what original functionality I should re-implement in overridden methods. I certainly need a way to catch events like when clients connect or set themselves ready and so on to refresh my own lobby.

    I assume another alternative would be to just use NetworkServer and Clients and do everything manually? Though I don't know if that's a smart thing. But I don't even know yet what I'm loosing if I did.
     
  49. MCoburn

    MCoburn

    Joined:
    Feb 27, 2014
    Posts:
    71
    Unless you have issues or asset that cannot work with NET Standard 2.0, I recommend using:

    At least 2018.3.6 (preferably .7 since that fixes the remote code execution bug)
    Scripting Runtime: NET 4.x Equivalent
    API Compatibility Level: NET Standard 2.0

    The reason I suggest NET Standard is that it's lighter and doesn't have all the baggage of a full NET 4.x runtime. Some plugins may not work, but for my shooter game I've had no incompatibilities with NET Standard 2.0 (yet).

    Also I believe that Mirror should come with a network lobby demo scene? I think I saw it in the git version, haven't checked the AS packaged version.
     
  50. MrG

    MrG

    Joined:
    Oct 6, 2012
    Posts:
    368
    Using Unity 2018.3.6+ defaults to .NET 4.x Equivalent" as Scripting Runtime Version and ".NET 4.x" as Api Compatibility Level so that's why he said that. Yes you need to use those or .Net Standard 2.0 as MCoburn said.

    There is a complete example included in the Examples/Lobby folder that demonstrates what you need to do for your custom Lobby layout. If you still need help, drop by our Discord anytime.