Raster layers After successfully implementing loading and rendering of a new vector layer in MLT format inside a PMTiles container, it was time to do the same with the raster layers. The idea was to analyze the 4 raster layers bundled with the game (land, relief, population and buildup), decide to use a newer of different dataset (or not), and use some existing industry tool to convert the dataset…
New train motion integration loop Simulation games use the concept of “time slice” to advance the time of a simulation. At the start of processing a new simulation frame, a clock is simulated which advances a certain amount of time, and the various simulation systems also change the state of the simulation based on the elapsed time for the given frame, starting from the current state…
Final design for script data extensions in UI Last month I arrived to the realization that scripts alone, without player accessible and editable data, were a bad idea, and started work on making script configuration data a first class system of the game UI. This is the motivation of struct extensions. As a reminder, this is how they look like in the script side: struct SignalPrio extend Signal {…
Script input data should be flexible As mentioned in the last devblog, solving the script binding problem is the first focus of 1.18. To solve this problem a design on how “glue” game objects to scripts must be developed. This is a very important, core design decision of the system, maybe even more important than the scripting language itself. If the access to script data is slow…
1.17 Dynamic train braking Trains are now capable of braking for the simulation-dynamic obstacles of (potential) red signals and other train tails. This has been implemented as a generic capability of placing a dynamic “speed bump waypoint” on the existing train path, rather than more specific coding for these conditions, so other “obstacles” could be added in the future.…
NimbyScript progress NimbyScript development continued in June. I started work in one big item, memory ownership, because it is closely related to the already implemented borrow checker, but it was giving me a lot of trouble, so I decided to first tackle some other smaller features which were much required anyway. Formalize a standalone compiler build (as standalone as possible) to run the test…
WARNING! This post is very technical, much more than usual. It is of little interest for virtually all players. NimbyScript, once it is introduced in the game, will receive a proper guide and examples. This post is NOT the NimbyScript guide and examples. Faster game DB with better memory usage The past couple months have been focused on NimbyScript, but some other developments, related to it, have…
Stacked stop logic rationalization (1.16) DISCLAIMER: this section is an exercise in game rules lawyering maybe 1% of the player base cares about. The TL:DR is that 1.16 will do a smarter but different thing when two train stops are the same in a row, for some new definition of “same”. With the rewrite and separation of the train driving code and scheduling code in 1.16, I needed to…
1.16 is dynamic schedules (actually dynamic train dispatching, but more on that later) The goal of 1.16 is to implement dynamic schedules, and see how it goes from there. What exactly that means, and what is already implemented in 1.16, will be explained in this post, but it’s by no means the end of it, since some very interesting possibilities have now opened up. But first, “dynamic…
Major track editor internals rewrite and predictive editing Implementing predictive editing for the track editor turned out to be a massive undertaking. Most of November was spent in this task. And it started by realizing that the track editor internals, which have code dating back to 5 years, were in no state to accomplish the goal of predictive editing. So the first task was to basically throw…
Completely redesigned multiplayer internals Even thought multiplayer has been a feature since 1.1, released almost four years ago, it has never fully worked properly. Part of the initial problem was wanting to make the simulation properly networked. This proved to be impossible because the simulation code was never written to be deterministic (for example, it is very tricky to make train motion…
Schedules After trying and testing some design ideas in July, a new scheduling system was implemented in August. To recap, the design ideas that pass the filter of soundness and compatibility were: Schedules as a top level object, on par with lines or trains, rather than being a configuration detail of trains. An explicit shift system, rather than the very limited “auto copy” system of…
Where next? The first half of July was devoted to deciding “where next?”, advancing a little on the design a variety of options, both for roadmap and non-roadmap objectives. One of the ways I work is by collecting thoughts and ideas under some heading, like “signals” or “orders”, which at some point are tidied up, elaborated further into its own project, then…
Asset listing map overlay 1.13 was released in the Steam beta branch early in the month. The new walk leg and station hall systems were bugfixed and further developed while in beta. One unannounced feature which made it to the 1.13 beta was a map overlay for station and train asset listings: These blobs are circles whose area is proportional to the listing max value. You can change the colors,…
End of 1.12 beta The first half of May was dedicated to 1.12 beta development. Overall the 1.12 launch went quite smooth and it only triggered real problems on extreme saves, like saves with 5k+ stations and/or which had 10k+ activated tiles. In response to this, and to other overall problems with the 1.12 design some changes were made during the beta. 1.12 increased the station catch radius to…
Distance curve as interpolated points The original plan and implementation for the distance factor of the pax curve was to use some smooth function, like the Gaussian function. This was implemented back in March and it worked well, but it felt too limiting. There’s plenty of interesting shapes which don’t really fit a single function, much less if also wanting to do more than one…
Overlapping station areas As hinted in the last post, the new pax demand system was being developed with support for overlapping station areas from the start. I’ve decided to go this route. The Voronoi shapes puzzle is no more, and now station areas fuse with each other: This fits perfectly well the with 1.12 pax spawn system, which is now based on map points rather than on stations. Pax…
End of 1.11 development The first half of February saw some QoL development in the 1.11 beta branch, in addition to the usual bugfixes. A player favorite: it is now possible to change the start of day for the accounting time. But the main goal for February was to start the implementation of some new pax generation ideas I have been collecting over the years. At the start of the month I…
More pax pathfinder features In addition to the new board and disembark options developed in December, I also tackled two additional major changes to the pax pathfinder prior to the 1.11 beta release. Pax pathfinding can now consider a pax staying inside a train for more than 2 train runs. This limit has been in the game since 1.5 and it is now finally removed. The pax pathfinder can now plan a…
Accounting code rewrite Work continued in the core game code to make it faster and more parallel. One of the remaining big non-parallel offenders was accounting. Accounting just takes a ridiculous amount of CPU compared to other game systems, and to make it worse, it required multiple non-parallel steps to properly aggregate all the data streams produced in the parallel sections. It was feeling…
Stop and continue After 1.10 was finalized in October, I analyzed what remains to do in the roadmap, plus what are the outstanding issues in the game, in order to decide what to do in 1.11. What is clear is that the remaining roadmap items will have an outsized impact in game performance. It cannot be assumed that, for example, the game will suddenly allow pax to pick routes based on multiple…
Enabling Direct3D12 and Vulkan renderers With 1.10 a major cleanup of the rendering code came about, specially around texturing and shaders. I was then able to diagnose what was preventing the game from using the existing BGFX Direct3D12 and Vulkan renderers. For Vulkan, I discovered the game was running out of shader uniform space, due to the fact the Vulkan renderer using the default Vulkan…
Adventures in map processing As I explained last month, this time I wanted to rebuild the map on modest hardware, just an i3-12100 with 32GB RAM. The strategy was mainly about avoiding large memory allocations so it fits in the limited RAM, with every OSM shape already pre-sorted into buckets corresponding to the game highest level of detail tile. It was looking doable, but in the end the limiting…
More optimized drawing Last month, as preparation for the new map, I started optimizing map line drawing to make it consume less RAM, plus some optimizations for area polygons. It was working very well so I decided that rather than jumping into the new map tasks, I would continue until all old drawing code was replaced with new code, using the same optimization ideas as the line drawing. This…
1.9 beta I would prefer not to talk about this, and instead look into the future and forget this episode altogether. You can refer to the 1.9 beta log in the Steam Forum for a purely technical overview of how 1.9 evolved. The new track tracing system developed in June is now powering what eventually became the 1.9 final design, and that’s what matters in the end. Major speedup in complex…
Track + point line stops editor In May the code was ready for track + point line stops, but the UI was not. This was added in early June: It works as described in May: you can click on any point in any track to create a line stop, and then on the second click you choose the facing direction for the stop. The footprint of the line reference train is also displayed, so you can pick a position which…
Push-pull 1.8 introduces in-place train flipping, allowing trains to reverse without having to “bounce” off a track or platform end, which has been a meme in the game since 1.1 days. After 1.8 stabilized during its beta period it was time to implement the next step of this feature: push-pull. Push-pull capable train sets can change direction without reorienting and without rearranging…
Track + point pathfinder The new track pathfinder is now implemented in 1.8. As a recap, this new pathfinder is capable of finding paths when given an start and goal represented by points in a track, rather than using pairs of consecutive tracks as start and goals (the internal steps of the path still are, and always have been, capable of being represented as a track and point). All systems have…
Fixed departure times With 1.7 came another round of reviews and fixes for the line leg estimation. This time it was focused on braking times and properly timing paths involving reversal of direction. The concept of stop departure was also changed to properly account for the braking time. All these changes improve the game mechanics, but create extra work for players when loading a previous…
Custom train compositions Starting in version 1.7 players can compose their own trains, both from stock carriages (named from now and in-game as “cars” for brevity, beyond the various regional naming) and from mod cars. It was always possible for mod authors to provide pre-made compositions in their mods. Indeed it was the only way to provide a train for players. For this reason the…
NIMBY Rails is two years old January 26th 2023 marked the second anniversary of the NIMBY Rails Early Access release. This second year has continued the same theme of the first, improving core systems of the game to meet the objectives of the roadmap. If the major evolution of 2021 was the new track system, in 2022 it was timetables. I consider the remaining roadmap to be more expansive than…
Discarded station tape tool, replaced with platform promotion At the end of last month blog post I shared a new tape tool coming in the (then unreleased) 1.6 beta, the station tool. At the time it was still half implemented. It was a challenging tool, since the idea was to be able to place a station on any existing set of tracks and have it reproduce all the features of the stand alone station…
Multiplayer: the problem The challenge of implementing multiplayer in NIMBY Rails is the fact the state (this would be data involved in the player built objects and the simulation run on top of them) is very large by video game standards, easily going into hundreds of MB while at the same time having the expectation of running a simulation at perfect 60fps. It is not possible for the server to…
Wrapping up 1.5 2/3rds of October were devoted to the second beta series of v1.5, which will end very soon. I kept the beta branch going for longer than I anticipated since there are a couple of pax behaviors which don’t look very good, namely the late train behavior and the matching on line+stop, and I wanted to see how players worked around it with the current version. In the end…
1.5 first beta phase is done Version 1.5 is ready to go into the default branch. During this month long beta phase a huge amount of work was devoted to making the new order system more usable and complete, and to fix many issues with it. After 1.5 is made default, a new 1.5 beta series will start to implement the remaining 1.5 features. Orders Orders are the user facing interface for timetables,…
Timetable support for train AI August started with the decision to base timetables on the “train run” system as explained last month. Trains will have a sequence of “runs”, which is a simple combination of start time plus a line to run. These runs are tightly packed and must cover 100% of the week seconds. How the player interacts with runs was the big headache, so I…
Pax pathfinder dead ends June ended with a working, but very slow pax timetable pathfinder. It was still a plain A* pathfinder, using dynamic edges derived from the arrival time at the node (station) based on the departures within the next 3h (the station waiting limit for pax, still the same in 1.5). Its heuristic was just as bad as ever, based on the geographical distance times the max possible…
Multithreading for train AI Pax and station processing became so optimized in v1.4 that for a relatively low ratio of trains vs pax, train AI became the major factor of CPU usage. Train AI was still single threaded so it was time to update it to the same standard as pax and stations and make it multithreaded. Unlike pax and train processing at stations, which are fully independent from each other,…
Pax flow rework As part of the multithreaded station processing introduced at the end of April, I changed the way station pax are processed. In particular the meaning of the “flow”, the system used to fairly divide the frame processing time between stations and trains. It is now based on equating individual pax clusters moved to/from trains to one flow unit, rather than equating every…
Platform stop signals are back It was pointed out there were aesthetic reasons to manually set a stopping point for trains in platforms, specially now that the visuals of a platforms can be completely player defined. So platform stop have been enabled again. The existing caveats in 1.4 still apply, so if you set the platform stop points in a way that makes the train not fit the platform, and/or…
Station footprint extension building The new building system in v1.4 is not just meant for cosmetic architecture. It’s also meant to enable new gameplay elements, to give an additional user buildable object which is not a track segment. The first use of this capability is platform footprint extension: This building is special. It is only displayed in editor mode, and it has no texture.…
Final set of building textures Max has prepared a set of 28 building textures and they have been integrated in game: It’s a mix of roofing, glass roofing (to make it less common to need to toggle the roof layers if you want to see the inside of your closed station), floors and generic material surfaces which go well as bases or any other layer. Most of the non-glass textures are…
One year ago… … NIMBY Rails launched in early access! The year has seen 7000 internal builds, more than 100 public ones, and 100K+ lines of code added, changed or deleted. Some features back in January 2021 were barely a hint of what they have become one year later. And despite this there’s still ambitious work to do on some of the most basic game systems, like v1.2 did with…
End of v1.3 development, end of year, start of v1.4 v.1.3.15 is the final release in the v1.3 series, and it implements the new multiplayer simulation sync system exposed in the last post . v1.3 was shorter and more focused than v1.2, which is to be expected given the very large scope of v1.2. My hope for v1.4 and future versions is to keep this shorter development cycle. After v1.3.15 was done I…
New multiplayer simulation state synchronization idea NIMBY Rails multiplayer is based on state streaming, with two major data streams: the database and the simulation. The database is everything a player manually creates, edits and removes from the game. The server collects all these changes from the clients, merges them into a consistent state, which becomes the absolute truth, and then…
v1.3 released v1.3 was released on the beta branch on October 15th. The focus of the initial build was on the new map data, with the other scheduled v1.3 features to be added as betas in the coming weeks. Map processing was going on until the very last day, since some serious performance problems were found in the map indexing step and had to be solved before the final map file was generated. But…
New map processing and format for vector data If August saw the raster processing for the new map system, September was dedicated to vector data from OSM. Vector data is a lot less straightforward to handle. For starters it requires spatial indexing and an intermediate database, since the OSM PBF files are not suitable for geospatial queries. The new intermediate database is based on libmdbx . It…
Private train track pathfinding When some part of the game (the train AI, the line system, the UI, etc.) needs to find a track path from point A to point B over your line network, it uses the track pathfinder. On a first look this appears to be a process with little variety, always existing some optimal path from A to B, which the pathfinder (hopefully) is capable of finding. But in reality it all…
“Long” path signals When a train stops at (or comes up to) a path signal, a path check is performed. This path traces the tracks between the train and its current destination (or a blocking/facing signal) and checks if said path touches any reservation or train. This is the basic principle of how path signals work. By default this rule is sufficiently powerful to regulate many…
Path signals The first builds of version v1.2 only had simple block signals. The signal check for simple block signals is to look for a train inside the “block”, which is every reachable track segment from the signal, up to the next signal or balise. This includes track segments the train will never take, like those that start at diamonds or from branched tracks in the opposite…