How we reduced bandwidth usage by 60x in Astro Force (Roblox RTS)

Why are you using an obscure data type to pack your data instead of simply directly sending a binary string which would not only reduce your bandwith usage even further but be faster to run as well as it would simplify your code.
You also run the risk that roblox might change the replication behavior for these data types down the line.

1 Like

Great post! Awesome work on the game so far, itā€™s looking real cool.

As a couple others have referenced, Roblox backported Lua 5.3ā€™s string.pack and string.unpack in August 2020 (more than a year after my original topic). Combined with table.concat, these functions allow you to easily encode and decode an entire list of values to and from one compact binary string. The savings you would get going from your current setup to this approach are relatively minuscule, but preparing data to go over the wire is perhaps the most appropriate use for string.pack on Roblox right now. it certainly suits the task better than these funny int16 vectors. Nevertheless, I appreciate your appreciation of my wild hack :stuck_out_tongue:

7 Likes

Other people have mentioned using binary packing in lieu of a Vector2int16 but for your case that would actually up the bandwidth! The footprint of a string is 5 + n bytes (where n is the length of the string) compared to a set 5 for Vector2int16.

In your case, if you changed nothing else, you would end up with a 7 byte payload if you sent a stringā€¦ At which point you may as well just send the number outright.

3 Likes

This is only true for very small packets in which case bandwidth wouldnā€™t be an issue anyway.
For large payloads assuming your own numbers are correct if you were to send for example a packet with a size of 300 bytes you would end up with a bandwidth usage of 305 bytes for a binary string, 350 bytes if you are sending an array of 50 Vector3Int16 and 375 bytes if you are sending an array of 75 Vector2Int16 plus some additional overhead due to sending an array instead of a single string.

2 Likes

I didnā€™t think of that! Definitely something Iā€™ll have to try out! :slight_smile:

Thanks! Iā€™ll definitely check out the string thing soon too :smiley:

I use to do something like this. Someone told me it was bad practice, which didnā€™t make sense. But reading your topic, I may come back to this and redo my frameworks to include byte channel streams to manage.




Obviously still some bad practices in regards to how some packets are being used lol but the main idea behind byes is here I think?

Correct me if Iā€™m wrong because I donā€™t want to backtrack

Also try and ignore all those bad requires. This was very early code practice on the Roblox platform.

Just want to validate that the pattern I had is in line with this article.

Thanks for the read

3 Likes

At first glance, looks good! As long as itā€™s saving bandwidth :smiley:

1 Like

Yes thatā€™s why I said ā€œin [the OPā€™s] caseā€. Obviously the math works out to being more efficient the more data you add - thatā€™s very basic math. Itā€™s more efficient for every case but one where youā€™re sending a single Vector2int16ā€¦ Which is what the OP seems to be suggesting that theyā€™re doing.

Given that, it seems pertinent to mention it.

1 Like

The number of Vector2int16s sent depends on how many units are moving! In most cases there are more than a couple units moving so the string idea is not a bad idea in theory. Iā€™ll have to test it out though! :slight_smile:

3 Likes

Wow, great read, wish there were more posts like this. I like some of the unthought of optimizations you used, now I think I may explore the same optimizations aswell for my games.

4 Likes

Thanks!

  1. This is fired when the value changes to the relevant clients. This consumes basically no bandwidth in comparison to moving units, so we didnā€™t take any particular steps to optimize this as itā€™s not worth it.
  2. We can take a part that is part of terrain and calculate the height of terrain based on the partā€™s bounding box. We then save this data so that we donā€™t need to recalculate. :slight_smile:
  3. Yep, we use animation controllers. We then just throw in some of Robloxā€™s walking/running animations and can modify the parts we need.
2 Likes

I donā€™t know if I just overlooked this in the post but how do you override Robloxā€™s replication system?

2 Likes

Since we donā€™t use parts on the server, no replication is done automatically. Positions are stored inside scripts (for example, Unit.Position = SomePositionHere), and we can control when we send position updates to clients.

2 Likes

You only update goal positions when the actual goal changes right? Ie they reached a node. Then delay a bit and interpolate on the client. This is what I do and it works great

1 Like

We send position updates for moving units at about 10 FPS. We canā€™t just set a goal position because units can be pushed and stuff. Collisions and everything is simulated on the server and replicated to the client; all the client does is smooth out movement between replication steps :slight_smile:

How does this work with combat and/or projectile combat? What about hit detection? Calculating distance to check for every hit seems kinda redundant to me, and you canā€™t trust the client to make these calculations, but they are the only ones who can.

I feel this system is very specific for this type of RTS, but good job on being able to optimize your game to this degree.

This is very specific to our game as I mentioned! The optimizations definitely wouldnā€™t work for many other kinds of games. For an RTS, however, these optimizations work well since anything important is done on the server.

This is some big brain crap right here. Probably the most networking optimized thing Iā€™ve ever seen. Great job!

1 Like

what method did you use for smoothing out the movement on the client?

1 Like