Search Unity

NetworkTransport game example

Discussion in 'Multiplayer' started by aabramychev, Oct 4, 2017.

  1. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    I attached here small example of the game implemented on llapi only. The implementation is straight forward and very stupid, but (i hope) it is easy to understand and can be useful (so far we have only chat-like example). demo based on RollingBall game from unity tutorials. Compile everything, start 3 instance, press startServer on one pf them, press StartClient on others.... Should work after that I guess
     

    Attached Files:

  2. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    ***EDIT*** SocketClient and SocketServer is a bad idea. Prevents full P2P. So feel free to ignore this post

    Thanks for the demo. I was looking for LLAPI examples.

    However, it did not work for me. Maybe I need a new version (currently 5.6.1f1)?
    -The server did not have a ball, but clients did.
    -Some objects had missing script warnings.




    tldr;
    Instead of a LLAPI which is a massive list of static methods like NetworkTransform.SomeMethod(...) I think an object structure would be much easier to use and protect against using the wrong methods or method data. I think having Socket objects with methods like Socket.OpenPort(...), Socket.AttemptToConnect(...), Socket.isConnected, Socket.SendData(...), Socket.OnDisconnectCallback(...), etc. would be cleaner.


    -------------------------------------------------------------------------


    I made a list of some some things I'm struggling with
    -Terminology is confusing.
    ----NetworkTransport.AddHost in LLAPI means open socket?
    ----NetworkServer.StartHost in HLAPI means StartServer + StartClient?
    -Id's are confusing
    ----connection Id's are local and aren't the same between client and server
    ----socket/hostId is local and isn't known elsewhere
    ----there is no global synced ID # that is the same on clients AND server
    -Checking status of the NetworkTransport socket/connection isn't easy to understand. Is the port open? Is it connected? Who is it connected to? Is it currentling attempting to connect? Did it timeout or succeed attempting to connect? Did it timeout while connected? Did other errors get thrown? I know all these pieces of info are in the LLAPI somewhere... it's just not easy to understand.




    Maybe I'm going about it all wrong. I don't know. I'm just wondering if restructuring the LLAPI would be better? Currently the LLAPI is a massive list of static methods. Instead a giant list of static NetworkTransport.MethodHere(...) would object instances of class Socket be easier to use? Objects are much easier (at least for me) to work with.

    Like having 2 classes
    -Abstract Class Socket
    -Sealed SocketServer : Socket
    -Sealed SocketClient : Socket

    You'd create an instance of each socket allowing multiple SocketClients per application (for splitscreen) or multiple SocketServers (for hosting multiple games)
    -new SocketServer(...)
    -new SocketClient(...)

    Then these classes would have initialization & disconnect methods
    -Socket.OpenPort(port, IP, out args) //args returns info about the attempt to open a port like errorCode
    -Socket.ClosePort() //closes port. for both SocketServer and SocketClient. used to disconnect SocketClient or to completely shut down SocketServer. Attempts to sends disconnect messages to open connections before closing.
    -SocketClient.ConnectToServer(..., out args) //args returns info about the attempt to open a port like errorCode. On successful connect sets SocketClient's global ID# via connect callback message.
    -SocketServer.DisconnectClient(...) //disconnect removes 1 specific client. sends message to that client

    For normal data transfer you would use something like
    -Socket.AddOnDataEventListener(delegate listener) //adds a callback listener when data is received to this socket similar to NetworkTransport.ReceiveFromHost(...). Maybe make part of constructor to avoid 0 or 2+ listeners that could screw up deserialization?
    -SocketServer.SendToClient(..., out args) //send to specific client where ... is MessageBase or NetworkWriter
    -SocketClient.SendToServer(..., out args) //where ... is MessageBase or NetworkWriter
    -If you wanted you could add additional methods like Socket.SendToAllClient, Socket.SendToAllClientRemote, Socket.SendToAllClient, Socket.SendToClient (first sends to server, then attempts to bounce to client... i.e. for chat whispering) but that's just fluff that could be accomplished with core methods.

    The Sockets would return information for debugging and such (this would be a big improvement I think)
    -Socket.portInfo //get the port info.
    -Socket.ip //get the IP.
    -Socket.isPortOpen //returns true/false
    -SocketClient.isConnectedToServer //returns true/false.
    -Or alternatively ClientSocket.status w/ callback when it changes. A portStatus Enum like PortClosed, Port Open, AttemptingOpen Port. And connnectionStatus Enum like NotConnected, Connected, AttemptingToConnect
    -SocketClient.clientSharedId //an int shared Id # that is constant on all servers & clients for making things easy to manage. This is -1 when there is no connection or open port, and is assigned to clients by the SocketServer when a SocketClient connects. reset to -1 on after disconnect. Each SocketServer could have it's own ~global list. Client's would know their own ID... but I'm not sure about other client's ID's. Not 100% necessary but I feel this would be a good thing to have.
    -SocketServer.GetClientInfo() //returns List<info> about all connected clients sharedId's, if they are local to application or remote, or anything else that might be useful

    Connect/Disconnect Callback Events
    -SocketServer.AddOnConnectEventListener(delegate listener) //called when a SocketClient connects to this SocketServer. contains data about who connected like globalID, if they are local or remote.
    -SocketServer.AddOnDisconnectEventListener(delegate listener) //similar to above. contains info if client quit or timed out. This is higher level than the NetworkEventType.DisconnectEvent as the disconnect would internally adjust the GetClientInfo() List<info>.
    -SocketClient.AddOnDisconnectEventListener(delegate listener) //called when the SocketClient is disconnected from the SocketServer. out args contains info about if it was a timeout or forced by SocketServer. This is higher level than NetworkEventType.DisconnectEvent because it internally sets SocketClient.isConnected. In otherwords the callback contains args about the disconnect (was it forced, or a timeout) essentially lumping 2 things together (it lumps the NetworkEventType.DisconnectEvent + NetworkTransport.ReceiveFromHost w/ NetworkError.Timeout together automatically). This is important!!!

    It's all the same functionality NetworkTransport currently has, but wrapped in (what I think are) easier to used object instances of SocketServer and SocketClient. A massive list of static methods like NetworkTransport.MethodHere(...) has a lot of pitfalls and opportunity for incorrect usage and that's where I'm having the most trouble. I think restructuring as objects with information & methods specific to that object would really clean things up. The only real new addition is the global id# that is synced between server and clients (instead of a bunch of local ID#'s that don't match) but again not 100% necessary just a nice-to-have that I think many programmers would use.

    I really needs to emphasize having automatic LLAPI disconnect handling I think is really important. Currently you must both listen for disconnect messages NetworkEventType.DisconnectEvent and also for disconnect timeout errors during NetworkTransport.ReceiveFromHost w/ NetworkError.Timeout to keep track if a disconnect occurs. It would be so much easier and robust if both those were lumped together in a callback and the Socket class kept track of if it was connected or not, pushing a disconnect callback, and internally sets Socket.isConnected.

    Maybe this is too much like NetworkServerSimple... not sure. Just some thoughts on where I'm getting hung up.

    I spent most of the day with the tutorial and writing this, so if you take the time read this monstrosity thanks!
     
    Last edited: Oct 8, 2017
  3. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    I didn't check with 5.6, with 2017.2 beta only, but I was hope that code is obvious :( ball on server has been instantiated in OnConnect callback in the server side, and it is generic method how game object can be instantiated in unity, no any special network here.

    according statics, it is not statics it is function accessing to singleton methods implemented on c++. As (for client) the object library can be only one, all methods belong to this objects. Exposure many c++ objects to c# layer is headache and will cause more bugs than singleton access :(

    another thing: consider how you open file ->
    File.Open(path, FileMode.Open, FileAccess.Write, FileShare.None)
    what is the main difference with
    NetworkTransport.Connect();...?
    in both cases both call will translated to OperationalSystem.(please).FileOpen ... :)

    According names, probably bad term, but it is not socket :) it is socket + udp protocol. Take a look on definition: "A network host is a computer or other device connected to a computer network. A network host may offer information resources, services, and applications to users or other nodes on the network. A network host is a network node that is assigned a network address." When You AddHost you create virtual device which offer game information to users, why not?

    Transport Library supports not only client server but p2p too, in this case it is a little bit difficult to define who is the server who is the client.

    for connection id - it is similar situation with bsd sockets, connection can be the same but socket number on different ends of connection usually different.

    About callbacks: Again it is example how you can create game using transport layer only I specially did use only simple structures, to make code understandable and do not hide everything under syntax sugar, on top of this you can do everything which you want: clients, servers and so on :)

    About disconnect, yes I will make them more robust, I know that it is problem here, unfortunately the problem will still there. Imagine that you watching you favourite movie, and electrical company switched off electricity: You didn't swich you tv off but no movie for you anymore:) or the same situation when you call somebody by phone and he will close talking without saying bye ... Setting Socket.isConnected - won't help because in the time when you ask about that parameter it can be connected but in time when you send it has been already disconnected...

    Sorry if cannot satisfy you or was unclear or not answer for all questions :( again i understood problem with disconnect and will make them more robust, (that means you will receive timeout error rare) but unfortunately I cannot to change nature :(
     
    KyleOlsen and Zullar like this.
  4. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    oops forget to mention, i will check tomorrow this game with 5.6 and will update if it won't work.
     
    Zullar likes this.
  5. Daegit

    Daegit

    Joined:
    Nov 20, 2015
    Posts:
    32
    work for me on 2017.1
     
    Zullar likes this.
  6. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    Hmm, just checked with 5.6 - everything works :(
     
    Zullar likes this.
  7. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    OK thanks I'll see if I can narrow down the source of the problems. If I find it I'll post here.
     
  8. Alvarz

    Alvarz

    Joined:
    May 20, 2015
    Posts:
    9
    Thanks about this post! I'll try it tonight
     
  9. marcV2g

    marcV2g

    Joined:
    Jan 11, 2016
    Posts:
    115
    If using the LLAPI is there any reason to use NetworkReader/Writer over the .net memory stream?
     
  10. Zullar

    Zullar

    Joined:
    May 21, 2013
    Posts:
    651
    They seem almost identical and I did not see a significant difference. UNET's read/write uint packed is nice though because most indexes, buffer lengths, and counters because only take 1byte instead of 4bytes.

    I ended up using a bitWriter/Reader instead of a byteWriter/Reader. Lots of bool flags are typically used in networking and no reason to send 8 bits for a bool when 1 bit will do (both .NET memory stream & UNET's NetworkWriter/Reader use 8 bits for a bool). Just round up to nearest byte before sending packet.
     
  11. Mickey_omar

    Mickey_omar

    Joined:
    Jan 7, 2017
    Posts:
    8
    Thanks for the example! Does anyone know how to host it on internet for example rather than on the local network? Thanks again