I like writing about bugs in Airships. I don't want to present myself as some infallible rock-star Indie developer, because I'm anything but. Airships is a game for builders and tinkerers, and I have seen again and again that you like reading about its creation, warts and all. So today we delve into The Mystery of HMS Longcat. (Note that there's a slightly nicer-formatted version of this post that includes animations here.) I was alerted to a weird bug by several users: their very largest airships would fail to reload their cannons. The first salvo would fire just fine, but new ammunition would never arrive, despite plenty of crew and ammo stores. One user helpfully supplied me with a ship design where this was happening. As an aside, this is basically the perfect setup for me to quickly diagnose and fix a problem:
- Tell me what you expect to happen: the cannon should be reloaded.
- Tell me what actually happens: the cannon does not get reloaded.
- Give me a simple and reliable way to see the problem for myself: a ship design where this reliably happens every time.
And indeed, after the initial salvo, crew members started walking to get ammo, only to stop and return to their posts, over and over again. Once a problem can be reproduced reliably, the next step is to try and reproduce it in as simple a way as possible. The Pale Mare 2 was a huge ship. It would be hard to pick out the exact problem from all the activity going on in the ship. The working hypothesis was that this problem only happened in very long ships, so I constructed the HMS Longcat:
This ridiculous design was much simpler but still as long as the Pale Mare 2. If the problem appeared here too, it was likely that length was the actual culprit. If it did not happen, perhaps it was related to the overall size of the ship instead. And indeed, it happened again. Next, I rebuilt the HMS Longcat into the HMS Shortcat, a ship with essentially the same modules, but more compact.
And behold, the problem went away! Crew started fetching ammunition perfectly reliably. There was one last thing to test before I started digging into the code: was the problem related to the overall length of the ship, or to the length of the part of the ship actually accessible to the crew? Given that the problem could be related to pathing, maybe the pathing failed if the crew-accessible area was too big? This resulted in the HMS Shortcat with a Tail:
And the problem was back! Simply attaching a long line of struts to a ship caused the bug to reappear. It was time to put in some logging. I started logging cases where a crewman abandoned a task for any reason, to see if I could catch them abandoning the ammo-fetching. And indeed, the log rapidly filled up with messages that crew kept on abandoning ammo jobs. I improved the logging to indicate the reason why a task was abandoned, and it told me that the ammo fetching got abandoned because there was another, much more important task to be done. So I homed in on that case and added logging to indicate the nature of these more important tasks, and the relative priority values of the old task and its replacement. Now these priority values are meant to be roughly between 0 and 1. A task with priority 1.0 is super-important and must be done immediately, while one with a priority less that 0.1 is something an air sailor can do if there's nothing else to do. Which is why I knew things had gone a little wrong when I got the following log message:
AmmoJob (priority -0.81) replaced by ReadyJob (priority 0.0000003).
Negative priorities were... not meant to be a thing. So the crewman was sent out to fetch ammo, but the next time the ship re-evaluated crew assignments, it would see that there was a much more important job for him to do: stand around at the ready in case something needed doing.
The ship would then promptly re-assign the ammo job to the crewman, and the cycle would start anew.
Next stop: the code for calculating the AmmoJob's priority, where I discovered the culprit, a single-letter typo:
return staffJobPriority(ship, self, type, x);
The staffJobPriority function calculates the appropriate priority for a normal job, such as fetching ammo. It's meant to be given the following information:
- ship, the ship the job is in
- self, the module it's for
- type, the module's type
- n, the number of the job
0.7 - n * 0.01;
So the first AmmoJob is meant to have a priority of 0.69, the second 0.68, and so on.
But the code passed in x instead of n. Which meant that the further to the right of the ship a weapon was, the less important was its AmmoJob. And on very long ships like the Pale Mare 2, where x was greater than 70, the resulting priority became negative.
And indeed, upon fixing that line to read
return staffJobPriority(ship, self, type, n);
everything started working just fine!
What's more, I found the same typo in the priority calculation for supplying coal to modules. It had lain there undetected simply because coal-using modules tend to be at the back of the ship, where the x-values are low enough to keep the priorities positive.
In the end, a very unlikely-sounding problem was all due to some bad cross-wiring of values. Careful investigation yielded results, and the problem will be gone in the next update.Airships: Conquer the Skies
David Stark
David Stark
2018-08-16
Action Indie Strategy Singleplayer Multiplayer
Game News Posts 306
🎹🖱️Keyboard + Mouse
Overwhelmingly Positive
(5250 reviews)
http://www.zarkonnen.com/airships/
https://store.steampowered.com/app/342560 
The Game includes VR Support
Airships Linux 53 [139.2 M]Airships Linux 64 [545.79 M]
Airships: Conquer the Skies - Soundtrack
Airships: Heroes and Villains
In the game, ships are viewed side-on, and their modules are operated by individual crew members. During combat, players give high-level commands to a small fleet, positioning their ships, ramming and boarding others. Ships and terrain are fully destructible: they can catch fire, explode, break apart, and fall. Players can also compete against one another in Internet and LAN matches.
The ships are highly detailed, teeming with sailors moving around at their individual tasks, like an ant farm or a cut-away drawing. The player's choices in ship layout are crucial, and an important part of the game is exploring the design space of different airships and their matching tactics.
- OS: Ubuntu/Debian/Mint
- Processor: 1.8 Ghz+Memory: 256 MB RAM
- Memory: 256 MB RAM
- Graphics: 1 GB VRAM+
- Storage: 1 GB available spaceAdditional Notes: Not currently compatible with Intel HD graphics controllers. May run on other Linux distros. but no guarantees.
- OS: Ubuntu/Debian/Mint
- Processor: 2.2Ghz+ Dual-coreMemory: 2 GB RAM
- Memory: 2 GB RAM
- Graphics: 2 GB VRAM+Network: Broadband Internet connection
- Storage: 1 GB available spaceAdditional Notes: Not currently compatible with Intel HD graphics controllers. May run on other Linux distros. but no guarantees.
[ 5166 ]
[ 1903 ]