Client-side websocket support with the llapi?

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!

As far as I can tell, only WebGL clients can connect to a server in WebSockets mode. So you can’t run a single server instance that supports both WebGL/WebSockets and native/UDP clients.

Looks like one option may be to run two NetworkServer instances at once, one for WebGL/WebSockets clients, and one for native/UDP clients:

@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.

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!

1 Like

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.

1 Like

@bluescrn very useful to know, thank you for that!

I think it;s not true for 5.6 anymore :slight_smile:
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…

1 Like

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.

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.

@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
1 Like

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.

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.

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

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.

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.

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?

@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.

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.

@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?

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.

1 Like