summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDico Karssiens <dico.karssiens@gmail.com>2018-07-27 01:10:46 +0100
committerDico Karssiens <dico.karssiens@gmail.com>2018-07-27 01:10:46 +0100
commit963b65714c1abf5a8edb748fc99e4692db7e5bf5 (patch)
tree5f774f90d6d0f7794ea66b7a989de198346d9131
parentea7c27a7fd7c127920eb5e2aa8f2b2b7c921c607 (diff)
Start adding listeners as per RedstonerServer/Parcels
-rw-r--r--dicore3/core/src/main/java/io/dico/dicore/ListenerMarker.java19
-rw-r--r--dicore3/core/src/main/java/io/dico/dicore/Registrator.java38
-rw-r--r--dicore3/core/src/main/java/io/dico/dicore/RegistratorListener.java10
-rw-r--r--src/main/kotlin/io/dico/parcels2/Parcel.kt2
-rw-r--r--src/main/kotlin/io/dico/parcels2/command/ParcelCommands.kt8
-rw-r--r--src/main/kotlin/io/dico/parcels2/listener/ParcelEditListener.kt248
-rw-r--r--src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt14
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/MaterialExtensions.kt92
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/PlayerExtensions.kt2
9 files changed, 396 insertions, 37 deletions
diff --git a/dicore3/core/src/main/java/io/dico/dicore/ListenerMarker.java b/dicore3/core/src/main/java/io/dico/dicore/ListenerMarker.java
new file mode 100644
index 0000000..e3c0e90
--- /dev/null
+++ b/dicore3/core/src/main/java/io/dico/dicore/ListenerMarker.java
@@ -0,0 +1,19 @@
+package io.dico.dicore;
+
+import org.bukkit.event.EventPriority;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface ListenerMarker {
+
+ String[] events() default {};
+
+ EventPriority priority() default EventPriority.HIGHEST;
+
+ boolean ignoreCancelled() default true;
+}
diff --git a/dicore3/core/src/main/java/io/dico/dicore/Registrator.java b/dicore3/core/src/main/java/io/dico/dicore/Registrator.java
index 9977418..588fba8 100644
--- a/dicore3/core/src/main/java/io/dico/dicore/Registrator.java
+++ b/dicore3/core/src/main/java/io/dico/dicore/Registrator.java
@@ -11,10 +11,6 @@ import org.bukkit.plugin.EventExecutor;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.RegisteredListener;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
import java.lang.reflect.*;
import java.util.*;
import java.util.function.Consumer;
@@ -434,22 +430,6 @@ public final class Registrator {
// # Public types
// ############################################
- public interface IEventListener<T extends Event> extends Consumer<T> {
- @Override
- void accept(T event);
- }
-
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.FIELD)
- public @interface ListenerInfo {
-
- String[] events() default {};
-
- EventPriority priority() default EventPriority.HIGHEST;
-
- boolean ignoreCancelled() default true;
- }
-
public static class Registration extends RegisteredListener {
private final EventExecutor executor;
@@ -658,17 +638,17 @@ public final class Registrator {
fieldLoop:
for (Field f : fields) {
if (isStatic != Modifier.isStatic(f.getModifiers())
- || !f.isAnnotationPresent(ListenerInfo.class)) {
+ || !f.isAnnotationPresent(ListenerMarker.class)) {
continue;
}
- if (!IEventListener.class.isAssignableFrom(f.getType())) {
- handleListenerFieldError(new ListenerFieldError(f, "Field type cannot be assigned to IEventListener: " + f.getGenericType().getTypeName()));
+ if (!RegistratorListener.class.isAssignableFrom(f.getType())) {
+ handleListenerFieldError(new ListenerFieldError(f, "Field type cannot be assigned to RegistratorListener: " + f.getGenericType().getTypeName()));
continue;
}
Type eventType = null;
- if (f.getType() == IEventListener.class) {
+ if (f.getType() == RegistratorListener.class) {
Type[] typeArgs;
if (!(f.getGenericType() instanceof ParameterizedType)
@@ -681,7 +661,7 @@ public final class Registrator {
eventType = typeArgs[0];
} else {
- // field type is subtype of IEventListener.
+ // field type is subtype of RegistratorListener.
// TODO: link type arguments from field declaration (f.getGenericType()) to matching TypeVariables
Type[] interfaces = f.getType().getGenericInterfaces();
for (Type itf : interfaces) {
@@ -702,7 +682,7 @@ public final class Registrator {
continue;
}
- if (itfClass == IEventListener.class) {
+ if (itfClass == RegistratorListener.class) {
if (arguments == null || arguments.length != 1) {
// Log a warning or throw an exception
handleListenerFieldError(new ListenerFieldError(f, ""));
@@ -749,7 +729,7 @@ public final class Registrator {
Class<? extends Event> baseEventClass = (Class<? extends Event>) eventType;
- ListenerInfo anno = f.getAnnotation(ListenerInfo.class);
+ ListenerMarker anno = f.getAnnotation(ListenerMarker.class);
String[] eventClassNames = anno.events();
if (eventClassNames.length > 0) {
@@ -844,9 +824,9 @@ public final class Registrator {
private static final class ListenerFieldInfo {
final Class<? extends Event> eventClass;
final Consumer<? super Event> lambda;
- final ListenerInfo anno;
+ final ListenerMarker anno;
- ListenerFieldInfo(Class<? extends Event> eventClass, Consumer<? super Event> lambda, ListenerInfo anno) {
+ ListenerFieldInfo(Class<? extends Event> eventClass, Consumer<? super Event> lambda, ListenerMarker anno) {
this.eventClass = eventClass;
this.lambda = lambda;
this.anno = anno;
diff --git a/dicore3/core/src/main/java/io/dico/dicore/RegistratorListener.java b/dicore3/core/src/main/java/io/dico/dicore/RegistratorListener.java
new file mode 100644
index 0000000..99fe072
--- /dev/null
+++ b/dicore3/core/src/main/java/io/dico/dicore/RegistratorListener.java
@@ -0,0 +1,10 @@
+package io.dico.dicore;
+
+import org.bukkit.event.Event;
+
+import java.util.function.Consumer;
+
+public interface RegistratorListener<T extends Event> extends Consumer<T> {
+ @Override
+ void accept(T event);
+}
diff --git a/src/main/kotlin/io/dico/parcels2/Parcel.kt b/src/main/kotlin/io/dico/parcels2/Parcel.kt
index cd05fb3..4df60b1 100644
--- a/src/main/kotlin/io/dico/parcels2/Parcel.kt
+++ b/src/main/kotlin/io/dico/parcels2/Parcel.kt
@@ -90,6 +90,8 @@ class Parcel(val world: ParcelWorld, val pos: Vec2i) : ParcelData {
world.storage.setParcelAllowsInteractInventory(this, value)
data.allowInteractInventory = value
}
+
+ var hasBlockVisitors: Boolean = false; private set
}
class ParcelDataHolder : ParcelData {
diff --git a/src/main/kotlin/io/dico/parcels2/command/ParcelCommands.kt b/src/main/kotlin/io/dico/parcels2/command/ParcelCommands.kt
index bae138a..ac09e4a 100644
--- a/src/main/kotlin/io/dico/parcels2/command/ParcelCommands.kt
+++ b/src/main/kotlin/io/dico/parcels2/command/ParcelCommands.kt
@@ -36,12 +36,9 @@ class ParcelCommands(val plugin: ParcelsPlugin) : ICommandReceiver.Factory {
"and gives it to you",
shortVersion = "sets you up with a fresh, unclaimed parcel")
suspend fun WorldScope.cmdAuto(player: Player): Any? {
- logger.info("cmdAuto thread before await: ${Thread.currentThread().name}")
val numOwnedParcels = plugin.storage.getNumParcels(ParcelOwner(uuid = player.uuid)).await()
- logger.info("cmdAuto thread before await: ${Thread.currentThread().name}")
val limit = player.parcelLimit
-
if (numOwnedParcels >= limit) {
error("You have enough plots for now")
}
@@ -67,15 +64,12 @@ class ParcelCommands(val plugin: ParcelsPlugin) : ICommandReceiver.Factory {
shortVersion = "teleports you to parcels")
@RequireParameters(0)
suspend fun cmdHome(player: Player,
- @NamedParcelDefault(FIRST_OWNED) target: NamedParcelTarget): Any?
- {
+ @NamedParcelDefault(FIRST_OWNED) target: NamedParcelTarget): Any? {
if (player !== target.player && !player.hasParcelHomeOthers) {
error("You do not have permission to teleport to other people's parcels")
}
- logger.info("cmdHome thread before await: ${Thread.currentThread().name}")
val ownedParcelsResult = plugin.storage.getOwnedParcels(ParcelOwner(uuid = target.player.uuid)).await()
- logger.info("cmdHome thread after await: ${Thread.currentThread().name}")
val uuid = target.player.uuid
val ownedParcels = ownedParcelsResult
diff --git a/src/main/kotlin/io/dico/parcels2/listener/ParcelEditListener.kt b/src/main/kotlin/io/dico/parcels2/listener/ParcelEditListener.kt
new file mode 100644
index 0000000..357819b
--- /dev/null
+++ b/src/main/kotlin/io/dico/parcels2/listener/ParcelEditListener.kt
@@ -0,0 +1,248 @@
+package io.dico.parcels2.listener
+
+import gnu.trove.TLongCollection
+import io.dico.dicore.ListenerMarker
+import io.dico.dicore.RegistratorListener
+import io.dico.parcels2.Parcel
+import io.dico.parcels2.ParcelWorld
+import io.dico.parcels2.Worlds
+import io.dico.parcels2.util.hasBanBypass
+import io.dico.parcels2.util.hasBuildAnywhere
+import io.dico.parcels2.util.sendParcelMessage
+import io.dico.parcels2.util.uuid
+import org.bukkit.Material.*
+import org.bukkit.block.Biome
+import org.bukkit.block.Block
+import org.bukkit.block.data.type.Bed
+import org.bukkit.entity.Player
+import org.bukkit.event.EventPriority.NORMAL
+import org.bukkit.event.block.*
+import org.bukkit.event.entity.EntityExplodeEvent
+import org.bukkit.event.entity.ExplosionPrimeEvent
+import org.bukkit.event.player.PlayerInteractEvent
+import org.bukkit.event.player.PlayerMoveEvent
+import org.bukkit.inventory.InventoryHolder
+
+@Suppress("NOTHING_TO_INLINE")
+class ParcelEditListener(val worlds: Worlds) {
+ val entityTracker = ParcelEntityTracker()
+
+ private inline fun <T> T?.isNullOr(condition: T.() -> Boolean): Boolean = this == null || condition()
+ private inline fun <T> T?.isPresentAnd(condition: T.() -> Boolean): Boolean = this != null && condition()
+ private inline fun
+ fun Parcel?.canBuildN(user: Player) = isPresentAnd { canBuild(user) } || user.hasBuildAnywhere
+
+ /**
+ * Get the world and parcel that the block resides in
+ * wo is the world, ppa is the parcel
+ * ppa for possibly a parcel - it will be null if not in an existing parcel
+ * returns null if not in a registered parcel world
+ */
+ private fun getWoAndPPa(block: Block): Pair<ParcelWorld, Parcel?>? {
+ val world = worlds.getWorld(block.world) ?: return null
+ return world to world.parcelAt(block)
+ }
+
+ /*
+ * Prevents players from entering plots they are banned from
+ */
+ @ListenerMarker(priority = NORMAL)
+ val onPlayerMove = RegistratorListener<PlayerMoveEvent> l@{ event ->
+ val user = event.player
+ if (user.hasBanBypass) return@l
+ val parcel = worlds.getParcelAt(event.to) ?: return@l
+ if (parcel.isBanned(user.uuid)) {
+ worlds.getParcelAt(event.from)?.also {
+ user.teleport(it.homeLocation)
+ user.sendParcelMessage(nopermit = true, message = "You are banned from this parcel")
+ } ?: run { event.to = event.from }
+ }
+ }
+
+ /*
+ * Prevents players from breaking blocks outside of their parcels
+ * Prevents containers from dropping their contents when broken, if configured
+ */
+ @ListenerMarker(priority = NORMAL)
+ val onBlockBreak = RegistratorListener<BlockBreakEvent> l@{ event ->
+ val (wo, ppa) = getWoAndPPa(event.block) ?: return@l
+ if (!event.player.hasBuildAnywhere && ppa.isNullOr { !canBuild(event.player) }) {
+ event.isCancelled = true; return@l
+ }
+
+ if (!wo.options.dropEntityItems) {
+ val state = event.block.state
+ if (state is InventoryHolder) {
+ state.inventory.clear()
+ state.update()
+ }
+ }
+ }
+
+ /*
+ * Prevents players from placing blocks outside of their parcels
+ */
+ @ListenerMarker(priority = NORMAL)
+ val onBlockPlace = RegistratorListener<BlockBreakEvent> l@{ event ->
+ val (wo, ppa) = getWoAndPPa(event.block) ?: return@l
+ if (!event.player.hasBuildAnywhere && !ppa.isNullOr { !canBuild(event.player) }) {
+ event.isCancelled = true
+ }
+ }
+
+ /*
+ * Control pistons
+ */
+ @ListenerMarker(priority = NORMAL)
+ val onBlockPistonExtend = RegistratorListener<BlockPistonExtendEvent> l@{ event ->
+ checkPistonMovement(event, event.blocks)
+ }
+
+ @ListenerMarker(priority = NORMAL)
+ val onBlockPistonRetractEvent = RegistratorListener<BlockPistonRetractEvent> l@{ event ->
+ checkPistonMovement(event, event.blocks)
+ }
+
+ // Doing some unnecessary optimizations here..
+ //@formatter:off
+ private inline fun Column(x: Int, z: Int): Long = x.toLong() or (z.toLong().shl(32))
+
+ private inline val Long.columnX get() = and(0xFFFF_FFFFL).toInt()
+ private inline val Long.columnZ get() = ushr(32).and(0xFFFF_FFFFL).toInt()
+ private inline fun TLongCollection.forEachInline(block: (Long) -> Unit) = iterator().let { while (it.hasNext()) block(it.next()) }
+ //@formatter:on
+ private fun checkPistonMovement(event: BlockPistonEvent, blocks: List<Block>) {
+ val world = worlds.getWorld(event.block.world) ?: return
+ val direction = event.direction
+ val columns = gnu.trove.set.hash.TLongHashSet(blocks.size * 2)
+
+ blocks.forEach {
+ columns.add(Column(it.x, it.z))
+ it.getRelative(direction).let { columns.add(Column(it.x, it.z)) }
+ }
+
+ columns.forEachInline {
+ val ppa = world.parcelAt(it.columnX, it.columnZ)
+ if (ppa.isNullOr { hasBlockVisitors }) {
+ event.isCancelled = true
+ return
+ }
+ }
+ }
+
+ /*
+ * Prevents explosions if enabled by the configs for that world
+ */
+ @ListenerMarker(priority = NORMAL)
+ val onExplosionPrimeEvent = RegistratorListener<ExplosionPrimeEvent> l@{ event ->
+ val (wo, ppa) = getWoAndPPa(event.entity.location.block) ?: return@l
+ if (ppa?.hasBlockVisitors == true) {
+ event.radius = 0F; event.isCancelled = true
+ } else if (wo.options.disableExplosions) {
+ event.radius = 0F
+ }
+ }
+
+ /*
+ * Prevents creepers and tnt minecarts from exploding if explosions are disabled
+ */
+ @ListenerMarker(priority = NORMAL)
+ val onEntityExplodeEvent = RegistratorListener<EntityExplodeEvent> l@{ event ->
+ entityTracker.untrack(event.entity)
+ val world = worlds.getWorld(event.entity.world) ?: return@l
+ if (world.options.disableExplosions || world.parcelAt(event.entity).isPresentAnd { hasBlockVisitors }) {
+ event.isCancelled = true
+ }
+ }
+
+ /*
+ * Prevents creepers and tnt minecarts from exploding if explosions are disabled
+ */
+ @ListenerMarker(priority = NORMAL)
+ val onBlockFromToEvent = RegistratorListener<BlockFromToEvent> l@{ event ->
+ val (wo, ppa) = getWoAndPPa(event.toBlock) ?: return@l
+ if (ppa.isNullOr { hasBlockVisitors }) event.isCancelled = true
+ }
+
+ /*
+ * Prevents players from placing liquids, using flint and steel, changing redstone components,
+ * using inputs (unless allowed by the plot),
+ * and using items disabled in the configuration for that world.
+ * Prevents player from using beds in HELL or SKY biomes if explosions are disabled.
+ */
+ @Suppress("NON_EXHAUSTIVE_WHEN")
+ @ListenerMarker(priority = NORMAL)
+ val onPlayerInteractEvent = RegistratorListener<PlayerInteractEvent> l@{ event ->
+ val user = event.player
+ val world = worlds.getWorld(user.world) ?: return@l
+ val clickedBlock = event.clickedBlock
+ val parcel = clickedBlock?.let { world.parcelAt(it) }
+
+ if (!user.hasBuildAnywhere && parcel.isPresentAnd { isBanned(user.uuid) }) {
+ user.sendParcelMessage(nopermit = true, message = "You cannot interact with parcels you're banned from")
+ event.isCancelled = true; return@l
+ }
+
+ when (event.action) {
+ Action.RIGHT_CLICK_BLOCK -> when (clickedBlock.type) {
+ REPEATER,
+ COMPARATOR -> run {
+ if (!parcel.canBuildN(user)) {
+ event.isCancelled = true; return@l
+ }
+ }
+ LEVER,
+ STONE_BUTTON,
+ ANVIL,
+ TRAPPED_CHEST,
+ OAK_BUTTON, BIRCH_BUTTON, SPRUCE_BUTTON, JUNGLE_BUTTON, ACACIA_BUTTON, DARK_OAK_BUTTON,
+ OAK_FENCE_GATE, BIRCH_FENCE_GATE, SPRUCE_FENCE_GATE, JUNGLE_FENCE_GATE, ACACIA_FENCE_GATE, DARK_OAK_FENCE_GATE,
+ OAK_DOOR, BIRCH_DOOR, SPRUCE_DOOR, JUNGLE_DOOR, ACACIA_DOOR, DARK_OAK_DOOR,
+ OAK_TRAPDOOR, BIRCH_TRAPDOOR, SPRUCE_TRAPDOOR, JUNGLE_TRAPDOOR, ACACIA_TRAPDOOR, DARK_OAK_TRAPDOOR
+ -> run {
+ if (!user.hasBuildAnywhere && !parcel.isNullOr { canBuild(user) || allowInteractInputs }) {
+ user.sendParcelMessage(nopermit = true, message = "You cannot use inputs in this parcel")
+ event.isCancelled = true; return@l
+ }
+ }
+
+ WHITE_BED, ORANGE_BED, MAGENTA_BED, LIGHT_BLUE_BED, YELLOW_BED, LIME_BED, PINK_BED, GRAY_BED, LIGHT_GRAY_BED, CYAN_BED, PURPLE_BED, BLUE_BED, BROWN_BED, GREEN_BED, RED_BED, BLACK_BED
+ -> run {
+ if (world.options.disableExplosions) {
+ val bed = clickedBlock.blockData as Bed
+ val head = if (bed == Bed.Part.FOOT) clickedBlock.getRelative(bed.facing) else clickedBlock
+ when (head.biome) {
+ Biome.NETHER, Biome.THE_END -> run {
+ user.sendParcelMessage(nopermit = true, message = "You cannot use this bed because it would explode")
+ event.isCancelled = true; return@l
+ }
+ }
+
+ }
+
+ }
+ }
+
+ Action.RIGHT_CLICK_AIR -> if (event.hasItem()) {
+ val item = event.item.type
+ if (world.options.blockedItems.contains(item)) {
+ user.sendParcelMessage(nopermit = true, message = "You cannot use this bed because it would explode")
+ event.isCancelled = true; return@l
+ }
+
+ if (!parcel.canBuildN(user)) {
+ when (item) {
+ LAVA_BUCKET, WATER_BUCKET, BUCKET, FLINT_AND_STEEL -> event.isCancelled = true
+ }
+ }
+ }
+
+
+ Action.PHYSICAL -> if (!user.hasBuildAnywhere && !parcel.isPresentAnd { canBuild(user) || allowInteractInputs }) {
+ event.isCancelled = true; return@l
+ }
+ }
+ }
+
+
+} \ No newline at end of file
diff --git a/src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt b/src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt
new file mode 100644
index 0000000..fb94b8b
--- /dev/null
+++ b/src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt
@@ -0,0 +1,14 @@
+package io.dico.parcels2.listener
+
+import io.dico.parcels2.Parcel
+import org.bukkit.entity.Entity
+
+class ParcelEntityTracker {
+ val map = mutableMapOf<Entity, Parcel>()
+
+ fun untrack(entity: Entity) {
+ map.remove(entity)
+ }
+
+
+} \ No newline at end of file
diff --git a/src/main/kotlin/io/dico/parcels2/util/MaterialExtensions.kt b/src/main/kotlin/io/dico/parcels2/util/MaterialExtensions.kt
new file mode 100644
index 0000000..5cfcb47
--- /dev/null
+++ b/src/main/kotlin/io/dico/parcels2/util/MaterialExtensions.kt
@@ -0,0 +1,92 @@
+package io.dico.parcels2.util
+
+import org.bukkit.Material
+import org.bukkit.Material.*
+
+/*
+colors:
+WHITE_$,
+ORANGE_$,
+MAGENTA_$,
+LIGHT_BLUE_$,
+YELLOW_$,
+LIME_$,
+PINK_$,
+GRAY_$,
+LIGHT_GRAY_$,
+CYAN_$,
+PURPLE_$,
+BLUE_$,
+BROWN_$,
+GREEN_$,
+RED_$,
+BLACK_$,
+
+wood:
+OAK_$,
+BIRCH_$,
+SPRUCE_$,
+JUNGLE_$,
+ACACIA_$,
+DARK_OAK_$,
+ */
+
+val Material.isBed get() = when(this) {
+ WHITE_BED,
+ ORANGE_BED,
+ MAGENTA_BED,
+ LIGHT_BLUE_BED,
+ YELLOW_BED,
+ LIME_BED,
+ PINK_BED,
+ GRAY_BED,
+ LIGHT_GRAY_BED,
+ CYAN_BED,
+ PURPLE_BED,
+ BLUE_BED,
+ BROWN_BED,
+ GREEN_BED,
+ RED_BED,
+ BLACK_BED -> true
+ else -> false
+}
+
+val Material.isWoodDoor get() = when(this) {
+ OAK_DOOR,
+ BIRCH_DOOR,
+ SPRUCE_DOOR,
+ JUNGLE_DOOR,
+ ACACIA_DOOR,
+ DARK_OAK_DOOR -> true
+ else -> false
+}
+
+val Material.isWoodTrapdoor get() = when(this) {
+ OAK_TRAPDOOR,
+ BIRCH_TRAPDOOR,
+ SPRUCE_TRAPDOOR,
+ JUNGLE_TRAPDOOR,
+ ACACIA_TRAPDOOR,
+ DARK_OAK_TRAPDOOR -> true
+ else -> false
+}
+
+val Material.isWoodFenceGate get() = when(this) {
+ OAK_FENCE_GATE,
+ BIRCH_FENCE_GATE,
+ SPRUCE_FENCE_GATE,
+ JUNGLE_FENCE_GATE,
+ ACACIA_FENCE_GATE,
+ DARK_OAK_FENCE_GATE -> true
+ else -> false
+}
+
+val Material.isWoodButton get() = when(this) {
+ OAK_BUTTON,
+ BIRCH_BUTTON,
+ SPRUCE_BUTTON,
+ JUNGLE_BUTTON,
+ ACACIA_BUTTON,
+ DARK_OAK_BUTTON -> true
+ else -> false
+}
diff --git a/src/main/kotlin/io/dico/parcels2/util/PlayerExtensions.kt b/src/main/kotlin/io/dico/parcels2/util/PlayerExtensions.kt
index 4953e8a..9054e3f 100644
--- a/src/main/kotlin/io/dico/parcels2/util/PlayerExtensions.kt
+++ b/src/main/kotlin/io/dico/parcels2/util/PlayerExtensions.kt
@@ -9,8 +9,8 @@ import org.bukkit.plugin.java.JavaPlugin
inline val OfflinePlayer.uuid get() = uniqueId
inline val Player.hasBanBypass get() = hasPermission("parcels.admin.bypass.ban")
-inline val Player.hasBuildAnywhere get() = hasPermission("parcels.admin.bypass.build")
inline val Player.hasGamemodeBypass get() = hasPermission("parcels.admin.bypass.gamemode")
+inline val Player.hasBuildAnywhere get() = hasPermission("parcels.admin.bypass.build")
inline val Player.hasAdminManage get() = hasPermission("parcels.admin.manage")
inline val Player.hasParcelHomeOthers get() = hasPermission("parcels.command.home.others")
inline val Player.hasRandomSpecific get() = hasPermission("parcels.command.random.specific")