tag:blogger.com,1999:blog-3064325214589649535.post2619411073132537228..comments2024-03-28T06:52:15.545+01:00Comments on Joost's Dev Blog: Bitcrunching numbers for bandwidth optimisationJoost van Dongenhttp://www.blogger.com/profile/00569566310604620045noreply@blogger.comBlogger9125tag:blogger.com,1999:blog-3064325214589649535.post-71158151104565251712014-05-11T21:01:46.356+02:002014-05-11T21:01:46.356+02:00Please do, this is really interesting stuff!Please do, this is really interesting stuff!Anonymousnoreply@blogger.comtag:blogger.com,1999:blog-3064325214589649535.post-32302183119601953762014-02-04T18:49:43.911+01:002014-02-04T18:49:43.911+01:00"This post misses out on the high-level techn..."This post misses out on the high-level techniques concerned with multiplayer code "<br />I try to pick a single small topic and go into depth on that, so there are indeed dozens of other interesting multiplayer topics I could be writing about. I really should do more of them in the future and cover more ground. :)Joost van Dongenhttps://www.blogger.com/profile/00569566310604620045noreply@blogger.comtag:blogger.com,1999:blog-3064325214589649535.post-29592533467942277642014-02-04T16:24:02.314+01:002014-02-04T16:24:02.314+01:00brilliant article! I have been using byte streams ...brilliant article! I have been using byte streams for this, but a bit stream is a brilliant optimization.<br /><br />One useful tip for your stream class, the stream should able to go into a read and write mode, then you can both read and write from a single function:<br /><br />void parseUnsignedInt(unsigned int& value, unsigned int numBits); // reads bits in read mode, otherwise writes bits in write mode<br /><br />This saves a huge amount of maintenance and dramatically avoids the chance of mismatching your parsing, which as you said is difficult to debug.<br /><br />This post misses out on the high-level techniques concerned with multiplayer code such as delta compression, input sync, etc but the techniques would apply to most networking implementations. Thank you Joost!<br />Danhttps://www.blogger.com/profile/04942789327676568967noreply@blogger.comtag:blogger.com,1999:blog-3064325214589649535.post-55336862839779326802014-01-04T23:39:59.886+01:002014-01-04T23:39:59.886+01:00Interesting, I had never heard of that! I just loo...Interesting, I had never heard of that! I just looked it up and read the basic description, but in practice I doubt it would have worked for us: we ended up using a lot of context-specific tricks for further optimisations (on top of the ones this blogpost is about), and such libraries usually combine really poorly with such custom requirements.Joost van Dongenhttps://www.blogger.com/profile/00569566310604620045noreply@blogger.comtag:blogger.com,1999:blog-3064325214589649535.post-32679442907997800632014-01-04T19:16:57.399+01:002014-01-04T19:16:57.399+01:00I'm wondering if you considered using Google&#...I'm wondering if you considered using Google's Protocol Buffers for this? It solves pretty much this exact problem.Unknownhttps://www.blogger.com/profile/05278390989396399920noreply@blogger.comtag:blogger.com,1999:blog-3064325214589649535.post-44250166167361642022014-01-04T13:35:37.875+01:002014-01-04T13:35:37.875+01:00We actually already have something like that on po...We actually already have something like that on positions in Awesomenauts, so on average they use a lot less than 13 bits. It did get rather complex in combination with unreliable packets, but it worked really well to further halve the average bits used for storing positions. :)Joost van Dongenhttps://www.blogger.com/profile/00569566310604620045noreply@blogger.comtag:blogger.com,1999:blog-3064325214589649535.post-89637930703612547712014-01-04T13:04:40.105+01:002014-01-04T13:04:40.105+01:00You can actually further optimize this.
The examp...You can actually further optimize this.<br /><br />The example of determining the size of the world and store that as position is still a 'naive' approach. <br />What actually changes is the change since the last network transmission.<br />So what you could do is check if the position is changed since the last network transmission. But again, keeping track of the absolute position is unnecessary. Creeps can only move a certain amount of units each network transmission interval. So instead of storing the complete position. Split the world up in cells of eg 16, again split each cell of 16 up in 16 smaller, again and again. For example a recursion of 4. Note for this is no data structure necessary.<br /><br />Now when the position of a creep changes see if its position in the virtual biggest 16 cells is actually changed. Do this for the 16 smaller, and the other 16 smaller and once again. <br /><br />Now if you split the world in to some clever value so that actually only the smallest cell changes (due to the network transmission interval) only the change in that cell has to be sent. <br /><br />This incurs an overhead of 4 bits on top of the position since you have to let the recipient know whether a cell has changed and need to be read out.<br /><br />So in worst case scenario when all cells are different, you actually sent 4 bits more than needed but that is the worst case scenario which only can actually happen when a unit teleports.Barthttps://www.blogger.com/profile/02707141310032131696noreply@blogger.comtag:blogger.com,1999:blog-3064325214589649535.post-86482302931682553942014-01-04T12:40:22.616+01:002014-01-04T12:40:22.616+01:00Awesomenauts being a complex online multiplayer ga...Awesomenauts being a complex online multiplayer game, we of course spend ages on all the aspects of multiplayer. :)<br /><br />We tried client-side prediction, but it turned out to be really messy: it is possible to instantly turn around in Awesomenauts and that means that whenever you do that, the client predicts the wrong movement. Correcting that looked pretty bad, so I removed it. Either I am misunderstanding some important aspects, or client-side prediction just doesn't work as good in a game with movement as erratic as in Awesomenauts. I guess it works better in a more predictable game like a racing game, where the only drastic frame-to-frame changes that can happen are collisions, which the client can also predict. Things like suddenly braking, steering and accelerating are relatively smooth effects and thus won't break the prediction as much.<br /><br />Having said that, there are still plenty of opportunities for client-side prediction in specific elements. We are specifically going to experiment with predicting bullet movement in Awesomenauts in the coming months, hopefully this will decrease lag problems a bit. If that works well, we might look into specific skills to see what elements in them are predictable.<br /><br />A big challenge here is that context-specific prediction implementations make a mess of code, but I don't think a generalised prediction system can work well in Awesomenauts.Joost van Dongenhttps://www.blogger.com/profile/00569566310604620045noreply@blogger.comtag:blogger.com,1999:blog-3064325214589649535.post-16984505268979757332014-01-04T12:16:36.423+01:002014-01-04T12:16:36.423+01:00Very interesting post. I feel bandwidth optimisat...Very interesting post. I feel bandwidth optimisation is an huge subject same as AI stuff, and others.. I tried few years ago to make a realtime network multiplayer game and It turned out to be a mess.<br /><br />I read a lot about client-side prediction, data synchronisation and so on. How much did you use this kind of things in Awesomenauts ? <br /><br />(Just to say, I'm really interested on more post about networking and multiplayer :) )Anonymoushttps://www.blogger.com/profile/04988405233958826591noreply@blogger.com