GML How to optimize in-game with online co-op

Leoah

Member
Hi, I'm learning and know a little bit about making online co-op games using GMS. Currently I am using GMnet. I have searched on google but there is probably too little information about optimizing in GMS co-op games. I have seen a very good game made in GMS with online co-op function, which is Forager.
Forager (Beta) [Online Co-op] : Co-op Campaign
Although this game has been discontinued for online co-op, I have a problem to figure out: how to optimize in game, which means in forager there are a lot of objects created and made how to optimize game without lag or drop in fps? I came across this game author's optimization here:
FORAGER: OPTIMIZATION IN GAMEMAKER
but that's only for offline games, so what's the way to optimize with online co-op? Is it different from the normal way offline. Hope someone who has ever done co-op online using GMS can suggest or help me. I sincerely thank.
 

FrostyCat

Member
There is no such thing as "the way to optimize with online co-op", you won't get results that way. The basic idea of optimizing ANY networked game is to think of how to say as little as possible. For example, instead of sending messages about where everything is every step, send messages only when things are actively created, updated, or destroyed.
 

Leoah

Member
There is no such thing as "the way to optimize with online co-op", you won't get results that way. The basic idea of optimizing ANY networked game is to think of how to say as little as possible. For example, instead of sending messages about where everything is every step, send messages only when things are actively created, updated, or destroyed.
Thanks for your suggestion. I understand the problem but maybe I will still need some more clarification because I still can't figure out how to do it and the best optimization when there are many other objects in the game like forager did.
 

ThraxxMedia

Member
There's actually a pretty short, but still very good article on the topic of networking and optimization on the Valve developer community hub: https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking

It's rather basic in its explanations, but still helped me out tremendously when it comes to understanding actual net code. One of the issues, for example, is that most (if not all) of the available GMS2 networking tutorials out there teach you how to set up a client and server, and exchange data packets... but they usually tend to do this every single step by just relaying whatever data was received. This is not only very inefficient, but will also kill your bandwidth in no time and cause congestion (especially when using TCP).

This is where the concept of snapshots falls into place, which are basically states that were captured at a given point in time, sent in a set interval (commonly known and referred to in the above article as "tick rate"). It's not so much the size of each individual packet that you would need to worry about, but moreso the rate at which they are sent and received. Imagine having lots and lots of players, objects, or other stuff in your game that you'd like to synchronize... and every single one of them is sending its data whenever it is available. That's like a small DDoS attack you're bringing upon yourself, eventually leading to lag or even disruption of service.

So if you want to optimize your networking for online play, start at the core question of: when do I need to exchange data? (as opposed to: what data do I need to exchange?)
 

FrostyCat

Member
Thanks for your suggestion. I understand the problem but maybe I will still need some more clarification because I still can't figure out how to do it and the best optimization when there are many other objects in the game like forager did.
There is no such thing as "the best optimization" that applies everywhere. You have to consider the exact details of your project, and determine a means of handling it on a specific basis.

Consider 2 kinds of in-game objects:
  • Chest: Spawns once, indestructible, doesn't move, can be opened once by a player
  • Bullet: Spawns all the time, destructible, moves around with seeking motion
To synchronize a chest, you only need to send a message telling other players of its existence and position in the room, and wait for a one-time acknowledgement from them. Then once you know everyone knows about the chest, you never talk about it again until it is opened.

To synchronize a bullet, not only do you need to send a message telling other players of its existence and position, you also need to send regular updates on its new position and direction/speed, and of course another message for when the bullet hits something and gets destroyed.

Both the chest and bullet use cases count as "when there are other objects in the game". Yet the handling is completely different, and would be far from optimized or even usable if you believed that either approach is universal.

You, like any other starry-eyed rookie wanting to make an online game, must accept that there is NO universal "best" solution. It is always a matter of considering tradeoffs. If you don't want to put your own effort into designing the protocol to suit your own game, don't waste your time or ours trying to develop a multiplayer game.
 

Leoah

Member
There's actually a pretty short, but still very good article on the topic of networking and optimization on the Valve developer community hub: https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking

It's rather basic in its explanations, but still helped me out tremendously when it comes to understanding actual net code. One of the issues, for example, is that most (if not all) of the available GMS2 networking tutorials out there teach you how to set up a client and server, and exchange data packets... but they usually tend to do this every single step by just relaying whatever data was received. This is not only very inefficient, but will also kill your bandwidth in no time and cause congestion (especially when using TCP).

This is where the concept of snapshots falls into place, which are basically states that were captured at a given point in time, sent in a set interval (commonly known and referred to in the above article as "tick rate"). It's not so much the size of each individual packet that you would need to worry about, but moreso the rate at which they are sent and received. Imagine having lots and lots of players, objects, or other stuff in your game that you'd like to synchronize... and every single one of them is sending its data whenever it is available. That's like a small DDoS attack you're bringing upon yourself, eventually leading to lag or even disruption of service.

So if you want to optimize your networking for online play, start at the core question of: when do I need to exchange data? (as opposed to: what data do I need to exchange?)
Thanks a lot. I will read it to understand more
 

Leoah

Member
There is no such thing as "the best optimization" that applies everywhere. You have to consider the exact details of your project, and determine a means of handling it on a specific basis.

Consider 2 kinds of in-game objects:
  • Chest: Spawns once, indestructible, doesn't move, can be opened once by a player
  • Bullet: Spawns all the time, destructible, moves around with seeking motion
To synchronize a chest, you only need to send a message telling other players of its existence and position in the room, and wait for a one-time acknowledgement from them. Then once you know everyone knows about the chest, you never talk about it again until it is opened.

To synchronize a bullet, not only do you need to send a message telling other players of its existence and position, you also need to send regular updates on its new position and direction/speed, and of course another message for when the bullet hits something and gets destroyed.

Both the chest and bullet use cases count as "when there are other objects in the game". Yet the handling is completely different, and would be far from optimized or even usable if you believed that either approach is universal.

You, like any other starry-eyed rookie wanting to make an online game, must accept that there is NO universal "best" solution. It is always a matter of considering tradeoffs. If you don't want to put your own effort into designing the protocol to suit your own game, don't waste your time or ours trying to develop a multiplayer game.
Thanks for the clearer suggestion. I have done 1/2 of the project, everything works fine with online co-op using Gmnet. However, because the project I do is about survival, it requires a lot of environments, such as trees, animals, plants, soil... so the number of objects is up to hundreds of thousands objects. What I need is how to make the project work smoothly, no lag, no fps drop even on hosts and clients. It's almost the same way that forager did, or like how Stardew Valley has succeeded in optimizing so many objects that have already been created that I don't understand how to do this. I know I still haven't mastered and understood these matters because I'm stupid. Therefore I really need your suggestions or help. No, I'm trying to save time - I don't want to waste time, because I've been doing it, what I need is to try to use my time to ask someone for suggestions for direction and a more accurate way to do it (of course this can be done by me). get the answer on my own but it will probably take more time than a suggestion from someone else).
 

TailBit

Member
For a start then I would suggest making farmable areas arrays, so you can have all the map areas open at once, as they usually are not that many in games like this
GML:
map[area][4][5] = [contains,date_planted,damage,watered]; // array or struct
That way they can be changed and updated while you are on different maps and others are working there.

on map farm2, tile (3,5), waterspreader was used -> tell server -> server tells players -> they change their maps to be wet on a 3x3 square around that tile ..

player goes to sleep -> tell server -> server noticed that all players are sleeping -> tells everyone to go to next day -> all players increase their day counter and clear all maps for water / fills them for water if it is raining the next day and all the other "new day" stuff

Gathering spots like berries and such can just be pre set areas where they spawn, maybe give them a number in the creation code that it will use to check if it have been picked in an array, so if you pick up a berry then you can just tell all the others on the screen, I picked up from gathering spot 5, and then it is confirmed by the server, and told to the others, if they are on the screen it is deleted for them (if 2 tries to pick the same up at ones, then one of them will get a NO from the server and told to not carry anything)

Trees that grow back, instead of setting a true/false flag, you could give it a counter instead, and a damage value, and when day change you just lower the counters and spawn the tree there if the counter is at 0 when the player enters the area containing the tree with that index .. but both could be the same .. gathering_spot[index] = [tree,respawn_countdown,dmg];

For NPC and interactable animals,
GML:
entity[map][list_of_animals] = {what,x,y, .. other stuff };// struct
only have server consider moving them if players are on the same map area as them, and only inform player on that part of the map ..[/CODE]
 
Last edited:
There is no such thing as "the best optimization" that applies everywhere.
I would kind of disagree, here. Of course, there's no magical code, but some principles apply across the board, such as:
  • Send only the necessary data
  • Access only the necessary data
  • Whenever possible don't store your data multiple places and access it from the source
  • etc. (you get my drift)
But none of these things are tied in any way to GML, so yeah...just working on your networking skills is probably the best optimization one can ever do, plus it'll affect all the future projects in a positive way as well
 
Top