There hasn't been much progress in the last months. My free time was very limited and while there is a certain amount of steady external traffic, showing that there is interest in the game, there were no contributions from other developers.
Also the development is a bit stuck. The original code has been simplified quite a significant amount without giving up functionality. The properties of Java helped a lot in this regard. But there are still some knots and complex parts left in the code structure. It would require quite a substantial continued effort to rework the code before you could even think about adding new features.
With the changes in how Java is deployed (modular JARs, JavaFX not included anymore) also some changes to the infrastructure of the project are necessary.
But I recently checked and the game still starts smoothly. I think it's therefore possible to continue right at the point where development stopped. I just hope that I or someone else will find the time.
Showing posts with label freerails. Show all posts
Showing posts with label freerails. Show all posts
Thursday, June 6, 2019
Thursday, October 4, 2018
FreeRails: Are we on the right track?
Track management is among the most often performed actions within any railroad simulation. It's also very close to the heart of the programming and design of any railroad simulation. Lately, I was interested in getting a better overview about how the track management in FreeRails work as well as possibly streamlining it and documenting it properly.
The map consists of an rectangular grid consisting of square-sized tiles. Each tile (except those at the border) have exactly eight neighbors which can be uniquely identified by compass points (north, north-east, ...) given the current center tile or by grid positions (row, column).
The total track on the map consists of many track pieces, where each piece connects two neighboring tiles (diagonal connections have ~1.41 (square-root of 2) times the length of horizontal or vertical connections).
Path finding of the trains works on a graph where the tiles are nodes and the track pieces connecting neighboring tiles are the edges.
Building and removing track works by adding and removing track pieces. In particular, the planning of a longer piece of newly built track is done by path finding again.
The track itself is visualized by rendering each tile according to its track configuration. The track configuration is an 8 bit value indicating if there is a connecting to one of the 8 neighbors from the current tile. See the attached image for some examples.
The track configurations are not independent from each other. For every connection on a tile towards a neighboring tile, this neighboring tile must also have a connection to this tile. This invariant must be obeyed by not allowing to change track configurations directly, but only by allowing adding or removing of track pieces at a time.
Track pieces have no direction, any train can go on them both ways. However, a train can change direction at every tile at most by 90 degree, effectively inducing some kind of directionality.
Track pieces can be single tracked or double tracked. There can only be one running train on each track piece (and trains have a certain extent, also measured in track pieces). However, stopped trains do not count as obstacles.
The track configuration of a tile is sufficient to draw it uniquely on the tile. Not all possible 8 bit values are valid.
Bridges and stations are a special case. Stations have a orientation and only allow track parallel to their orientation. Bridges span a water tile (other track cannot be put on water) and consist of two track pieces resulting in a parallel configuration.
That should be all for now. There is of course more (like trains). FreeRails currently follows the concept outlined above quite well. For some reason the track configuration is a 9 bit value (center part is also encoded and used to indicate no track at all) where I think that 8 bits would be sufficient and it's possible to change track configurations directly, whereas it's better to only change track pieces and change the track configuration only at a single place in the model.
Will be continued...
The map consists of an rectangular grid consisting of square-sized tiles. Each tile (except those at the border) have exactly eight neighbors which can be uniquely identified by compass points (north, north-east, ...) given the current center tile or by grid positions (row, column).
The total track on the map consists of many track pieces, where each piece connects two neighboring tiles (diagonal connections have ~1.41 (square-root of 2) times the length of horizontal or vertical connections).
Path finding of the trains works on a graph where the tiles are nodes and the track pieces connecting neighboring tiles are the edges.
Building and removing track works by adding and removing track pieces. In particular, the planning of a longer piece of newly built track is done by path finding again.
The track itself is visualized by rendering each tile according to its track configuration. The track configuration is an 8 bit value indicating if there is a connecting to one of the 8 neighbors from the current tile. See the attached image for some examples.
![]() |
Track configuration encoded as 8 bit value |
Track pieces have no direction, any train can go on them both ways. However, a train can change direction at every tile at most by 90 degree, effectively inducing some kind of directionality.
Track pieces can be single tracked or double tracked. There can only be one running train on each track piece (and trains have a certain extent, also measured in track pieces). However, stopped trains do not count as obstacles.
The track configuration of a tile is sufficient to draw it uniquely on the tile. Not all possible 8 bit values are valid.
Bridges and stations are a special case. Stations have a orientation and only allow track parallel to their orientation. Bridges span a water tile (other track cannot be put on water) and consist of two track pieces resulting in a parallel configuration.
That should be all for now. There is of course more (like trains). FreeRails currently follows the concept outlined above quite well. For some reason the track configuration is a 9 bit value (center part is also encoded and used to indicate no track at all) where I think that 8 bits would be sufficient and it's possible to change track configurations directly, whereas it's better to only change track pieces and change the track configuration only at a single place in the model.
Will be continued...
Sunday, September 2, 2018
FreeRails: Integrated CVS, SVN and Git history from 2000-2017
Typically, there are lots of warnings of changing the history of Git repositories after they were already pushed to the public, but I think that this is one of the typical exceptions from this rule.
After starting with FreeRails I learned a lot about converting CVS and SVN repositories to Git and about using advanced Git history editing commands like git replace or git filter-branch. Therefore I could really include the history of the FreeRails 1&2&3 and Railz 1&2 projects in a single Git repository.
On the other hand, although there are three forks on Github, there has not been done any work on them yet. The chances that somebody did do something and gets into trouble now is rather very slim. However, in this case, I'd be happy to assist. Nothing is lost. It's just a matter of chaining sufficiently many git commands.
After starting with FreeRails I learned a lot about converting CVS and SVN repositories to Git and about using advanced Git history editing commands like git replace or git filter-branch. Therefore I could really include the history of the FreeRails 1&2&3 and Railz 1&2 projects in a single Git repository.
On the other hand, although there are three forks on Github, there has not been done any work on them yet. The chances that somebody did do something and gets into trouble now is rather very slim. However, in this case, I'd be happy to assist. Nothing is lost. It's just a matter of chaining sufficiently many git commands.
Tuesday, August 14, 2018
FreeRails: Next programming steps
I finished quite some substantial changes under the hood, but I'm far from finished. It left me a bit exhausted mentally. Getting your head to solve complex puzzles in your free time is rewarding but also somewhat tiring. That's why I'm currently looking for some easier tasks as well as some planning tasks before returning to the inner workings.
Possible tasks include
Possible tasks include
- Go through all locations in the code marked TODO and work on the easier ones.
- Make some hard-coded properties of the game model like the economic climates (recession, moderate, boom) or the game rules (can connect to other railroads) serializable and then load their default state from a file when a scenario is loaded
- Go through the code (especially the moves, the move generators and the handler) and identify code that does game logic and move it to the model.
- Add to the design document details of the planned client-server interaction.
- Describe the game model in the design document.
- Moving Activities from the world to the Trains where they belong
- Replacing CompositeMoves with single step comprehensive Moves and removing undo on the moves (we don't undo anymore)
- Create a Player specific World view, so that the player doesn't always have to specify his Player object (alternatively, store your Player object with your credentials in a context, that then is stored next to the world)
Monday, August 6, 2018
FreeRails: Still under the hood
Progress was a bit slower in the last couple of months. Time for an update. Work is done mainly under the hood working on the model and the model updates in order to make it simpler and more resilient. The aim is to fully understand the game model, make it error free and easy to maintain and extend. A side effect is unified loading/saving of scenarios and savegames.
Only after this essential work has been finished, one can think about adding a new chassis (client interface). As a reminder, the latest dev progress is shown here.
Only after this essential work has been finished, one can think about adding a new chassis (client interface). As a reminder, the latest dev progress is shown here.
Wednesday, May 2, 2018
FreeRails: Taking notes...
Usually, I like scribbling down things with a pen on paper a lot. It gives me a lot of creative freedom.
But piles of paper are difficult to keep organized (or from vanishing). So for this project, I started writing down notes with an office application. Basically just long bullet lists of things that some objects do or how they are connected or how actions are sequenced, mixed with some conclusions of what to change.
Now there are already 16 pages of notes and the file is still growing. However, while I continue to make changes, most of the information in these notes gets outdated again, the overall value is limited. It's really just an extension of my mental capacities thing but still an essential tool for my work.
But piles of paper are difficult to keep organized (or from vanishing). So for this project, I started writing down notes with an office application. Basically just long bullet lists of things that some objects do or how they are connected or how actions are sequenced, mixed with some conclusions of what to change.
Now there are already 16 pages of notes and the file is still growing. However, while I continue to make changes, most of the information in these notes gets outdated again, the overall value is limited. It's really just an extension of my mental capacities thing but still an essential tool for my work.
Friday, April 20, 2018
FreeRails: Back to the drawing board
This is a bit technical post.
Now is the time to go back to the drawing board, write down the existing design and even change it. One such issue is the overall design of the client/server framework. Looking at what is there and what is regarded as modern design I came up with this proposal.
The client is basically a Model-View-Presenter scheme with the View being very passive and easy to change if for example and Android or Web port is attempted. The presentation logic is in the presenter which updates the view and reacts on user input. The presenter/controller is a big black box here and needs to be detailed later. The client also contains a full copy of the model/game world, making him a thick client. He acts upon changes in the model and proposes changes to it. However, the model just reroutes these proposed changes to the server.
The server checks the proposed change for applicability and either accepts it or rejects it. It then applies the change to itself and sends it to all clients so they can apply it to their copy of the model and the user will see them. It follows that this way all the client models will be in sync with the server model, although they may lag behind. To make sure they don't miss anything, the broadcasted, accepted changes will be enumerated or similar.
One can see nicely, how the information flows in a circle, from the view (user input) through presenter, local client model, server model, local client model again, presenter again and finally a change is displayed.
I think this requires the lowest amount of coding effort while still delivering robust performance and good separation of concern and modularity.
P.S. For drawing the design diagrams I use draw.io which is an excellent tool and works for me like a charm.
Now is the time to go back to the drawing board, write down the existing design and even change it. One such issue is the overall design of the client/server framework. Looking at what is there and what is regarded as modern design I came up with this proposal.
![]() |
Schematic of the proposed Client/Server design in FreeRails |
The server checks the proposed change for applicability and either accepts it or rejects it. It then applies the change to itself and sends it to all clients so they can apply it to their copy of the model and the user will see them. It follows that this way all the client models will be in sync with the server model, although they may lag behind. To make sure they don't miss anything, the broadcasted, accepted changes will be enumerated or similar.
One can see nicely, how the information flows in a circle, from the view (user input) through presenter, local client model, server model, local client model again, presenter again and finally a change is displayed.
I think this requires the lowest amount of coding effort while still delivering robust performance and good separation of concern and modularity.
P.S. For drawing the design diagrams I use draw.io which is an excellent tool and works for me like a charm.
Wednesday, April 18, 2018
FreeRails: Replacement of world differences object
In the last week I could refactor the current code in such a way that generic differences of world objects and actions that update world objects with these differences aren't needed anymore. I replaced the uses of these powerful but also very complex objects by a series of more primitive updates on the world. This also allowed me to remove code that tracked changes between nested lists (needed to represent differences of the world object).
I could reduce the size of the code base considerably without changing the functionality except for a small bit on the client side when displaying user messages which can be repaired later.
This step should make it easier to understand and advancing the code. Immediate next step will be some software design of the server-client relation and of the user interface as an initial step of rebuilding the client.
I could reduce the size of the code base considerably without changing the functionality except for a small bit on the client side when displaying user messages which can be repaired later.
This step should make it easier to understand and advancing the code. Immediate next step will be some software design of the server-client relation and of the user interface as an initial step of rebuilding the client.
Friday, April 6, 2018
FreeRails: Next step, rebuilding the client
The refactoring of the code is coming to an end. I made some pages of notes on how the code works. The next step seems to be clear: the rebuilding of the client using JavaFX and in the course of this simplifying the server and client interaction if possible while retaining all the features.
This should result in a simpler, easier to modify code base and also more modern look at the same time. However, it will also take some time and meanwhile it will look from the outside as if not much progress is happening. This will surely limit the interest until this task is finished.
On the other side, someone else posted about the project on Reddit and I posted about it on the FreeGameDev and Java Gaming forums. This brought considerable interest and visitors on the project page. It's a good start.
This should result in a simpler, easier to modify code base and also more modern look at the same time. However, it will also take some time and meanwhile it will look from the outside as if not much progress is happening. This will surely limit the interest until this task is finished.
On the other side, someone else posted about the project on Reddit and I posted about it on the FreeGameDev and Java Gaming forums. This brought considerable interest and visitors on the project page. It's a good start.
Thursday, February 22, 2018
FreeRails: Understanding the code
I begin to understand the code. That took quite some time staring at the screen and doing some refactoring. To quantify, roughly two hours per night for three nights a week for two months. Indeed, that long.
With a better documentation the start might have been faster, but I guess that ultimately there is just almost always a huge cost upfront when learning about a new code base. It just takes time.
To give an analogy: In the beginning the code was just like a bunch of single trees to me. Now it's like group of trees interacting and a vague notion of the whole forest, aka the complete picture.
There is hope of getting the complete picture rather sooner than later and there is hope that once you have the complete picture you can do anything you want to do with it including any simplification or continuation of the development as well as documenting the complete picture so that others have it a bit easier.
One thing I consider is branching from the code and, for the first time, really cut some functionality of the original code (the world difference update moves). The disadvantage would be that functionality would get lost and the advantage that quite some code would not be necessary anymore, so I would need to understand less and also I don't like the idea of moves which basically update the whole world. Once you have them you basically don't need any other moves anymore. Of course the missing functionality would have to be included again at a later time. Hmm, it's a difficult decision. I will postpone it a bit to give me more time thinking about it.
With a better documentation the start might have been faster, but I guess that ultimately there is just almost always a huge cost upfront when learning about a new code base. It just takes time.
To give an analogy: In the beginning the code was just like a bunch of single trees to me. Now it's like group of trees interacting and a vague notion of the whole forest, aka the complete picture.
There is hope of getting the complete picture rather sooner than later and there is hope that once you have the complete picture you can do anything you want to do with it including any simplification or continuation of the development as well as documenting the complete picture so that others have it a bit easier.
One thing I consider is branching from the code and, for the first time, really cut some functionality of the original code (the world difference update moves). The disadvantage would be that functionality would get lost and the advantage that quite some code would not be necessary anymore, so I would need to understand less and also I don't like the idea of moves which basically update the whole world. Once you have them you basically don't need any other moves anymore. Of course the missing functionality would have to be included again at a later time. Hmm, it's a difficult decision. I will postpone it a bit to give me more time thinking about it.
Thursday, February 15, 2018
FreeRails: Current screenshot
Monday, February 5, 2018
FreeRails: Current development goals
I'm intending to bring the project to a state where it is relatively simple to implement all the intended features for a "version 1.0" release. I hope others will join and will bring it to the full feature release then. With limited resources on my side, bringing the game to this intermediate point may take some time.
The milestones I want to reach in any case (may take some time) are:
The milestones I want to reach in any case (may take some time) are:
- More complete description of the game design in the documentation
- Clear separation of model, view, controller, server, client, serialization code
- Reduction of dependencies and complexity of the code
- Improved graphics and graphical user interface using JavaFX
- Runnable, bug-free version with an installer
- Some kind of roadmap towards version 1.0
Monday, January 29, 2018
FreeRails: How to untangle code?
There are three basically different approaches
- Study the code, find the crucial parts that are connected but should not, find a solution to untangling them, then do the programming
- Study the code and untangle code wherever you find it, until all but the crucial part remains, then tackle it
- Study the code and rewrite the code (in a simpler form) in another set of sources which then could replace the original code at some point
Thursday, January 18, 2018
FreeRails: How to reduce complexity of the code?
I looked at the code base of FreeRails now for quite some time. It's not simple to understand. There is quite a lot of complexity involved.
On the one hand that is expected. Managing railways isn't simple. Incorporating the logic of trains running on tracks with a delivery schedule, cargo producers, financial transactions, extending the track network in a changing world, ... that is even a difficult problem in the real world. :)
Mapping this to a client/server framework where the server even has to defend itself against illegal moves (no underwater tracks so far) of the client or offer some kind of undo capability adds its share to the problem.
Add some common practices like missing documentation or using overly complex (cyclic) dependencies and the code soon mutates into a huge spaghetti monster. (That is by no means an accuse of anyone, it's just what happens naturally. Also reading code is often harder than writing it.)
How to untangle the spaghetti, reduce the complexity and facilitate further development? That is the big question!
I'm not aware of an easy way to do that. It rather takes much time and the first steps are usually the hardest while later most things more or less fall in place. But the project is open source and on Github, so everyone can take part.
On the one hand that is expected. Managing railways isn't simple. Incorporating the logic of trains running on tracks with a delivery schedule, cargo producers, financial transactions, extending the track network in a changing world, ... that is even a difficult problem in the real world. :)
Mapping this to a client/server framework where the server even has to defend itself against illegal moves (no underwater tracks so far) of the client or offer some kind of undo capability adds its share to the problem.
Add some common practices like missing documentation or using overly complex (cyclic) dependencies and the code soon mutates into a huge spaghetti monster. (That is by no means an accuse of anyone, it's just what happens naturally. Also reading code is often harder than writing it.)
How to untangle the spaghetti, reduce the complexity and facilitate further development? That is the big question!
I'm not aware of an easy way to do that. It rather takes much time and the first steps are usually the hardest while later most things more or less fall in place. But the project is open source and on Github, so everyone can take part.
Tuesday, January 16, 2018
Railway Empire looks so nice
Most of the times commercial games look much better than open source games. A large group of skilled professionals working full time for many months with highly refined tools and frameworks - that cannot help but must outshine all attempts of a few partly skilled volunteers in their free time.
And so it is here too. There are indeed some Railway management games out there and since at least 10 years in quite good 3D graphics.
But the soon to be released Railway Empire (to be released on 26th January 2018) by Kalypso Media/Gaming Minds Studio just stuns me by the beautiful graphics.
Need a proof? Look at that gorgeous screenshot of a train in a landscape.
Makes me wonder how meaningful the revival of FreeRails is anymore? On the one hand it's fun to go through the code and improve it and surely the look can be improved dramatically from the look back then even with modest means, but on the other hand professional, commercial products have improved so dramatically from the early 2000s to now. Maybe there was a demand and a reason to clone RailRoad Tycoon in 2000-2005, but I'm not sure there is any reason now anymore.
And so it is here too. There are indeed some Railway management games out there and since at least 10 years in quite good 3D graphics.
But the soon to be released Railway Empire (to be released on 26th January 2018) by Kalypso Media/Gaming Minds Studio just stuns me by the beautiful graphics.
Need a proof? Look at that gorgeous screenshot of a train in a landscape.
Makes me wonder how meaningful the revival of FreeRails is anymore? On the one hand it's fun to go through the code and improve it and surely the look can be improved dramatically from the look back then even with modest means, but on the other hand professional, commercial products have improved so dramatically from the early 2000s to now. Maybe there was a demand and a reason to clone RailRoad Tycoon in 2000-2005, but I'm not sure there is any reason now anymore.
Friday, January 12, 2018
FreeRails: Refactoring, refactoring, refactoring
The complexity of the current code base of FreeRails is quite high. There are many classes and methods which are highly (sometimes cyclically) dependent on each other and often enough comments are missing. Additionally the game was thought to be a complex multi-player game with a server-client structure, with pathfinding for the trains, and complicated updates of the game world state (especially the trains).
That might be a part of the reason why development on FreeRails more or less stalled after 2005. It's very quite difficult to read this code and possibly extend or modify it.
On the other hand, the original makers used tests to continuously check their code and they wrote down their design ideas in a document. Also Java as a strongly typed language running on a standardized virtual machine, offers many tools to entangle such difficult to understand code bases without loosing the ability to execute the game.
That's why I could refactor the code base now for a week without loosing anything. Using static code analysis (code inspections in IntelliJ) and removing unused code, applying automatic fixes and manual improvements, replacing custom solutions by Java standards (which did not all exist in 2005 like Lambda functions in Java 8) I could reduce the number of code lines from 39k lines of code in version 0.4.1 to 33k lines of code now which means roughly 15% less code to understand. And as I said without loosing anything in functionality, the game looks and runs as before.
That might be a part of the reason why development on FreeRails more or less stalled after 2005. It's very quite difficult to read this code and possibly extend or modify it.
On the other hand, the original makers used tests to continuously check their code and they wrote down their design ideas in a document. Also Java as a strongly typed language running on a standardized virtual machine, offers many tools to entangle such difficult to understand code bases without loosing the ability to execute the game.
That's why I could refactor the code base now for a week without loosing anything. Using static code analysis (code inspections in IntelliJ) and removing unused code, applying automatic fixes and manual improvements, replacing custom solutions by Java standards (which did not all exist in 2005 like Lambda functions in Java 8) I could reduce the number of code lines from 39k lines of code in version 0.4.1 to 33k lines of code now which means roughly 15% less code to understand. And as I said without loosing anything in functionality, the game looks and runs as before.
Tuesday, January 2, 2018
FreeRails: Minor release 0.4.1
After an initial round of cleanup of the code base, and building the original FreeRails 0.4.0 code with Java 8, I released this slightly improved version as 0.4.1. Downloads will be hosted on bintray.
Download 0.4.1
I used the right to increase the version of the GPL-2.0 open source license and published the code under the GPL-3.0 license. However, the content and look is almost exactly the same as version 0.4.0 from 2008.
Download 0.4.1
I used the right to increase the version of the GPL-2.0 open source license and published the code under the GPL-3.0 license. However, the content and look is almost exactly the same as version 0.4.0 from 2008.
Thursday, December 28, 2017
FreeRails: the journey continues
Originally I just wanted to import the sources of the original FreeRails project to Github to preserve them and to facilitate further development with the aim to rescue an abandoned project.
However, I could not stop myself and started to continue myself. The project used Maven as build system. I converted this to Gradle. I cleaned up a bit, started a restructured text based documentation that can be automatically be created by readthedocs each time the code repository gets updated and I setup Travis CI (it was ridiculously easy) to automatically run the tests and report errors each time the code repository gets updated.
The goal is to jump-start the continuation of the project by
However, I could not stop myself and started to continue myself. The project used Maven as build system. I converted this to Gradle. I cleaned up a bit, started a restructured text based documentation that can be automatically be created by readthedocs each time the code repository gets updated and I setup Travis CI (it was ridiculously easy) to automatically run the tests and report errors each time the code repository gets updated.
The goal is to jump-start the continuation of the project by
- Updating the code base to Java 8 (applying the full code inspection capabilities IDEs like IntelliJ can provide)
- Switching the GUI framework from Swing to JavaFX with somewhat improved/scaled artwork
- Reducing complexity in the code base and the game model
- Removing unused or unnecessary parts of the code base
- Delivering installers for Windows
Tuesday, December 19, 2017
FreeRails: Images from 0.2.6
Sunday, December 17, 2017
FreeRails: Import of original sources
I imported the releases on the FreeRails I, II, III projects on Sourceforge and saved the available source package in a branch of the Github repository. I also re-released some of the historic available versions.
These branches and releases cover the existing development as far as I know it.
- Last release (0.2.7) of FreeRails (2000-2005) Link
- Last release (0.4.0) of FreeRails2 (2007-2008) Link
- Last release (0.0.4) of FreeRails3 (2016) Link
These branches and releases cover the existing development as far as I know it.
Subscribe to:
Posts (Atom)