Example Game
Exploring the example game is the best way to get started with BlueDragon software. This guide will break down the main class and the necessary configuration file.
Configuration File
This file must be named game.properties
and be placed in the root of the compiled JAR file.
Only one game can be registered per JAR. If you wish to combine multiple games into one project, we recommend using Gradle subprojects.
Anatomy of the Main Class
There are only two requirements for a game’s main class:
- It must inherit
com.bluedragonmc.server.Game
- It must override the
initialize
method
Here is an example main class from our ExampleGame project:
Let’s break this down!
The class declaration
Every game needs to extend BlueDragon’s Game
class.
When overriding the constructor, we recommend keeping the game name (the name
constructor parameter) constant.
Your constructor is called in different ways depending on the number of parameters it accepts:
# of Parameters Accepted | Roles of Constructor Parameters |
---|---|
0 | Called with no parameters. |
1 | Map name |
2 | Map name, Game mode |
This logic can be found here.
The game mode can be any arbitrary string. The Game implementation can use the game mode string to change various game mechanics.
The initialize
method
The initialize
method is the time to use game modules. In this example, we’re using the VoidDeathModule and the CountdownModule.
Each module should have a single purpose and ideally shouldn’t contain much code. They are designed to be easy to use in many games without much adjustment.
The module registration callback
If a module has dependencies, calling use
may not initialize it right away.
Trying to get an instance of a module immediately after usage is not considered safe, since the module
may be waiting for its dependencies to load (and therefore hasn’t registered itself yet).
Instead, use the callback option in the second parameter of the use
method.
When the module is registered, the instance of the module will be passed to the callback.
You can register additional modules in this callback as well, and callbacks can be nested multiple times if necessary.
Loading maps
Loading maps, just like everything else, is delegated to a module.
- The AnvilFileMapProviderModule loads the map into an InstanceContainer and prevents loading the map multiple times into memory.
- The SharedInstanceModule uses the
InstanceContainer
created in theAnvilFileMapProviderModule
to create SharedInstances with the same world content. This allows the map to only be loaded once while keeping players and entities separated.
Creating a game module
You can create your own modules by extending the GameModule class and overriding the initialize
and deinitialize
methods.
Module Dependencies
Dependencies are specified with the DependsOn
and SoftDependsOn
annotations.
If a module lists a dependency, that dependency will be registered before the dependent module is registered.
However, for soft dependencies, if the dependency is not registered by the time initialize
is fully invoked, the module will be registered instead of throwing an exception.
Scoped Event Nodes
Every module gets its own EventNode, which is scoped to the game. All events that pass through this EventNode must be related to a player in the game, an instance that this game owns, or the game itself.
The only exception to this is the ServerTickMonitorEvent. See the source code for details.
Unregistering Modules
When a module is unregistered (typically after the game ends), each of its modules get unregistered.
At this point, the module’s deinitialize
method will be invoked.
This is one final time to do any cleanup, like closing file handles or database connections or reverting any non-scoped changes.
Further Reading
- Get started with the BlueDragon codebase using our quickstart guide.
- Learn more about our project structure.
- Read the source code of the Game class or the module resolution system.