--- name: dominion-addon-dev description: >- Develop Dominion addon plugins using the DominionAPI. Use when creating new Dominion addon plugins, writing code that interacts with the Dominion land-claim system, listening to Dominion events, operating on dominion/group/member data via Providers, registering custom flags, or checking privilege/environment flags within dominions. Also use when setting up Gradle/Maven build files for DominionAPI dependency, creating plugin.yml for Dominion addons, or debugging Dominion API integration issues. compatibility: - DominionProtect --- # Dominion Addon Development Skill You are an expert developer for **Dominion** addon plugins (Minecraft Paper/Spigot). Dominion is a land-claim protection plugin; addons extend it using the **DominionAPI**. ## Key References - **JavaDoc**: https://lunadeermc.github.io/DominionAPI/ - **Documentation**: https://github.com/LunaDeerMC/DominionDocs - **API Reference**: Load `references/dominion-api-reference.md` for complete API details. ## Project Setup ### Gradle (Kotlin DSL) — Recommended ```kotlin repositories { mavenLocal() mavenCentral() maven("https://oss.sonatype.org/content/groups/public") maven("https://repo.papermc.io/repository/maven-public/") maven("https://jitpack.io") } dependencies { compileOnly("io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT") compileOnly("cn.lunadeer:DominionAPI:4.7.3") } ``` ### Gradle (Groovy) ```groovy dependencies { compileOnly 'cn.lunadeer:DominionAPI:4.7.3' } ``` ### Maven ```xml cn.lunadeer DominionAPI 4.7.3 provided ``` ### plugin.yml Requirements The addon's `plugin.yml` MUST include `Dominion` in the `depend` list: ```yaml name: YourAddonPlugin version: '1.0.0' main: com.example.yourplugin.YourPlugin api-version: '1.20' depend: - Dominion ``` Set `folia-supported: true` if your addon supports Folia. ## Getting the API Instance Always obtain `DominionAPI` in `onEnable()` after verifying the Dominion plugin is loaded: ```java import cn.lunadeer.dominion.api.DominionAPI; public final class YourPlugin extends JavaPlugin { private DominionAPI dominionAPI; @Override public void onEnable() { if (Bukkit.getPluginManager().isPluginEnabled("Dominion")) { dominionAPI = DominionAPI.getInstance(); getLogger().info("DominionAPI loaded successfully"); } else { throw new IllegalStateException("Dominion plugin is not enabled."); } getServer().getPluginManager().registerEvents(this, this); } } ``` ## Core API Patterns ### 1. Query Dominion Data (Read-Only) Use `DominionAPI` methods for all read operations — they read from cache and are safe on any thread. ```java // Get dominion at a location DominionDTO dom = dominionAPI.getDominion(player.getLocation()); // Get dominion by name or ID DominionDTO dom = dominionAPI.getDominion("myDominion"); DominionDTO dom = dominionAPI.getDominion(42); // Get player's current dominion DominionDTO current = dominionAPI.getPlayerCurrentDominion(player); // Get all dominions owned by a player List owned = dominionAPI.getAllDominionsOfPlayer(player.getUniqueId()); // Get player info PlayerDTO playerDTO = dominionAPI.getPlayer(player.getUniqueId()); // Get member in a dominion MemberDTO member = dominionAPI.getMember(dom, player); // Get group of a member GroupDTO group = dominionAPI.getGroup(member); ``` ### 2. Check Flags ```java // Check privilege flag (with player notification on denial) boolean canBuild = dominionAPI.checkPrivilegeFlag(location, priFlag, player); // Check privilege flag silently (no notification) boolean canBuild = dominionAPI.checkPrivilegeFlagSilence(location, priFlag, player); // Check environment flag boolean hasFire = dominionAPI.checkEnvironmentFlag(location, envFlag); ``` **Important (since 4.5.0)**: Always prefer the `Location`-based overloads over `DominionDTO`-based overloads. The `Location`-based methods also check world-wide flags. ### 3. Modify Data via Providers All data modifications MUST go through Providers to ensure consistency and trigger events. Provider methods are asynchronous and return `CompletableFuture`. The `operator` parameter controls permission checks: - Pass a `Player` to enforce permission checks - Pass `Bukkit.getConsoleSender()` to bypass permission checks (console-level access) ```java // DominionProvider — create, delete, rename, resize, transfer dominions DominionProvider domProvider = dominionAPI.getDominionProvider(); CompletableFuture future = domProvider.createDominion( Bukkit.getConsoleSender(), // operator "newDominion", // name playerUUID, // owner world, // world new CuboidDTO(x1,y1,z1, x2,y2,z2), // boundaries null, // parent (null = top-level) false // skipEconomy ); DominionDTO created = future.get(); // null means failure // GroupProvider — create, delete, rename groups; manage group members and flags GroupProvider groupProvider = dominionAPI.getGroupProvider(); // MemberProvider — add, remove members; set member flags MemberProvider memberProvider = dominionAPI.getMemberProvider(); ``` ### 4. Listen to Dominion Events Register listeners the standard Bukkit way. All events extend `CallableEvent`. ```java import cn.lunadeer.dominion.events.dominion.DominionCreateEvent; import cn.lunadeer.dominion.events.member.MemberAddedEvent; public class MyListener implements Listener { @EventHandler public void onDominionCreate(DominionCreateEvent event) { if (event.isCancelled()) return; // React to dominion creation } @EventHandler public void onMemberAdded(MemberAddedEvent event) { if (event.isCancelled()) return; // Use callback to get the result after data is processed event.afterAdded(memberDTO -> { if (memberDTO == null) return; // addition failed DominionDTO dominion = event.getDominion(); Player player = Bukkit.getPlayer(memberDTO.getPlayerUUID()); if (player != null) { player.teleportAsync(dominion.getTpLocation()); } }); } } ``` **Key event categories:** | Package | Events | |---------|--------| | `cn.lunadeer.dominion.events` | `PlayerMoveInDominionEvent`, `PlayerMoveOutDominionEvent`, `PlayerCrossDominionBorderEvent`, `FlagRegisterEvent` | | `cn.lunadeer.dominion.events.dominion` | `DominionCreateEvent`, `DominionDeleteEvent` | | `cn.lunadeer.dominion.events.dominion.modify` | `DominionRenameEvent`, `DominionSizeChangeEvent`, `DominionSetEnvFlagEvent`, `DominionSetGuestFlagEvent`, `DominionSetMapColorEvent`, `DominionSetMessageEvent`, `DominionSetTpLocationEvent`, `DominionTransferEvent` | | `cn.lunadeer.dominion.events.group` | `GroupCreateEvent`, `GroupDeleteEvent`, `GroupRenamedEvent`, `GroupSetFlagEvent`, `GroupAddMemberEvent`, `GroupRemoveMemberEvent` | | `cn.lunadeer.dominion.events.member` | `MemberAddedEvent`, `MemberRemovedEvent`, `MemberSetFlagEvent` | **Data operation events** (like `DominionCreateEvent`, `MemberAddedEvent`) process the actual data **after** all listeners run. Use provided callback methods (e.g., `event.afterAdded(...)`) to access results. ### 5. Register Custom Flags (since 4.7.0) Two flag types exist: - **`EnvFlag`** — environment flags (not player-specific, e.g., weather control) - **`PriFlag`** — privilege flags (player-specific, e.g., can-build) ```java import cn.lunadeer.dominion.api.dtos.flag.EnvFlag; import cn.lunadeer.dominion.api.dtos.flag.PriFlag; import cn.lunadeer.dominion.api.dtos.flag.Flags; // Define custom flags public static EnvFlag NO_RAIN = new EnvFlag( "no_rain", // unique flag_name (no spaces) "No Rain", // display_name "Prevents rain in this dominion.", // description false, // default_value true, // enabled Material.SUNFLOWER // CUI material icon ); public static PriFlag CUSTOM_ACTION = new PriFlag( "custom_action", // unique flag_name (no spaces) "Custom Action", // display_name "Allows custom action in dominion.", // description false, // default_value true, // enabled Material.RED_BED // CUI material icon ); // Register and apply in onEnable() Flags.registerEnvFlag(NO_RAIN); Flags.registerPriFlag(CUSTOM_ACTION); Flags.applyNewCustomFlags(); // Must call after registration ``` ## DTO Quick Reference | DTO | Key Methods | |-----|------------| | `DominionDTO` | `getId()`, `getName()`, `getOwner()`, `getWorld()`, `getCuboid()`, `getTpLocation()`, `getEnvFlagValue(flag)`, `getGuestFlagValue(flag)`, `getGroups()`, `getMembers()`, `getParentDomId()`, `getJoinMessage()`, `getLeaveMessage()` | | `PlayerDTO` | `getId()`, `getUuid()`, `getLastKnownName()`, `getSkinUrl()` | | `MemberDTO` | `getId()`, `getPlayerUUID()`, `getDomID()`, `getGroupId()`, `getFlagValue(flag)`, `getPlayer()` | | `GroupDTO` | `getId()`, `getDomID()`, `getNamePlain()`, `getNameRaw()`, `getFlagValue(flag)`, `getMembers()` | | `CuboidDTO` | `getPos1()`, `getPos2()`, `x1()..z2()`, `xLength()`, `yLength()`, `zLength()`, `getSquare()`, `getVolume()`, `contain(...)`, `intersectWith(...)` | ## Rules 1. DominionAPI is a `compileOnly` / `provided` dependency — never shade it into your jar. 2. Always verify `Dominion` is enabled before calling `DominionAPI.getInstance()`. 3. Use `Location`-based flag checks over `DominionDTO`-based ones (since 4.5.0) to include world-wide flags. 4. All Provider operations are async (`CompletableFuture`) — handle appropriately. 5. Event callbacks (e.g., `afterAdded`) run after actual data processing — use them for post-operation logic. 6. Custom flag names must be unique and contain no spaces. 7. Call `Flags.applyNewCustomFlags()` after registering all custom flags. 8. Never modify DTO data directly — always use Providers for writes. 9. Paper API 1.20.1+ is the minimum supported version. 10. The plugin must declare `depend: [Dominion]` in `plugin.yml`.