Skip to content

Repository files navigation

Lobby Plugin

A modular lobby plugin. Every behavior is a self-contained, independently toggleable feature — persistent spawn, no hunger, no death, no player collision, and a fixed gamemode — managed by a small feature-registry framework so new features can be added without touching existing code.

The feature framework

Every behavior implements LobbyFeature:

public interface LobbyFeature {
    String name();
    void enable();
    void disable();
}

LobbyPlugin.onEnable() registers each feature together with a BooleanSupplier that says whether it should be active — normally a LobbyConfig getter:

featureManager.register(new NoHungerFeature(this), lobbyConfig::isNoHungerEnabled);

FeatureManager is the only class that knows how to turn that on/off, and it does so generically — it has no idea what "no-hunger" even means. Calling featureManager.reload() (wired to /lobbyreload) re-checks every supplier and enables/disables features to match, without a restart. This is what makes runtime management work: flip a value in config.yml, run /lobbyreload, done.

Adding a new feature later means: write one class implementing LobbyFeature, add one featureManager.register(...) line in LobbyPlugin. Nothing else changes.

Config (config.yml)

features:
  spawn: true
  no-hunger: true
  no-death: true
  no-collision: true
  fixed-gamemode:
    enabled: true
    gamemode: CREATIVE

Run /lobbyreload (permission lobby.reload, default op) after editing this file to apply changes live.

What each rule feature does

  • no-hunger — cancels FoodLevelChangeEvent for players, so hunger never drops.
  • no-death — cancels EntityDamageEvent for players outright. This is independent of gamemode, so it still protects players even if fixed-gamemode is turned off separately.
  • fixed-gamemode — sets the configured GameMode on join, and immediately re-applies it to everyone online when the feature is (re-)enabled (e.g. right after a /lobbyreload).
  • no-collision — uses the standard LivingEntity#setCollidable(false) flag (plain Bukkit API) on join; restores collisions on disable.

Design decisions

SOLID

  • SRPLobbyPlugin only wires things together; each feature class owns exactly one behavior; LobbyConfig is the only class that reads config.yml; FeatureManager only tracks enabled/active state.
  • OCP — new features are added by registering them, never by editing FeatureManager or other features.
  • LSP — any LobbyFeature or SpawnRepository implementation is a drop-in replacement.
  • ISPLobbyFeature exposes exactly three methods; nothing unused.
  • DIPFeatureManager depends on the LobbyFeature interface and a BooleanSupplier, never on concrete feature classes or LobbyConfig itself.

Patterns used

  • Strategy / plugin-module patternLobbyFeature + FeatureManager is a small framework for interchangeable, independently toggleable behaviors.
  • Repository patternSpawnRepository / YamlSpawnRepository (unchanged).
  • FacadeSpawnService (unchanged); LobbyConfig is a facade over raw YAML config.
  • Command pattern — Bukkit's CommandExecutor, one class per command.
  • Composition root / manual DILobbyPlugin builds the whole object graph once at startup.

Modern JDK usage — Java 25 toolchain, records, pattern-matching instanceof, Optional, Supplier/BooleanSupplier for lazy, always-current config reads.

Persistence

Spawn data lives in plugins/LobbyPlugin/spawn.yml, loaded once and cached in memory. Since this lobby only ever has one world, SpawnPoint stores just x, y, z, yaw, pitch — coordinates are always resolved against the server's primary world (Bukkit.getWorlds().get(0)).

Paper vs. Spigot

Targets Paper (Java 25 toolchain, paper-api) but runs unmodified on Spigot: commands are registered the classic plugin.yml + CommandExecutor way, and setCollidable/event cancellation are plain Bukkit API. The only Paper-only surface is Adventure's Component for chat messages — if you need plain Spigot support, swap those sendMessage(Component...) calls for legacy ChatColor strings (see the command classes).

Building

Requires JDK 25 and Gradle.

./gradlew build

The shaded jar is produced at build/libs/lobby-*.jar.

Permissions

Permission Default Effect
lobby.setspawn op Allows /setspawn
lobby.spawn true Allows /spawn
lobby.reload op Allows /lobbyreload

About

Modular Paper/Spigot lobby plugin with persistent spawn and hot-reloadable lobby rules

Resources

Stars

Watchers

Forks

Releases

Contributors

Languages