Goobmodules and You
What?
Goobstation provides a way to isolate your code into separate, custom modules. These custom modules retain full functionality like the core modules, while solving the problem of having to recompile the entire game when making changes specific to your downstream.
Why?
As stated above, there are two primary reasons:
-
Streamlined Testing and Deployment: By separating downstream-specific code from the rest of the game, you can compile and test your custom features independently.
-
Enhanced Modularity: Instead of managing files and folders within the already bloated Content.Client/Shared/Server projects, you can organize your work into four distinct, fork-specific projects.
This approach is specifically designed to accommodate Robust Modularity should it be implemented in the future.
Terminology
-
Core Module: Modules belonging to the base space-station-14 repository. These include
Content.Client
,Content.Server
,Content.Shared
, and their dependencies likeContent.Shared.Database
. -
Custom Module: Modules that are part of the Client or Server process but don’t belong to Core Modules. In Goobstation’s case, these are prefixed with
Content.Goobstation.
. -
Engine Module: Modules that are part of RobustToolbox (the game engine). These are prefixed with
Robust.
. -
.Common: A module type intended to be shared between Custom and Core modules. These hold interfaces, components, and other types that both module types need to share.
-
ModLoader: The Module Loader system responsible for loading both core and custom modules.
-
Infix: The module identifier, which is the middle part of a module name. For example, “Goobstation” in
Content.Goobstation.Common
.
How
The client loader, unless configured otherwise, loads every Assembly from the Assemblies
folder with a specific prefix.
This prefix can be defined in the manifest.yml
file and defaults to Content.
.
By creating new projects with the Content.
prefix, you can have the game automatically load them at startup alongside the core modules.
The dependency structure works as follows:
Engine Modules
↑ ↑ ↑
| | |
| | |
Goobmodules → Core Modules
↑ |
| | (if same type)
| ↓
└── .Common Module
This means:
- Goobmodules (custom modules) can directly reference core modules.
- Core modules cannot directly reference Goobmodules if they are of the same type (Core.Shared-Custom.Shared), as this would create a circular dependency.
- Client or Server Core modules can reference Custom shared, but this is heavily discouraged.
- If the types are the same, core modules must communicate with Goobmodules through an intermediary
.Common
module. - The Common module must not depend on either core or custom modules and should be able to build standalone.
- Any part of this system can depend on Engine Modules.
Implementation
1. Check Configuration
Review your manifest.yml
file to check if any prefixes have been set there.
2. Create Your Projects
Create four projects with appropriate naming:
- Prepend them with the correct prefix (default is
Content.
) - Give them a meaningful name
- Suffix them with the module type (Client, Shared, Server, Common)
For example: Content.Goobstation.Client
, Content.Goobstation.Server
, etc.
3. Set Up Dependencies
Follow the dependency chain described above. You can use Core Modules as dependencies for your new modules, but not vice versa.
4. Create base files
Each module must have an EntryPoint class which inherits from the appropriate type:
GameClient
for Client modulesGameShared
for Shared or Common modulesGameServer
for Server modules
Each of these base classes provides override methods for each RunLevel (PreInit, Init, PostInit). Refer to the engine documentation for more information about these.
Additionally, to have autogenerated and networking files working you need to have global usings and relevant imports Every module needs to import Robust.Properties.
5. Configure IoC
You’ll need to set up Inversion of Control. Refer to the Space Wizards IoC documentation for detailed information.
6. Configure Build Paths
When building your project:
- Ensure your
Client
custom module is built in the same folder as the Core client module - Similarly, ensure your
Server
custom module is built in the same folder as the Core server module Shared
andCommon
modules should be built as dependencies of the above, so you don’t need to set specific build paths for them
Verification
If you’ve done everything correctly, Content.Client or Content.Server should load your custom module on startup, with everything registering and initializing properly.