It's been awhile since I've written a dev journal and we've got some new faces around here, so I'll take the opportunity to introduce myself. I'm Cari Begle, and I'm Stardock's Senior Game Designer and the programming lead on Elemental. I've been working here at Stardock for 10 years.
Today I'm going to talk about Multiplayer. I'll start with a quick rundown of the features for the people who haven't tried the beta, and then get into some techie talk for those of you who like to peek under the hood.
Elemental is true client-server where we host the servers, rather than the host player's machine acting as the server (which is a modified version of peer to peer) or true peer to peer where all the clients are connected to each other. This means that shouldn't need to open ports, and if the host player drops, the server picks a new host and the game can continue.
There are two multiplayer modes: quick match and custom games. In quick matches, you choose either 1 v 1 or 1 v AI, pick your sovereign and faction, and you will be matched with another player on a randomly chosen map. In custom games, the host picks the world settings and how many players and then waits in a lobby for other players to join by clicking on the game entry in the available games list.
With 1.09, we're enabling multiplayer save games for custom and 1 v AI games. Only the host can save, and the game also auto saves periodically. The save games overwrite, so there is only ever one save per game, and if a host player quits or disconnects before the end of a game and the new host saves the game, the original host's save game is removed so that the new host is the only one with a save for that game. Save games are also automatically removed when the end game results are posted. Save games are saved to the cloud, so they can be loaded from any computer as long as you're logged in as the player who saved it.
In order to help you out at the beginning of a multiplayer game, you start with a spouse. Also, all the multiplayer maps have gold and fertile land placed around the starting locations of the players. If you let the game pick the map randomly, it will attempt to pick one that has enough starting location for all the players, but if you open up additional slots you may need to return to the world setup screen to pick a new map.
All battles are instant battles like in Civ5. We won't be enabling tactical battles in multiplayer until after they've been revamped.
To chat, hit the quote/single quote key. Currently, it only supports chat to all because I need a better dialog for it with tabs or something.
Multiplayer is interesting to code because you can't simply do something, you have to send a message and wait for the response so that all the clients stay in synch. This means that you can't code linearly, and you have to handle not receiving a response. It's much like programming a multi-threaded application, except slightly more complicated because you're sending and receiving data from other computers, not just other threads. It requires you to think a different way when writing your code, and unfortunately most schools don't really do a good job of teaching this, even the game development schools like Digipen and FullSail. At least the graduates from game dev schools generally have more practical programming experience than schools with a traditional computer science degrees.
Say you want to move a unit to a notable location. If you were only concerned with single player, you'd simply translate the coordinates of the right mouse click to world coordinates, set the destination so that the unit can calculate a path, and boom, it starts moving as soon as the path is calculated. In multiplayer, there are more concerns.
To start with, every object in the game that is not purely cosmetic has to have the same ID as the corresponding object on the server and other clients so that it can be identified. This allows us to send events which can originate either on a client or the server with the data needed to perform the desired action, and an identifier in the event to indicate what the action is. When the event is received by the server, it processes it and either marks the event as failed or succeeded and in most cases forwards it to the clients to be processed. In some cases, like when the player requests a new turn, we just want to notify the server and not forward the message to the other clients. Then when all the players have requested a new turn, the server sends out an event notifying the clients. When the server or clients receive an event, they use the data stored in the event to access the objects that sent the event and perform the action that was requested.
For example, if Unit A attacks Unit B, I create an Attack event and store Unit A's ID as the attacker and Unit B's ID as the defender. The event is converted to a block of bytes and sent out to the server. The server restores the event from the block of bytes and gets pointers to Unit A and Unit B. If unit B isn't already dead from a previous attack, the server performs the attack and stores the results in the event, which it forwards to the clients. The clients receive the event, get pointers to A and B, and process the battle results (brings up the results screen, levelupwnd, etc). Now, since turns are simultaneous, it's possible that Unit C may have also tried to attack Unit B but was a little slower and so its event arrives on the server second. If Unit B is already killed, the server simply marks the event as failed and forwards it on to the clients so that they can handle the failure. Otherwise, the event is processed normally.
Well, I've stayed up working on this journal later than I intended, so I'm going to call it a night.