# Systems
Observer is composed of interconnected systems, each managed by a dedicated manager class. This page provides a detailed breakdown of each system's API interface, available methods, events, and how they interact programmatically.
---
## Event Lifecycle
The core flow of an Observer-managed event follows a three-phase lifecycle controlled by the `GameState` enum.
### Phase 1: IN_LOBBY
Players connect and are held in the lobby world. During this phase:
- The **LobbyManager** manages the lobby world and player positioning.
- The **PlayerManager** tracks player connections and initializes `IPlayerData`.
- The **KitManager** allows staff to prepare kits.
- The **CapsuleManager** can pre-configure capsule locations and types.
- The **RestrictionManager** can set up item and enchantment restrictions.
### Phase 2: PRE_GAME
Triggered by a state change from `IN_LOBBY` to `PRE_GAME`. This fires `PreGameStateChangeEvent` (cancellable, supports tick delay) followed by `GameStateChangeEvent`.
During this phase:
- The **CapsuleManager** assigns players to capsules based on the configured `CapsuleType`.
- If Lead is installed, teams are assigned to capsules via `teamId`.
- The **PlayerStateManager** prepares player states.
- The **LateScatterManager** configuration determines how late joiners will be handled.
### Phase 3: IN_GAME
Triggered by a state change from `PRE_GAME` to `IN_GAME`. The event is now actively running.
During this phase:
- The **CapsuleManager** releases players from capsules via `release()`.
- The **EliminationManager** tracks deaths and fires `PlayerEliminatedEvent`.
- The **LifestealManager** handles heart drops, consumption, and withdrawal.
- The **DecayManager** tracks and decays placed blocks.
- The **MechanicsManager** enforces all gameplay toggles.
- The **WorldEventManager** can activate and deactivate world events.
- The **PedestalManager** monitors pedestal interactions and crafting.
- The **CustomRecipesManager** manages active custom recipes.
- The **RespawnManager** captures and restores player states on death.
- The **HelpOpManager** accepts player help requests.
- The **TranslationManager** resolves and dispatches messages.
---
## Capsule System
**API Interface:** `ICapsuleManager`
**Config File:** `capsules.yml`
The capsule system determines how players are distributed into the event world. Each capsule is a `Capsule` record containing a UUID, location, and optional team ID.
### Capsule Types
| Type | Behavior |
|---|---|
| `BATTLE_ROYALE` | Scatters players randomly across the map within a min/max distance range. |
| `CIVILIZATION` | Groups players into clusters within a configurable radius. |
| `WORLD_SPAWN` | Spawns players near the world spawn within a configurable radius. |
### Key Operations
- `setCapsules(List<Capsule>)` - Set capsule locations directly.
- `sendPlayersToCapsules(Player executor)` - Assign all players to capsules. Fires `PlayerAssignedToCapsuleEvent` for each assignment.
- `release()` - Release all players from their capsules (start the game).
- `swapCapsules(Player, Player)` - Swap two players' capsule assignments. Fires `PlayerSwapCapsulesEvent`.
- `sendPlayerToCapsule(Player, Capsule)` - Send a specific player to a specific capsule.
### Team Integration
When Lead is installed, capsules can be bound to teams via the `teamId` field. The `CapsuleManager` assigns team members to their team's capsule during the `sendPlayersToCapsules()` operation. If Lead is not installed and a team operation is attempted, `LeadNotInstalledException` is thrown.
---
## Elimination System
**API Interface:** `IEliminationManager`
**Config File:** `managers/elimination.yml`
The elimination system intercepts player deaths and applies configurable consequences.
### Flow
1. A player dies, triggering a `PlayerDeathEvent`.
2. Observer creates a `PlayerEliminatedEvent` (cancellable) with the player, killer, death message, and drops.
3. If not cancelled, the player's gamemode is set to `gamemode_on_death` (default: `SPECTATOR`).
4. If `lightning_on_kill` is enabled, lightning strikes at the death location.
5. The death message translation is broadcast using the configured `death_message` key.
6. If `auto_ban.enabled` is true and the player lacks the bypass permission, they are banned and shown the `kick_message` translation.
7. The remaining player count is updated (offset by `minimum_remaining_players`).
### Auto-Respawn
When `auto_respawn` is enabled, eliminated players are automatically respawned instead of staying on the death screen. This works in conjunction with the **RespawnManager**.
---
## Lifesteal System
**API Interface:** `ILifestealManager`
**Config File:** `managers/lifesteal.yml`
The lifesteal system adds health-based item mechanics to the game.
### Lifesteal Types
| Type | Behavior |
|---|---|
| `DROP` | Hearts drop as items when a player is killed. |
| `CONSUME` | Hearts are consumed directly on kill, granting health to the killer. |
| `OBTAIN` | Hearts are added to the killer's inventory on kill. |
| `ANYTIME` | Hearts can be obtained at any time. |
### Heart Items
Hearts are custom items (default: Nether Star) registered through Bookshelf's item system. They have configurable display names, lore (MiniMessage format), material, item model, and stackability.
### Withdrawal
When `can_withdraw` is true, players use `/withdraw [amount]` to convert their health into heart items. Each withdrawal removes 2 health points (1 heart) and produces one heart item. Withdrawal is blocked if the player's health would drop below `min_health`. The `PlayerWithdrawHeartEvent` is fired and can be cancelled.
### Consumption
When a player right-clicks a heart item, the `PlayerConsumeHeartEvent` is fired. If not cancelled, the player gains 2 health points per heart. Consumption is blocked at `max_health`. If `should_remove_heart` is true, the heart item is consumed.
### Health Bounds
- `max_health` (default: 40) — Maximum achievable health.
- `min_health` (default: 14) — Minimum health before withdrawal is blocked.
---
## Decay System
**API Interface:** `IDecayManager`
The decay system tracks player-placed blocks and reverts them to air after a configurable time.
### Key Operations
- `markBlockForDecay(Block block)` - Mark a block for decay with the default timer.
- `markBlockForDecay(Block block, int decayTime)` - Mark a block for decay with a custom timer in ticks.
- `unmarkBlockForDecay(Block block)` - Cancel a pending decay.
- `isMarkedForDecay(Location location)` - Check if a block is pending decay.
### Global Block Decay
When `should_global_block_decay` is enabled in `mechanics.yml`, all player-placed blocks are automatically marked for decay.
---
## Pedestal System
**API Interface:** `IPedestalManager`
**Config File:** `pedestals.yml`
Pedestals are world-placed crafting stations that require specific ingredients and produce a result item.
### Pedestal Types
| Type | Behavior |
|---|---|
| `SINGLE_USE` | The pedestal can only be used once, globally. |
| `PER_PLAYER` | Each player can use the pedestal up to `maxUses` times. |
| `REUSABLE` | The pedestal has unlimited uses. |
### PedestalData Record
Each pedestal is a `PedestalData` record containing:
- `id` - Unique string identifier.
- `position` - World location.
- `ingredients` - List of required `ItemStack` ingredients.
- `result` - The `ItemStack` produced on craft.
- `maxUses` - Maximum number of uses (for PER_PLAYER type).
- `itemHeight` - Height offset for the holographic item display.
- `pedestalType` - The usage limitation type.
- `uses` - Per-player usage tracking map.
### Events
- `PrePedestalCraftEvent` (cancellable) - Fired before ingredients are consumed.
- `PedestalCraftEvent` - Fired after the craft completes.
- `PedestalLoadEvent` - Fired when a pedestal is loaded from configuration.
---
## Mechanics System
**API Interface:** `IMechanicsManager`
**Config File:** `mechanics.yml`
The mechanics system provides toggles for a wide range of gameplay behaviors. Each toggle has a getter and setter method on the `IMechanicsManager` interface.
### Combat Logging
The `ICombatLoggingManager` (nested interface within `IMechanicsManager`) tracks combat state:
- `canCombatLog()` - Whether combat logging detection is enabled.
- `getCombatTimer()` - Duration of combat tag in seconds.
- `getDisplayType()` - Where the combat notification appears (`ACTION_BAR`, `TITLE`, `CHAT`).
- `getDisplayMessage()` - The message template with `{time}` placeholder.
Combat state is tracked per-player through `IPlayerData.inCombat()` and `IPlayerData.setCombat(boolean)`.
---
## World Event System
**API Interface:** `IWorldEventManager`
**Config File:** `managers/world_events.yml`
World events are named occurrences that execute commands and broadcast translation messages when activated.
### WorldEvent Data
Each `WorldEvent` contains:
- `id` - Unique string identifier.
- `itemIcon` - Material used as the icon in the GUI.
- `translationId` - Translation key broadcast on activation/deactivation.
- `commands` - List of commands executed on activation.
### Key Operations
- `addWorldEvent(WorldEvent)` - Register a new world event.
- `activateWorldEvent(String eventId)` - Start a world event. Fires `StartWorldEvent`.
- `deactivateWorldEvent(String eventId)` - End a world event. Fires `EndWorldEvent`.
- `isWorldEventActive(String eventId)` - Check if a specific event is active.
- `hasActiveWorldEvent()` - Check if any event is active.
- `getActiveWorldEvents()` - Get all currently active event IDs.
---
## Kit System
**API Interface:** `IKitManager`
The kit system saves and restores complete player states as named kits.
### RespawnData Record
Kits use the `RespawnData` record which captures:
- Inventory contents (serialized as bytes)
- Health, food level, saturation
- Experience and level
- Absorption amount
- Fire ticks
- Active potion effects
- Location (optional)
- Metadata: ID, timestamp, name, saved-by player
### Key Operations
- `savePlayerState(Player, String kitId, boolean saveLocation)` - Capture a player's current state as a kit.
- `loadPlayerState(Player, RespawnData)` - Apply a kit to a player.
- `deleteKit(String kitId)` - Remove a kit.
- `renameKit(String kitId, String newName)` - Rename a kit.
- `getKitById(String kitId)` - Retrieve a specific kit.
- `getKitIds()` - List all kit IDs.
- `getKits()` - Retrieve all kit data.
### Export and Import
Kits can be exported to shareable codes or mclo.gs URLs and imported back, enabling kit sharing across servers.
---
## Custom Recipes System
**API Interface:** `ICustomRecipesManager`
**Config File:** `custom_recipes.yml`
Register custom shaped and shapeless crafting recipes that persist across server restarts.
### Key Operations
- `newEmptyShaped(String id, ItemStack result)` - Create a new empty shaped recipe.
- `newEmptyShapeless(String id, ItemStack result)` - Create a new empty shapeless recipe.
- `add(ShapedRecipe)` / `add(ShapelessRecipe)` - Register a recipe. Throws `RecipeAddException` on failure.
- `remove(String id)` - Unregister a recipe.
- `get(String id)` - Retrieve a recipe by ID.
- `reload()` / `save()` - Reload from or persist to configuration.
---
## Respawn System
**API Interface:** `IRespawnManager`
**Config File:** `managers/respawn.yml`
The respawn system captures player state snapshots and restores them on respawn.
- `createRespawnData(Player)` - Capture the player's current state.
- `respawnPlayer(Player, RespawnData)` - Restore a player from a saved state.
- `isEnabled()` / `setEnabled(boolean)` - Toggle the system.
---
## Late Scatter System
**API Interface:** `ILateScatterManager`
**Config File:** `managers/late_scatter.yml`
Handles players who join after the game has started by scattering them into the event world.
- `isEnabled()` / `setEnabled(boolean)` - Toggle late scatter.
- `getGamemode()` / `setGamemode(GameMode)` - The gamemode assigned to late joiners.
- `getItems()` / `setItems(ItemStack[])` - Starting inventory for late joiners.
- `getTranslation()` / `setTranslation(String)` - Translation key for the late join broadcast.
Per-player tracking via `IOfflinePlayerData.hasBeenLateScattered()` prevents duplicate scattering.
---
## Player Data System
**API Interface:** `IPlayerManager`, `IPlayerData`, `IOfflinePlayerData`
**Config File:** `players.yml`
Tracks per-player state throughout the event.
### IPlayerData (Online)
| Method | Description |
|---|---|
| `inCombat()` | Whether the player is in combat. |
| `isInLobbyMode()` | Whether the player is in lobby mode. |
| `isDead()` | Whether the player is dead/eliminated. |
| `isStaffing()` | Whether the player is in staff mode. |
| `getBindedTeam()` | The team ID the player is bound to (requires Lead). |
### IOfflinePlayerData
| Method | Description |
|---|---|
| `hasBeenLateScattered()` | Whether the player has been late scattered. |
| `isMarkedAsDead()` | Whether the player has been eliminated. |
| `isSittingOut()` | Whether the player is sitting out. |
| `getRegion()` | The WorldGuard region the player is assigned to. |
---
## Translation System
**API Interface:** `ITranslationManager`
**Config File:** `translations.yml`
The translation system resolves message keys into `Translation` objects that can include tellraw messages, titles, sounds, and commands.
```java
ITranslationManager translations = api.getTranslationManager();
// Simple translation
Translation msg = translations.translate("ELIMINATION_MESSAGE");
msg.send(player); // Send to one player
msg.broadcast(); // Broadcast to all players
// Translation with variables
Translation msg = translations.translate("PEDESTAL_CRAFT",
VariableContext.of("player", player.getName(), "item_name", "Diamond Sword"));
msg.broadcast();
```
### Translation Structure
Each translation key can define:
- `tellraw` - MiniMessage chat message. Prefix with `<center>` for centered text.
- `title.title` / `title.subtitle` - Title and subtitle display.
- `sound.sound` / `sound.volume` / `sound.pitch` - Sound effect.
- `broadcastable` - Whether the translation supports broadcasting.
- `commands` - Commands to execute alongside the translation.
---
## HelpOp System
**API Interface:** `IHelpOpManager`
**Config File:** `managers/helpop.yml`
A simple staff assistance system with cooldown management.
- `isEnabled()` / `setEnabled(boolean)` - Toggle the system.
- `getCooldown()` / `setCooldown(long)` - Get or set the cooldown in milliseconds.
- `clearHelpOps()` - Clear all pending help requests.
Staff members with the `lodestone.observer.staff` permission receive notifications when players submit help requests.
---
## System Interaction Diagram
The following describes the primary interactions between systems during a typical event:
1. **IN_LOBBY** - `PlayerManager` tracks joins. `KitManager` and `RestrictionManager` prepare the event.
2. **PRE_GAME** - `CapsuleManager` assigns players. `PlayerStateManager` saves lobby states.
3. **IN_GAME** - `CapsuleManager.release()` starts the game. `EliminationManager` watches for deaths. `LifestealManager` drops hearts. `DecayManager` tracks blocks. `MechanicsManager` enforces rules. `WorldEventManager` triggers events. `PedestalManager` monitors crafting. `TranslationManager` delivers messages.
4. **End of Event** - State transitions back to `IN_LOBBY`. Managers reset their state.
---
## Related Pages
- [[Observer/Developers/Overview]] — Developer overview
- [[Observer/Developers/API Reference]] — API classes and interfaces