I have an RTS game, with deterministic simulation, but if I want multiplayer to actually work, I need commands sent between computers to be executed at the exact same time. My game's networking is just sending commands between the players' computers, and the simulator executes the commands in order, which, hopefully, will result in each player seeing the exact same game. However, if the commands aren't executed at the EXACT same time, then the simulation will become out of step and everything will be wrong. How could I do this, and are there other ways to make sure everything is in sync?
There are two possible approaches to what you are describing, one wrong and the other useful.
The wrong approach is to simply delay the user input from activating the command. Assuming you know the other clients can be informed 99.9% of the time in half a second, delay the command for half a second and send it to the other clients as the pair
<command, activationTime>so the other clients could all preform the command synchronously. Obviously, you have to sync the clocks when the processes start which is a question on it's own.
The correct approach would be to perform the command slightly later on other clients but have them behave programmatically as if the command occurred at an earlier time. i.e you time-step back some milliseconds into the past, preform the command and then re-evaluate the simulation from that point, preforming any other later command as necessary until the current time. This could lead to jittering (sudden changes in position). You can smooth these out by interpolating the animation between the true state and the subjective state on the client. i.e starting from
t * trueState + (1 - t) * subjectiveStateand increasing
tby easing out and easing in.
Alternatively, you could abandon this approach completely and use one of the clietns as a Server and the others as "dumb terminals" that only accept input and display the current state of the game; this way instead of sending orders, you constantly send updates on the new positions of units, evaluating a few steps into the future for slower connections and a more accurate present state for faster (LAN) or low latency connections.
Doing the third approach is easier, there is only one simulation. Synchronizing two simulations would be very hard, to the point of impossible. It is an interesting academic experiment and perhaps could yield useful lessons but does not seem likely unless the gameplay is very insensitve to slight variations in timing which most real time games simply aren't.
This is an example of the graph for easing out and easing in when interpolating / tweening states: