How-to: Add a Custom League
A league in Library of Exile represents a season or game mode that occupies a specific server-side context (dimension, structure, or positional check). Leagues are hardcoded — they are not JSON-driven.
1. Implement League
public class MyLeague extends League {
public static final String ID = "my_mod:my_league";
public MyLeague() {
this.id = ID;
}
/**
* Return true when the given position is considered "inside" this league.
* Common checks: dimension key, structure tags, or custom capability data.
*/
@Override
public boolean isInSide(ServerLevel level, BlockPos pos) {
// Example: active whenever the player is in your custom dimension.
return level.dimension().equals(
ResourceKey.create(Registries.DIMENSION, new ResourceLocation("my_mod", "my_dimension"))
);
}
@Override
public ChatFormatting getTextColor() {
return ChatFormatting.LIGHT_PURPLE;
}
@Override
public String modid() {
return "my_mod";
}
@Override
public String locName() {
return "My League";
}
// ExileRegistry contract:
@Override
public ExileRegistryType getExileRegistryType() {
return LibDatabase.LEAGUE;
}
@Override
public int Weight() { return 1000; }
}
2. Register the league
Create an ExileRegistryEventClass for the LEAGUE type:
public class MyLeagueRegistrar extends ExileRegistryEventClass {
@Override
public ExileRegistryType getType() {
return LibDatabase.LEAGUE;
}
@Override
public void init(ExileRegistryEvent e) {
e.add(new MyLeague(), ExileRegistrationInfo.of("my_mod"));
}
}
Return it from getRegisterEvents() in your OrderedModConstructor:
@Override
public List<ExileRegistryEventClass> getRegisterEvents() {
return List.of(new MyLeagueRegistrar());
}
3. Look up the active league
At runtime, find the league that is active at any server-side position:
ServerLevel level = /* ... */;
BlockPos pos = player.blockPosition();
League league = League.getFromPosition(level, pos);
if (league.GUID().equals(MyLeague.ID)) {
// Player is in My League
}
If no league matches, League.getFromPosition returns LibLeagues.INSTANCE.EMPTY.get().
4. Work with CurrentLeague
CurrentLeague provides richer context for a player inside a map dimension:
Optional<CurrentLeague> current = CurrentLeague.get(level, pos);
current.ifPresent(cl -> {
// cl.dimension — the MapDimensionInfo for the current dimension
// cl.structure — Optional<MapStructure> if inside a structure
// cl.connectedFrom — Optional connection data if teleported in
});
5. Listen for league teleport events
ApiForgeEvents.registerForgeEvent(OnTeleportToLeagueEvent.class, event -> {
ServerPlayer player = event.getPlayer();
League destination = event.getLeague();
if (destination.GUID().equals(MyLeague.ID)) {
// Prepare the player: apply buffs, reset state, etc.
}
});
Notes
- Leagues use
SyncTime.NEVER— they are server-only. Do not assume client-side access. - Only one
Leaguecan be "active" at a position at a time;getFromPositionreturns the first match in registry order. Make yourisInSideconditions mutually exclusive. - The
EmptyLeague(GUID = "empty") is always present as the fallback. Never usenullfor a league reference.