XMage’s game engine is designed to be extended without modifying core server code. Almost every user-facing game variant — from Two Player Duel to Commander to Jumpstart — is delivered as a separate JAR plugin that the server discovers and loads at startup. This architecture makes it possible to add new game modes, formats, and tournament structures by dropping a new JAR into theDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/magefree/mage/llms.txt
Use this file to discover all available pages before exploring further.
plugins/ directory and registering it in config.xml.
How Plugin Loading Works
At startup,Main.java scans the plugins/ directory (relative to the server working directory) and uses a PluginClassLoader to load each JAR. Plugin classes are then registered into the appropriate factory (GameFactory, TournamentFactory, PlayerFactory, CubeFactory, DeckValidatorFactory) based on which <…Types> section of config.xml they appear in.
The server also scans an extensions/ directory for extension packages. Each subdirectory inside extensions/ is treated as an extension package and loaded via ExtensionPackageLoader.
Plugin JARs are loaded in the order they appear in
config.xml. If two plugins register the same name, the last one wins. Extension packages in the extensions/ directory are loaded after all plugin JARs. Extension packages can contribute additional cards, sets, and token images without modifying the main server distribution.Plugin Categories
config.xml defines five plugin categories, each mapped to a dedicated XML element.
1. <playerTypes> — Player Implementations
Defines the types of players that can sit at a table. Each entry maps a display name to a Java class that implements the Player interface.
2. <gameTypes> — Game Variants
Each <gameType> entry wires together a Match implementation (which manages a best-of-N series) and a MatchType implementation (which describes the rules). Both are required.
config.xml:
| Display Name | Match Class | Type Class |
|---|---|---|
| Two Player Duel | TwoPlayerMatch | TwoPlayerDuelType |
| Free For All | FreeForAllMatch | FreeForAllType |
| Commander Two Player Duel | CommanderDuelMatch | CommanderDuelType |
| Commander Free For All | CommanderFreeForAllMatch | CommanderFreeForAllType |
| Tiny Leaders Two Player Duel | TinyLeadersDuelMatch | TinyLeadersDuelType |
| Canadian Highlander Two Player Duel | CanadianHighlanderDuelMatch | CanadianHighlanderDuelType |
| Penny Dreadful Commander Free For All | PennyDreadfulCommanderFreeForAllMatch | PennyDreadfulCommanderFreeForAllType |
| Freeform Commander Two Player Duel | FreeformCommanderDuelMatch | FreeformCommanderDuelType |
| Freeform Commander Free For All | FreeformCommanderFreeForAllMatch | FreeformCommanderFreeForAllType |
| Freeform Unlimited Commander | FreeformUnlimitedCommanderMatch | FreeformUnlimitedCommanderType |
| Custom Pillar of the Paruns Two Player Duel | CustomPillarOfTheParunsDuelMatch | CustomPillarOfTheParunsDuelType |
| Oathbreaker Two Player Duel | OathbreakerDuelMatch | OathbreakerDuelType |
| Oathbreaker Free For All | OathbreakerFreeForAllMatch | OathbreakerFreeForAllType |
| Brawl Two Player Duel | BrawlDuelMatch | BrawlDuelType |
| Brawl Free For All | BrawlFreeForAllMatch | BrawlFreeForAllType |
| Momir Basic Two Player Duel | MomirDuelMatch | MomirDuelType |
| Momir Basic Free For All | MomirFreeForAllMatch | MomirFreeForAllType |
3. <tournamentTypes> — Tournament Formats
Tournament types follow the same two-class pattern (className for the runnable tournament, typeName for the descriptor). The built-in set covers Constructed (elimination and Swiss), multiple Booster Draft variants, Sealed, and Jumpstart:
4. <deckTypes> — Format Validators
Deck type entries only require name, jar, and className (no typeName). Each class validates a submitted deck against a specific format’s legality rules. The single JAR mage-deck-constructed.jar ships classes for every constructed and block-constructed format:
| Format Family | Examples |
|---|---|
| Rotating constructed | Standard, Pioneer, Modern, Legacy, Vintage, Pauper, Historic |
| Highlander variants | Australian, Canadian, European Highlander |
| Commander family | Commander, Duel Commander, MTGO 1v1, Centurion, Freeform Commander |
| Old School | Old School 93/94, Italian Rules, Channel Fireball Rules, EudoGames, EC Rules |
| Block Constructed | Innistrad, Scars of Mirrodin, Return to Ravnica, Khans of Tarkir, and more |
| Variant | Tiny Leaders, Momir Basic, Brawl, Oathbreaker, Freeform, Freeform Unlimited |
| Limited | mage-deck-limited.jar → mage.deck.Limited |
5. <draftCubes> — Cube Configurations
Draft cube entries don’t use typeName. Each class defines the card pool and pack composition for cube drafts. All ship inside mage-tournament-booster-draft.jar:
Plugin Entry Attribute Summary
Every plugin element inconfig.xml shares the same attribute schema:
| Attribute | Required | Description |
|---|---|---|
name | ✅ | Display name shown in the client UI |
jar | ✅ | Filename of the JAR inside the plugins/ directory |
className | ✅ | Fully-qualified name of the main implementation class |
typeName | Game & tournament types only | Fully-qualified name of the companion type descriptor class |
Maven Module Structure
Each plugin inconfig.xml corresponds to a Maven module under Mage.Server.Plugins/. The module compiles to the JAR named in the jar attribute:
Adding a New Game Mode
Create a Maven module
Add a new directory under
Mage.Server.Plugins/ (e.g. Mage.Game.MyVariant) with its own pom.xml. Reference the parent POM in Mage.Server.Plugins/pom.xml.Implement the required interfaces
Create a class extending an existing
Match subclass (e.g. TwoPlayerMatch) for your match logic, and a class implementing MatchType for the rules descriptor. Both classes must be in the same JAR.