Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Client-side websocket support with the llapi?

Discussion in 'Multiplayer' started by donnysobonny, Feb 19, 2017.

  1. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    Hey all,

    I've been pulling my hair out for the past few days trying to work this one out so any advice would be greatly appreciated. Basically, we're building a small online game that we plan to launch on android, ios and the web (over webgl). Our initial research into the tech that we wanted to use made us prefer the llapi because it was less bloated than the hlapi, plus we needed to be able to ensure that the networking was super-lean to handle high numbers of players over mobile devices.

    So far everything has gone well. Testing has been very successful and we've got an android and ios build nearing completion (along with windows/mac for testing). Naturally, realizing that the web build was going to need to utilize websockets, we left that one until last...

    This week i've been tasked with preparing for the web build, and as a result it's been a tough week! Initially, with the vague-ness of the documentation on this topic, and with the fact that it does state that "WebSocket on client has been supported. For client side, all steps described above (including topology and configuration) should be the same", I had assumed that implementing the web version would be fairly simple. However, with the testing I've done, and the few additional bits of info i've found dotted around the forum that doesn't seem the case.

    So my questions are as follows:
    - is it actually the case that unet does support websockets client-side via the llapi? If so, how?
    - if the above isn't the case, are there plans to implement websocket support? Is there an estimated time when this might happen?
    - if neither of the above is the case, what would be the best way to implement a client-side that can easily mimic what we're doing with udp?

    Many thanks in advance!
     
  2. bluescrn

    bluescrn

    Joined:
    Feb 25, 2013
    Posts:
    642
    Last edited: Feb 20, 2017
  3. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    @bluescrn thanks for the input, however you can run a server that supports udp and websockets (by simply setting up two "sockets"/"hosts", depending on whether you're using unet's terminology or the more commonly known terminology). One for udp, and one for websockets. Obviously they would both want to listen on different ports, and if you're clever about it, you could set it up so that both socket's/host's peers pool into a single array/collection so that you can treat the whole solution as a single server (this is ultimately what i'm doing on my server side).

    I have managed to come to a solution on the issues that I was having. I'll post more information shortly.

    Thanks again.
     
  4. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    Okay so, I made one last-ditch attempt to answer the questions I had and also find a solution to the issues that I was having in supporting websockets in the web-build of the game, and I figured I'd post this here for anyone else who is struggling.

    Moving away from the LLAPI

    The first thing I had to do was ditch my reliance on the LLAPI. The documentation states (within the WebGL section of the llapi documentation) that client side websockets ARE supported, however I am 90% convinced now that this is not the case. On the server-side, you are able to set up a websocket socket by simply calling NetworkTransport.AddWebsocketHost (https://docs.unity3d.com/ScriptReference/Networking.NetworkTransport.AddWebsocketHost.html), however, there is no way to connect to this host/socket from the client side while using the llapi. You could obviously use a custom websocket solution here, however my point is that llapi doesn't provide sufficient websocket support currently. I presume though that this will change in the future.

    Also, attempting to implement a custom client-side using a websocket library will mean that you need to be able to decipher unity's byte arrays. At this level, the arrays never seem to be formatted exactly how you expect which makes it very difficult. Doing this is likely to also break your solution in future updates of unet.

    Considering using certain HLAPI elements

    I was convinced that unet must support websockets somewhere, since it's talked about in the documentation. After looking into the HLAPI elements in more detail, I noticed a few settings related to websockets and figured I'd try implementing certain parts of the HLAPI into my solution. I knew that this would add additional layers to my solution (potentially adding overhead) however at this point I had no choice.

    Ultimately I managed to get a pretty solid solution using the NetworkClient and NetworkServerSimple classes. The combination of these classes allows for the use of websockets, and using these classes alone allows us to avoid the bloated-ness of the HLAPI (if you don't need all of the additional functionality).

    I used the NetworkClient class as a way to handle the client-side connection and messaging. NetworkServerSimple (as apposed to NetworkServer, which is the more bloated version) was used to set up udp and websocket sockets, and handle incoming peer connections and messaging.

    Note however that when testing the NetworkClient from within the editor, calling the NetworkClient.Connect method will ALWAYS try and connect as a udp peer (so trying to connect to a websocket server-side will always fail in the editor, even if WebGL is your selected platform!). When a NetworkClient.Connect is used within a WebGL build however, it will ALWAYS connect as a websocket peer (so in this case you will need to connect to a websocket server-side). This took me a while to figure out...

    Getting used to handlers

    In the LLAPI, the meat of your business logic will originate from NetworkTransport.Receive or NetworkTransport.ReceiveFromHost. In the HLAPI however, you make use of handlers. A dated example exists here (this code is no longer correct, but the idea is the same): https://docs.unity3d.com/ScriptReference/Networking.NetworkClient.Connect.html. This ads a slight bit of overhead no matter how you implement them (as apposed to the llapi), however the HLAPI requires that you use them. Trying to use the llapi Receive/ReceiveFromHost for example will cause you problems here, because the HLAPI formats the byte arrays in a certain way to be able to identify the type of "message".

    So ultimately, you'll need to move the meat of your business logic from the Receive/ReceiveFromHost methods into handlers.

    Conclusion

    As of writing this, websockets are not supported fully in the LLAPI. It is likely that support for websockets in unet will improve over time, however currently if you require the ability to use websockets at a low-level (if you don't want to use the HLAPI), then at minimum you will need to use the NetworkClient and NetworkServerSimple classes.

    Hopefully this helps someone!
     
    bluescrn likes this.
  5. bluescrn

    bluescrn

    Joined:
    Feb 25, 2013
    Posts:
    642
    They can actually run on the same port, as websockets are TCP and 'normal UNET' is UDP. That briefly confused me when looking at the code in the post linked above, which was initialising two instances on the same port.
     
    donnysobonny likes this.
  6. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    @bluescrn very useful to know, thank you for that!
     
  7. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    I think it;s not true for 5.6 anymore :)
    OK, initially web socket implementation was developed to support UNITY<--> web browser implementation. It is why only server was supported. In 5.6 all 3 "PC"- pltforms (win, linux and mac) supports web-socket client/server and mixed modes....
     
    donnysobonny likes this.
  8. TomPo

    TomPo

    Joined:
    Nov 30, 2013
    Posts:
    86
    Could you please paste here simplest setup for server and client for using websocket on both?
    For now is lack of docummentation about this new feature.
     
  9. pathMark-er

    pathMark-er

    Joined:
    Dec 7, 2016
    Posts:
    1
    I've tested it out and it works just fine. I just oppened web socket host with: int webId = NetworkTransport.AddWebsocketHost(topology, port, null); in the server side and then sent messages to the client with this id.
    Note: my server is a stand alone, the client is built in webGL.
     
  10. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    @TomPo
    1. create simple game containing client and server using llapi only
    2. change AddHost to AddWebsocketHost on both side (On client and on server)
    3. run
    it is only what you need
     
    benio33 likes this.
  11. RandomPoint

    RandomPoint

    Joined:
    Jul 21, 2017
    Posts:
    14
    Is it possible to use the HLAPI with a combination of WebGL clients and standalone clients? I can get one or the other to connect, but not both.
     
  12. angusmf

    angusmf

    Joined:
    Jan 19, 2015
    Posts:
    261
    The HLAPI is either/or if we use the NetworkManager, because it uses NetworkServer, essentially a singleton, and it is either/or (because it is inherited from NetworkServerSimple, which is either/or.) The OP had to write his own HL code around NetworkServerSimple so he could actually create two server instances. That's the only option besides modifying the HLAPI from source.
     
  13. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    Sorry for not getting back to you dude. Yeah @angusmf is on point with this one, if you are using the HLAPI, which is built for convenience, you're limited to a single port for connections over either udp or websockets. The information I wrote in here is pretty dated now, in that the LLAPI has supported websockets for a while now. When I started this thread it didn't, and I had to implement a work-around until it did. So my use of the NetworkServerSimple class was the work-around. If you can, I would avoid the HLAPI entirely and just roll with the LLAPI, which will give you plenty of flexibility. Including the ability to set up multiple ports like I did for https://frogar.io (which has web/mobile/desktop clients all connecting to the same server)

    Let me know if you need more info
     
  14. RandomPoint

    RandomPoint

    Joined:
    Jul 21, 2017
    Posts:
    14
    Thanks for your insights. This is for a volunteer STEM project, so I am looking for the path of least development because the people involved have limited time and limited Unity experience.
     
  15. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    Hmm... this is a really tricky one. Off the top if my head, from having around 6+ years in development of networked games/apps I don't think there is realistically a short path for development. Network programming sits somewhere close to the complexity level of multi-threaded programming. In short: it's not simple to grasp because it realistically cannot be. There's so many cogs and screws in what makes multiplayer games work efficiently and if one of those cogs or screws isn't quite aligned then the whole thing will break.

    So maybe it's the case that if you're looking for a challenge that a set of volunteers can take on with little experience, network programming isn't a great idea. I could be wrong here, i'm totally self-taught and learned about everything on my own so maybe with quality learning resources/documentation things would be easier but again, you can't make something as complicated as network programming simple... at least not in my opinion.

    Let me know if you need more help on this one or additional tips/advice. I'd be happy to help.
     
  16. RandomPoint

    RandomPoint

    Joined:
    Jul 21, 2017
    Posts:
    14
    We are not going for a bullet-proof, commercial-grade game. It may be used for one or two competitions and that's it. It will probably be a multi-player board-based puzzle game where some of the players may be driven by AI. We have volunteer devs that understand networking, but not how Unity does it.

    How hard would it be to extend NetworkServerSimple to accept both types of connections? If that could be made to work, then couldn't we stick to the simple HLAPI across both the standalone and browser clients?
     
  17. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    @RandomPoint I would recommend to take a look on pure llapi. It is really not difficult to implement logic by using this. I will need to implement some technical stuff (like callback by yourself) but nothing really. Just spend 2-3 days for network implementation skeleton and 2-3 days for testing for performance measuring. If you will have problems, you can directly ping me and I will try to help.
     
  18. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    Yeah alex is on point with this one. If they understand networking as you've said, they will actually understand the LLAPI far easier than the HLAPI, because the HLAPI extends the basic networking concepts to implement convenient features while the LLAPI pretty much provides a basic level of networking. So basically they would be able to start using and building something with the LLAPI within a day of playing around, while with the HLAPI they are going to have to learn the architecture of it before they can understand how to use it... plus, if all you are planning is a simple turn-based puzzle game then the HLAPI will be awkward as hell to use. As I said before, it's pretty much designed for the most common thing that first-time unity developers do: room/lobby based match-made FPS games.

    So yeah, to sum things up:
    - use the LLAPI. If you want to make the use of the LLAPI slightly easier (providing a functional layer on top of it) let me know. I have done this myself a few times for a few different types of networking scenarios so I could help with that.
    - as alex said, get a test/dev environment set up and make sure it meets your minimum and maximum requirements

    If you are desperate to use the HLAPI to make the setting up of all of this easier for you then I recommend the following:
    - since it sounds like you are doing this for some sort of educational/awareness type thing, teach good practice. Hacking away at things and using work-arounds is bad practice and should never be taught, you should teach them to avoid that. So if you are trying to bend the will of the HLAPI to something that it isn't designed to do, you're pretty much teaching these volunteers how not to do things...
    - build something that the HLAPI can support. It doesn't necessarily have to have the things that I mentioned above (lobby/room based match-made FPS). The lobby/room and matchmaking can be avoided as those are optional, but something like an arena or fps game where players control a single character within an online world of 10-20 other players is what the HLAPI is particularly good at handling.
    - bear in mind again though that the HLAPI isn't "common networking" so the understanding that your volunteers have of networking won't prepare them for the HLAPI. The HLAPI is an extension of the LLAPI (which is common networking) so if you go with the HLAPI, your volunteers are going to have to learn a lot on top of what they already know before they can even build something that works.

    Hopefully this helps.
     
  19. RandomPoint

    RandomPoint

    Joined:
    Jul 21, 2017
    Posts:
    14
    @aabramychev @donnysobonny I really appreciate your guidance on this. I hope that the future questions I ask on this thread will be much more specific, real implementation issues.

    What I was really hoping for was that some smart person would say that it's easy to modify the transport layer behind the HLAPI to allow both standard and websocket connections (by coding a simple multiplexer or adapter and inserting it at the right spot). But that appears to not be the consensus.

    We were hoping to use the Lobby features of the HLAPI for setting up multi-player game sessions, and to use the HLAPI features to sync the player movements and board state among all the clients. But maybe it's not to be. However, before I concede: Is it possible to get the standalone clients to use websockets, and solve the problem that way?
     
  20. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    To translate what you are looking for into language that developers understand, you want to hack code that is managed by unity, without really understanding what it does, to implementing a work-around. There is no "good practice" way to do what you have suggested above, but there are obviously plenty of ways to do it in a way which is not good practice. To my knowledge, the HLAPI is open source so if you really wanted to go down this route, you could. I wont repeat what I said above since I don't want to seem like I am raining on your good will, but yeah, teaching good practice is just so much more beneficial to these volunteers/potential developers than giving them the impression that development is all about hacking other people's code.

    Yeah, on the face of it, this is what the HLAPI can do quite well. It sounds though that you maybe haven't tried it out for yourself yet? If so I would highly recommend that you try and do what you are expecting your volunteers to do. You will see what I mean once you try it out: it's not as convenient as you might want it to be. There's quite a bit to getting even a basic thing working without any issues. So again, if you can stomach it, a simple functional layer on top of the LLAPI to help your volunteers into the whole process might be a better shout... either way make sure you spend some time with it yourself first.

    I can't actually confirm this 100% because I have never tried it. To my knowledge it's not possible but I do remember reading that unity wanted to allow this so it may well be the case that you can now. Maybe alex can get back to you on this if you aren't able to set up a test to try it out for yourself.

    I don't necessarily think you could call it bad practice using websockets for this, as apposed to the obvious better choice being UDP... sometimes you have to use what is available to you. Maybe just explain to them that UDP would be the better choice if it was available in your situation.
     
    aabramychev likes this.
  21. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    @RandomPoint
    not sure exept you will change hlapi layer, transport itself support web sockets for server and client... Sorry about this news :(
     
  22. RandomPoint

    RandomPoint

    Joined:
    Jul 21, 2017
    Posts:
    14
    I appreciate that you are trying to keep me on the righteous path, and I assure you that I am not intending to stray. I would not want to directly modify the HLAPI code. I was hoping that it could be extended in an object-oriented manner, but maybe that is not in the cards. It is helpful that the source code is available. I did look at it briefly.

    Just to clarify, I am one of a small group of adult volunteer developers trying to build a platform to help high school students get excited about STEM. We are building the Unity application. The students will take on the challenge of creating their own software to drive a player in the game. Their software can be written in any language, and will connect to our game via a well-defined interface using a simple text-based protocol. Many of the students are enrolled in AP Computer Science, and will write their code in Java or Python. They will not have to know anything about Unity.
     
  23. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    @RandomPoint in this case, probably "server.dll" will be proper solution for you? It is just dll separated from unity but supported unet protocol. Using this library you can connect and exchange messages between any client supported dynamic linkage and unity using unet. There are wrappers for c# there. Other languages can use supported api directly as fas as they support them. But again it is transport layer.
     
  24. RandomPoint

    RandomPoint

    Joined:
    Jul 21, 2017
    Posts:
    14
    @aabramychev Thanks for that tip! That could be useful. It would allow the student code to talk directly to a Unity server.

    I'm not sure how tricky it would be to wrap it up for Java and Python for different platforms, so maybe we would have to make a little Unity proxy app that would run on the client host. The student app would send messages to the local Unity proxy app, which would forward them to the server.
     
  25. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    @RandomPoint PM me please for access so far I have windows binaries only, so for mac it will take a little bit more, again PM me. I do not see any problem with python integration, for java just don't know. as well i can publish all export functions signatures (or you can grab them from dll too :))
     
  26. RandomPoint

    RandomPoint

    Joined:
    Jul 21, 2017
    Posts:
    14
    @aabramychev It's going to take some discussion amongst my team to decide which approach everyone feels comfortable with. If we do decide to create a proxy module for Java and Python, I will definitely contact you for help. I appreciate your willingness to help.
     
    aabramychev likes this.
  27. angusmf

    angusmf

    Joined:
    Jan 19, 2015
    Posts:
    261
    If one was to modify the existing NetworkServer for this, you have to deal with the fact there are two hosts. I'm experimenting with this now and trying to decide if it's better to break the API and ask for hostId everywhere that asks for a connectionId (in order to find a connection internally) or "pack" the hostId into the NetworkConnection.connectionId integer. NetworkIdentity.connectionId would no longer (necessarily) be the same value as the id in the LLAPI, but it would be transparent.
     
  28. angusmf

    angusmf

    Joined:
    Jan 19, 2015
    Posts:
    261
    I am leaning towards packing as it will be the least work internally and transparent (as long as you don't rely on the fact that the LLAPI connid and HLAPI connid are the same currently,) and in fact, everything should work identically if not trying to run both hosts. The packing scheme would assign 1 bit of connectionId to represent udp/ws. When not using both hosts, whatever host is being used would be assigned 0, so the packing would result in the same connid as before in that case. If anyone needed the LLAPI connid, it could be available in a new property or obtained by unpacking connid using NetworkConnection.hostId.
    When running both hosts, the websocket bit will be 1, and websocket connids will effectively be multiplied by the bitshift, resulting in a unique connid, and that's pretty much all the HLAPI guaranteed you to begin with. I have to look at the original code again and make sure they don't use it as an index or count anywhere. If user code tries to use it as index or count, they'd hate this too.
    I guess another approach is to just assign connids that have nothing to do with the LLAPI connids and manage them separately. Make the LLAPI connid available in a new property

    @aabramychev It would be great if the LLAPI didn't assign colliding connids in the first place.
     
    Last edited: Nov 11, 2017
  29. angusmf

    angusmf

    Joined:
    Jan 19, 2015
    Posts:
    261
    On the topic of hacking the HLAPI, I'll disagree as per usual and say that's a super useful skill to have and one that students could stand to learn earlier. Only knowing how to write good code is probably sufficient for some people, but exactly none of my real world jobs (non game dev or otherwise) have started with a clean sheet. I roll in and the first thing the boss asks for is to fix or replace some existing project. Whichever route you choose, or directive you're given, you can be sure there are no requirements docs you could build the thing from. That means you will be reading and understanding that old code (and reading bug reports, talking to QA and other devs...the internal corporate equivalent of internet forums and SO?) no matter what. Far more than half the time I find it easier, more fruitful, or simply more realistic to fix at least some of the old code.
     
  30. donnysobonny

    donnysobonny

    Joined:
    Jan 24, 2013
    Posts:
    220
    So just reading the solution you're going for... yeah that sounds like far too much work. The bottom line is (and keep us up to date on this for experience purposes) you're going to run into complications using this method. I can think of a few off the top of my head (such as how you handle messages that need to go to everyone...) but it sounds like it will be more useful for you to learn this on your own. It takes experience to know that the more complicated a solution to a problem is, the more chances are that it will fail, and the much harder it will be to maintain in the long run. Again though, you'll only learn this by trying, so feel free to keep going with it.

    As for your input on good practices and whether they are useful or not, there's a very important point to make here. The reason why you've gone into jobs and been told to "fix" things is because of the lack of developers using good practices in the first place, because development nowadays is much more accessible than it used to be and educational systems haven't caught up. Look at the push for things like agile development which is a practice that is being adopted by many medium to large scale businesses nowadays because it promotes good practice and avoids hiring people and having to tell them to "fix" things. So, the reason you've been in that situation is because the developers that worked on things before you haven't followed good practices, that certainly doesn't mean that you need to do the same.

    Personally, I turn down jobs like the one that you have mentioned above, and have actually caused many problems with fellow co-workers due to my constant nagging that we follow good practices but at the end of the day, every company and every project that I have finished has ended up better off as a result, with systems that are maintainable and scalable and that wont cause the issues that you have mentioned above. I'm not saying that I am better or worse than anyone else, but the main difference between me and many developers or small businesses is that I think in the long-term. Most think in the short-term and consider hacky work-arounds to be a sufficient solution. So it mainly comes down to who you are and who/what you want to be. Personally, I want to make software development a better industry for everyone, no matter how small a fish I am and how big the pond is, and in my eyes using good practices is better for everyone, while avoiding them is only good for yourself.
     
    Last edited: Nov 11, 2017
  31. angusmf

    angusmf

    Joined:
    Jan 19, 2015
    Posts:
    261
    Oh, thank you.

    This already works in my build but won't drop in to another HLAPI project. Took a couple half days. Totally worth it to me. So if you have any input on what I asked... feel free to keep going with it.

    As for the rest... shrug. Must be nice to live in your world.
     
  32. dienat

    dienat

    Joined:
    May 27, 2016
    Posts:
    417
    I am using 5.6 and android client or editor client dont connect to a linux webgl server with websockets, but it does a webgl client
     
  33. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    What happened when you did what he instructed in comment #10?
     
  34. dienat

    dienat

    Joined:
    May 27, 2016
    Posts:
    417
    I was using hlapi, but made it work anyways with other solution, i had my firewall ports blocking the connection