Building a multiplayer game server in Go and Webassembly | Arne Wieding

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] can I ask before we start maybe who has any experience with game development in general like any kind of experience okay and then multiplayer games probably even less okay some people that's cool yeah I guess we can start I'm German I have to start on time anyway so yeah so in the NGO community we talk a lot about like distributed systems and micro services and like infrastructure tools and so on I want to talk to you or show you a quite different distributed system which is a multiplayer game and more specifically the web's the the game server which is written in go and then also a way how I'm using logic that is running on the game server which is go in the JavaScript game because the game is kind of a brother game and I'm reusing some logic from the server in the client so we have a lot of stuff to talk about so it might be a bit fast in some places so I hope it's not too much but you can also look at the slides later I'll talk to me so Who am I my name is Anna I work for our delivery hero here in Berlin when we have a lot of we run a lot of popular like food delivery platforms you might know food or food panda um except the T in Turkey and so on we have a couple of hundred engineers here in Berlin and we have also booth upstairs we are hiring surprise I guess everybody in Berlin is kind of hiring so if you want to do go at scale and like a lot of we have a lot of back-end services and go I really do a lot of go please talk to us but this talk has nothing to do with deliver here that just to say now yeah my colleagues call me the angry german but I always tell them no I'm actually just German being angry is implicit and I'm also not a professional game developer so take everything I say with a grain of salt because I'm just kind of playing around with this um so the project the game itself is called pants yo pants is kind of the German word for tank so very innovative name there but it's just a side project as I said very much a prototype so please see it as that there are a lot of problems rough edges and so on but the server I wrote in go which is called trip vac which I will talk to you about now is open source so you can already find it on on github look at it if you don't understand anything I would love to hear your feedback get some contributions or even just fork it and do whatever you want with it you should probably not use it in production like go doesn't have a strong ecosystem for games stuff like unity 3d or Unreal Engine if you want to be really serious our about games it worked for me in this case but if you're serious about creating a game this is probably not the right thing to do but maybe it can inspire you to build something so that we have kind of a picture in mind I want to show you the game itself so this is running in your browser you are kind of steering this tank you see in the center do I have audio by the way it doesn't ok anyway and the other tanks they drive around there are kind of other players that play on their laptops and you see them in this view and can you basically just shoot as each other rumors say these are delivery here employees that play 10 games while working I cannot confirm that but yeah so the goal is just very simply shoot as many tanks as you can and it's running in the browser and then has a very low barrier to entry also that was one of my goals ok so punch IO itself the game just very briefly so that we have some context the game is based entirely on open source technologies which I will also talk a bit more about using the web as a distribution platform so the game itself is running in the browser you don't need to install anything it's kind of the server is lightweight and fast which was one of my main goals and the serve loads fast and is easy to entry and one of the main motivations I had as well was exploring some of these fundamental multiplayer techniques which were kind of interesting to me and I wanted to kind of look into that and also extend my gor knowledge because this is kind of stuff that I don't do at work at all like we build web api is like most people micro services and so on so this was kind of a different challenge these are entirely the wrong reasons to build a successful game by the way just but everybody has to have their motivation and for me this kind of worked well so if we look at Panzer I Oh from the architecture perspective you have this client application that you see there on the Left which is running in the web browser and it's a JavaScript application that uses three J's which is like a rendering library to talk to WebGL to kind of display the image on your screen or in your browser and then the server is a golang application with the only dependency being the gorilla WebSocket library and you could even use the standard library web socket from golang I just thought gorilla is kind of more full-featured and so on that's why I used it and then the game the server talk to each other we are WebSocket over tcp/ip and any serious web the game developer will actually tell you that tcp/ip is very bad for multiplayer games because of its properties that are very good for web browsing and so on like reliability but for online games it's actually pretty bad because also for everything that is real-time streaming TCP is not really the ideal case but since it's a browser game WebSockets are the only thing we can use and then as you see in the middle the server and the client are sharing some of this core Gong core game logic in this web assembly module and why is that it's important I will talk about later and if we zoom out a bit more to kind of how the deployment of this looks and you have the game as a JavaScript application is on Amazon s3 you access it through your browser and then the game servers are running on some dedicated machine inside docker containers and as I said the game client talks to the server via this WebSocket connection but the client and the server also talked to a central API server the game server talks with we're G RPC and the game talks to it we are GRDC to arrest gateway I'd like to get the server list and the service kind of persists all the score boards and so on to this central API but what I want to talk about is just this game server part that you see inside the docker container there so this is what I called tweet back to Vegas German for like jet engine I guess and it's just kind of a cool sounding word maybe you can see it as packets coming in being mingled up and coming out on the other side I don't know it's written and go obviously otherwise I would not be talking to you today and again just a prototype to whatever you want yeah be inspired I don't know before I can tell you more about how three flag works exactly I need to very briefly go some game development basics as we don't have a lot of people that have experience in that regard so how games actually work is you have this game loop which is essentially an infinite loop that runs all the time which kind of processes your input from the keyboard from your mouse applies it to some game state and then moves your player forward for example move some objects in the word forward according to some physical rules to kind of the next state and then uses a rendering of the game engine to display that to the screen and this happens ideally 30 to 60 or even more times per second so you have smooth gameplay experience when you have more than thirty frames per second or even sixty is kind of the idea nowadays so this runs all the time and each iteration then for 60 frames per second has only 16.7 milliseconds to finish this update of the game world and render everything now in the multiplayer game or the one that I'm showing you this game loop is not actually running inside your game locally I mean it is - but the authority of this game loop is rank is running on the server so the server running this simulation and all your input if you press a key it is sent to the server then kind of apply to this game state and then the game state is broadcasted back to all the clients who can then show it this has a lot of benefits to prevent cheating because we also know this from other applications you can never trust clients so they could just tell you okay now I'm here in the next frame I'm super far away and then as a server you have to kind of try to make sense of that actually is possible according to the physical rules of the world and kind of do something which is very complex that's why it's easier to kind of simulate the world on the server and have that have the authority and then prevent cheating like that but obviously you can imagine if every key you press has to be sent to a server and back before you see results the game will feel you feel feel latency on every key press so you really will feel it will not be a good gameplay experience like steering a boat because everything is like 200 milliseconds off that's why in the 90s John Carmack came up with this concept called client-side prediction and server reconciliation first in quake word did anyone play one of these old kwai games by the way like 20 is amazing you're awesome I wasted so much time on that in my teenage years anyway this is exactly how it works and I'm doing the same concept here which basically means at the same time while the server's running this simulation the client does the same and kind of predicts what the server would do and then you synchronize with the server all the time and kind of have to see when the client diverges over time which it will eventually do because it's a lot of floating-point operations and non-deterministic calculations so you will always have some kind of divergence and you need to correct this ideally a lot of times in very small steps so that the player cannot notice this so that they don't see like you see here and this gif where you just snap to some other place to have this that's what should not happen but would happen if you have a lot of packet loss for example so this is kind of the idea of clients heart prediction to predict the same as the server would and then eventually kind of correct the state if it goes off what it should be another concept is client interpolation because the network updates you get about the state of the world are kind of lower than your frame rate so you don't have perfect information for every frame to show where players are so what people are usually doing is to kind of interpolate between the two last states that you got from the server and then just interpolate between them over time which is also sometimes called and conservative algorithm because you're dealing with data that you already know and you could also do extrapolation if you know the last position of a player and then the velocity and the direction you could also tell okay now he should be here and then do some kind of corrections but that's not what I'm doing in this case so now we can actually after we talked about this talk a bit more about three plug in itself so first I set some boundaries for the game or for the server to make everything a bit more or less complex more simple so everything even though you have the 3d isometric view is happening in two-dimensional space all the game logic is just in 2d basically you can't go up and down with the tanks it's all on flat surfaces input control is only keyboard because I also wanted people to easily play with the laptop the websites right now it's kind of limited to the others fits like 1020 players I never tried actually and slow-moving vehicles like tanks also kind of lend themselves well to kind of this kind of multiplayer scenario and I also totally wanted to avoid a physics engine because physics engines first there is nothing really for go you could maybe get something from C working somehow but they add a lot of CPU overhead and a lot of yeah they just use a lot of resources which I didn't want to get into so these were kind of the limitations that I from the beginning and then if you look at is this it's a bit bright maybe I hope you can see this so the yellow part down here is the game loop that we talked about which runs on the server which then updates the game state which is the map the controls collision detection weapons all of this kind of stuff this runs on the server and then for each player that is connected to the server there are two goroutines one that is writing to one that is reading from the WebSocket connection one that is writing to the WebSocket connection and then this runs continuously reading all the input from our players applying it to the world and broadcasting it again to all other players and I will talk to you a bit more about how that works exactly but this is kind of the basic setup of the server but then if we have this this game state simulation running on the server we also need to do this actually in go code so how the service is the players just as a bunch of points basically so you have this central people point which is like the player position in the end and then you have this a B C D points which kind of make up this rectangle or what I call a Collider polygon which is kind of what's used to do collision checks between players and this is essentially how the server sees each player nothing more than these 2d vectors in the end and then if you get a movement command to move forward for example then for movement you just do kind of a simple vector addition that you have like point a for example which has two coordinates and then you add the direction and vector to it multiplied by the velocity and then you have the next kind of state of this point and you do this for all the points and that's how the player moves around on the service essentially and for rotation it's kind of the same you use the people point and select the rotation base and then all the other points are rotated around this people point with some other mathematical formula that you can find online like I didn't come up with this obviously and that is basically the player movement then another important part is collision detection so if we have these rectangle colliders of each player of each tank they can collide with each other or run into each other and then we need to basically find out when do these polygons overlap and for that there I use an implementation of something that's called the separating axis theorem which sounds very fancy in the end what it does roughly if I understand correctly is like projecting the edges of each polygon or two onto its perpendicular axis and then you kind of compare these projections from other from the polygons overlap and if all of them overlap from the different directions then you have a collision otherwise you don't but in the end this is also something that I kind of adapted from C++ and watch the YouTube video on it to kind of understand how it works so no magic there as well and then for the collision with buildings you see you're building on the bottom there I built a small tool that I can kind of define these collider polygons for each building and I just store them in a JSON file that is loaded on the server and loaded on the client and then that is also used for collision detection and the last thing that you see on the bottom right is kind of how a bullet is kind of colliding with a building or tank which is just checking if a point lies within one of these polygons which is actually a much cheaper check than this separating access theorem so this is essentially most of the game logic that is used right now on most that I need it for this one other important part is the data transfer like how do we actually send this stay down to all the players like on the right you see how this could look like a simplified form in JSON so you have a bunch of positions which are all rotations which is are a bunch of 32-bit float values and if you would send this for 10 players like this imagine you have the state of 10 players and send it to everybody as Jason that would be like one over one kilobyte already and if you pick the same 32-bit flow it's just in four bytes and pack everything into a byte array and send it over the wire it's only 240 bytes so it's kind of a factor of five fish smaller and this obviously minimizes resource users of the network but also of the CPU you don't need any marshalling on marshalling of JSON or protobuf or whatever you want to use and but it also prevents packet segmentation because on the Internet Protocol layer you have this thing called the maximum transmission unit which is usually 1.5 kilobytes and the info are if one of these state packets would be bigger than that it would be segmented into different of these segments before it's sent over the wire and then if one of these segments get lost due to packet loss then tcp kind of stores the connection and waits for the whole packet to be resend until it resumed which is also very bad for online games or real-time streaming scenarios so that is why you will always want to kind of minimize the size of these packets and yeah that's kind of the main main thing about the networking transfer and this works very well in the end if you just have some float values it can of course get a bit more complicated if you have different data structures that you want to serialize so now the web assembly module is kind of using this logic that is running in this game loop that I talked about for collision detection and movement and all of that is exported into this web assembly file as you can see here how you kind of compile this into web assembly and then how to load it into JavaScript and then you in the last snippet you can kind of see how to expose one of these functions to the Java JavaScript scope and this is to do this kind of client-side prediction that I talked about earlier to use exactly the same code on the client that is running on the server and one downside is that it's 2 megabyte or I did get it smaller than two megabytes which is kind of still a limitation of go I think the guys are kind of working to improve this for my game which is kind of 25 fish megabytes it doesn't make a big difference but for your use case it might be a deal-breaker and the end so that is kind of one downside of this but it really enables you to run this the same code on the client as well so then I had this problem for wepa sembly like how do I get the data in and out in the most efficient way like I didn't want to serialize Jason on the client and then do that same thing so I'm using exactly exactly the same way as I'm sending the data over the wire I'm kind of getting the input which is just some boolean values into the webassembly like forward true backward true left-right and then calculating this next state based on the same logic as a service using putting everything into this byte array and then you can copy it over into JavaScript into an JavaScript by their images called an array buffer there I guess and then in JavaScript as you see on the bottom you have this construct called a data view where you can just load this and then read the values back in the same order that you store them so here you kind of also have to make sure that you are when you are writing a little endian byte order you also have to read in little-endian and big-endian oh whatever but in the end this works fine and then it's much more efficient than just sending big strings around or whatever and as far as I know you can't just take like a go struct and return it to your JavaScript application and then have some JavaScript object or if you can it would for sure take some reflection stuff that kind of uses a lot of resources yeah wrapping up then I created a playable prototype that kind of is a proof of concept that these kinds of using webassembly on the server and the client works which is a stream of isomorphic apps that JavaScript developers sometimes talk about it's not entirely the game is not entirely go of course but the essential stuff is go and the server's entirely go and uses like five megabytes of RAM and very low CPU all right now I haven't really stressed it yet and it's based entirely on open source there are no licensing fees for anything and it's actually fun that's like my colleagues that I played with and friends that I tested with actually like the game so that's actually the most important thing if you create a game but yeah for me it was kind of a technical project that also should be maybe something that I can release somewhere so what else I'm working on in some cleanups on three flex some stuff is not super nice yet but you can still already look at it it's on github on a WT ng / 3-pack that is my github profile would love to have some stars by the way and yeah again you can do whatever you want with it I would love to get your feedback talk about some things maybe I'm also talking in some areas probably and then I and I also wanted to put some articles out that kind of talk more about some of the details also about the client implementation which we can't really talk about here much because also nobody wants to hear about JavaScript in here I guess so yeah for for the articles follow me on Twitter I will probably put it there I will also put the slides on Twitter later and now I actually wanted to play a game with you but this Wi-Fi situation might be a bit might be preventing this a bit so if you have a laptop you could just go to panzer dot io / hash s / 4 P 7 8 P or you just go to pants io and then you see a server list and it would just ask you to register as a guest and you can just put in your nickname no gdpr panic no one no worries and then I would actually try if this works so by the way the Wi-Fi that I used now is boots guest 5g I hope this has the same password though did anyone see the password I don't know let's see if we can how much time do I have left any it's fine let's see if this is also now like a 20 mega byte on load so on I may be asking too much of this ah that is okay but I don't is somebody still here who knows this Wi-Fi password or does Wi-Fi work for anyone at all okay so you mean like this can people try that works and then the the sh would guest 5g is what was connected to see if it works success anyone yeah cool you still need it and then just go to pants or IO and then you can see the rest easily maybe we can have at least maybe I can shoot at one of you it would be nice okay yeah that can take maybe a minute no yes it's mostly like the assets like the textures and textures and so on oh actually somebody is here I guess looks like otherwise I would not be oh but this is not good yeah I imagine this could go wrong in all kinds of creative ways it's not really let me see what's going on here now WebSocket connections gone already okay that's not good let's try again but we're playing a 10-game in the bunker how cool is that no yeah unfortunately I think this will not be very successful and now we are stressing the same small connection which is probably too much at this point okay then maybe we can let it load in the in the background that's it from me thank you and yeah then we still have some time for questions I guess I have to think we still have like 10 minutes max okay cool any questions over there so I think even if you create like a hello world web assembly it's still 2 megabytes minimum so I don't know what exactly is going on there but it's I tried with like just a very minimal version and it's still kind of big so but I heard another talk at go days at dot goal last year where they were saying that they are working on to improve this because if you do the same in rust it's much smaller for example if you use the same code base for client/server is it possible to implement some kind of different knowledge so if I decline has only a smaller view of the world and does not is not allowed to know the same stuff as a server does umm yes since URI that that would be possible also for example how I do the collision detection right now is kind of inefficient because it's checking all players against all other players so on the client you could do things as just like checking players that are more in your VIN City to kind of have lower resource usage and you could probably also split the map up in different regions then the client only knows about parts of it that are relevant to him or something that should work I won one important thing that I maybe this may be interesting is that the web assembly while it's running actually has the complete state of the game in its own memory so it does all the collision detections in the kind of memory that it's running in all the time so it's not some kind of stateless thing it actually has all the game stage while the game is running yeah back there somebody I don't really see you well yes that's a good question actually I'm not right now the thing is that the collision detection is also running locally so you would first hit something locally and then the server will tell you that you hit something as well and this can it works kind of okayish for slow-moving vehicles but I think if stuff would move faster then you probably have to take like Network delay into account and then kind of play back your stay to see if this is a valid collision or something I'm not really an expert on that yet so for this if we have a reasonably low latency like below 50 milliseconds it works well enough right now let's say you're free to try it out once once you have great Wi-Fi I would love to play a game yeah yes I looked into that as well and kind of the main so WebRTC has a data channel that is udp-based which is why it's very interesting but it's made for a very different use case for real-time video audio streaming and there's a lot of setup going on in a lot of handshakes because it's also peer-to-peer based so we'd spend quite a lot of effort to get that working I think so I haven't really done anything but that would be a potential thing to explore or HTTP 3 aka quake which will be udp-based might also offer something eventually oh that sounds amazing pianist a name or okay nice cool thanks I would check that yes big there okay cool that's also a nice okay that sounds also very good yeah it's something I haven't looked into it heavily because in the end the game is quite large so it's not this big difference but yeah for if you have a lot of people playing this would for sure will make a difference anyone else yeah yeah it's kind of the side project so it's kind of on and off always some weeks more some weeks less I don't know how to say but I don't know 100 hours 200 hours maybe something like this I don't know over over one and a half years actually so it's not I also don't work on it every day but I would actually actually want to release it and people have actually play and then maybe spend money on some gimmicks I don't know let's see any other question I think no okay cool thanks a lot guys [Applause] [Music]
Info
Channel: GoDays
Views: 5,099
Rating: 5 out of 5
Keywords: #GoDays20, talk, goconference, golang, Berlin
Id: ZyGw1yLNO9E
Channel Id: undefined
Length: 33min 55sec (2035 seconds)
Published: Fri Feb 07 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.