Spiritual remake of the classic transport tycoon games. Build a profitable transport network and grow your worlds economy, either on your own in singleplayer or in multiplayer whether cooperatively or competitively.
So it's been quite a long time since I did an update on Steam, and internally our corporate side has been begging me to provide an update for you folks. So here it is!
[img]https://i.imgur.com/zL8hY2A.gif[/img]
[h3][i]Note: First two headings are general commentary, skip those if you just want game info[/i][/h3]
[h1]Background[/h1]
[quote][h3]If you just want to keep up-to-date, our internal processes automatically post "commit messages" [url=https://discord.com/channels/704545499415314532/705332160298745856]to our discord[/url]. This means that you can see changes [i]live [/i] as I make them to the game. I put pretty detailed commit messages so you can get a sense of the changes I am making and often some degree of why.[/h3][/quote]
[h2]It's been a while[/h2]
Firstly, apologies for not posting updates here sooner. This project started as a COVID lockdown project for me (Dean), so it's been a core passion for me. Unfortunately COVID also bought with it some pretty crippling social anxiety. I'm in this weird place where the reason I make games is to see people playing them, but I began to dread the bad possibilities from some of their reactions - the very reason I made games in the first place. Hard to explain, but hopefully that gives some rationality.
Additionally I'm not really very happy with where Steam is as a platform for my kind of games. When I made DayZ, I would stay up 18 hours developing, push updates, and then fix bugs. In terms of community and developers we were pretty much one unit. The lines between the two barely existed. It was chaotic, but it was an amazingly creative environment and pretty much the whole reason I make games. While Steam has made efforts to try and help with this process, I'd say its just not a good environment for the early creative stages of a project.
[h2]Steam release options like Steam Beta[/h2]
[img]https://i.imgur.com/qUKs7Cc.gif[/img]
I won't release on Steam, even in early access, until I'm really sure of the data structure and the core loop of the game. The priority at the moment is finding the core group of players who really want this kind of game and [i]are prepared to pay for it[/i]. I had discussed with Valve using their new Steam Beta program, which allows users to register interest in a game and allocates keys randomly to them. It's a cool idea. But the problem is you end up getting feedback from people who otherwise wouldn't have actually bought your game.
This can mean someone ends up trying your game and then proposing the game should be something completely different. You end up having to heavily manage expectations about your game and only attract the people who want [i]that[/i] experience. For similar reasons, I would suggest that Steam Reviews are largely a measure of expectations being met rather than a true guide of quality.
Art of the Rail will come out on Steam when it is ready, and it is totally worthwhile Wishlisting and Following our progress, but more regular updates and early playtesting are more likely over on our [url=https://discord.com/channels/704545499415314532/705332160298745856]Discord[/url].
[h1]Game Development Progress[/h1]
[img]{STEAM_CLAN_IMAGE}/38883601/4452c88884cce72fda8350b60b39266b05fcd26a.gif[/img]
While I might not have been posting here on Steam, I've been pretty steadily working on the game. One of the key things I want to do before any wide distribution of keys is to get the data structure really locked down. I mod a lot of games and with many of those games the developers had to make major changes to their data structures which caused major work for a lot of modders and customers. Being a very niche game, this game will live through mods. This means my main role is to get the right data structure so that it can survive through the game's life to support mods as best as it can. Additionally, I wanted to make sure stability was rock solid.
[h2]The rise of RocketNet[/h2]
AotR (Art of the Rail) is focused on providing [i]scale[/i], which I feel is neglected by many games today, and is a core part of tycoon games of the past. So the key focus has been to meet that scale on all sides. Our special R&D team (called "Enterprise" internally) took my proof-of-concept for a highly optimized networking approach and made a new system called RocketNet. This stuck to a "first principles" approach. Everything on the internet is sent via an "array" (think: collection) of bytes (well, technically speaking it would actually end up as bits but that's not strictly relevant here). So instead of "wrapping up" game data as "messages" (think of them like emails), we write those bytes directly into a collection, zip up the collection, cut that collection up into segments (1200B), and send those.
[img]{STEAM_CLAN_IMAGE}/38883601/5b1259cbdb5b82ea44c3c4dae9b73974a4eadec2.png[/img]
The results of this, when implemented in our other game [url=https://store.steampowered.com/app/544550/Stationeers/]Stationeers[/url], were staggering. It removed a lot of the convenience of using network messages, and required a much higher level of programmer understanding, but the scale achieved was two or even three orders of magnitude better.
So a huge focus for AotR has been improving the multiplayer stability over the last year, working with our Enterprise team to refine this technology. Most of this technology is written in C++ and "injected" into the C# used by the project. The Enterprise team has even been working on this injection process, called the "interop layer" - looking at how to make this more and more efficient.
So what does all this mean? It means that AotR is looking to support very high numbers of players, and the limitations around player numbers should then more be a question of general bandwidth. Hosting an AotR dedicated server with a 1GB connection, should be able to service a [i]lot[/i] of players.
[h2]Graphics & Game Optimization[/h2]
With multiplayer optimization going well, the next bottleneck was the game itself. I ripped out the old "fenced" threading system and replaced it with pooled threads, taking the broad approach of Unity's ECS but rolling my own. This was because Unity requires you to make your memory safe, which often defeated the goal of wanting a much better framerate.
Initially I had these fenced threads running fully concurrently with the rest of the game. But this made the project extremely complex and the smallest mistake on my part caused huge problems. This meant that the vehicle thread would be moving vehicles while the rest of the game was trying to do things. What I ended up doing was having multiple instances of vehicle threads, but getting them to work on the [i]next[/i] frame's data, and then forcing the game to wait if they weren't finished before starting the next frame. This gave the benefit of concurrent activity, scaling with the quantity of cores on your system, while keeping the data certainty of having a single thread state for the game itself like most games. The end result was excellent, so much so I was able to group a lot of things together as well as provide much more stability.
[h2]Customizable Corporate Liveries[/h2]
Initially the game was targeted at eight players max in a session and using a texture array per vehicle to manage the color schemes. This meant that each vehicle or building that wanted to display company colors had to have these eight different textures. As the number of vehicles and buildings increased, so did the number of textures. Additionally, during game start the game captures pictures of these buildings and vehicles - often in different cargo states - so that it can draw them efficiently later. This increases loading times dramatically as well as memory usage.
So this was replaced with a masking shader system. Instead of different textures for different company colors, there is a base texture colored white with a mask texture that shows where a primary, secondary, and stripe color would be applied. This is then used in a composite nature when rendering either the vehicle in the scene or the UI textures for buttons and windows. This meant two things, eight textures became two textures, and instead of being limited to eight company colors, we effectively get unlimited company colors with many variations of primary, primary and secondary, primary and secondary and stripes, primary and stripes, and so on.
[h2]Batch Rendering & Virtual Objects[/h2]
[img]{STEAM_CLAN_IMAGE}/38883601/122b0eccd8102f5338a7949d9e0338a519f9b21e.png[/img]
With the success of the existing method of rendering things in "batches" I expanded this significantly. Batching involves sending the mesh to the GPU once, and then sending it all the "transforms" of how you want it drawn, being the position, rotation, and scale. This is efficient but especially so with how AotR draws objects. Traditionally, you might send a mesh for a building to the graphics API, saying "please draw this here". Most game engines will try to be smart and batch stuff together, but it doesn't always scale well in a dynamic environment. So AotR is very deliberate about this. Most objects are actually a "constellation" of a group of "visualizers". That is, broken into small meshes which can be used across many different objects and then batched together. Cities Skylines follows a similar approach. AotR even goes further and in many instances does not have Unity (the game engine) objects at all, having them as pure C# data constructs and handing them directly to the graphics API for rendering.
There still needs to be some improvement here as in my many thousand vehicle test the game runs at 90 FPS except in certain views when a lot is on the screen. There are still many easy wins for consolidating the batch processes together. However, it still took me months of playing the game to get a save game big enough to get the FPS to drop from 90 to the occasional 45 in a certain view.
[h2]City Development[/h2]
[img]{STEAM_CLAN_IMAGE}/38883601/a83c4e2c2134e495d57010213d4682911aaa661c.png[/img]
Cities have been a highly requested feature internally. It's something I have been chipping away at alongside other improvements. This pushed my batch rendering system even further. Now chunks themselves are able to batch render things, such as straight pieces of track or city roads. I've also created the simple method for the roads themselves to expand and Petr, our amazing artist, has made a massive amount of content to allow the cities to grow. The cities will also be able to make use of the corporate liveries shader, as it will allow the buildings to have slightly different colors but be rendered in the same batch. Given the need for scale, this is incredibly important for performance reasons.
[h2]Industry Cargo System[/h2]
I redid the industry cargo system to be completely modular and entirely data driven. This fits with the development philosophy as having as much as possible driven by game data, and having that "core" game data loaded just like a mod would. This means, essentially, anything done data wise in the game is open to modders. Production for industries is data driven via rules, and this has opened up expandable industries based on rules, as well as bonuses based on rules. Providing a lumber mill with petrochemicals increases its efficiency temporarily, but having delivery of produced goods at above 90% on a rolling six month average would cause that industry to expand its production.
[h2]Terrain fixes[/h2]
Originally it wasn't intended that you could modify the terrain under a track. But I never actually wrote logic to stop that happening and it became surprisingly satisfying to modify and improve the terrain underneath the track. However, the logic for terrain and track generation never intended this to be supported. There was a lot of weirdness caused because terrain meshes were not being regenerated immediately upon change, as their performance wasn't great. It took roughly 50ms after a change for the terrain mesh to regenerate itself. Some of the data in this is necessary for the splines (tracks and roads) to be generated properly, specifically the terrain "normal" (direction a terrain point on the map is facing, if it is flat it would be straight up). So the spline mesh generation would then be delayed until after the terrain mesh regenerated.
This became really complex, convoluted, buggy, and messy. Lots of edge cases and possibility of race conditions. I completely removed the terrain generation system and made a new one. This new one was so performant that terrain mesh could be done on demand when needed. This means that when a mesh is required to give data for a spline, the game can regenerate the mesh immediately and then do the spline. It doesn't do this by default, allowing itself a little time to generate a mesh if it's not needed immediately. This solved a lot of problems and also made the code much simpler - which means much easier to maintain.
[h2]Load Balancing bays using custom tags[/h2]
[img]{STEAM_CLAN_IMAGE}/38883601/d51fce82a1094fb84e0ecc2a493468f8917942c8.png[/img]
Similar to tags in games like Factorio, you can tag vehicles and bays and then use those to do your own load balancing. This is in addition to the regular tools such as setting a bay to a particular cargo type.
[h2]Terrain Tool Improvements[/h2]
[img]https://i.imgur.com/YxquH0B.gif[/img]
[img]{STEAM_CLAN_IMAGE}/38883601/33644ac2bcb06ca0253a2a344ca5b10398469ec7.png[/img]
With the above fixes I was able to improve some of the terrain tools. The most popular tool internally has been the ramp tool. Placement in general was improved with keys to lock the cursor to cardinal directions as well as a height lock key.