The cheaters also found a small loophole in the hashing, because only specific fields are hashed and not entire objects, one important field was missed that gave cheaters an unfair advantage of seeing the current targets of their opponents' units. It is easy enough to fix when you know about it, fortunately.
You would choose a player to be considered to have the master copy by who is least likely to be cheating. In the case of a tie in votes, the player with the master copy could be chosen with a deterministic random number generator instead.
Still, desync errors are pretty common in early versions of RTS, I remember pulling my hair out while playing Starcraft and getting desynced non-stop. Or maybe it was the cheaters!
Robustness is no incentive either, since people will put up with a lot of bugs from games.
One thing it does make me wonder about is the difference between pure code and code with side-effects. Knowing large regions of your state-transformation code is pure would go a long way towards limiting the possible scope of these desync bugs. The fact that many of them are uninitialized variables and padding is interesting as well and makes me wonder what the language could do to prevent these sorts of problems.
Everyone had to exchange their inputs in one frame and then evaluate them in the next, so you were always a frame behind (1/24 of a second or so, or maybe 1/12). All math was fixed point which made it a bit easier. There was no resync; the game would just end if the checksums didn't line up, so lots of bugs were discovered this way :)
Lots of time was spent figuring out how to handle start-of-game, since either player could initiate and we had to agree on a common screen size since it affected game play.
Kudos to you :)
Somebody needs to turn on compiler warnings!
We're using the parallel simulation technique in Widelands. Only using integer arithmetic, compiling with -Wall and running Valgrind occasionally has kept us very safe. The only recent cases of desync I can remember is when either (a) somebody added a new feature and messed up the network protocol (which is usually very obvious because the desync happens just after the new feature is invoked) and (b) somebody new to the code uses a std::set<Foo*> to iterate over a collection of objects. Basing simulation decisions on pointer values is a bad idea.
Talking about the entire game in the browser, it clearly depends on how far you're willing to compromise in the feature set. Path-finding will likely be the most painful part for a purely human-vs-human game, and opponent AI will probably add some headaches as well.
The hash value sent between player also hints the mechanism for drop hack. My guess it that the hacker would pretend to be the victim and send a bad hash values to every other players. The hash check would fail and the victim would just end up disconnected from the game. Haven't heard of such hack in SC2, wonder how they fixed it.