summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDico <dico.karssiens@gmail.com>2018-09-23 20:42:14 +0100
committerDico <dico.karssiens@gmail.com>2018-09-23 20:42:14 +0100
commitb0d1fab486e04a415f971bb02f5ba76b83a62351 (patch)
tree0ebdb67ef24142a69c97dc945e4f76b0e26353b9
parent535df42c54bd95960ea7e1bd1a81fd6012c24f11 (diff)
Do some work on interactables
-rw-r--r--src/main/kotlin/io/dico/parcels2/AddedData.kt48
-rw-r--r--src/main/kotlin/io/dico/parcels2/Interactable.kt92
-rw-r--r--src/main/kotlin/io/dico/parcels2/Parcel.kt5
-rw-r--r--src/main/kotlin/io/dico/parcels2/command/CommandsParcelOptions.kt3
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/GlobalAddedDataManagerImpl.kt4
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt59
-rw-r--r--src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt75
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/Backing.kt4
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/DataConverters.kt38
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/Storage.kt8
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt33
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/exposed/IdTables.kt4
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/exposed/ListTables.kt11
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/migration/plotme/PlotmeMigration.kt2
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/UUIDUtil.kt6
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/ext/Material.kt4
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/ext/Math.kt5
-rw-r--r--todo.md2
18 files changed, 232 insertions, 171 deletions
diff --git a/src/main/kotlin/io/dico/parcels2/AddedData.kt b/src/main/kotlin/io/dico/parcels2/AddedData.kt
index 9835950..a23b36e 100644
--- a/src/main/kotlin/io/dico/parcels2/AddedData.kt
+++ b/src/main/kotlin/io/dico/parcels2/AddedData.kt
@@ -1,7 +1,12 @@
package io.dico.parcels2
+import io.dico.parcels2.AddedStatus.*
import org.bukkit.OfflinePlayer
+enum class AddedStatus {
+ DEFAULT, ALLOWED, BANNED;
+}
+
typealias StatusKey = PlayerProfile.Real
typealias MutableAddedDataMap = MutableMap<StatusKey, AddedStatus>
typealias AddedDataMap = Map<StatusKey, AddedStatus>
@@ -11,20 +16,20 @@ fun MutableAddedDataMap(): MutableAddedDataMap = hashMapOf()
interface AddedData {
val addedMap: AddedDataMap
- var addedStatusOfStar: AddedStatus
+ var statusOfStar: AddedStatus
- fun getAddedStatus(key: StatusKey): AddedStatus
- fun setAddedStatus(key: StatusKey, status: AddedStatus): Boolean
+ fun getStatus(key: StatusKey): AddedStatus
+ fun setStatus(key: StatusKey, status: AddedStatus): Boolean
- fun compareAndSetAddedStatus(key: StatusKey, expect: AddedStatus, status: AddedStatus): Boolean =
- getAddedStatus(key) == expect && setAddedStatus(key, status)
+ fun casStatus(key: StatusKey, expect: AddedStatus, status: AddedStatus): Boolean =
+ getStatus(key) == expect && setStatus(key, status)
- fun isAllowed(key: StatusKey) = getAddedStatus(key) == AddedStatus.ALLOWED
- fun allow(key: StatusKey) = setAddedStatus(key, AddedStatus.ALLOWED)
- fun disallow(key: StatusKey) = compareAndSetAddedStatus(key, AddedStatus.ALLOWED, AddedStatus.DEFAULT)
- fun isBanned(key: StatusKey) = getAddedStatus(key) == AddedStatus.BANNED
- fun ban(key: StatusKey) = setAddedStatus(key, AddedStatus.BANNED)
- fun unban(key: StatusKey) = compareAndSetAddedStatus(key, AddedStatus.BANNED, AddedStatus.DEFAULT)
+ fun isAllowed(key: StatusKey) = getStatus(key) == ALLOWED
+ fun allow(key: StatusKey) = setStatus(key, ALLOWED)
+ fun disallow(key: StatusKey) = casStatus(key, ALLOWED, DEFAULT)
+ fun isBanned(key: StatusKey) = getStatus(key) == BANNED
+ fun ban(key: StatusKey) = setStatus(key, BANNED)
+ fun unban(key: StatusKey) = casStatus(key, BANNED, DEFAULT)
fun isAllowed(player: OfflinePlayer) = isAllowed(player.statusKey)
fun allow(player: OfflinePlayer) = allow(player.statusKey)
@@ -34,29 +39,20 @@ interface AddedData {
fun unban(player: OfflinePlayer) = unban(player.statusKey)
}
-inline val OfflinePlayer.statusKey get() = PlayerProfile.nameless(this)
+inline val OfflinePlayer.statusKey: StatusKey
+ get() = PlayerProfile.nameless(this)
open class AddedDataHolder(override var addedMap: MutableAddedDataMap = MutableAddedDataMap()) : AddedData {
- override var addedStatusOfStar: AddedStatus = AddedStatus.DEFAULT
+ override var statusOfStar: AddedStatus = DEFAULT
- override fun getAddedStatus(key: StatusKey): AddedStatus = addedMap.getOrDefault(key, addedStatusOfStar)
+ override fun getStatus(key: StatusKey): AddedStatus = addedMap.getOrDefault(key, statusOfStar)
- override fun setAddedStatus(key: StatusKey, status: AddedStatus): Boolean {
- return if (status.isDefault) addedMap.remove(key) != null
+ override fun setStatus(key: StatusKey, status: AddedStatus): Boolean {
+ return if (status == DEFAULT) addedMap.remove(key) != null
else addedMap.put(key, status) != status
}
}
-enum class AddedStatus {
- DEFAULT,
- ALLOWED,
- BANNED;
-
- inline val isDefault get() = this == DEFAULT
- inline val isAllowed get() = this == ALLOWED
- inline val isBanned get() = this == BANNED
-}
-
interface GlobalAddedData : AddedData {
val owner: PlayerProfile
}
diff --git a/src/main/kotlin/io/dico/parcels2/Interactable.kt b/src/main/kotlin/io/dico/parcels2/Interactable.kt
index f1beac5..60539aa 100644
--- a/src/main/kotlin/io/dico/parcels2/Interactable.kt
+++ b/src/main/kotlin/io/dico/parcels2/Interactable.kt
@@ -1,14 +1,17 @@
package io.dico.parcels2
-import io.dico.parcels2.util.ext.findWoodKindPrefixedMaterials
+import io.dico.parcels2.util.ext.getMaterialsWithWoodTypePrefix
import org.bukkit.Material
+import java.lang.IllegalArgumentException
import java.util.EnumMap
class Interactables
-private constructor(val id: Int,
- val name: String,
- val interactableByDefault: Boolean,
- vararg val materials: Material) {
+private constructor(
+ val id: Int,
+ val name: String,
+ val interactableByDefault: Boolean,
+ vararg val materials: Material
+) {
companion object {
val classesById: List<Interactables>
@@ -22,35 +25,64 @@ private constructor(val id: Int,
listedMaterials = EnumMap(mapOf(*array.flatMap { clazz -> clazz.materials.map { it to clazz.id } }.toTypedArray()))
}
+ operator fun get(material: Material): Interactables? {
+ val id = listedMaterials[material] ?: return null
+ return classesById[id]
+ }
+
+ operator fun get(name: String): Interactables {
+ return classesByName[name] ?: throw IllegalArgumentException("Interactables class does not exist: $name")
+ }
+
+ operator fun get(id: Int): Interactables {
+ return classesById[id]
+ }
+
private fun getClassesArray() = run {
var id = 0
@Suppress("UNUSED_CHANGED_VALUE")
arrayOf(
- Interactables(id++, "button", true,
+ Interactables(
+ id++, "buttons", true,
Material.STONE_BUTTON,
- *findWoodKindPrefixedMaterials("BUTTON")
+ *getMaterialsWithWoodTypePrefix("BUTTON")
),
- Interactables(id++, "lever", true,
- Material.LEVER),
+ Interactables(
+ id++, "levers", true,
+ Material.LEVER
+ ),
- Interactables(id++, "pressure_plate", true,
+ Interactables(
+ id++, "pressure_plates", true,
Material.STONE_PRESSURE_PLATE,
- *findWoodKindPrefixedMaterials("PRESSURE_PLATE"),
+ *getMaterialsWithWoodTypePrefix("PRESSURE_PLATE"),
Material.HEAVY_WEIGHTED_PRESSURE_PLATE,
- Material.LIGHT_WEIGHTED_PRESSURE_PLATE),
+ Material.LIGHT_WEIGHTED_PRESSURE_PLATE
+ ),
- Interactables(id++, "redstone_components", false,
+ Interactables(
+ id++, "redstone", false,
Material.COMPARATOR,
- Material.REPEATER),
+ Material.REPEATER
+ ),
- Interactables(id++, "containers", false,
+ Interactables(
+ id++, "containers", false,
Material.CHEST,
Material.TRAPPED_CHEST,
Material.DISPENSER,
Material.DROPPER,
Material.HOPPER,
- Material.FURNACE)
+ Material.FURNACE
+ ),
+
+ Interactables(
+ id++, "gates", true,
+ *getMaterialsWithWoodTypePrefix("DOOR"),
+ *getMaterialsWithWoodTypePrefix("TRAPDOOR"),
+ *getMaterialsWithWoodTypePrefix("FENCE_GATE")
+ )
)
}
@@ -58,6 +90,27 @@ private constructor(val id: Int,
}
+val Parcel?.effectiveInteractableConfig: InteractableConfiguration
+ get() = this?.interactableConfig ?: pathInteractableConfig
+
+val pathInteractableConfig: InteractableConfiguration = run {
+ val data = BitmaskInteractableConfiguration().apply {
+ Interactables.classesById.forEach {
+ setInteractable(it, false)
+ }
+ }
+ object : InteractableConfiguration by data {
+ override fun setInteractable(clazz: Interactables, interactable: Boolean) =
+ throw IllegalStateException("pathInteractableConfig is immutable")
+
+ override fun clear() =
+ throw IllegalStateException("pathInteractableConfig is immutable")
+
+ override fun copyFrom(other: InteractableConfiguration) =
+ throw IllegalStateException("pathInteractableConfig is immutable")
+ }
+}
+
interface InteractableConfiguration {
val interactableClasses: List<Interactables> get() = Interactables.classesById.filter { isInteractable(it) }
fun isInteractable(material: Material): Boolean
@@ -67,8 +120,13 @@ interface InteractableConfiguration {
fun copyFrom(other: InteractableConfiguration) {
Interactables.classesById.forEach { setInteractable(it, other.isInteractable(it)) }
}
+
+ operator fun invoke(material: Material) = isInteractable(material)
+ operator fun invoke(className: String) = isInteractable(Interactables[className])
}
+fun InteractableConfiguration.isInteractable(clazz: Interactables?) = clazz != null && isInteractable(clazz)
+
class BitmaskInteractableConfiguration : InteractableConfiguration {
val bitmaskArray = IntArray((Interactables.classesById.size + 31) / 32)
@@ -98,7 +156,7 @@ class BitmaskInteractableConfiguration : InteractableConfiguration {
override fun clear(): Boolean {
var change = false
for (i in bitmaskArray.indices) {
- change = change || bitmaskArray[i] != 0
+ if (!change && bitmaskArray[i] != 0) change = true
bitmaskArray[i] = 0
}
return change
diff --git a/src/main/kotlin/io/dico/parcels2/Parcel.kt b/src/main/kotlin/io/dico/parcels2/Parcel.kt
index bdf4ff9..2c56627 100644
--- a/src/main/kotlin/io/dico/parcels2/Parcel.kt
+++ b/src/main/kotlin/io/dico/parcels2/Parcel.kt
@@ -45,9 +45,6 @@ interface ParcelData : AddedData {
fun canBuild(player: OfflinePlayer, checkAdmin: Boolean = true, checkGlobal: Boolean = true): Boolean
- var allowInteractInputs: Boolean
- var allowInteractInventory: Boolean
-
fun isOwner(uuid: UUID): Boolean {
return owner?.uuid == uuid
}
@@ -66,8 +63,6 @@ class ParcelDataHolder(addedMap: MutableAddedDataMap = mutableMapOf())
|| owner.let { it != null && it.matches(player, allowNameMatch = false) }
|| (checkAdmin && player is Player && player.hasBuildAnywhere)
- override var allowInteractInputs = true
- override var allowInteractInventory = true
override var interactableConfig: InteractableConfiguration = BitmaskInteractableConfiguration()
}
diff --git a/src/main/kotlin/io/dico/parcels2/command/CommandsParcelOptions.kt b/src/main/kotlin/io/dico/parcels2/command/CommandsParcelOptions.kt
index c77686e..b46e972 100644
--- a/src/main/kotlin/io/dico/parcels2/command/CommandsParcelOptions.kt
+++ b/src/main/kotlin/io/dico/parcels2/command/CommandsParcelOptions.kt
@@ -11,6 +11,7 @@ import org.bukkit.entity.Player
import kotlin.reflect.KMutableProperty
class CommandsParcelOptions(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
+ /* TODO options
@Cmd("inputs")
@Desc("Sets whether players who are not allowed to",
"build here can use levers, buttons,",
@@ -28,7 +29,7 @@ class CommandsParcelOptions(plugin: ParcelsPlugin) : AbstractParcelCommands(plug
@RequireParameters(0)
fun ParcelScope.cmdInventory(player: Player, enabled: Boolean?): Any? {
return runOptionCommand(player, Parcel::allowInteractInventory, enabled, "interaction with inventories")
- }
+ }*/
private inline val Boolean.enabledWord get() = if (this) "enabled" else "disabled"
private fun ParcelScope.runOptionCommand(player: Player,
diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/GlobalAddedDataManagerImpl.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/GlobalAddedDataManagerImpl.kt
index 49ab71f..ad7048c 100644
--- a/src/main/kotlin/io/dico/parcels2/defaultimpl/GlobalAddedDataManagerImpl.kt
+++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/GlobalAddedDataManagerImpl.kt
@@ -20,12 +20,12 @@ class GlobalAddedDataManagerImpl(val plugin: ParcelsPlugin) : GlobalAddedDataMan
private inline var data get() = addedMap; set(value) = run { addedMap = value }
private inline val isEmpty get() = data === emptyData
- override fun setAddedStatus(key: StatusKey, status: AddedStatus): Boolean {
+ override fun setStatus(key: StatusKey, status: AddedStatus): Boolean {
if (isEmpty) {
if (status == AddedStatus.DEFAULT) return false
data = mutableMapOf()
}
- return super.setAddedStatus(key, status).alsoIfTrue {
+ return super.setStatus(key, status).alsoIfTrue {
plugin.storage.setGlobalAddedStatus(owner, key, status)
}
}
diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt
index 59e84f4..d392a8f 100644
--- a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt
+++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt
@@ -9,9 +9,11 @@ import org.bukkit.OfflinePlayer
import org.joda.time.DateTime
import java.util.concurrent.atomic.AtomicInteger
-class ParcelImpl(override val world: ParcelWorld,
- override val x: Int,
- override val z: Int) : Parcel, ParcelId {
+class ParcelImpl(
+ override val world: ParcelWorld,
+ override val x: Int,
+ override val z: Int
+) : Parcel, ParcelId {
override val id: ParcelId = this
override val pos get() = Vec2i(x, z)
override var data: ParcelDataHolder = ParcelDataHolder(); private set
@@ -34,7 +36,7 @@ class ParcelImpl(override val world: ParcelWorld,
}
override val addedMap: AddedDataMap get() = data.addedMap
- override fun getAddedStatus(key: StatusKey) = data.getAddedStatus(key)
+ override fun getStatus(key: StatusKey) = data.getStatus(key)
override fun isBanned(key: StatusKey) = data.isBanned(key)
override fun isAllowed(key: StatusKey) = data.isAllowed(key)
override fun canBuild(player: OfflinePlayer, checkAdmin: Boolean, checkGlobal: Boolean): Boolean {
@@ -42,9 +44,9 @@ class ParcelImpl(override val world: ParcelWorld,
|| checkGlobal && world.globalAddedData[owner ?: return false].isAllowed(player)
}
- override var addedStatusOfStar: AddedStatus
- get() = data.addedStatusOfStar
- set(value) = run { setAddedStatus(PlayerProfile.Star, value) }
+ override var statusOfStar: AddedStatus
+ get() = data.statusOfStar
+ set(value) = run { setStatus(PlayerProfile.Star, value) }
val globalAddedMap: AddedDataMap? get() = owner?.let { world.globalAddedData[it].addedMap }
@@ -69,28 +71,12 @@ class ParcelImpl(override val world: ParcelWorld,
}
}
- override fun setAddedStatus(key: StatusKey, status: AddedStatus): Boolean {
- return data.setAddedStatus(key, status).alsoIfTrue {
+ override fun setStatus(key: StatusKey, status: AddedStatus): Boolean {
+ return data.setStatus(key, status).alsoIfTrue {
world.storage.setParcelPlayerStatus(this, key, status)
}
}
- override var allowInteractInputs: Boolean
- get() = data.allowInteractInputs
- set(value) {
- if (data.allowInteractInputs == value) return
- world.storage.setParcelAllowsInteractInputs(this, value)
- data.allowInteractInputs = value
- }
-
- override var allowInteractInventory: Boolean
- get() = data.allowInteractInventory
- set(value) {
- if (data.allowInteractInventory == value) return
- world.storage.setParcelAllowsInteractInventory(this, value)
- data.allowInteractInventory = value
- }
-
private var _interactableConfig: InteractableConfiguration? = null
override var interactableConfig: InteractableConfiguration
get() {
@@ -99,13 +85,15 @@ class ParcelImpl(override val world: ParcelWorld,
override fun isInteractable(material: Material): Boolean = data.interactableConfig.isInteractable(material)
override fun isInteractable(clazz: Interactables): Boolean = data.interactableConfig.isInteractable(clazz)
- override fun setInteractable(clazz: Interactables, interactable: Boolean): Boolean = data.interactableConfig.setInteractable(clazz, interactable).alsoIfTrue {
- // TODO update storage
- }
+ override fun setInteractable(clazz: Interactables, interactable: Boolean): Boolean =
+ data.interactableConfig.setInteractable(clazz, interactable).alsoIfTrue {
+ // TODO update storage
+ }
- override fun clear(): Boolean = data.interactableConfig.clear().alsoIfTrue {
- // TODO update storage
- }
+ override fun clear(): Boolean =
+ data.interactableConfig.clear().alsoIfTrue {
+ // TODO update storage
+ }
}
}
return _interactableConfig!!
@@ -165,9 +153,11 @@ private object ParcelInfoStringComputer {
append(infoStringColor1)
append(')')
}) {
- stringList.joinTo(this,
+ stringList.joinTo(
+ this,
separator = infoStringColor1.toString() + ", " + infoStringColor2,
- limit = 150)
+ limit = 150
+ )
}
}
@@ -198,6 +188,7 @@ private object ParcelInfoStringComputer {
append('\n')
appendAddedList(local, global, AddedStatus.BANNED, "Banned")
+ /* TODO options
if (!parcel.allowInteractInputs || !parcel.allowInteractInventory) {
appendField("Options") {
append("(")
@@ -206,7 +197,7 @@ private object ParcelInfoStringComputer {
appendField("inventory") { append(parcel.allowInteractInventory) }
append(")")
}
- }
+ }*/
}
} \ No newline at end of file
diff --git a/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt b/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt
index 6d89ee6..e39583c 100644
--- a/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt
+++ b/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt
@@ -3,10 +3,7 @@ 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.ParcelProvider
-import io.dico.parcels2.ParcelWorld
-import io.dico.parcels2.statusKey
+import io.dico.parcels2.*
import io.dico.parcels2.storage.Storage
import io.dico.parcels2.util.ext.*
import org.bukkit.Material.*
@@ -31,11 +28,14 @@ import org.bukkit.event.weather.WeatherChangeEvent
import org.bukkit.event.world.ChunkLoadEvent
import org.bukkit.event.world.StructureGrowEvent
import org.bukkit.inventory.InventoryHolder
+import java.util.EnumSet
@Suppress("NOTHING_TO_INLINE")
-class ParcelListeners(val parcelProvider: ParcelProvider,
- val entityTracker: ParcelEntityTracker,
- val storage: Storage) {
+class ParcelListeners(
+ val parcelProvider: ParcelProvider,
+ val entityTracker: ParcelEntityTracker,
+ val storage: Storage
+) {
private inline fun Parcel?.canBuildN(user: Player) = isPresentAnd { canBuild(user) } || user.hasBuildAnywhere
/**
@@ -170,6 +170,7 @@ class ParcelListeners(val parcelProvider: ParcelProvider,
if (ppa.isNullOr { hasBlockVisitors }) event.isCancelled = true
}
+ private val bedTypes = EnumSet.copyOf(getMaterialsWithWoodTypePrefix("BED").toList())
/*
* Prevents players from placing liquids, using flint and steel, changing redstone components,
* using inputs (unless allowed by the plot),
@@ -191,49 +192,33 @@ class ParcelListeners(val parcelProvider: ParcelProvider,
when (event.action) {
Action.RIGHT_CLICK_BLOCK -> run {
- 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
- }
- }
+ val type = clickedBlock.type
+ val interactable = parcel.effectiveInteractableConfig.isInteractable(type) || parcel.isPresentAnd { canBuild(user) }
+ if (!interactable) {
+ val interactableClassName = Interactables[type]!!.name
+ user.sendParcelMessage(nopermit = true, message = "You cannot interact with $interactableClassName 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
- }
+ if (bedTypes.contains(type)) {
+ 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 -> {
+ if (world.options.disableExplosions || parcel.isNullOr { !canBuild(user) }) {
+ user.sendParcelMessage(nopermit = true, message = "You cannot use this bed because it would explode")
+ event.isCancelled = true; return@l
}
-
}
-
}
}
+
onPlayerInteractEvent_RightClick(event, world, parcel)
}
Action.RIGHT_CLICK_AIR -> onPlayerInteractEvent_RightClick(event, world, parcel)
- Action.PHYSICAL -> if (!user.hasBuildAnywhere && !parcel.isPresentAnd { canBuild(user) || allowInteractInputs }) {
+ Action.PHYSICAL -> if (!user.hasBuildAnywhere && !parcel.isPresentAnd { canBuild(user) || interactableConfig("pressure_plates") }) {
user.sendParcelMessage(nopermit = true, message = "You cannot use inputs in this parcel")
event.isCancelled = true; return@l
}
@@ -322,7 +307,7 @@ class ParcelListeners(val parcelProvider: ParcelProvider,
@field:ListenerMarker(priority = NORMAL)
val onPlayerDropItemEvent = RegistratorListener<PlayerDropItemEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.itemDrop.location.block) ?: return@l
- if (!ppa.canBuildN(event.player) && !ppa.isPresentAnd { allowInteractInventory }) event.isCancelled = true
+ if (!ppa.canBuildN(event.player) && !ppa.isPresentAnd { interactableConfig("containers") }) event.isCancelled = true
}
/*
@@ -343,7 +328,7 @@ class ParcelListeners(val parcelProvider: ParcelProvider,
val user = event.whoClicked as? Player ?: return@l
if ((event.inventory ?: return@l).holder === user) return@l // inventory null: hotbar
val (wo, ppa) = getWoAndPPa(event.inventory.location.block) ?: return@l
- if (ppa.isNullOr { !canBuild(user) && !allowInteractInventory }) {
+ if (ppa.isNullOr { !canBuild(user) && !interactableConfig("containers") }) {
event.isCancelled = true
}
}
@@ -385,10 +370,10 @@ class ParcelListeners(val parcelProvider: ParcelProvider,
val cancel: Boolean = when (event.newState.type) {
- // prevent ice generation from Frost Walkers enchantment
+ // prevent ice generation from Frost Walkers enchantment
FROSTED_ICE -> player != null && !ppa.canBuild(player)
- // prevent snow generation from weather
+ // prevent snow generation from weather
SNOW -> !hasEntity && wo.options.preventWeatherBlockChanges
else -> false
diff --git a/src/main/kotlin/io/dico/parcels2/storage/Backing.kt b/src/main/kotlin/io/dico/parcels2/storage/Backing.kt
index 3875467..6c91714 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/Backing.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/Backing.kt
@@ -58,10 +58,12 @@ interface Backing {
fun setLocalPlayerStatus(parcel: ParcelId, player: PlayerProfile, status: AddedStatus)
+ fun setParcelOptionsInteractBitmask(parcel: ParcelId, bitmask: IntArray?)
+/*
fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean)
fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean)
-
+*/
fun transmitAllGlobalAddedData(channel: SendChannel<AddedDataPair<PlayerProfile>>)
diff --git a/src/main/kotlin/io/dico/parcels2/storage/DataConverters.kt b/src/main/kotlin/io/dico/parcels2/storage/DataConverters.kt
new file mode 100644
index 0000000..80f41b2
--- /dev/null
+++ b/src/main/kotlin/io/dico/parcels2/storage/DataConverters.kt
@@ -0,0 +1,38 @@
+package io.dico.parcels2.storage
+
+import java.lang.IllegalArgumentException
+import java.nio.ByteBuffer
+import java.util.UUID
+
+/* For putting it into the database */
+fun UUID.toByteArray(): ByteArray =
+ ByteBuffer.allocate(16).apply {
+ putLong(mostSignificantBits)
+ putLong(leastSignificantBits)
+ }.array()
+
+/* For getting it out of the database */
+fun ByteArray.toUUID(): UUID =
+ ByteBuffer.wrap(this).run {
+ val mostSignificantBits = getLong()
+ val leastSignificantBits = getLong()
+ UUID(mostSignificantBits, leastSignificantBits)
+ }
+
+/* For putting it into the database */
+fun IntArray.toByteArray(): ByteArray =
+ ByteBuffer.allocate(size * Int.SIZE_BYTES).also { buf ->
+ buf.asIntBuffer().put(this)
+ }.array()
+
+/* For getting it out of the database */
+fun ByteArray.toIntArray(): IntArray {
+ if (this.size % Int.SIZE_BYTES != 0)
+ throw IllegalArgumentException("Size must be divisible by ${Int.SIZE_BYTES}")
+
+ return ByteBuffer.wrap(this).run {
+ IntArray(remaining() / 4).also { array ->
+ asIntBuffer().get(array)
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/kotlin/io/dico/parcels2/storage/Storage.kt b/src/main/kotlin/io/dico/parcels2/storage/Storage.kt
index 7b04bce..c9c0d4a 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/Storage.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/Storage.kt
@@ -50,9 +50,7 @@ interface Storage {
fun setParcelPlayerStatus(parcel: ParcelId, player: PlayerProfile, status: AddedStatus): Job
- fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean): Job
-
- fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean): Job
+ fun setParcelOptionsInteractBitmask(parcel: ParcelId, bitmask: IntArray): Job
fun transmitAllGlobalAddedData(): ReceiveChannel<AddedDataPair<PlayerProfile>>
@@ -100,9 +98,7 @@ class BackedStorage internal constructor(val b: Backing) : Storage {
override fun setParcelPlayerStatus(parcel: ParcelId, player: PlayerProfile, status: AddedStatus) = b.launchJob { b.setLocalPlayerStatus(parcel, player, status) }
- override fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean) = b.launchJob { b.setParcelAllowsInteractInventory(parcel, value) }
-
- override fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean) = b.launchJob { b.setParcelAllowsInteractInputs(parcel, value) }
+ override fun setParcelOptionsInteractBitmask(parcel: ParcelId, bitmask: IntArray) = b.launchJob { b.setParcelOptionsInteractBitmask(parcel, bitmask) }
override fun transmitAllGlobalAddedData(): ReceiveChannel<AddedDataPair<PlayerProfile>> = b.openChannel { b.transmitAllGlobalAddedData(it) }
diff --git a/src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt b/src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt
index 39a32e0..b7f9f82 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt
@@ -5,12 +5,9 @@ package io.dico.parcels2.storage.exposed
import com.zaxxer.hikari.HikariDataSource
import io.dico.parcels2.*
import io.dico.parcels2.PlayerProfile.Star.name
-import io.dico.parcels2.storage.AddedDataPair
-import io.dico.parcels2.storage.Backing
-import io.dico.parcels2.storage.DataPair
+import io.dico.parcels2.storage.*
+import io.dico.parcels2.util.ext.clampMax
import io.dico.parcels2.util.ext.synchronized
-import io.dico.parcels2.util.toByteArray
-import io.dico.parcels2.util.toUUID
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.ArrayChannel
import kotlinx.coroutines.channels.LinkedListChannel
@@ -196,8 +193,9 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
AddedLocalT.setPlayerStatus(parcel, profile, status)
}
- setParcelAllowsInteractInputs(parcel, data.allowInteractInputs)
- setParcelAllowsInteractInventory(parcel, data.allowInteractInventory)
+ val bitmaskArray = (data.interactableConfig as? BitmaskInteractableConfiguration ?: return).bitmaskArray
+ val isAllZero = bitmaskArray.fold(false) { cur, elem -> cur || elem != 0 }
+ setParcelOptionsInteractBitmask(parcel, if (isAllZero) null else bitmaskArray)
}
override fun setParcelOwner(parcel: ParcelId, owner: PlayerProfile?) {
@@ -227,19 +225,19 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
AddedLocalT.setPlayerStatus(parcel, player.toRealProfile(), status)
}
- override fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean) {
- val id = ParcelsT.getOrInitId(parcel)
- ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
- it[parcel_id] = id
- it[interact_inventory] = value
+ override fun setParcelOptionsInteractBitmask(parcel: ParcelId, bitmask: IntArray?) {
+ if (bitmask == null) {
+ val id = ParcelsT.getId(parcel) ?: return
+ ParcelOptionsT.deleteWhere { ParcelOptionsT.parcel_id eq id }
+ return
}
- }
- override fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean) {
+ if (bitmask.size != 1) throw IllegalArgumentException()
+ val array = bitmask.toByteArray()
val id = ParcelsT.getOrInitId(parcel)
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
it[parcel_id] = id
- it[interact_inputs] = value
+ it[interact_bitmask] = array
}
}
@@ -263,8 +261,9 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
val id = row[ParcelsT.id]
ParcelOptionsT.select { ParcelOptionsT.parcel_id eq id }.firstOrNull()?.let { optrow ->
- allowInteractInputs = optrow[ParcelOptionsT.interact_inputs]
- allowInteractInventory = optrow[ParcelOptionsT.interact_inventory]
+ val source = optrow[ParcelOptionsT.interact_bitmask].toIntArray()
+ val target = (interactableConfig as? BitmaskInteractableConfiguration ?: return@let).bitmaskArray
+ System.arraycopy(source, 0, target, 0, source.size.clampMax(target.size))
}
addedMap = AddedLocalT.readAddedData(id)
diff --git a/src/main/kotlin/io/dico/parcels2/storage/exposed/IdTables.kt b/src/main/kotlin/io/dico/parcels2/storage/exposed/IdTables.kt
index afbaa6e..745895e 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/exposed/IdTables.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/exposed/IdTables.kt
@@ -5,8 +5,8 @@ package io.dico.parcels2.storage.exposed
import io.dico.parcels2.ParcelId
import io.dico.parcels2.ParcelWorldId
import io.dico.parcels2.PlayerProfile
-import io.dico.parcels2.util.toByteArray
-import io.dico.parcels2.util.toUUID
+import io.dico.parcels2.storage.toByteArray
+import io.dico.parcels2.storage.toUUID
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.statements.UpdateBuilder
import org.joda.time.DateTime
diff --git a/src/main/kotlin/io/dico/parcels2/storage/exposed/ListTables.kt b/src/main/kotlin/io/dico/parcels2/storage/exposed/ListTables.kt
index c976f69..f41d545 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/exposed/ListTables.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/exposed/ListTables.kt
@@ -3,6 +3,8 @@
package io.dico.parcels2.storage.exposed
import io.dico.parcels2.*
+import io.dico.parcels2.AddedStatus.ALLOWED
+import io.dico.parcels2.AddedStatus.DEFAULT
import kotlinx.coroutines.channels.SendChannel
import org.jetbrains.exposed.sql.*
import java.util.UUID
@@ -12,8 +14,7 @@ object AddedGlobalT : AddedTable<PlayerProfile>("parcels_added_global", Profiles
object ParcelOptionsT : Table("parcel_options") {
val parcel_id = integer("parcel_id").primaryKey().references(ParcelsT.id, ReferenceOption.CASCADE)
- val interact_inventory = bool("interact_inventory").default(true)
- val interact_inputs = bool("interact_inputs").default(true)
+ val interact_bitmask = binary("interact_bitmask", 4).default(ByteArray(4) { 0 }) // all zero by default
}
typealias AddedStatusSendChannel<AttachT> = SendChannel<Pair<AttachT, MutableAddedDataMap>>
@@ -25,7 +26,7 @@ sealed class AddedTable<AttachT>(name: String, val idTable: IdTransactionsTable<
val index_pair = uniqueIndexR("index_pair", attach_id, profile_id)
fun setPlayerStatus(attachedOn: AttachT, player: PlayerProfile.Real, status: AddedStatus) {
- if (status.isDefault) {
+ if (status == DEFAULT) {
val player_id = ProfilesT.getId(player) ?: return
idTable.getId(attachedOn)?.let { holder ->
deleteWhere { (attach_id eq holder) and (profile_id eq player_id) }
@@ -38,7 +39,7 @@ sealed class AddedTable<AttachT>(name: String, val idTable: IdTransactionsTable<
upsert(conflictIndex = index_pair) {
it[attach_id] = holder
it[profile_id] = player_id
- it[allowed_flag] = status.isAllowed
+ it[allowed_flag] = status == ALLOWED
}
}
@@ -97,6 +98,6 @@ sealed class AddedTable<AttachT>(name: String, val idTable: IdTransactionsTable<
}
}
- private inline fun Boolean?.asAddedStatus() = if (this == null) AddedStatus.DEFAULT else if (this) AddedStatus.ALLOWED else AddedStatus.BANNED
+ private inline fun Boolean?.asAddedStatus() = if (this == null) AddedStatus.DEFAULT else if (this) ALLOWED else AddedStatus.BANNED
}
diff --git a/src/main/kotlin/io/dico/parcels2/storage/migration/plotme/PlotmeMigration.kt b/src/main/kotlin/io/dico/parcels2/storage/migration/plotme/PlotmeMigration.kt
index 3fae57f..0dcf36d 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/migration/plotme/PlotmeMigration.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/migration/plotme/PlotmeMigration.kt
@@ -9,7 +9,7 @@ import io.dico.parcels2.storage.Storage
import io.dico.parcels2.storage.exposed.abs
import io.dico.parcels2.storage.exposed.greater
import io.dico.parcels2.storage.migration.Migration
-import io.dico.parcels2.util.toUUID
+import io.dico.parcels2.storage.toUUID
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.newFixedThreadPoolContext
diff --git a/src/main/kotlin/io/dico/parcels2/util/UUIDUtil.kt b/src/main/kotlin/io/dico/parcels2/util/UUIDUtil.kt
index 268c1b9..1398037 100644
--- a/src/main/kotlin/io/dico/parcels2/util/UUIDUtil.kt
+++ b/src/main/kotlin/io/dico/parcels2/util/UUIDUtil.kt
@@ -11,10 +11,4 @@ fun getPlayerName(uuid: UUID): String? {
return Bukkit.getOfflinePlayer(uuid)?.takeIf { it.isValid }?.name
}
-fun UUID.toByteArray(): ByteArray =
- ByteBuffer.allocate(16).apply {
- putLong(mostSignificantBits)
- putLong(leastSignificantBits)
- }.array()
-fun ByteArray.toUUID(): UUID = ByteBuffer.wrap(this).run { UUID(long, long) }
diff --git a/src/main/kotlin/io/dico/parcels2/util/ext/Material.kt b/src/main/kotlin/io/dico/parcels2/util/ext/Material.kt
index c375cb2..e160e55 100644
--- a/src/main/kotlin/io/dico/parcels2/util/ext/Material.kt
+++ b/src/main/kotlin/io/dico/parcels2/util/ext/Material.kt
@@ -79,7 +79,7 @@ private fun getMaterialPrefixed(prefix: String, name: String): Material {
return Material.getMaterial("${prefix}_$name") ?: throw IllegalArgumentException("Material ${prefix}_$name doesn't exist")
}
-fun findWoodKindPrefixedMaterials(name: String) = arrayOf(
+fun getMaterialsWithWoodTypePrefix(name: String) = arrayOf(
getMaterialPrefixed("OAK", name),
getMaterialPrefixed("BIRCH", name),
getMaterialPrefixed("SPRUCE", name),
@@ -88,7 +88,7 @@ fun findWoodKindPrefixedMaterials(name: String) = arrayOf(
getMaterialPrefixed("DARK_OAK", name)
)
-fun findColorPrefixedMaterials(name: String) = arrayOf(
+fun getMaterialsWithWoolColorPrefix(name: String) = arrayOf(
getMaterialPrefixed("WHITE", name),
getMaterialPrefixed("ORANGE", name),
getMaterialPrefixed("MAGENTA", name),
diff --git a/src/main/kotlin/io/dico/parcels2/util/ext/Math.kt b/src/main/kotlin/io/dico/parcels2/util/ext/Math.kt
index 32540fd..62ee220 100644
--- a/src/main/kotlin/io/dico/parcels2/util/ext/Math.kt
+++ b/src/main/kotlin/io/dico/parcels2/util/ext/Math.kt
@@ -29,4 +29,7 @@ fun IntRange.clamp(min: Int, max: Int): IntRange {
return IntRange(first, max)
}
return this
-} \ No newline at end of file
+}
+
+// the name coerceAtMost is bad
+fun Int.clampMax(max: Int) = coerceAtMost(max) \ No newline at end of file
diff --git a/todo.md b/todo.md
index c04937a..93e9c02 100644
--- a/todo.md
+++ b/todo.md
@@ -79,4 +79,6 @@ Implement a container that doesn't require loading all parcel data on startup (C
~~Update player profiles in the database on join to account for name changes.~~
+Store player status on parcel (allowed, default banned) as a number to allow for future additions to this set of possibilities
+