Do some work on interactables
This commit is contained in:
@@ -1,7 +1,12 @@
|
|||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
|
import io.dico.parcels2.AddedStatus.*
|
||||||
import org.bukkit.OfflinePlayer
|
import org.bukkit.OfflinePlayer
|
||||||
|
|
||||||
|
enum class AddedStatus {
|
||||||
|
DEFAULT, ALLOWED, BANNED;
|
||||||
|
}
|
||||||
|
|
||||||
typealias StatusKey = PlayerProfile.Real
|
typealias StatusKey = PlayerProfile.Real
|
||||||
typealias MutableAddedDataMap = MutableMap<StatusKey, AddedStatus>
|
typealias MutableAddedDataMap = MutableMap<StatusKey, AddedStatus>
|
||||||
typealias AddedDataMap = Map<StatusKey, AddedStatus>
|
typealias AddedDataMap = Map<StatusKey, AddedStatus>
|
||||||
@@ -11,20 +16,20 @@ fun MutableAddedDataMap(): MutableAddedDataMap = hashMapOf()
|
|||||||
|
|
||||||
interface AddedData {
|
interface AddedData {
|
||||||
val addedMap: AddedDataMap
|
val addedMap: AddedDataMap
|
||||||
var addedStatusOfStar: AddedStatus
|
var statusOfStar: AddedStatus
|
||||||
|
|
||||||
fun getAddedStatus(key: StatusKey): AddedStatus
|
fun getStatus(key: StatusKey): AddedStatus
|
||||||
fun setAddedStatus(key: StatusKey, status: AddedStatus): Boolean
|
fun setStatus(key: StatusKey, status: AddedStatus): Boolean
|
||||||
|
|
||||||
fun compareAndSetAddedStatus(key: StatusKey, expect: AddedStatus, status: AddedStatus): Boolean =
|
fun casStatus(key: StatusKey, expect: AddedStatus, status: AddedStatus): Boolean =
|
||||||
getAddedStatus(key) == expect && setAddedStatus(key, status)
|
getStatus(key) == expect && setStatus(key, status)
|
||||||
|
|
||||||
fun isAllowed(key: StatusKey) = getAddedStatus(key) == AddedStatus.ALLOWED
|
fun isAllowed(key: StatusKey) = getStatus(key) == ALLOWED
|
||||||
fun allow(key: StatusKey) = setAddedStatus(key, AddedStatus.ALLOWED)
|
fun allow(key: StatusKey) = setStatus(key, ALLOWED)
|
||||||
fun disallow(key: StatusKey) = compareAndSetAddedStatus(key, AddedStatus.ALLOWED, AddedStatus.DEFAULT)
|
fun disallow(key: StatusKey) = casStatus(key, ALLOWED, DEFAULT)
|
||||||
fun isBanned(key: StatusKey) = getAddedStatus(key) == AddedStatus.BANNED
|
fun isBanned(key: StatusKey) = getStatus(key) == BANNED
|
||||||
fun ban(key: StatusKey) = setAddedStatus(key, AddedStatus.BANNED)
|
fun ban(key: StatusKey) = setStatus(key, BANNED)
|
||||||
fun unban(key: StatusKey) = compareAndSetAddedStatus(key, AddedStatus.BANNED, AddedStatus.DEFAULT)
|
fun unban(key: StatusKey) = casStatus(key, BANNED, DEFAULT)
|
||||||
|
|
||||||
fun isAllowed(player: OfflinePlayer) = isAllowed(player.statusKey)
|
fun isAllowed(player: OfflinePlayer) = isAllowed(player.statusKey)
|
||||||
fun allow(player: OfflinePlayer) = allow(player.statusKey)
|
fun allow(player: OfflinePlayer) = allow(player.statusKey)
|
||||||
@@ -34,29 +39,20 @@ interface AddedData {
|
|||||||
fun unban(player: OfflinePlayer) = unban(player.statusKey)
|
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 {
|
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 {
|
override fun setStatus(key: StatusKey, status: AddedStatus): Boolean {
|
||||||
return if (status.isDefault) addedMap.remove(key) != null
|
return if (status == DEFAULT) addedMap.remove(key) != null
|
||||||
else addedMap.put(key, status) != status
|
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 {
|
interface GlobalAddedData : AddedData {
|
||||||
val owner: PlayerProfile
|
val owner: PlayerProfile
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
import io.dico.parcels2.util.ext.findWoodKindPrefixedMaterials
|
import io.dico.parcels2.util.ext.getMaterialsWithWoodTypePrefix
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
import java.util.EnumMap
|
import java.util.EnumMap
|
||||||
|
|
||||||
class Interactables
|
class Interactables
|
||||||
private constructor(val id: Int,
|
private constructor(
|
||||||
val name: String,
|
val id: Int,
|
||||||
val interactableByDefault: Boolean,
|
val name: String,
|
||||||
vararg val materials: Material) {
|
val interactableByDefault: Boolean,
|
||||||
|
vararg val materials: Material
|
||||||
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val classesById: List<Interactables>
|
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()))
|
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 {
|
private fun getClassesArray() = run {
|
||||||
var id = 0
|
var id = 0
|
||||||
@Suppress("UNUSED_CHANGED_VALUE")
|
@Suppress("UNUSED_CHANGED_VALUE")
|
||||||
arrayOf(
|
arrayOf(
|
||||||
Interactables(id++, "button", true,
|
Interactables(
|
||||||
|
id++, "buttons", true,
|
||||||
Material.STONE_BUTTON,
|
Material.STONE_BUTTON,
|
||||||
*findWoodKindPrefixedMaterials("BUTTON")
|
*getMaterialsWithWoodTypePrefix("BUTTON")
|
||||||
),
|
),
|
||||||
|
|
||||||
Interactables(id++, "lever", true,
|
Interactables(
|
||||||
Material.LEVER),
|
id++, "levers", true,
|
||||||
|
Material.LEVER
|
||||||
|
),
|
||||||
|
|
||||||
Interactables(id++, "pressure_plate", true,
|
Interactables(
|
||||||
|
id++, "pressure_plates", true,
|
||||||
Material.STONE_PRESSURE_PLATE,
|
Material.STONE_PRESSURE_PLATE,
|
||||||
*findWoodKindPrefixedMaterials("PRESSURE_PLATE"),
|
*getMaterialsWithWoodTypePrefix("PRESSURE_PLATE"),
|
||||||
Material.HEAVY_WEIGHTED_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.COMPARATOR,
|
||||||
Material.REPEATER),
|
Material.REPEATER
|
||||||
|
),
|
||||||
|
|
||||||
Interactables(id++, "containers", false,
|
Interactables(
|
||||||
|
id++, "containers", false,
|
||||||
Material.CHEST,
|
Material.CHEST,
|
||||||
Material.TRAPPED_CHEST,
|
Material.TRAPPED_CHEST,
|
||||||
Material.DISPENSER,
|
Material.DISPENSER,
|
||||||
Material.DROPPER,
|
Material.DROPPER,
|
||||||
Material.HOPPER,
|
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 {
|
interface InteractableConfiguration {
|
||||||
val interactableClasses: List<Interactables> get() = Interactables.classesById.filter { isInteractable(it) }
|
val interactableClasses: List<Interactables> get() = Interactables.classesById.filter { isInteractable(it) }
|
||||||
fun isInteractable(material: Material): Boolean
|
fun isInteractable(material: Material): Boolean
|
||||||
@@ -67,8 +120,13 @@ interface InteractableConfiguration {
|
|||||||
fun copyFrom(other: InteractableConfiguration) {
|
fun copyFrom(other: InteractableConfiguration) {
|
||||||
Interactables.classesById.forEach { setInteractable(it, other.isInteractable(it)) }
|
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 {
|
class BitmaskInteractableConfiguration : InteractableConfiguration {
|
||||||
val bitmaskArray = IntArray((Interactables.classesById.size + 31) / 32)
|
val bitmaskArray = IntArray((Interactables.classesById.size + 31) / 32)
|
||||||
|
|
||||||
@@ -98,7 +156,7 @@ class BitmaskInteractableConfiguration : InteractableConfiguration {
|
|||||||
override fun clear(): Boolean {
|
override fun clear(): Boolean {
|
||||||
var change = false
|
var change = false
|
||||||
for (i in bitmaskArray.indices) {
|
for (i in bitmaskArray.indices) {
|
||||||
change = change || bitmaskArray[i] != 0
|
if (!change && bitmaskArray[i] != 0) change = true
|
||||||
bitmaskArray[i] = 0
|
bitmaskArray[i] = 0
|
||||||
}
|
}
|
||||||
return change
|
return change
|
||||||
|
|||||||
@@ -45,9 +45,6 @@ interface ParcelData : AddedData {
|
|||||||
|
|
||||||
fun canBuild(player: OfflinePlayer, checkAdmin: Boolean = true, checkGlobal: Boolean = true): Boolean
|
fun canBuild(player: OfflinePlayer, checkAdmin: Boolean = true, checkGlobal: Boolean = true): Boolean
|
||||||
|
|
||||||
var allowInteractInputs: Boolean
|
|
||||||
var allowInteractInventory: Boolean
|
|
||||||
|
|
||||||
fun isOwner(uuid: UUID): Boolean {
|
fun isOwner(uuid: UUID): Boolean {
|
||||||
return owner?.uuid == uuid
|
return owner?.uuid == uuid
|
||||||
}
|
}
|
||||||
@@ -66,8 +63,6 @@ class ParcelDataHolder(addedMap: MutableAddedDataMap = mutableMapOf())
|
|||||||
|| owner.let { it != null && it.matches(player, allowNameMatch = false) }
|
|| owner.let { it != null && it.matches(player, allowNameMatch = false) }
|
||||||
|| (checkAdmin && player is Player && player.hasBuildAnywhere)
|
|| (checkAdmin && player is Player && player.hasBuildAnywhere)
|
||||||
|
|
||||||
override var allowInteractInputs = true
|
|
||||||
override var allowInteractInventory = true
|
|
||||||
override var interactableConfig: InteractableConfiguration = BitmaskInteractableConfiguration()
|
override var interactableConfig: InteractableConfiguration = BitmaskInteractableConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import org.bukkit.entity.Player
|
|||||||
import kotlin.reflect.KMutableProperty
|
import kotlin.reflect.KMutableProperty
|
||||||
|
|
||||||
class CommandsParcelOptions(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
class CommandsParcelOptions(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||||
|
/* TODO options
|
||||||
@Cmd("inputs")
|
@Cmd("inputs")
|
||||||
@Desc("Sets whether players who are not allowed to",
|
@Desc("Sets whether players who are not allowed to",
|
||||||
"build here can use levers, buttons,",
|
"build here can use levers, buttons,",
|
||||||
@@ -28,7 +29,7 @@ class CommandsParcelOptions(plugin: ParcelsPlugin) : AbstractParcelCommands(plug
|
|||||||
@RequireParameters(0)
|
@RequireParameters(0)
|
||||||
fun ParcelScope.cmdInventory(player: Player, enabled: Boolean?): Any? {
|
fun ParcelScope.cmdInventory(player: Player, enabled: Boolean?): Any? {
|
||||||
return runOptionCommand(player, Parcel::allowInteractInventory, enabled, "interaction with inventories")
|
return runOptionCommand(player, Parcel::allowInteractInventory, enabled, "interaction with inventories")
|
||||||
}
|
}*/
|
||||||
|
|
||||||
private inline val Boolean.enabledWord get() = if (this) "enabled" else "disabled"
|
private inline val Boolean.enabledWord get() = if (this) "enabled" else "disabled"
|
||||||
private fun ParcelScope.runOptionCommand(player: Player,
|
private fun ParcelScope.runOptionCommand(player: Player,
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ class GlobalAddedDataManagerImpl(val plugin: ParcelsPlugin) : GlobalAddedDataMan
|
|||||||
private inline var data get() = addedMap; set(value) = run { addedMap = value }
|
private inline var data get() = addedMap; set(value) = run { addedMap = value }
|
||||||
private inline val isEmpty get() = data === emptyData
|
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 (isEmpty) {
|
||||||
if (status == AddedStatus.DEFAULT) return false
|
if (status == AddedStatus.DEFAULT) return false
|
||||||
data = mutableMapOf()
|
data = mutableMapOf()
|
||||||
}
|
}
|
||||||
return super.setAddedStatus(key, status).alsoIfTrue {
|
return super.setStatus(key, status).alsoIfTrue {
|
||||||
plugin.storage.setGlobalAddedStatus(owner, key, status)
|
plugin.storage.setGlobalAddedStatus(owner, key, status)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ import org.bukkit.OfflinePlayer
|
|||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
class ParcelImpl(override val world: ParcelWorld,
|
class ParcelImpl(
|
||||||
override val x: Int,
|
override val world: ParcelWorld,
|
||||||
override val z: Int) : Parcel, ParcelId {
|
override val x: Int,
|
||||||
|
override val z: Int
|
||||||
|
) : Parcel, ParcelId {
|
||||||
override val id: ParcelId = this
|
override val id: ParcelId = this
|
||||||
override val pos get() = Vec2i(x, z)
|
override val pos get() = Vec2i(x, z)
|
||||||
override var data: ParcelDataHolder = ParcelDataHolder(); private set
|
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 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 isBanned(key: StatusKey) = data.isBanned(key)
|
||||||
override fun isAllowed(key: StatusKey) = data.isAllowed(key)
|
override fun isAllowed(key: StatusKey) = data.isAllowed(key)
|
||||||
override fun canBuild(player: OfflinePlayer, checkAdmin: Boolean, checkGlobal: Boolean): Boolean {
|
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)
|
|| checkGlobal && world.globalAddedData[owner ?: return false].isAllowed(player)
|
||||||
}
|
}
|
||||||
|
|
||||||
override var addedStatusOfStar: AddedStatus
|
override var statusOfStar: AddedStatus
|
||||||
get() = data.addedStatusOfStar
|
get() = data.statusOfStar
|
||||||
set(value) = run { setAddedStatus(PlayerProfile.Star, value) }
|
set(value) = run { setStatus(PlayerProfile.Star, value) }
|
||||||
|
|
||||||
val globalAddedMap: AddedDataMap? get() = owner?.let { world.globalAddedData[it].addedMap }
|
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 {
|
override fun setStatus(key: StatusKey, status: AddedStatus): Boolean {
|
||||||
return data.setAddedStatus(key, status).alsoIfTrue {
|
return data.setStatus(key, status).alsoIfTrue {
|
||||||
world.storage.setParcelPlayerStatus(this, key, status)
|
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
|
private var _interactableConfig: InteractableConfiguration? = null
|
||||||
override var interactableConfig: InteractableConfiguration
|
override var interactableConfig: InteractableConfiguration
|
||||||
get() {
|
get() {
|
||||||
@@ -99,13 +85,15 @@ class ParcelImpl(override val world: ParcelWorld,
|
|||||||
override fun isInteractable(material: Material): Boolean = data.interactableConfig.isInteractable(material)
|
override fun isInteractable(material: Material): Boolean = data.interactableConfig.isInteractable(material)
|
||||||
override fun isInteractable(clazz: Interactables): Boolean = data.interactableConfig.isInteractable(clazz)
|
override fun isInteractable(clazz: Interactables): Boolean = data.interactableConfig.isInteractable(clazz)
|
||||||
|
|
||||||
override fun setInteractable(clazz: Interactables, interactable: Boolean): Boolean = data.interactableConfig.setInteractable(clazz, interactable).alsoIfTrue {
|
override fun setInteractable(clazz: Interactables, interactable: Boolean): Boolean =
|
||||||
// TODO update storage
|
data.interactableConfig.setInteractable(clazz, interactable).alsoIfTrue {
|
||||||
}
|
// TODO update storage
|
||||||
|
}
|
||||||
|
|
||||||
override fun clear(): Boolean = data.interactableConfig.clear().alsoIfTrue {
|
override fun clear(): Boolean =
|
||||||
// TODO update storage
|
data.interactableConfig.clear().alsoIfTrue {
|
||||||
}
|
// TODO update storage
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _interactableConfig!!
|
return _interactableConfig!!
|
||||||
@@ -165,9 +153,11 @@ private object ParcelInfoStringComputer {
|
|||||||
append(infoStringColor1)
|
append(infoStringColor1)
|
||||||
append(')')
|
append(')')
|
||||||
}) {
|
}) {
|
||||||
stringList.joinTo(this,
|
stringList.joinTo(
|
||||||
|
this,
|
||||||
separator = infoStringColor1.toString() + ", " + infoStringColor2,
|
separator = infoStringColor1.toString() + ", " + infoStringColor2,
|
||||||
limit = 150)
|
limit = 150
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,6 +188,7 @@ private object ParcelInfoStringComputer {
|
|||||||
append('\n')
|
append('\n')
|
||||||
appendAddedList(local, global, AddedStatus.BANNED, "Banned")
|
appendAddedList(local, global, AddedStatus.BANNED, "Banned")
|
||||||
|
|
||||||
|
/* TODO options
|
||||||
if (!parcel.allowInteractInputs || !parcel.allowInteractInventory) {
|
if (!parcel.allowInteractInputs || !parcel.allowInteractInventory) {
|
||||||
appendField("Options") {
|
appendField("Options") {
|
||||||
append("(")
|
append("(")
|
||||||
@@ -206,7 +197,7 @@ private object ParcelInfoStringComputer {
|
|||||||
appendField("inventory") { append(parcel.allowInteractInventory) }
|
appendField("inventory") { append(parcel.allowInteractInventory) }
|
||||||
append(")")
|
append(")")
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,10 +3,7 @@ package io.dico.parcels2.listener
|
|||||||
import gnu.trove.TLongCollection
|
import gnu.trove.TLongCollection
|
||||||
import io.dico.dicore.ListenerMarker
|
import io.dico.dicore.ListenerMarker
|
||||||
import io.dico.dicore.RegistratorListener
|
import io.dico.dicore.RegistratorListener
|
||||||
import io.dico.parcels2.Parcel
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.ParcelProvider
|
|
||||||
import io.dico.parcels2.ParcelWorld
|
|
||||||
import io.dico.parcels2.statusKey
|
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import io.dico.parcels2.util.ext.*
|
import io.dico.parcels2.util.ext.*
|
||||||
import org.bukkit.Material.*
|
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.ChunkLoadEvent
|
||||||
import org.bukkit.event.world.StructureGrowEvent
|
import org.bukkit.event.world.StructureGrowEvent
|
||||||
import org.bukkit.inventory.InventoryHolder
|
import org.bukkit.inventory.InventoryHolder
|
||||||
|
import java.util.EnumSet
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
class ParcelListeners(val parcelProvider: ParcelProvider,
|
class ParcelListeners(
|
||||||
val entityTracker: ParcelEntityTracker,
|
val parcelProvider: ParcelProvider,
|
||||||
val storage: Storage) {
|
val entityTracker: ParcelEntityTracker,
|
||||||
|
val storage: Storage
|
||||||
|
) {
|
||||||
private inline fun Parcel?.canBuildN(user: Player) = isPresentAnd { canBuild(user) } || user.hasBuildAnywhere
|
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
|
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,
|
* Prevents players from placing liquids, using flint and steel, changing redstone components,
|
||||||
* using inputs (unless allowed by the plot),
|
* using inputs (unless allowed by the plot),
|
||||||
@@ -191,49 +192,33 @@ class ParcelListeners(val parcelProvider: ParcelProvider,
|
|||||||
|
|
||||||
when (event.action) {
|
when (event.action) {
|
||||||
Action.RIGHT_CLICK_BLOCK -> run {
|
Action.RIGHT_CLICK_BLOCK -> run {
|
||||||
when (clickedBlock.type) {
|
val type = clickedBlock.type
|
||||||
REPEATER,
|
val interactable = parcel.effectiveInteractableConfig.isInteractable(type) || parcel.isPresentAnd { canBuild(user) }
|
||||||
COMPARATOR -> run {
|
if (!interactable) {
|
||||||
if (!parcel.canBuildN(user)) {
|
val interactableClassName = Interactables[type]!!.name
|
||||||
event.isCancelled = true; return@l
|
user.sendParcelMessage(nopermit = true, message = "You cannot interact with $interactableClassName in this parcel")
|
||||||
}
|
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
|
if (bedTypes.contains(type)) {
|
||||||
-> run {
|
val bed = clickedBlock.blockData as Bed
|
||||||
if (world.options.disableExplosions) {
|
val head = if (bed == Bed.Part.FOOT) clickedBlock.getRelative(bed.facing) else clickedBlock
|
||||||
val bed = clickedBlock.blockData as Bed
|
when (head.biome) {
|
||||||
val head = if (bed == Bed.Part.FOOT) clickedBlock.getRelative(bed.facing) else clickedBlock
|
Biome.NETHER, Biome.THE_END -> {
|
||||||
when (head.biome) {
|
if (world.options.disableExplosions || parcel.isNullOr { !canBuild(user) }) {
|
||||||
Biome.NETHER, Biome.THE_END -> run {
|
user.sendParcelMessage(nopermit = true, message = "You cannot use this bed because it would explode")
|
||||||
user.sendParcelMessage(nopermit = true, message = "You cannot use this bed because it would explode")
|
event.isCancelled = true; return@l
|
||||||
event.isCancelled = true; return@l
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onPlayerInteractEvent_RightClick(event, world, parcel)
|
onPlayerInteractEvent_RightClick(event, world, parcel)
|
||||||
}
|
}
|
||||||
|
|
||||||
Action.RIGHT_CLICK_AIR -> 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")
|
user.sendParcelMessage(nopermit = true, message = "You cannot use inputs in this parcel")
|
||||||
event.isCancelled = true; return@l
|
event.isCancelled = true; return@l
|
||||||
}
|
}
|
||||||
@@ -322,7 +307,7 @@ class ParcelListeners(val parcelProvider: ParcelProvider,
|
|||||||
@field:ListenerMarker(priority = NORMAL)
|
@field:ListenerMarker(priority = NORMAL)
|
||||||
val onPlayerDropItemEvent = RegistratorListener<PlayerDropItemEvent> l@{ event ->
|
val onPlayerDropItemEvent = RegistratorListener<PlayerDropItemEvent> l@{ event ->
|
||||||
val (wo, ppa) = getWoAndPPa(event.itemDrop.location.block) ?: return@l
|
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
|
val user = event.whoClicked as? Player ?: return@l
|
||||||
if ((event.inventory ?: return@l).holder === user) return@l // inventory null: hotbar
|
if ((event.inventory ?: return@l).holder === user) return@l // inventory null: hotbar
|
||||||
val (wo, ppa) = getWoAndPPa(event.inventory.location.block) ?: return@l
|
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
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -385,10 +370,10 @@ class ParcelListeners(val parcelProvider: ParcelProvider,
|
|||||||
|
|
||||||
val cancel: Boolean = when (event.newState.type) {
|
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)
|
FROSTED_ICE -> player != null && !ppa.canBuild(player)
|
||||||
|
|
||||||
// prevent snow generation from weather
|
// prevent snow generation from weather
|
||||||
SNOW -> !hasEntity && wo.options.preventWeatherBlockChanges
|
SNOW -> !hasEntity && wo.options.preventWeatherBlockChanges
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
|
|||||||
@@ -58,10 +58,12 @@ interface Backing {
|
|||||||
|
|
||||||
fun setLocalPlayerStatus(parcel: ParcelId, player: PlayerProfile, status: AddedStatus)
|
fun setLocalPlayerStatus(parcel: ParcelId, player: PlayerProfile, status: AddedStatus)
|
||||||
|
|
||||||
|
fun setParcelOptionsInteractBitmask(parcel: ParcelId, bitmask: IntArray?)
|
||||||
|
/*
|
||||||
fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean)
|
fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean)
|
||||||
|
|
||||||
fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean)
|
fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean)
|
||||||
|
*/
|
||||||
|
|
||||||
fun transmitAllGlobalAddedData(channel: SendChannel<AddedDataPair<PlayerProfile>>)
|
fun transmitAllGlobalAddedData(channel: SendChannel<AddedDataPair<PlayerProfile>>)
|
||||||
|
|
||||||
|
|||||||
38
src/main/kotlin/io/dico/parcels2/storage/DataConverters.kt
Normal file
38
src/main/kotlin/io/dico/parcels2/storage/DataConverters.kt
Normal file
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,9 +50,7 @@ interface Storage {
|
|||||||
|
|
||||||
fun setParcelPlayerStatus(parcel: ParcelId, player: PlayerProfile, status: AddedStatus): Job
|
fun setParcelPlayerStatus(parcel: ParcelId, player: PlayerProfile, status: AddedStatus): Job
|
||||||
|
|
||||||
fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean): Job
|
fun setParcelOptionsInteractBitmask(parcel: ParcelId, bitmask: IntArray): Job
|
||||||
|
|
||||||
fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean): Job
|
|
||||||
|
|
||||||
|
|
||||||
fun transmitAllGlobalAddedData(): ReceiveChannel<AddedDataPair<PlayerProfile>>
|
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 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 setParcelOptionsInteractBitmask(parcel: ParcelId, bitmask: IntArray) = b.launchJob { b.setParcelOptionsInteractBitmask(parcel, bitmask) }
|
||||||
|
|
||||||
override fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean) = b.launchJob { b.setParcelAllowsInteractInputs(parcel, value) }
|
|
||||||
|
|
||||||
|
|
||||||
override fun transmitAllGlobalAddedData(): ReceiveChannel<AddedDataPair<PlayerProfile>> = b.openChannel { b.transmitAllGlobalAddedData(it) }
|
override fun transmitAllGlobalAddedData(): ReceiveChannel<AddedDataPair<PlayerProfile>> = b.openChannel { b.transmitAllGlobalAddedData(it) }
|
||||||
|
|||||||
@@ -5,12 +5,9 @@ package io.dico.parcels2.storage.exposed
|
|||||||
import com.zaxxer.hikari.HikariDataSource
|
import com.zaxxer.hikari.HikariDataSource
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.PlayerProfile.Star.name
|
import io.dico.parcels2.PlayerProfile.Star.name
|
||||||
import io.dico.parcels2.storage.AddedDataPair
|
import io.dico.parcels2.storage.*
|
||||||
import io.dico.parcels2.storage.Backing
|
import io.dico.parcels2.util.ext.clampMax
|
||||||
import io.dico.parcels2.storage.DataPair
|
|
||||||
import io.dico.parcels2.util.ext.synchronized
|
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.*
|
||||||
import kotlinx.coroutines.channels.ArrayChannel
|
import kotlinx.coroutines.channels.ArrayChannel
|
||||||
import kotlinx.coroutines.channels.LinkedListChannel
|
import kotlinx.coroutines.channels.LinkedListChannel
|
||||||
@@ -196,8 +193,9 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
|
|||||||
AddedLocalT.setPlayerStatus(parcel, profile, status)
|
AddedLocalT.setPlayerStatus(parcel, profile, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
setParcelAllowsInteractInputs(parcel, data.allowInteractInputs)
|
val bitmaskArray = (data.interactableConfig as? BitmaskInteractableConfiguration ?: return).bitmaskArray
|
||||||
setParcelAllowsInteractInventory(parcel, data.allowInteractInventory)
|
val isAllZero = bitmaskArray.fold(false) { cur, elem -> cur || elem != 0 }
|
||||||
|
setParcelOptionsInteractBitmask(parcel, if (isAllZero) null else bitmaskArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setParcelOwner(parcel: ParcelId, owner: PlayerProfile?) {
|
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)
|
AddedLocalT.setPlayerStatus(parcel, player.toRealProfile(), status)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean) {
|
override fun setParcelOptionsInteractBitmask(parcel: ParcelId, bitmask: IntArray?) {
|
||||||
val id = ParcelsT.getOrInitId(parcel)
|
if (bitmask == null) {
|
||||||
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
|
val id = ParcelsT.getId(parcel) ?: return
|
||||||
it[parcel_id] = id
|
ParcelOptionsT.deleteWhere { ParcelOptionsT.parcel_id eq id }
|
||||||
it[interact_inventory] = value
|
return
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean) {
|
if (bitmask.size != 1) throw IllegalArgumentException()
|
||||||
|
val array = bitmask.toByteArray()
|
||||||
val id = ParcelsT.getOrInitId(parcel)
|
val id = ParcelsT.getOrInitId(parcel)
|
||||||
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
|
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
|
||||||
it[parcel_id] = 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]
|
val id = row[ParcelsT.id]
|
||||||
ParcelOptionsT.select { ParcelOptionsT.parcel_id eq id }.firstOrNull()?.let { optrow ->
|
ParcelOptionsT.select { ParcelOptionsT.parcel_id eq id }.firstOrNull()?.let { optrow ->
|
||||||
allowInteractInputs = optrow[ParcelOptionsT.interact_inputs]
|
val source = optrow[ParcelOptionsT.interact_bitmask].toIntArray()
|
||||||
allowInteractInventory = optrow[ParcelOptionsT.interact_inventory]
|
val target = (interactableConfig as? BitmaskInteractableConfiguration ?: return@let).bitmaskArray
|
||||||
|
System.arraycopy(source, 0, target, 0, source.size.clampMax(target.size))
|
||||||
}
|
}
|
||||||
|
|
||||||
addedMap = AddedLocalT.readAddedData(id)
|
addedMap = AddedLocalT.readAddedData(id)
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ package io.dico.parcels2.storage.exposed
|
|||||||
import io.dico.parcels2.ParcelId
|
import io.dico.parcels2.ParcelId
|
||||||
import io.dico.parcels2.ParcelWorldId
|
import io.dico.parcels2.ParcelWorldId
|
||||||
import io.dico.parcels2.PlayerProfile
|
import io.dico.parcels2.PlayerProfile
|
||||||
import io.dico.parcels2.util.toByteArray
|
import io.dico.parcels2.storage.toByteArray
|
||||||
import io.dico.parcels2.util.toUUID
|
import io.dico.parcels2.storage.toUUID
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.statements.UpdateBuilder
|
import org.jetbrains.exposed.sql.statements.UpdateBuilder
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
package io.dico.parcels2.storage.exposed
|
package io.dico.parcels2.storage.exposed
|
||||||
|
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
|
import io.dico.parcels2.AddedStatus.ALLOWED
|
||||||
|
import io.dico.parcels2.AddedStatus.DEFAULT
|
||||||
import kotlinx.coroutines.channels.SendChannel
|
import kotlinx.coroutines.channels.SendChannel
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
@@ -12,8 +14,7 @@ object AddedGlobalT : AddedTable<PlayerProfile>("parcels_added_global", Profiles
|
|||||||
|
|
||||||
object ParcelOptionsT : Table("parcel_options") {
|
object ParcelOptionsT : Table("parcel_options") {
|
||||||
val parcel_id = integer("parcel_id").primaryKey().references(ParcelsT.id, ReferenceOption.CASCADE)
|
val parcel_id = integer("parcel_id").primaryKey().references(ParcelsT.id, ReferenceOption.CASCADE)
|
||||||
val interact_inventory = bool("interact_inventory").default(true)
|
val interact_bitmask = binary("interact_bitmask", 4).default(ByteArray(4) { 0 }) // all zero by default
|
||||||
val interact_inputs = bool("interact_inputs").default(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias AddedStatusSendChannel<AttachT> = SendChannel<Pair<AttachT, MutableAddedDataMap>>
|
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)
|
val index_pair = uniqueIndexR("index_pair", attach_id, profile_id)
|
||||||
|
|
||||||
fun setPlayerStatus(attachedOn: AttachT, player: PlayerProfile.Real, status: AddedStatus) {
|
fun setPlayerStatus(attachedOn: AttachT, player: PlayerProfile.Real, status: AddedStatus) {
|
||||||
if (status.isDefault) {
|
if (status == DEFAULT) {
|
||||||
val player_id = ProfilesT.getId(player) ?: return
|
val player_id = ProfilesT.getId(player) ?: return
|
||||||
idTable.getId(attachedOn)?.let { holder ->
|
idTable.getId(attachedOn)?.let { holder ->
|
||||||
deleteWhere { (attach_id eq holder) and (profile_id eq player_id) }
|
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) {
|
upsert(conflictIndex = index_pair) {
|
||||||
it[attach_id] = holder
|
it[attach_id] = holder
|
||||||
it[profile_id] = player_id
|
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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import io.dico.parcels2.storage.Storage
|
|||||||
import io.dico.parcels2.storage.exposed.abs
|
import io.dico.parcels2.storage.exposed.abs
|
||||||
import io.dico.parcels2.storage.exposed.greater
|
import io.dico.parcels2.storage.exposed.greater
|
||||||
import io.dico.parcels2.storage.migration.Migration
|
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.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.newFixedThreadPoolContext
|
import kotlinx.coroutines.newFixedThreadPoolContext
|
||||||
|
|||||||
@@ -11,10 +11,4 @@ fun getPlayerName(uuid: UUID): String? {
|
|||||||
return Bukkit.getOfflinePlayer(uuid)?.takeIf { it.isValid }?.name
|
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) }
|
|
||||||
|
|||||||
@@ -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")
|
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("OAK", name),
|
||||||
getMaterialPrefixed("BIRCH", name),
|
getMaterialPrefixed("BIRCH", name),
|
||||||
getMaterialPrefixed("SPRUCE", name),
|
getMaterialPrefixed("SPRUCE", name),
|
||||||
@@ -88,7 +88,7 @@ fun findWoodKindPrefixedMaterials(name: String) = arrayOf(
|
|||||||
getMaterialPrefixed("DARK_OAK", name)
|
getMaterialPrefixed("DARK_OAK", name)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun findColorPrefixedMaterials(name: String) = arrayOf(
|
fun getMaterialsWithWoolColorPrefix(name: String) = arrayOf(
|
||||||
getMaterialPrefixed("WHITE", name),
|
getMaterialPrefixed("WHITE", name),
|
||||||
getMaterialPrefixed("ORANGE", name),
|
getMaterialPrefixed("ORANGE", name),
|
||||||
getMaterialPrefixed("MAGENTA", name),
|
getMaterialPrefixed("MAGENTA", name),
|
||||||
|
|||||||
@@ -30,3 +30,6 @@ fun IntRange.clamp(min: Int, max: Int): IntRange {
|
|||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the name coerceAtMost is bad
|
||||||
|
fun Int.clampMax(max: Int) = coerceAtMost(max)
|
||||||
2
todo.md
2
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.~~
|
~~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
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user