This essay delves deeper into the software architecture of the OpenRCT2 project. The architecture is first examined from different views, based on the book Software systems architecture by Rozanski and Woods. Then, the software is decomposed and each component’s function is explained. Next, the main architectural pattern of the project is explained and finally the trade-offs between the non-functional properties of OpenRCT2 are discussed.
Relevant architectural views
An architectural view, according to Rozanski and Woods, is a representation of one or more structural aspects of an architecture that illustrates how the architecture addresses one or more concerns held by one or more of its stakeholders.1
So, a view should:
- Enable stakeholders to determine whether their concerns have been met.
- Enable stakeholders to perform their role in the system.
Rozanski and Woods introduce a viewpoint catalog, whose viewpoints can be seen as templates from which views are constructed. These viewpoints apply differently to different architectures. The most relevant viewponts to the OpenRCT2 architecture are discussed here:
- The Context viewpoint describes the “relationships, dependencies, and interactions between the system and its environment”. This viewpoint addresses concerns of all stakeholders, for example:
- Players, testers and developers can determine ways of communicating with other players, testers and developers. This enables them to find other people to play together with, to report bugs at the right place, and to organize development.
- Developers can determine what programming language and version control system is used, enabling them to contribute to the project.
- Sponsors can determine which of their services are used. This enables them to provide these services correctly.
- The Functional viewpoint describes “the system’s run-time functional elements, their responsibilities, interfaces and primary interactions”. This viewpoint addresses concerns of all stakeholders, for example:
- Players can determine what kind of gameplay they can expect. It enables them to play the game that they expected to play.
- Developers can determine the features that they need to implement. It enables them to make valuable contributions.
- Translators can determine what parts of the system need translation and in how many languages it needs to be translated. It enables them to add translations to the game where it is needed.
- The Development viewpoint describes “the architecture that supports the software development process”. This viewpoint adresses concerns of developers and testers, for example:
- Developers can determine what style of coding they should adopt. It enables them to contribute code that is similar to code that other developers contribute.
- Testers can determine what the behavior of certain components should be. It enables them to write tests that test for component-specific behavior.
- The Deployment viewpoint describes “the environment into which the system will be deployed and the dependencies that the system has on elements of it”. This viewpoint is addresses concerns of players, developers and testers, for example:
- Player can determine where to download the latest stable release and what other software they require, such as the original data files of RCT2. It enabled them to actually play the game.
- Testers can determine where to download the latest development build. It enables them to test the latest commits for bugs.
- Developers can determine for what kind of platforms the game will be deployed on. It enables them to write code that support platform-specific functionalities, such as different folder structures.
The information, concurrency and operational viewpoints are not very relevant for the OpenRCT2 architecture. OpenRCT2 does not handle big amounts of data, parallelization is limited and the operation is simple because it is an isolated application.
The software is separated into components. Every component has a set of tasks relating to the in-game entity it corresponds to. For example, the peep component corresponds to the people in the game and handles all their behaviour. The complete list of components and their descriptions can be found in the appendix at the end of this essay.
Individual components have a very large amount of inter-dependencies. Therefore, figure 1 shows the components grouped in a higher level of abstraction. The most important interactions between the groups are displayed as arrows, with the type of interaction as text.
Other aspects of the OpenRCT2 project which make the system more reliable and easier to maintain by the developers include the in-game console. This console can be used to perform actions such as: getting or setting values of variables, listing variables, or manipulating objects. Moreover, the code includes a diagnostic level that can be set before compiling, which changes the level of detail of logging.
The code can be built manually on Windows using
make on Linux. The continuous integration system comprises TravisCI and AppVeyor, which automatically build for Linux and MacOS, and Windows respectively. Binaries of builds of the
development branches are automatically published to the OpenRCT2 website. Furthermore, a launcher is available, which automatically updates OpenRCT2.
Concerning standardization of design, the OpenRCT2 project has coding style rules that developers have to adhere to. This coding style comprises rules on aspects such as: variable naming, indentation, usage of comments, and maximum line width.
Furthermore, the OpenRCT2 project has a
clang-format program that is used to check whether code adheres to the coding style, and which can reformat code to adhere to the style if a there is a violation2. This
clang-format program is used by the continuous integration system, ensuring that pull requests do not contain coding style violations. Additionally, a git hook is available, enabling developers to check their code’s adherence to the coding style before committing their code. Finally, the project has a specific format for git commit messages. This ensures consistency and precision among commit messages of different developers.
To illustrate how components interact at run-time, we consider the common scenario of performing a start-up of OpenRCT2. In the following scenario, components are written as
After executing OpenRCT2.exe, the
Context component from
Engine performs initialization. First, it tries to locate the RCT2 or RCT1 directory, for the original game data dependencies. Next, internal dependencies such as managers and repositories are instantiated. If the Discord setting is enabled, a service is created for it (
network). Then the game is set to use the configured language, and defaults to British English if opening the configured language fails. The component warns the user if the game has elevated privileges, as these are not necessary.
ui window is created, and tracks (
track), scenarios (
scenario), and objects (
object) are loaded. The
audio sub-system is initialized, and sounds are loaded. A
network environment is created, and a chat is initialized. User files of the original RCT2 game are copied if available. Viewports (
interface) are initialized and a GameState (
Engine) is instantiated. Then, the TitleScreen (
title) is created. Finally, the initialization procedure finishes and the game launch is called.
The launch procedure launches the main menu. In the background a park shows, which is downloaded or loaded from file. If the game is launched as a server, the network fields are populated. Finally, the GameLoop is run.
Now, the main menu is shown to the user, as seen in figure 2. A park is shown in the background, and the user can start or load a game by pressing the buttons on the screen.
The GameLoop calls RunFrame repeatedly until the finished flag is set to true. Each call:
- RunFrame determines the number of ticks that have elapsed since its last run, by calling a function from the
platformcomponent, as this is a platform dependent operation.
- It calls the
uito process user input.
- It updates the time.
- It then calls the update methods of TitleScreen, GameState, UI, console, and chats.
- From the
worldcomponent, it obtains the next position of each sprite.
- It then calls the
drawingcomponent to draw, and the
paintcomponent to paint.
- Run-time software requirements: For OpenRCT2 to work, the data files (containing graphics, sounds and models) from the original RollerCoaster Tycoon 2 are needed. The original software has to be bought and installed before playing OpenRCT2. 3
- Operating Systems: The game can run on both 32-bit and 64-bit Windows (Vista/7/8/8.1/10), macOS, Linux, FreeBSD, OpenBSD, and Android operating systems. 4
- Hardware Requirements: OpenRCT2 is able to run on most reasonably modern computers. It requires about 250 MB of disk space, although 1 GB or more is recommended. Furthermore, about 500 MB of free RAM is required. 4
- Network requirements: To use the multiplayer online functionality, a stable internet connection is required. Servers can be created and hosted by any player. There are also dedicated servers run by the community.4
The primary architectural pattern used in OpenRCT2 is the model-view-controller pattern.5
The GameState class is a wrapper for all the game logic and represents the model component of the architecture. It initializes the game world and implements an Update functions that runs every frame. This function updates all the game logic components, like guests, rides or stalls.
The Drawing component handles the drawing of sprites and effects. It represents the view component. It uses the state of the game as input and draws the game world.
The controller is represented by the interface component. The interface draws and handles windows and UI elements that the user can see and interact with. Clicking on something in the game opens a window where the user can interact with the object.
Non-functional properties and trade-offs
The OpenRCT2 project has some goals that dictate the most important non-functional requirements of the project, but these requirements also come with trade-offs.
Compatibility with modern systems
The game should run on macOS, Linux, Windows and Android. This means the game needs more different build configurations and dependencies to compile for different platforms. Consistently testing all builds is a very time-consuming activity. There are also features of the original game that did not translate naturally to modern systems because of this. For example, text input boxes in the original game depended on windows so in OpenRCT2 a different way had to be developed to allow text input. 6
Graphical interface improvements
The graphical interface of the game was improved to allow features like different resolutions and framerate options. Furthermore, it is possible to choose between different rendering modes such as software rendering and OpenGL.
Compatibility with original game files
OpenRCT2 depends on the assets of the original game to run and supports the save files and scenario’s of the original. This is very convenient for people that want to load their old save files, but it does mean the limitations of the original game also apply to OpenRCT2. Currently the OpenRCT2 team is working on removing these limitations by implementing a new save format.
The original codebase was developed by IntelOrca7, he started the project and defined the initial goals and requirements. As the project grew, a core team was introduced that contained 8 other people. Since then, these people discuss trade-offs and decide on solutions with the support of IntelOrca. IntelOrca usually has the final say if the developers are divided. Any other contributors are also free to join in on discussions. The developers usually have the discussions about the design of the project in the issues on github or on the developer chatroom on gitter.
actionsHandles all player actions and it queues pending actions. For instance, the player can place/remove footpaths, buy/sell land rights, hire staff and load/quit/pause the game.
audioHandles sound for rides, weather and effects. Moreover, it handles music for rides and the game. It also controls volume levels and mixes sound/music.
cmdlineHandles and stores command line commands, which specify how the game can be run through the command line, for example, to run the game in headless mode when starting a server.
configHandles the in-game settings, such as the game resolution, enabling multithreading or changing the autosave frequency.
coreHandles reading and writing the console. It also handles encryption and decryption for multiplayer. Lastly, it handles writing, reading and compressing files/data.
drawingHandles drawing of sprites, effects such as rain/light, text (using various fonts) and images. It can do this using OpenGL or the X8 drawing engine.
engineHandles game logic at startup and run-time, which it updates at an interval. It handles how cheats are applied, keeps track of time/date and it enables saving/pausing and quitting. Also, it controls the scenario and track editor.
inputHandles player input from the mouse and the keyboard.
interfaceIt controls the in-game windows and their viewports as well as the various UI themes. It is responsible for how the chat is displayed. Stores color and font types. It stores and handles console commands. It handles how screenshots are taken.
localizationHandles which language and currency is displayed and stores guest names.
managementThis handles all park management logic, such as receiving rewards, finances, marketing, news and research. For instance, a park might receive a reward for the “best rides” or there might be news about new research.
networkHandles all multiplayer related logic, such as displaying servers, joining/leaving a server, sending andd receiving messages/commands and it synchronises player actions across the network. It also handles the Twitch and Discord integration.
objectThis controls all park objects behavior (e.g. rides, shops, scenery, paths, etc.).
paintHandles how sprites for all game objects such as rides, shops, scenery should be drawn.
peepDeals with all non player characters (NPC’s). It handles their sprite animations, pathfinding, behavior (riding rides, queueing, buying tickets, etc.), thoughts and interactions with player actions.
platformHandles platform specific logic, as specifies directory structures for other OS’s and reads and applies the platform language for localization.
rct1Handles importing RollerCoaster Tycoon 1 (RCT1) save and track design files (S4 and T4) and converting them to the RCT2 formats (S6 and T6).
rct12Handles importing RCT1/2 shared files and converting them
rct2Handles importing/exporting RCT2 files (S6 and T6), which are still used by OpenRCT2.
rideManage all ride (rollercoasters, transport, etc.) and shops behavior. Also controls track design behavior for the rides.
scenarioControls and stores game scenarios.
testpaintTests rides, such as the ride tracks for specified rides in the game.
testsTests functionality of components, such as pathfinding in the
peepcomponent or the ride ratings and encryption/decryption used in multiplayer.
titleLoads and updates the title screen sequence.
uiHandles how the the player actions influence the
interace, such as opening in-game windows. It also specifies how the interface is displayed on other platforms than windows, such as Linux or MacOS.
utilContains a collection of utility functions such as unit conversion, string helper functions, compression and several more.
windowsHandles and stores window logic and definitions for all different windows in the game. For instance, it specifies the position of various buttons or a viewport in a window.
worldControls the world objects and mechanics, such as weather, terrain.
Rozanski, Nick, and Eoin Woods. Software Systems Architecture: Working with Stakeholders Using Viewpoints and Perspectives. Addison-Wesley, 2012. ↩
https://clang.llvm.org/ Clang: C language front-end for LLVM ↩
https://openrct2.org/quickstart Quickstart guide to run OpenRCT2 ↩
Coplien, J. O., & Bjørnvig, G. (2011). Lean architecture: for agile software development. Section 8.1. Chichester: Wiley. ↩
https://mostlyprog.wordpress.com/tag/sdl2-0-text-input/ Developer blog post about text input in OpenRCT2 ↩
https://openrct2.org/about About page of OpenRCT2 ↩