The multiplayer code in Imperium has seen a lot of work this summer. It’s shaping up quite well and it’s soon in a state where it can be tested live. Setting up games works fine via a server hosted by https://www.digitalocean.com/. Latencies seem to be ok but I still need to do some measuring to make sure there are no issues. The lobby works ok and it’s possible to set up games that others can join.
The video below shows how to set up an online game from scratch as well as how to edit armies.
The multiplayer code in Imperium has seen a bit of activity lately. A new server has been written to work as the backend server and the old PubNub backend was ditched. Before that I used Photon, but it was a real cluster mess when used from Objective-C, it was quite clear that they did not care one bit about keeping that API up to date. So, an own simple server it was. That server is open source and can be downloaded from GitHub. I will host the backend where Imperium connects to on Digital Ocean.
The main change to the multiplayer code is that previously multiplayer battles were predefined scenarios with a fixed map and fixed units. That meant that there was not too much variation between battles. The new thing is that the player can define own armies which are used in multiplayer battles. These armies are a bit like decks in Clash Royale and similar games. There can be three different armies defined and they can contain any kind of units. When the player starts a multiplayer battle he/she first selects the army to be used and then proceeds to either host a game or join an existing game.
The army selection screen looks like this:
Army selection screen
Select the current army from the buttons on the left, view the contents of the selected army on the right and then tap Play to continue with the multiplayer setup.
Pressing Edit takes the player to the army editing screen where the contents of the selected army can be changed.
Army editor screen
When creating an army there are two limitations:
the army can contain a maximum of 20 units
the total cost of the army can be max 1000 credits.
The three buttons on the left select what troop types should be shown on the right side field. The Standard troops (shown above) are normal infantry and cavalry troops. The Artillery troops contains all artillery units and the Support troops are various smaller support teams such as machine guns, mortars, snipers and flamethrowers.
All units have a cost associated with them. An army can cost 1000 credits. The cost of each unit is shown after the unit name.
All units are available as individual units as well as larger formations. The larger formations all come with a headquarter unit and various other units. The larger formations give price discounts as well as a headquarter as a bonus unit. The contents of each larger formation is shown below the formation name.
Imperium will use a dedicated server for handling online games. An online game is always between two human players that currently have online access. The server is written in Python and is very minimal. The server handles both TCP and UDP:
TCP is used for all setup for the games, such as lobby handling, announcing games, player data etc.
UDP is used for all updates once the game has started.
The server know about announced games and connected player and handles the starting of games when a player has joined an announced game. Basically everything that relates to handling a lobby. Anything to do with the real Imperium data or logic is unknown to it. When the games start the server becomes a simple data relay that just forwards packets to the other player. The only exception here is a ping packet which the server answers.
Imperium will have a really simple “lobby” where available games are shown and you can choose to host a game of your own. There will be no filtering, ranking or similar, all open games are available to all players. Initially when players connect to the lobby they enter a name that will be shown to other players. No filtering or sanity checks are done (yet) on these names. Time will tell if that needs to be done.
Once a name has been entered Imperium will connect to the server and show the lobby. The lobby lists games that other players host that currently await an opponent as well as the scenarios that the local player can choose to host. To join a game in the lobby simply tap on it and it will start. To host an own game just select a scenario from the list and tap Host on the next screen. Imperium will now show a waiting screen while it waits for some other player to connect to the game. Once a player connects the game starts. As soon as both players have loaded the scenario in question the server starts the game.
Game engine architecture
It’s quite hard to get a good architecture for doing realtime games. As time is a factor when resolving action it all depends on where the action is resolved so that it’s fait to both players. There are a few possibilities:
the server resolves all action and the players just display the results and handle input. This is fait to both players, but requires a server with full knowledge of the game logic, basically a client without any graphics. Imperium’s server is very dumb and doesn’t know anything about the game other than sending some data back and forth.
one player does all the calculations. This is unfair to the second player who will always have a lagging connection to the server. The local player will be able to perform actions and see results a bit faster, thus getting an unfair edge.
both players calculate all action. This would be fair to both players, but would be a bit complex when it comes to keeping it all in sync.
both players handle the calculations of the local player’s units.
The last of the options has been chosen for Imperium. Each client will handle the calculations for all the local player’s units. This is fair to both players as both handle their own units without any lag. There will be a fair deal of synchronization going on as both clients will send all changed missions to the other as well as updates for moving units. This method will make it possible that a client acts on old data, for example firing on a unit that technically has moved out of range. But as the action is very slow paced and it doesn’t really matter much if some limit will be exceeded a bit, this shouldn’t really be a problem.
All the updates for units that move or change state somehow will be sent as UDP packets to minimize lag. Periodically extra data with all missions etc will be sent so that both clients can keep their state in sync.
Some real like issues have more or less prevented me from doing much on Imperium since the last update. I won’t have much time over this fall, but there has been some progress though and I’ll try my best to push out a new test version soon.
The AI has seen a bit of an overhaul and now the foundations are looking very good. The rules that actually make the computer units do things will still need a lot of work, but everything needed to make those decisions is ready. The efficiency of the AI code is also improved and the AI calculations are now spread out more in order to avoid hiccups in the game when the AI is executed.
There is now a new weapon type: howitzers. These are guns that can be used to do direct fire just like the other cannons but they can also be used to provide indirect fire just like the mortars. Their range is longer than that of the mortars, so howitzer units can be used to provide efficient fire support and attack units they can not see themselves.
Headquarters automatically rally units that have routed that are within their command control radius. Now the headquarters can also be given an explicit rally mission that has the headquarter focus on a particular own unit and makes it rally much faster.
The networking component will be PubNub. Originally Photon was to be used, but their Objective-C API is a real mess and very hard to use. It’s basically just a very low level set of calls without any documentation whatsoever apart from a badly designed example application. I wasted a lot of time with Photon in the past and during the summer while trying to get the new version to work. PubNub is much cleaner and the API is magnitudes easier to use. It has not yet proved itself to actually work in a realtime game context though, so we’ll see how it goes. The idea now is to see if the multiplayer could be added to version 1.0 after all.
The multiplayer code for Imperium has progressed a bit since the last update. It is now possible to more or less completely set up multiplayer games on two iPads. There is a surprising amount of things to get right when two devices are talking to each other, but it seems to be working now. The player that hosts the game will select a size for the battle and after that the Bonjour service is set up and the game is announced on the local wifi. At this point the other player can connect to the hosted game and both player will be presented with this screen where they can purchase their units:
The first organization in the unit list are regiments that contain a headquarter and some subordinate units. Buying organizations is cheaper than buying individual companies or artillery batteries. Once the player is satisfied with the purchased units it’s time to deploy the units on the map. This is also done simultaneously by both players. Initially the units are simply laid out on the map in nice rows, like this:
The player can now select units, tap on a location and move the unit to the location or make it face the tapped location. The red line indicates how far to the east the units can be deployed. The other player has a similar line which indicates how far to the west his/her units can be deployed.
What is still missing here is a button to complete the deployment and start the real game. At that point both players need to synchronize so that both start at the same time, which means that one of the players needs to wait for the other to complete purchasing and deploying his/her units.
After some thinking during the weekend I decided to redo the multiplayer code for Imperium a little bit. The previous code worked ok but it would have been a lot of work to design scenarios for that as it relied on predeployed troops on maps. I would have had to design a range of maps and select suitable troops for them as well as come up with a deployment. I already do that for all the single player campaign maps, but for multiplayer there should probably have been 20 maps or so, and that is a lot of work.
The new design relies on predesigned empty maps and the player selected and deploys the wanted forces. This means that I don’t need to worry too much about balancing as the players can buy any kind of troop setup they want. During setup one of the player decides on how large the battle should be and based on that a random map is selected and credits are given. A smaller battle gives a smaller map and less credits etc. I still need to create a set of empty maps, but that is a far smaller task than creating fully populated and balanced scenarios. As a small bonus I can also mirror the maps in both x and y directions, thus giving the players a bit more the play on. Could also rotate them 90 degrees, thus more or less creating totally new maps.
When the players select their forces they get given a number of credits and with those they can buy various formations. There are larger formations like regiments that contain a headquarter and a number of subordinate units as well as individual units. Larger formations are cheaper to buy compared to individual units. The force selection screen is shown below:
Of course I still need to add code for the actual deployment phase where the players position their troops on the map. I’ll do something simple and allow the players to put the units any way they want as long as they keep inside a deployment area.