From 48e1d86fcbd2700ab220d64ffa624b6129232832 Mon Sep 17 00:00:00 2001 From: Dico Date: Fri, 17 Aug 2018 10:59:19 +0100 Subject: Add interactable api --- src/main/kotlin/io/dico/parcels2/Interactable.kt | 106 +++++++++++++++++++++ src/main/kotlin/io/dico/parcels2/Parcel.kt | 6 +- .../io/dico/parcels2/defaultimpl/ParcelImpl.kt | 24 +++++ .../io/dico/parcels2/util/MaterialExtensions.kt | 32 +++++++ 4 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/io/dico/parcels2/Interactable.kt diff --git a/src/main/kotlin/io/dico/parcels2/Interactable.kt b/src/main/kotlin/io/dico/parcels2/Interactable.kt new file mode 100644 index 0000000..36a8bdd --- /dev/null +++ b/src/main/kotlin/io/dico/parcels2/Interactable.kt @@ -0,0 +1,106 @@ +package io.dico.parcels2 + +import io.dico.parcels2.util.findWoodKindPrefixedMaterials +import org.bukkit.Material +import java.util.EnumMap + +class Interactables +private constructor(val id: Int, + val name: String, + val interactableByDefault: Boolean, + vararg val materials: Material) { + + companion object { + val classesById: List + val classesByName: Map + val listedMaterials: Map + + init { + val array = getClassesArray() + classesById = array.asList() + classesByName = mapOf(*array.map { it.name to it }.toTypedArray()) + listedMaterials = EnumMap(mapOf(*array.flatMap { clazz -> clazz.materials.map { it to clazz.id } }.toTypedArray())) + } + + private fun getClassesArray() = run { + var id = 0 + @Suppress("UNUSED_CHANGED_VALUE") + arrayOf( + Interactables(id++, "button", true, + Material.STONE_BUTTON, + *findWoodKindPrefixedMaterials("BUTTON")), + + Interactables(id++, "lever", true, + Material.LEVER), + + Interactables(id++, "pressure_plate", true, + Material.STONE_PRESSURE_PLATE, + *findWoodKindPrefixedMaterials("PRESSURE_PLATE"), + Material.HEAVY_WEIGHTED_PRESSURE_PLATE, + Material.LIGHT_WEIGHTED_PRESSURE_PLATE), + + Interactables(id++, "redstone_components", false, + Material.COMPARATOR, + Material.REPEATER), + + Interactables(id++, "containers", false, + Material.CHEST, + Material.TRAPPED_CHEST, + Material.DISPENSER, + Material.DROPPER, + Material.HOPPER, + Material.FURNACE) + ) + } + + } + +} + +interface InteractableConfiguration { + val interactableClasses: List get() = Interactables.classesById.filter { isInteractable(it) } + fun isInteractable(material: Material): Boolean + fun isInteractable(clazz: Interactables): Boolean + fun setInteractable(clazz: Interactables, interactable: Boolean): Boolean + fun clear(): Boolean + fun copyFrom(other: InteractableConfiguration) { + Interactables.classesById.forEach { setInteractable(it, other.isInteractable(it)) } + } +} + +class BitmaskInteractableConfiguration : InteractableConfiguration { + val bitmaskArray = IntArray((Interactables.classesById.size + 31) / 32) + + private fun isBitSet(classId: Int): Boolean { + val idx = classId.ushr(5) + return idx < bitmaskArray.size && bitmaskArray[idx].and(0x1.shl(classId.and(0x1F))) != 0 + } + + override fun isInteractable(material: Material): Boolean { + val classId = Interactables.listedMaterials[material] ?: return false + return isBitSet(classId) != Interactables.classesById[classId].interactableByDefault + } + + override fun isInteractable(clazz: Interactables): Boolean { + return isBitSet(clazz.id) != clazz.interactableByDefault + } + + override fun setInteractable(clazz: Interactables, interactable: Boolean): Boolean { + val idx = clazz.id.ushr(5) + if (idx >= bitmaskArray.size) return false + val bit = 0x1.shl(clazz.id.and(0x1F)) + val oldBitmask = bitmaskArray[idx] + bitmaskArray[idx] = if (interactable != clazz.interactableByDefault) oldBitmask.or(bit) else oldBitmask.and(bit.inv()) + return bitmaskArray[idx] != oldBitmask + } + + override fun clear(): Boolean { + var change = false + for (i in bitmaskArray.indices) { + change = change || bitmaskArray[i] != 0 + bitmaskArray[i] = 0 + } + return change + } + +} \ No newline at end of file diff --git a/src/main/kotlin/io/dico/parcels2/Parcel.kt b/src/main/kotlin/io/dico/parcels2/Parcel.kt index 3b82d32..6d8a1ca 100644 --- a/src/main/kotlin/io/dico/parcels2/Parcel.kt +++ b/src/main/kotlin/io/dico/parcels2/Parcel.kt @@ -39,6 +39,7 @@ interface ParcelData : AddedData { var owner: PlayerProfile? val lastClaimTime: DateTime? var ownerSignOutdated: Boolean + var interactableConfig: InteractableConfiguration fun canBuild(player: OfflinePlayer, checkAdmin: Boolean = true, checkGlobal: Boolean = true): Boolean @@ -54,8 +55,8 @@ interface ParcelData : AddedData { } } -class ParcelDataHolder(addedMap: MutableAddedDataMap = mutableMapOf()) : AddedDataHolder(addedMap), ParcelData { - +class ParcelDataHolder(addedMap: MutableAddedDataMap = mutableMapOf()) + : ParcelData, AddedDataHolder(addedMap) { override var owner: PlayerProfile? = null override var lastClaimTime: DateTime? = null override var ownerSignOutdated = false @@ -65,5 +66,6 @@ class ParcelDataHolder(addedMap: MutableAddedDataMap = mutableMapOf()) : AddedDa override var allowInteractInputs = true override var allowInteractInventory = true + override var interactableConfig: InteractableConfiguration = BitmaskInteractableConfiguration() } diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt index 7755363..dd3c121 100644 --- a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt +++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt @@ -4,6 +4,7 @@ import io.dico.dicore.Formatting import io.dico.parcels2.* import io.dico.parcels2.util.Vec2i import io.dico.parcels2.util.alsoIfTrue +import org.bukkit.Material import org.bukkit.OfflinePlayer import org.joda.time.DateTime import kotlin.reflect.KProperty @@ -90,6 +91,29 @@ class ParcelImpl(override val world: ParcelWorld, data.allowInteractInventory = value } + private var _interactableConfig: InteractableConfiguration? = null + override var interactableConfig: InteractableConfiguration + get() { + if (_interactableConfig == null) { + _interactableConfig = object : InteractableConfiguration { + 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 clear(): Boolean = data.interactableConfig.clear().alsoIfTrue { + // TODO update storage + } + } + } + return _interactableConfig!! + } + set(value) { + data.interactableConfig.copyFrom(value) + // TODO update storage + } } diff --git a/src/main/kotlin/io/dico/parcels2/util/MaterialExtensions.kt b/src/main/kotlin/io/dico/parcels2/util/MaterialExtensions.kt index a2aefc8..fadd722 100644 --- a/src/main/kotlin/io/dico/parcels2/util/MaterialExtensions.kt +++ b/src/main/kotlin/io/dico/parcels2/util/MaterialExtensions.kt @@ -74,3 +74,35 @@ val Material.isWoodButton DARK_OAK_BUTTON -> true else -> false } + +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( + getMaterialPrefixed("OAK", name), + getMaterialPrefixed("BIRCH", name), + getMaterialPrefixed("SPRUCE", name), + getMaterialPrefixed("JUNGLE", name), + getMaterialPrefixed("ACACIA", name), + getMaterialPrefixed("DARK_OAK", name) +) + +fun findColorPrefixedMaterials(name: String) = arrayOf( + getMaterialPrefixed("WHITE", name), + getMaterialPrefixed("ORANGE", name), + getMaterialPrefixed("MAGENTA", name), + getMaterialPrefixed("LIGHT_BLUE", name), + getMaterialPrefixed("YELLOW", name), + getMaterialPrefixed("LIME", name), + getMaterialPrefixed("PINK", name), + getMaterialPrefixed("GRAY", name), + getMaterialPrefixed("LIGHT_GRAY", name), + getMaterialPrefixed("CYAN", name), + getMaterialPrefixed("PURPLE", name), + getMaterialPrefixed("BLUE", name), + getMaterialPrefixed("BROWN", name), + getMaterialPrefixed("GREEN", name), + getMaterialPrefixed("RED", name), + getMaterialPrefixed("BLACK", name) +) \ No newline at end of file -- cgit v1.2.3