Dealing with "everyones ready" in the sim
Moderator: Moderators
Dealing with "everyones ready" in the sim
I need the following sequence:
1.) unsynced code sends "i'm ready" to sim
2.) when every player is ready sim sends "we're all ready"
3.) synced event occurs in following game frame
Now presumably this is something like how game start and pause work but the GameServer code is pretty intimidating and I was hoping somebody could boil down the process for me. In short, how do I create a new sync event and action and get all players to execute said action on the same frame from C++? Pseudocode would be appreciated.
1.) unsynced code sends "i'm ready" to sim
2.) when every player is ready sim sends "we're all ready"
3.) synced event occurs in following game frame
Now presumably this is something like how game start and pause work but the GameServer code is pretty intimidating and I was hoping somebody could boil down the process for me. In short, how do I create a new sync event and action and get all players to execute said action on the same frame from C++? Pseudocode would be appreciated.
Re: Dealing with "everyones ready" in the sim
look at the existing synced commands, e.g. /cheat. you should be able to trace what you need from there.
Re: Dealing with "everyones ready" in the sim
Don't get me wrong, I'm not trying to be lazy. I'm just trying to circumvent wasted time poking at the wrong code. However, you're right, /cheat does seem like a reasonable starting point. I can probably shave some time off if I can learn how to use breakpoints in gdb (at the moment i need spring to crash before I can backtrace and see what called what).
What's difficult about this particular situation is I can't just say , "oh cheat() calls X(), and X() calls Y()" because the process involves callbacks and network processes that break the usual program flow.
Anyway, not complaining, just telling you why I'm asking first and poking around second.
What's difficult about this particular situation is I can't just say , "oh cheat() calls X(), and X() calls Y()" because the process involves callbacks and network processes that break the usual program flow.
Anyway, not complaining, just telling you why I'm asking first and poking around second.
Re: Dealing with "everyones ready" in the sim
for debugging, get qt creator. it can open cmake files, but you can configure cmake to include debug symbols externally; the ide will pick up this configuration. if you put qtcreator's gdb helpers dll in the same directory as spring.exe, you'll get pretty nice support for stl containers (like, say, sane printing of contents of std::vector, etc.)
it can also set and clear breakpoints while spring is running without pausing it, which is something i've never managed to do with console gdb.
it can also set and clear breakpoints while spring is running without pausing it, which is something i've never managed to do with console gdb.
Re: Dealing with "everyones ready" in the sim
Thanks for the tip. I'm currently using Eclipse (because I use it for PHP and Coldfusion) and I have downloaded code::blocks but I haven't managed yet to get debugging or cmake integration working.
From what you just said switching to qtcreator or learning to use the IDE's I have sounds like a reasonable first step. I guess I just like the console because I have a bash script set up to build and install spring from toolchain files.
I'd just like to have the same simplicity when building from an IDE but I typically get stuck configuring the project and compile options and go back to the shell.
From what you just said switching to qtcreator or learning to use the IDE's I have sounds like a reasonable first step. I guess I just like the console because I have a bash script set up to build and install spring from toolchain files.
Code: Select all
./build-spring.sh linux && ./build-spring.sh win32
Re: Dealing with "everyones ready" in the sim
with qtcreator's cmake support you configure everything using cmake, you can even build using cmake and use qtcreator's external application debug support (which is what i do to avoid rebuilds). i suggest qtcreator due to it's awesome 1) autocompletion, 2) smart rename of variables, 3) go to definition/find usage, 4) speed (it's subjectively very responsive).
Re: Dealing with "everyones ready" in the sim
have a look at these files:
they are what i had to fiddle with when doing synced/unsynced commands for AIs.
in the first too, look for the giant switch statements, handling commands.
Code: Select all
rts/Game/Game.cpp
rts/Game/GameServer.cpp
rts/System/BaseNetProtocol.h
rts/System/BaseNetProtocol.cpp
in the first too, look for the giant switch statements, handling commands.
-
- Spring Developer
- Posts: 1254
- Joined: 24 Jun 2007, 08:34
Re: Dealing with "everyones ready" in the sim
Its not really clear what you try to achive, but keep in mind the network latency. You cannot assume that it the server will get the "ready" event from all players immediately, and thus there can be a reasonable time delay in between.SpliFF wrote:I need the following sequence:
1.) unsynced code sends "i'm ready" to sim
2.) when every player is ready sim sends "we're all ready"
3.) synced event occurs in following game frame
Now presumably this is something like how game start and pause work but the GameServer code is pretty intimidating and I was hoping somebody could boil down the process for me. In short, how do I create a new sync event and action and get all players to execute said action on the same frame from C++? Pseudocode would be appreciated.
Also basically what hoijui said, except that for cheat all files you need are Game.cpp and GameServer.cpp. Make Game forward the command, GameServer to wait for everyone and then send the ready event, parse it in GameServer. It might be even better to make GameServer broadcast individual ready events and let the clients track them, depending on the problem you try to solve.
Re: Dealing with "everyones ready" in the sim
The problem I'm trying to solve is this:
The first time a model is used it needs to be loaded. Spring doesn't do this on load, it does it on-demand (ie, the first time a unit is built, the first time a nuke is fired).
Currently this is done in the sim, which I assume means the sim stays on the current frame until every player has loaded the asset. If any player takes longer than a few milliseconds to load you presumably get a stutter in the game. Because it only happens the first time any player builds an instance of that unit it would presumably go unnoticed most of the time or passed off as general network lag.
I want to load assets in a seperate thread so the sim can get on with the game while your second core deals with the loading and postprocessing of the model. Whatever order tried to create the unit will be queued and deferred until all clients are ready to use it. This would translate into order lag rather than sim lag (ie, a building might take 1/2 a second to start the unit build but in the meantime units continue to fight.
Anyway, depending on how optimised you want your models, the assimp importer may take a while to complete. The time required will be hardware dependent obviously so all players loading the asset will finish on different frames. I want all clients to know when the slowest client finished loading so all clients (re)issue / begin the real-time build or fire order on the same frame (assuming the factory wasn't killed or the order cancelled in the meantime).
I apologise if Spring already does this. I'm still coming to grips with the code so I might be trying to solve a problem that doesn't exist. Regardless, I'd like to know how to do this as it will most likely come up again once I migrate the model loader and renderer to seperate threads. I know zerver has also been working on something like this but I'm unsure wether this particular issue has been solved.
The first time a model is used it needs to be loaded. Spring doesn't do this on load, it does it on-demand (ie, the first time a unit is built, the first time a nuke is fired).
Currently this is done in the sim, which I assume means the sim stays on the current frame until every player has loaded the asset. If any player takes longer than a few milliseconds to load you presumably get a stutter in the game. Because it only happens the first time any player builds an instance of that unit it would presumably go unnoticed most of the time or passed off as general network lag.
I want to load assets in a seperate thread so the sim can get on with the game while your second core deals with the loading and postprocessing of the model. Whatever order tried to create the unit will be queued and deferred until all clients are ready to use it. This would translate into order lag rather than sim lag (ie, a building might take 1/2 a second to start the unit build but in the meantime units continue to fight.
Anyway, depending on how optimised you want your models, the assimp importer may take a while to complete. The time required will be hardware dependent obviously so all players loading the asset will finish on different frames. I want all clients to know when the slowest client finished loading so all clients (re)issue / begin the real-time build or fire order on the same frame (assuming the factory wasn't killed or the order cancelled in the meantime).
I apologise if Spring already does this. I'm still coming to grips with the code so I might be trying to solve a problem that doesn't exist. Regardless, I'd like to know how to do this as it will most likely come up again once I migrate the model loader and renderer to seperate threads. I know zerver has also been working on something like this but I'm unsure wether this particular issue has been solved.
Re: Dealing with "everyones ready" in the sim
I think you are assuming there is something like "global time", or synchronization in the traditional (i.e. multi-threading) sense between different clients.
Nothing like that.
While one client is executing frame 1412, another client may already be executing frame 1415. This just means the first client has a slightly higher ping.
Same thing when loading models. For the other players of the game it doesn't matter if player X takes 2 sec to load a model. They will only observe it as a lag spike from that player, because during this 2 seconds he is not executing simulation code, but loading the asset. When the 2 seconds are finished, the network messages for new simulation frames are in the input buffer, and they are quickly executed to catch up, until the network buffer is empty.
When you want to delay asset loading, do NOT slave the synced simulation to unsynced things like assert loading. The asset loading should always be slaved to the simulation, so as to keep the simulation as simple and straightforward as possible (it's complex enough already.)
So, instead of having the unit being created in a deferred way, create the unit normally and just block the clients or, make some heuristic by which you can predict what assets will be needed soon. For example, it would be safe to trigger loading of the assets for building X in the background when you have queued the building, but the builder still needs to move to the build site. Or, you could ensure all construction options of all builders/factories currently alive are always preloaded.
Nothing like that.
While one client is executing frame 1412, another client may already be executing frame 1415. This just means the first client has a slightly higher ping.
Same thing when loading models. For the other players of the game it doesn't matter if player X takes 2 sec to load a model. They will only observe it as a lag spike from that player, because during this 2 seconds he is not executing simulation code, but loading the asset. When the 2 seconds are finished, the network messages for new simulation frames are in the input buffer, and they are quickly executed to catch up, until the network buffer is empty.
When you want to delay asset loading, do NOT slave the synced simulation to unsynced things like assert loading. The asset loading should always be slaved to the simulation, so as to keep the simulation as simple and straightforward as possible (it's complex enough already.)
So, instead of having the unit being created in a deferred way, create the unit normally and just block the clients or, make some heuristic by which you can predict what assets will be needed soon. For example, it would be safe to trigger loading of the assets for building X in the background when you have queued the building, but the builder still needs to move to the build site. Or, you could ensure all construction options of all builders/factories currently alive are always preloaded.
Re: Dealing with "everyones ready" in the sim
Ah, well.. In that case you're right. What you just described is much simpler than what I had in mind.
Re: Dealing with "everyones ready" in the sim
To explain the network design a bit better:
All network connections in Spring are order-preserving.
Every client just eats through the network stream it receives from the server at his own speed.
User commands are sent to the server immediately after they are given. The simulation does not get to see them yet.
The server receives these user commands, and broadcasts them in the order it received them to all clients. Since network connections preserve the order of everything that is sent over them, the commands will arrive in exactly the same order on all clients. 30 times per second the server also sends a NEWFRAME message. This instructs clients it should execute a simulation frame when it receives this.
So you see that, the server nor other clients really care about how much a client lags behind. The only impact this will have, is that commands given by the user of this client, while it has just rendered frame X (so the user thinks the state of the game is as it is in frame X), will only arrive at the server after the server already broadcasted a NEWFRAME message for frame X+D-1. So the command will effectively take effect only in frame X+D, resulting in a delay of D frames between the frame an order is given and the frame in which the simulation "knows about it". If this delay D gets too big, the game will obviously be unplayable, but technically it does not matter.
All network connections in Spring are order-preserving.
Every client just eats through the network stream it receives from the server at his own speed.
User commands are sent to the server immediately after they are given. The simulation does not get to see them yet.
The server receives these user commands, and broadcasts them in the order it received them to all clients. Since network connections preserve the order of everything that is sent over them, the commands will arrive in exactly the same order on all clients. 30 times per second the server also sends a NEWFRAME message. This instructs clients it should execute a simulation frame when it receives this.
So you see that, the server nor other clients really care about how much a client lags behind. The only impact this will have, is that commands given by the user of this client, while it has just rendered frame X (so the user thinks the state of the game is as it is in frame X), will only arrive at the server after the server already broadcasted a NEWFRAME message for frame X+D-1. So the command will effectively take effect only in frame X+D, resulting in a delay of D frames between the frame an order is given and the frame in which the simulation "knows about it". If this delay D gets too big, the game will obviously be unplayable, but technically it does not matter.