diff --git a/docs/README.skills.md b/docs/README.skills.md index 1f24d0b37..1894a3ceb 100644 --- a/docs/README.skills.md +++ b/docs/README.skills.md @@ -209,6 +209,7 @@ See [CONTRIBUTING.md](../CONTRIBUTING.md#adding-skills) for guidelines on how to | [microsoft-docs](../skills/microsoft-docs/SKILL.md) | Query official Microsoft documentation to find concepts, tutorials, and code examples across Azure, .NET, Agent Framework, Aspire, VS Code, GitHub, and more. Uses Microsoft Learn MCP as the default, with Context7 and Aspire MCP for content that lives outside learn.microsoft.com. | None | | [microsoft-skill-creator](../skills/microsoft-skill-creator/SKILL.md) | Create agent skills for Microsoft technologies using Learn MCP tools. Use when users want to create a skill that teaches agents about any Microsoft technology, library, framework, or service (Azure, .NET, M365, VS Code, Bicep, etc.). Investigates topics deeply, then generates a hybrid skill storing essential knowledge locally while enabling dynamic deeper investigation. | `references/skill-templates.md` | | [migrating-oracle-to-postgres-stored-procedures](../skills/migrating-oracle-to-postgres-stored-procedures/SKILL.md) | Migrates Oracle PL/SQL stored procedures to PostgreSQL PL/pgSQL. Translates Oracle-specific syntax, preserves method signatures and type-anchored parameters, leverages orafce where appropriate, and applies COLLATE "C" for Oracle-compatible text sorting. Use when converting Oracle stored procedures or functions to PostgreSQL equivalents during a database migration. | None | +| [minecraft-plugin-development](../skills/minecraft-plugin-development/SKILL.md) | Use this skill when building or modifying Minecraft server plugins for Paper, Spigot, or Bukkit, including plugin.yml setup, commands, listeners, schedulers, player state, team or arena systems, configuration files, Adventure text, and version-safe API usage. Trigger for requests like "build a Minecraft plugin", "add a Paper command", "fix a Bukkit listener", "create plugin.yml", "implement a minigame mechanic", or "debug server plugin behavior". | `references/bootstrap-registration.md`
`references/config-data-and-async.md`
`references/maps-heroes-and-feature-modules.md`
`references/minigame-instance-flow.md`
`references/project-patterns.md`
`references/state-sessions-and-phases.md` | | [mkdocs-translations](../skills/mkdocs-translations/SKILL.md) | Generate a language translation for a mkdocs documentation stack. | None | | [model-recommendation](../skills/model-recommendation/SKILL.md) | Analyze chatmode or prompt files and recommend optimal AI models based on task complexity, required capabilities, and cost-efficiency | None | | [msstore-cli](../skills/msstore-cli/SKILL.md) | Microsoft Store Developer CLI (msstore) for publishing Windows applications to the Microsoft Store. Use when asked to configure Store credentials, list Store apps, check submission status, publish submissions, manage package flights, set up CI/CD for Store publishing, or integrate with Partner Center. Supports Windows App SDK/WinUI, UWP, .NET MAUI, Flutter, Electron, React Native, and PWA applications. | None | diff --git a/skills/minecraft-plugin-development/SKILL.md b/skills/minecraft-plugin-development/SKILL.md new file mode 100644 index 000000000..4bb163e65 --- /dev/null +++ b/skills/minecraft-plugin-development/SKILL.md @@ -0,0 +1,262 @@ +--- +name: minecraft-plugin-development +description: 'Use this skill when building or modifying Minecraft server plugins for Paper, Spigot, or Bukkit, including plugin.yml setup, commands, listeners, schedulers, player state, team or arena systems, configuration files, Adventure text, and version-safe API usage. Trigger for requests like "build a Minecraft plugin", "add a Paper command", "fix a Bukkit listener", "create plugin.yml", "implement a minigame mechanic", or "debug server plugin behavior".' +--- + +# Minecraft Plugin Development + +Use this skill for Minecraft server plugin work in the Paper, Spigot, and Bukkit ecosystem. + +This skill is especially useful for gameplay-heavy plugins such as combat systems, wave or boss encounters, war or team modes, arenas, kit systems, cooldown-based abilities, scoreboards, and config-driven game rules. + +For grounded implementation patterns drawn from real Paper plugins, load these references as needed: + +- [`references/project-patterns.md`](references/project-patterns.md) for high-level architecture patterns seen in real gameplay plugins +- [`references/bootstrap-registration.md`](references/bootstrap-registration.md) for `onEnable`, command wiring, listener registration, and shutdown expectations +- [`references/state-sessions-and-phases.md`](references/state-sessions-and-phases.md) for player session modeling, game phases, match state, and reconnect-safe logic +- [`references/config-data-and-async.md`](references/config-data-and-async.md) for config managers, database-backed player data, async flushes, and UI refresh tasks +- [`references/maps-heroes-and-feature-modules.md`](references/maps-heroes-and-feature-modules.md) for map rotation, hero or class systems, and modular feature growth +- [`references/minigame-instance-flow.md`](references/minigame-instance-flow.md) for arena instances, countdowns, loot refreshes, wave systems, visibility isolation, and entity-to-game ownership + +## Scope + +- In scope: Paper, Spigot, Bukkit plugin development +- In scope: `plugin.yml`, commands, tab completion, listeners, schedulers, configs, permissions, Adventure text, player state, minigame flow, arena instances, map copies, loot, waves, and PvP/PvE game loops +- In scope: Java-based server plugin architecture, debugging, refactoring, and feature implementation +- Out of scope by default: Fabric mods, Forge mods, client mods, Bedrock add-ons + +If the user says "Minecraft plugin" but the stack is unclear, first determine whether the project is Paper/Spigot/Bukkit or a modding stack. + +## Default Working Style + +When this skill triggers: + +1. Identify the server API and version target. +2. Identify the build system and Java version. +3. Inspect `plugin.yml`, the main plugin class, and command or listener registration. +4. Map the gameplay flow before editing code: + - player lifecycle + - game phases + - timers and scheduled tasks + - team, arena, or match state + - config and persistence +5. Make the smallest coherent change that keeps registration, config, and runtime behavior aligned. + +If the plugin is gameplay-heavy or stateful, read [`references/project-patterns.md`](references/project-patterns.md) and [`references/state-sessions-and-phases.md`](references/state-sessions-and-phases.md) before editing. + +If the task touches arena isolation, map instances, chest or resource refills, wave spawning, route voting, spectator visibility, or game-specific chat, also read [`references/minigame-instance-flow.md`](references/minigame-instance-flow.md). + +## Project Discovery Checklist + +Check these first when present: + +- `plugin.yml` +- `pom.xml`, `build.gradle`, or `build.gradle.kts` +- the plugin main class extending `JavaPlugin` +- command executors and tab completers +- listener classes +- config bootstrap code for `config.yml`, messages, kits, arenas, or custom YAML files +- scheduler usage through Bukkit scheduler APIs +- any player data, team state, arena state, or match state containers + +## Core Rules + +### Prefer the concrete server API in the repo + +- If the project already targets Paper APIs, keep using Paper-first APIs instead of downgrading to generic Bukkit unless compatibility is explicitly required. +- Do not assume an API exists across all versions. Check the existing dependency and surrounding code style first. + +### Keep registration in sync + +When adding commands, permissions, or listeners, update the relevant registration points in the same change: + +- `plugin.yml` +- plugin startup registration in `onEnable` +- any permission checks in code +- any related config or message keys + +### Respect main-thread boundaries + +- Do not touch world state, entities, inventories, scoreboards, or most Bukkit API objects from async tasks unless the API explicitly permits it. +- Use async tasks for external I/O, heavy computation, or database work, then switch back to the main thread before applying gameplay changes. + +### Model gameplay as state, not scattered booleans + +For gameplay plugins, prefer explicit state objects over duplicated flags: + +- match or game phase +- player role or class +- cooldown state +- team membership +- arena assignment +- alive, eliminated, spectating, or queued state + +When the feature affects match-heavy minigames or persistent-brawl gameplay, look for hidden state transitions first before patching symptoms. + +For multi-arena plugins, isolate per-game visibility, chat recipients, scoreboards, loot, and entity ownership. Do not let one arena observe or mutate another arena by accident. + +### Favor config-driven values + +When the feature includes damage, cooldowns, rewards, durations, messages, map settings, or toggles: + +- prefer config-backed values over hardcoding +- provide sensible defaults +- keep key names stable and readable +- validate or sanitize missing values + +### Be careful with reload behavior + +- Avoid promising safe hot reload unless the code already supports it well. +- On config reload, ensure in-memory caches, scheduled tasks, and gameplay state are handled consistently. + +## Implementation Patterns + +### Commands + +For new commands: + +- add the command to `plugin.yml` +- implement executor and tab completion when needed +- validate sender type before casting to `Player` +- separate parsing, permission checks, and gameplay logic +- send clear player-facing feedback for invalid usage + +Minimal registration shape: + +```yaml +commands: + arena: + description: Join or leave an arena + usage: /arena +``` + +```java +@Override +public void onEnable() { + ArenaCommand command = new ArenaCommand(gameService); + PluginCommand arena = getCommand("arena"); + if (arena != null) { + arena.setExecutor(command); + arena.setTabCompleter(command); + } +} +``` + +### Listeners + +For event listeners: + +- guard early and return early +- check whether the current player, arena, or game phase should handle the event +- avoid doing expensive work in hot events such as move, damage, or interact spam +- centralize repeated checks where practical + +### Scheduled Tasks + +For timers, rounds, countdowns, cooldowns, or periodic checks: + +- store task handles when cancellation matters +- cancel tasks on plugin disable and when a match or arena ends +- avoid multiple overlapping tasks for the same gameplay concern unless explicitly intended +- prefer one authoritative game loop over many loosely coordinated repeating tasks +- ensure countdown or refill tasks self-cancel when the game leaves the expected state + +Main-thread handoff shape: + +```java +Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { + PlayerData data = repository.load(playerId); + Bukkit.getScheduler().runTask(plugin, () -> { + Player player = Bukkit.getPlayer(playerId); + if (player != null && player.isOnline()) { + scoreboard.update(player, data); + } + }); +}); +``` + +### Player and Match State + +For per-player or per-match state: + +- define ownership clearly +- clean up on quit, kick, death, match end, and plugin disable +- avoid memory leaks from stale maps keyed by `Player` +- prefer `UUID` for persistent tracking unless a live player object is strictly needed + +### Text and Messages + +When the project uses Adventure or MiniMessage: + +- follow the existing formatting approach +- avoid mixing legacy color codes and Adventure styles without a reason +- keep message templates configurable when messages are gameplay-facing + +## High-Risk Areas + +Pay extra attention when editing: + +- damage handling and custom combat logic +- death, respawn, spectator, and elimination flow +- arena join and leave flow +- scoreboard or boss bar updates +- inventory mutation and kit distribution +- async database or file access +- version-sensitive API calls +- shutdown and cleanup in `onDisable` +- cross-arena visibility, chat, and broadcast isolation +- map copy, unload, and folder deletion logic +- mob, NPC, projectile, or temporary entity ownership +- chest or resource refill systems + +## Output Expectations + +When implementing or revising plugin code: + +- produce runnable Java code, not pseudo-code, unless the user asks for design only +- mention any required updates to `plugin.yml`, config files, build files, or resources +- call out version assumptions explicitly +- point out thread-safety or API-compatibility risks when they exist +- preserve the project's existing conventions and folder structure + +When the requested change touches plugin startup, async data, match flow, class systems, or rotating maps, consult the matching reference file before editing. + +## Validation Checklist + +Before finishing, verify as many of these as the task allows: + +- the command, listener, or feature is registered correctly +- `plugin.yml` matches the implemented behavior +- imports and API types match the targeted server stack +- scheduler usage is safe +- config keys referenced in code exist or have defaults +- state cleanup paths exist for match end, player quit, and plugin disable +- per-arena chat, visibility, scoreboards, and broadcasts are isolated +- temporary worlds, mobs, tasks, and generated resources are cleaned up +- there are no obvious null, cast, or lifecycle hazards + +## Common Gotchas + +- Casting `CommandSender` to `Player` without checking +- Updating Bukkit state from async tasks +- Forgetting to register listeners or declare commands in `plugin.yml` +- Using `Player` objects as long-lived map keys when `UUID` is safer +- Leaving repeating tasks alive after a round, arena, or plugin shutdown +- Hardcoding gameplay constants that should live in config +- Assuming Paper-only APIs in a Spigot-targeted plugin +- Treating reload as free even though stateful plugins often break under reload +- Broadcasting, showing players, or applying scoreboard changes across unrelated game instances +- Loading or mutating chest/container blocks before their chunks are available +- Forgetting to unregister spawned mobs or temporary entities from the owning game + +## Preferred Response Shape + +For substantial requests, structure work like this: + +1. Current plugin context and assumptions +2. Gameplay or lifecycle impact +3. Code changes +4. Required registration or config updates +5. Validation and remaining risks + +For small requests, keep the answer concise but still mention any needed `plugin.yml`, config, or lifecycle updates. diff --git a/skills/minecraft-plugin-development/references/bootstrap-registration.md b/skills/minecraft-plugin-development/references/bootstrap-registration.md new file mode 100644 index 000000000..d8edac765 --- /dev/null +++ b/skills/minecraft-plugin-development/references/bootstrap-registration.md @@ -0,0 +1,100 @@ +# Bootstrap And Registration + +Use this reference when changing `onEnable`, `onDisable`, command setup, event wiring, or startup ordering. + +## Bootstrap pattern from real plugins + +### Match-heavy minigame bootstrap + +Common traits: + +- connect database first +- register configuration serialization when needed +- initialize multiple config managers +- create gameplay managers and GUI helpers +- apply lobby UI to already-online players +- register many listeners explicitly +- start repeating tasks +- register commands and tab completers last + +This pattern works well when startup must assemble many gameplay subsystems before the server can safely accept interactions. + +### Persistent class-brawl bootstrap + +Common traits: + +- save default config and bundled resources first +- construct config wrapper and progression config +- connect database and create repository/service layers +- construct scoreboard, map, hero, and game services +- wire service dependencies together +- start background tasks +- preload async cache, then schedule main-thread UI refreshes +- register listeners and commands after service graph is ready + +This pattern works well when player data and async services are first-class dependencies. + +## Command registration rules + +Observed practices: + +- Match-heavy minigames often declare all commands in `plugin.yml`, then set executors and tab completers in code. +- Persistent brawl modes may declare a small command surface such as `leave`, then null-check `getCommand` before assigning the executor. + +Recommended rules: + +- always add new commands to `plugin.yml` +- if a command may be optional or renamed, null-check `getCommand` +- if tab completion exists, register it in the same change +- keep usage, permission, and permission-message aligned with actual code behavior + +## Listener registration rules + +Observed practices: + +- both plugins register listeners in one place during startup +- listener constructors receive only the services they actually need + +Recommended rules: + +- keep registration centralized in the main plugin class or a clearly named bootstrap helper +- inject services explicitly instead of having listeners discover globals everywhere +- if a listener depends on a task, GUI, or manager, construct that dependency first + +## Repeating tasks and startup ordering + +Observed practices: + +- Match-heavy minigames often start periodic gameplay tasks directly from startup for boundary checks and spectator UI refreshes +- Persistent brawl modes often start background tasks via services such as player data and game services + +Recommended rules: + +- start repeating tasks only after required state holders exist +- cancel them in shutdown +- if the task mutates gameplay state, ensure it runs on the main thread +- if the task does I/O or cache rebuilds, prefer async execution and hop back to main thread for Bukkit work + +## Shutdown expectations + +Observed practices: + +- Match-heavy minigames delete games, unload maps, flush pending stats, close DB resources, and clear sidebars +- Persistent brawl modes shut down game service, player data service, map manager, then disconnect database + +Recommended rules: + +- stop tasks +- flush dirty data +- detach or clear UI objects +- unload temporary worlds if your plugin creates them +- close database pools last + +## Contribution guidance for this skill + +When generating code for startup or shutdown, mention: + +- which config or resource files must exist +- which commands or listeners must be registered +- what tasks must be started or canceled +- what resources require cleanup on disable diff --git a/skills/minecraft-plugin-development/references/config-data-and-async.md b/skills/minecraft-plugin-development/references/config-data-and-async.md new file mode 100644 index 000000000..a58b603d6 --- /dev/null +++ b/skills/minecraft-plugin-development/references/config-data-and-async.md @@ -0,0 +1,120 @@ +# Config, Data, And Async Patterns + +Use this reference when a task touches config loading, persistence, caches, scoreboards, or background refreshes. + +## Config patterns from real plugins + +### Multi-config minigame layer + +Large minigames may use multiple config-oriented classes: + +- `PluginConfigManager` +- `GameConfigurationManager` +- `KillMessagesConfig` +- `MessagesConfig` +- `LevelsConfig` +- `MapConfig` +- `PlayerConfig` + +This pattern works well when gameplay systems each own a distinct config surface. + +Tradeoff: + +- easy to grow per-domain config +- harder to keep defaults and reload semantics consistent unless carefully managed + +### Defensive wrapper config layer + +Persistent brawl modes may use a defensive wrapper around the main config and separate loaders for other domain files such as progression and heroes. + +Observed strengths: + +- fallback values +- warning logs on invalid config +- one wrapper for core lobby and material settings + +Guidance: + +- if the project is still compact, prefer a typed wrapper with fallbacks +- split into many config managers only when domain complexity truly requires it + +## Database and player data patterns + +### Match-heavy minigame observations + +- uses a database manager plus stats and brand-related storage +- flushes pending updates before disconnecting + +### Persistent-brawl observations + +- separates `DatabaseManager`, repository, and service +- keeps in-memory cache keyed by `UUID` +- tracks dirty players +- flushes asynchronously +- rebuilds leaderboards from cached data +- uses dirty sets for sidebar and rank UI so scoreboards are refreshed in batches +- snapshots leaderboard data before presenting it to gameplay or UI code + +Guidance: + +- use a repository or DAO boundary when persistence logic grows +- keep a cache for hot player stats +- record dirty entries instead of writing on every event +- flush on intervals and on shutdown +- debounce or batch leaderboard rebuilds when kills, deaths, or ranks can change frequently +- publish immutable snapshots or copies from async-maintained caches + +## Async rules for Paper plugins + +Observed safe persistent-brawl pattern: + +- preload cache asynchronously +- when data is ready, switch to the main thread for Bukkit-side UI refreshes +- async leaderboard rebuilds avoid blocking gameplay + +Recommended rules: + +- async: + - SQL + - file-heavy processing + - leaderboard rebuilds + - cache recomputation +- main thread: + - teleport + - inventory changes + - entity or world mutation + - scoreboard and visible UI changes unless the API is explicitly thread-safe + +## Background task patterns + +Observed persistent-brawl patterns: + +- async periodic leaderboard rebuild checks +- async dirty-player flush task +- throttled UI refresh strategy with dirty sets +- main-thread scoreboard flush from UUID dirty sets +- async cache preload followed by main-thread scoreboard, tab name, and leaderboard refresh + +Observed match-heavy minigame patterns: + +- main-thread periodic game-stage task +- per-session cooldown ticking +- time-sensitive display refreshes tied to game progression + +Guidance: + +- use async tasks for data maintenance +- use main-thread tasks for gameplay progression +- if a task can be event-driven plus dirty-flagged, prefer that over brute-force refreshing everything every tick +- copy mutable cached data before saving or sorting it asynchronously +- avoid starting async work from inside an async repeating task unless you need distinct lifecycle control + +## Config contribution guidance + +When generating config-aware code: + +- provide defaults +- validate inputs +- document required keys +- avoid silently crashing on invalid material names or missing locations +- mention whether reload is safe for the specific subsystem diff --git a/skills/minecraft-plugin-development/references/maps-heroes-and-feature-modules.md b/skills/minecraft-plugin-development/references/maps-heroes-and-feature-modules.md new file mode 100644 index 000000000..8d3ba95d5 --- /dev/null +++ b/skills/minecraft-plugin-development/references/maps-heroes-and-feature-modules.md @@ -0,0 +1,120 @@ +# Maps, Heroes, And Feature Modules + +Use this reference when building map systems, rotating arenas, class systems, kits, or modular gameplay features. + +## Map patterns from real plugins + +### Per-game map-instance usage + +Observed traits: + +- per-game map instances +- allowed map filtering through configuration +- gameplay objects tied to the active map instance +- match mode can constrain which maps are used + +This works well for isolated match instances where each game owns its world and objectives. + +### Persistent battlefield map rotation + +Observed traits: + +- one active combat world at a time +- source maps copied into temporary active worlds +- old worlds unloaded and deleted after rotation +- rotation warnings broadcast before swap +- spawn leaderboards refreshed after rotation + +This works well for a persistent shared mode where the world rotates on a timer. + +### Sky-island arena map usage + +Observed traits: + +- one game owns one copied map instance +- teams are assigned to configured island spawn locations +- chests are grouped by island, middle, or center role +- countdowns control cage removal, game start, refill timing, and game end +- visibility and chat are scoped to players in the same game instance + +This works well for SkyWars-style modes where every match needs isolated islands, loot, spectators, and cleanup. + +### Dungeon-node map usage + +Observed traits: + +- one game owns a lobby map plus temporary combat or event node maps +- route choices are generated from stage metadata +- players vote or confirm before advancing +- each combat node owns its wave queue and active mob set +- old node maps are unloaded only after players move to the new map or lobby + +This works well for PvE roguelike, dungeon, wave, or boss progression plugins. + +## Guidance for map architecture + +- Per-instance minigame: + - use a `GameMap` owned by a game object +- Shared rotating battlefield: + - use a `MapManager` with one active world plus a rotation timer +- Temporary copied worlds: + - always teleport players out before unload + - clean folders after unload + - reapply gamerules after world creation +- Sky-island match: + - group spawn and chest locations by team or island role + - reset cages, inventories, scoreboards, and spectators per match +- Dungeon or route-node mode: + - treat every node as a temporary stage with explicit load, enter, clear, and unload steps + - keep mob ownership tied to the game, not just the world + +## Class and hero system patterns + +Observed class-system traits: + +- `HeroRegistry` +- `HeroService` +- definitions grouped by theme +- hero tier progression +- hero skill config and handler +- selector GUI separated from assignment logic + +Observed minigame power-selection parallels: + +- brands and special items function like modular player powers +- selection limits and categories are explicit +- match rules can constrain available choices + +Guidance: + +- keep definitions separate from runtime assignment +- use registries for discoverable content +- store unlock rules and tiers in data, not hardcoded listener branches +- separate: + - what a class is + - how it is selected + - how it is applied + - how its active skills are triggered + +## Feature module pattern + +Good candidate modules for separate packages: + +- map rotation +- hero or class system +- item powers +- boss systems +- match rules +- shops and GUIs +- scoreboards +- progression + +Do not merge all these into one listener or one “game utils” class. + +## Practical heuristic + +If a feature has all three of these, it deserves its own module: + +- custom data model +- config or definitions +- one or more listeners, commands, or scheduled tasks diff --git a/skills/minecraft-plugin-development/references/minigame-instance-flow.md b/skills/minecraft-plugin-development/references/minigame-instance-flow.md new file mode 100644 index 000000000..57bc89849 --- /dev/null +++ b/skills/minecraft-plugin-development/references/minigame-instance-flow.md @@ -0,0 +1,187 @@ +# Minigame Instance Flow + +Use this reference when building arena-style PvP games, SkyWars-style island games, dungeon or wave modes, rotating map instances, or any plugin where multiple players, worlds, mobs, scoreboards, and timers belong to a specific game instance. + +## Instance ownership pattern + +Good minigame plugins make ownership explicit: + +- a global `GameManager` or `GameService` tracks active games +- each `Game` owns its map or world instance +- players are mapped to exactly one active game or lobby state +- temporary mobs, projectiles, NPCs, or spawned objects are mapped back to their owning game +- scoreboards, visibility, chat recipients, loot, and timers are scoped to the owning game + +Recommended maps: + +- `Map` for active games by generated ID +- `Map` or `Map` for player ownership +- `Map` for spawned mob or entity ownership when using MythicMobs, custom NPCs, or boss waves + +Avoid relying on world name, inventory contents, scoreboard text, or entity display names as the only source of truth. + +## State machine for arena games + +Common PvP arena states: + +- `WAITING` +- `STARTING` +- `STARTED` +- `ENDED` + +Common persistent-brawl states: + +- `LOBBY` +- `RESPAWNING` +- `IN_BRAWL` + +Common dungeon or route-node states: + +- lobby or route-selection phase +- active combat node +- peaceful room, shop, event, or rest node +- victory or cleanup phase + +Guidance: + +- gate every event listener by state before applying gameplay effects +- when transitioning state, update timers, scoreboards, visibility, player inventory, and protected areas together +- use state changes as the single place to start countdowns, refill tasks, end countdowns, and wave spawning +- if a task only makes sense in one state, it should cancel itself when the game leaves that state + +## Player isolation + +Multi-arena plugins must isolate more than teleport destinations. + +Check these surfaces: + +- player visibility with `showPlayer` and `hidePlayer` +- chat recipients, especially in `AsyncChatEvent` +- scoreboard instances and sidebar updates +- tab list names or ranks +- boss bars and title broadcasts +- lobby items and game-only inventory state +- damage, block, item pickup, item drop, interact, teleport, respawn, and quit events + +Rules: + +- if two players are not in the same visibility group, hide them from each other from both directions +- lobby players should not receive arena chat or arena broadcasts +- arena players should not receive unrelated lobby or other-arena game messages +- spectator players should be excluded from combat, pickup, block, and interaction logic unless explicitly allowed + +## Countdown and repeating task lifecycle + +Typical tasks: + +- start countdown +- end countdown +- chest or resource refill countdown +- scoreboard or sidebar flush +- phase or wave delay +- map rotation ticker +- dirty data flush + +Rules: + +- store `BukkitTask` handles when cancellation matters +- do not start a second task for the same game concern without canceling or checking the first +- countdown tasks should read the current game state on every tick and self-cancel when stale +- delay tasks should re-check that the game still exists and is still running before acting +- clean up tasks on game end and plugin shutdown + +## Loot and resource refill systems + +Sky-island and arena plugins often need config-driven resource distribution. + +Useful structure: + +- group container locations by role, such as island, middle, center, normal, rare, or overpowered +- load weighted loot from config +- build a total loot pool for a group +- shuffle items before placing them +- choose random empty inventory slots with a bounded retry loop +- validate missing or invalid loot config by warning and falling back safely + +Container safety: + +- load the chunk before reading a configured chest or barrel +- verify the block is a `Container` before casting +- if the configured block is missing, either recreate it intentionally or warn and skip it +- clear previous contents before refill if the design expects a full reset +- avoid heavy loot generation in hot events + +## Wave, mob, and route-node systems + +Dungeon-style plugins commonly combine route selection with combat waves. + +Recommended model: + +- keep a queue of pending mob IDs for the current wave +- keep a set of active mob UUIDs for spawned mobs +- register each spawned mob UUID to the owning game +- on mob death, remove it from the active set and unregister ownership +- a wave is clear only when both the pending queue and active set are empty +- after a wave clears, schedule the next wave or return to the route/lobby phase + +Route voting guidance: + +- only alive and active players should vote or proceed +- prune vote maps against currently active player UUIDs before checking thresholds +- handle missing stage templates with a fallback or a clean victory/end path +- peaceful rooms should have a clear proceed gate instead of silently advancing + +Cleanup rules: + +- unregister mobs on death, game stop, and plugin disable +- unload old stage maps only after players are safely teleported out +- clear wave queues and active mob sets when a game ends +- never let a stale mob death event advance a completed or deleted game + +## Map instance and rotation rules + +For copied temporary worlds: + +- copy the source map into a unique active folder +- create or load the world from that folder +- configure gamerules after the world exists +- set autosave intentionally +- teleport players out before unload +- unload the world before deleting its folder +- delete old folders after unload and log failures + +For rotating shared battlefields: + +- warn players before rotation +- snapshot current participants before loading the next map +- move participants to the new spawn and reset transient class or ability state +- refresh scoreboards, tab names, leaderboards, and visibility after rotation +- prevent scoreboard refresh from running every tick if the displayed countdown changes slowly + +## Listener heuristics + +For every listener touching gameplay state: + +- return early if the entity or player has no session +- resolve the owning game once and reuse it +- check the game state before mutating blocks, inventory, health, drops, or scoreboards +- check spectator, safe-zone, team, and combat-tag rules before allowing damage +- keep world-to-game and entity-to-game checks consistent +- do not assume `Player#getKiller()` is enough for custom combat; use combat tags when projectile, skill, or ability damage matters + +## Third-party plugin integrations + +Common integrations: + +- PlaceholderAPI for scoreboards, tab names, or external placeholders +- MythicMobs for custom mob spawning and skills +- menu plugins for lobby selectors +- database libraries for player progression + +Rules: + +- declare hard dependencies in `depend` only when startup cannot work without them +- use `softdepend` and runtime checks for optional features +- keep optional integration registration isolated from core startup +- when casting external skills or spawning external mobs, handle missing IDs and API failures gracefully +- prefer service boundaries so the rest of the game code does not directly depend on every integration API diff --git a/skills/minecraft-plugin-development/references/project-patterns.md b/skills/minecraft-plugin-development/references/project-patterns.md new file mode 100644 index 000000000..e1033801b --- /dev/null +++ b/skills/minecraft-plugin-development/references/project-patterns.md @@ -0,0 +1,143 @@ +# Real Project Patterns + +This reference captures architecture patterns observed in real Paper gameplay plugins: + +- match-heavy, multi-phase minigames with maps, teams, power selections, boss waves, scoreboards, and match-mode overlays +- class-based persistent brawl modes with hero progression, map rotation, player data services, and async leaderboard refreshes + +Use this file when the user asks for repo structure, feature placement, or how to organize a growing Minecraft plugin. + +## Pattern 1: Central plugin bootstrap with explicit subsystems + +Both styles keep one main plugin class responsible for constructing and wiring core subsystems. + +Observed examples: + +- A match-heavy minigame wires database, config managers, game manager, match manager, GUI objects, sidebar services, listeners, commands, and repeating tasks from `onEnable`. +- A persistent class-brawl plugin wires config, progression, database, repository, player data service, scoreboard manager, map manager, hero registry, hero service, game service, and hero skill handler from `onEnable`. + +Guidance: + +- Keep plugin startup readable and ordered. +- Construct core services before registering listeners or commands that depend on them. +- Treat the main plugin class as an orchestration root, not a dumping ground for gameplay logic. + +## Pattern 2: Stateful gameplay belongs in dedicated session or manager objects + +Both styles avoid storing all gameplay data directly on listeners. + +Observed examples: + +- Match-heavy minigames use `GameManager`, `MatchManager`, `Game`, `PlayerSession`, `GamePhase`, and `MatchSession` style objects. +- Persistent class-brawl modes use `GameService`, `PlayerSession`, `PlayerState`, `HeroService`, and `MapManager`. + +Guidance: + +- Put long-lived state into session, manager, or service classes. +- Keep listeners thin: validate the event, delegate to the relevant service, and exit. +- Prefer explicit gameplay state models over scattered flags. + +## Pattern 3: Complex plugins grow by domain modules + +As plugin scope grows, both styles split features into domain-oriented packages. + +Observed match-heavy minigame domains: + +- `Command` +- `Game` +- `Match` +- `GameConfig` +- `InitialListener` +- `Shop` +- `tasks` +- `Database` + +Observed persistent class-brawl domains: + +- `bootstrap` +- `command` +- `data` +- `game` +- `hero` +- `listener` +- `map` +- `gui` + +Guidance: + +- Group by gameplay domain or subsystem, not by vague “utils” buckets. +- Split once a feature has its own state, configuration, and lifecycle. +- Keep package names aligned with how you reason about the game. + +## Pattern 4: Two valid architecture styles emerge + +Match-heavy minigames lean toward manager-centric gameplay orchestration. + +- Good fit for: + - rounds + - team elimination + - map-specific game instances + - match overlays on top of base game rules + +Persistent class-brawl modes lean toward service-centric runtime orchestration. + +- Good fit for: + - a persistent combat lobby + - class selection and respawn loops + - progression and player data integration + - rotating maps with a shared game mode + +Guidance: + +- Prefer manager-centric architecture for per-match or per-arena instances. +- Prefer service-centric architecture for one persistent shared mode with reusable systems. + +## Pattern 5: Real plugins need both gameplay and operational layers + +Real gameplay plugins combine gameplay code with operational subsystems: + +- config loading +- database connectivity +- scoreboard refreshes +- map loading +- command and listener registration +- shutdown cleanup + +Guidance: + +- Do not design only the combat mechanic. +- Also design startup, shutdown, persistence, UI refreshes, and failure paths. + +## Pattern 6: Instance-heavy plugins need explicit isolation layers + +SkyWars-style and dungeon-style plugins need a clear boundary around each active game instance. + +Common isolated surfaces: + +- player-to-game session ownership +- world or map instance ownership +- temporary mob or entity ownership +- game-specific chat recipients +- visibility groups +- per-game scoreboards and titles +- resource refill or wave timers + +Guidance: + +- Treat `Game` as the owner of anything that should not leak into another arena. +- Keep global managers responsible for lookup and lifecycle, not for every gameplay rule. +- When adding a new listener, first decide whether it is global, lobby-only, or game-instance-only. +- If the plugin can run multiple games at once, every event should resolve the owning game before mutating gameplay state. + +## When to reuse which pattern + +- New minigame with rounds, teams, and map instances: + - prefer `GameManager` + `Game` + `PlayerSession` + optional `MatchManager` +- Persistent PvP lobby with class selection and map rotation: + - prefer `GameService` + `PlayerSession` + `HeroService` + `MapManager` +- SkyWars-style isolated arena: + - prefer `GameManager` + `Game` + `GameMap` + countdown tasks + per-game scoreboard and loot managers +- PvE dungeon or wave progression: + - prefer `Game` + lobby map + `RoundManager` or stage manager + entity ownership map + explicit cleanup hooks +- Plugin already large and messy: + - use the domain package split pattern before adding more features diff --git a/skills/minecraft-plugin-development/references/state-sessions-and-phases.md b/skills/minecraft-plugin-development/references/state-sessions-and-phases.md new file mode 100644 index 000000000..c8b72f429 --- /dev/null +++ b/skills/minecraft-plugin-development/references/state-sessions-and-phases.md @@ -0,0 +1,121 @@ +# State, Sessions, And Phases + +Use this reference when designing player state, match flow, cooldowns, respawn logic, class selection, or round progression. + +## Session modeling in real plugins + +### Rich minigame session + +Feature-heavy minigames often keep rich per-player runtime state in `PlayerSession`, including: + +- current team +- kill and final kill counters +- death flag +- persistent potion-like buffs +- selected brands grouped by category +- per-brand cooldowns +- special item cooldowns + +This is a strong pattern for feature-heavy minigames where one player can carry many temporary gameplay modifiers. + +### Lean persistent-brawl session + +Persistent brawl modes often keep a leaner `PlayerSession`, including: + +- `PlayerState` +- selected hero +- fall protection state +- safe-zone tracking +- generic cooldown map + +This is a strong pattern when the plugin has one dominant game loop and most feature-specific behavior lives in services. + +## Rule 1: model player state explicitly + +Do not infer state from inventory contents, world, or scoreboard text alone. + +Prefer an enum or similarly explicit model such as: + +- `LOBBY` +- `RESPAWNING` +- `IN_BRAWL` +- queueing +- spectating +- eliminated +- reconnect-pending + +## Rule 2: use sessions as the source of temporary truth + +Good session contents: + +- cooldowns +- selected class or hero +- selected team +- in-round modifiers +- safe-zone knowledge +- reconnect markers +- fall protection or spawn protection + +Avoid placing these as scattered listener fields. + +## Rule 3: gameplay phases deserve first-class objects + +Observed match-heavy minigame pattern: + +- `GamePhase` +- scheduled phase transitions +- boss and bed-destruction events tied to phases +- phase-dependent spawners and world border changes + +Guidance: + +- for round-based modes, use a phase enum or state machine +- trigger map-wide events from phase transitions, not random listeners +- keep the “what happens at phase N” logic centralized + +## Rule 4: match overlays should not be mixed blindly into normal rounds + +Observed match overlay pattern: + +- `MatchManager` +- `MatchSession` +- separate handling for participants, observers, reconnects, brand rules, and round interception + +Guidance: + +- if tournament or match mode changes the base game rules, isolate it behind a dedicated manager +- keep “normal game” and “match override” behavior composable, not tangled + +## Rule 5: reconnect and cleanup paths matter + +Observed concerns: + +- match participants may disconnect and reconnect +- game sessions can outlive the current online `Player` object +- cleanup must happen on quit, death, round end, and plugin shutdown + +Guidance: + +- prefer `UUID` for durable identity +- if you must keep live `Player` references, also define detach/reattach behavior +- always think through quit, reconnect, death, respawn, and shutdown together + +## Rule 6: cooldowns should be centralized + +Observed patterns: + +- Some match-heavy minigames tick cooldown maps during stage task updates +- Some persistent-brawl modes store cooldown expiry timestamps in session data + +Choose based on your mode: + +- tick-down integers: + - good for per-second synchronized gameplay pacing +- expiry timestamps: + - good for lightweight cooldown checks across arbitrary actions + +## Practical design heuristic + +If your feature changes what a player is allowed to do for some period of time, it probably belongs in session state. + +If your feature changes what the whole match is doing, it probably belongs in game or match state.