Improve (ParcelTarget)ing for commands, ParcelOwner things, various little bits
This commit is contained in:
@@ -5,7 +5,7 @@ import org.bukkit.OfflinePlayer
|
||||
import java.util.*
|
||||
|
||||
interface AddedData {
|
||||
val added: Map<UUID, AddedStatus>
|
||||
val addedMap: Map<UUID, AddedStatus>
|
||||
|
||||
fun getAddedStatus(uuid: UUID): AddedStatus
|
||||
fun setAddedStatus(uuid: UUID, status: AddedStatus): Boolean
|
||||
@@ -28,12 +28,12 @@ interface AddedData {
|
||||
fun unban(player: OfflinePlayer) = unban(player.uuid)
|
||||
}
|
||||
|
||||
open class AddedDataHolder(override var added: MutableMap<UUID, AddedStatus>
|
||||
open class AddedDataHolder(override var addedMap: MutableMap<UUID, AddedStatus>
|
||||
= mutableMapOf<UUID, AddedStatus>()) : AddedData {
|
||||
override fun getAddedStatus(uuid: UUID): AddedStatus = added.getOrDefault(uuid, AddedStatus.DEFAULT)
|
||||
override fun getAddedStatus(uuid: UUID): AddedStatus = addedMap.getOrDefault(uuid, AddedStatus.DEFAULT)
|
||||
override fun setAddedStatus(uuid: UUID, status: AddedStatus): Boolean = status.takeIf { it != AddedStatus.DEFAULT }
|
||||
?.let { added.put(uuid, it) != it }
|
||||
?: added.remove(uuid) != null
|
||||
?.let { addedMap.put(uuid, it) != it }
|
||||
?: addedMap.remove(uuid) != null
|
||||
}
|
||||
|
||||
enum class AddedStatus {
|
||||
|
||||
@@ -23,7 +23,7 @@ class GlobalAddedDataManagerImpl(val plugin: ParcelsPlugin) : GlobalAddedDataMan
|
||||
data: MutableMap<UUID, AddedStatus> = emptyData)
|
||||
: AddedDataHolder(data), GlobalAddedData {
|
||||
|
||||
private inline var data get() = added; set(value) = run { added = value }
|
||||
private inline var data get() = addedMap; set(value) = run { addedMap = value }
|
||||
private inline val isEmpty get() = data === emptyData
|
||||
|
||||
override fun setAddedStatus(uuid: UUID, status: AddedStatus): Boolean {
|
||||
|
||||
@@ -1,26 +1,14 @@
|
||||
package io.dico.parcels2
|
||||
|
||||
import io.dico.dicore.Formatting
|
||||
import io.dico.parcels2.util.Vec2i
|
||||
import io.dico.parcels2.util.getPlayerName
|
||||
import io.dico.parcels2.util.hasBuildAnywhere
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.OfflinePlayer
|
||||
import org.bukkit.entity.Player
|
||||
import org.joda.time.DateTime
|
||||
import java.util.*
|
||||
|
||||
interface ParcelData : AddedData {
|
||||
var owner: ParcelOwner?
|
||||
val since: DateTime?
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* Parcel implementation of ParcelData will update the database when changes are made.
|
||||
@@ -31,16 +19,12 @@ interface ParcelData : AddedData {
|
||||
* Therefore, database query callbacks should schedule their updates using the bukkit scheduler.
|
||||
*/
|
||||
class Parcel(val world: ParcelWorld, val pos: Vec2i) : ParcelData {
|
||||
var data: ParcelData = ParcelDataHolder(); private set
|
||||
|
||||
val id get() = "${pos.x}:${pos.z}"
|
||||
val homeLocation get() = world.generator.getHomeLocation(this)
|
||||
private var blockVisitors = 0
|
||||
|
||||
val infoString: String
|
||||
get() {
|
||||
return "$id; owned by ${owner?.let { it.name ?: Bukkit.getOfflinePlayer(it.uuid).name }}"
|
||||
}
|
||||
|
||||
var data: ParcelData = ParcelDataHolder(); private set
|
||||
val infoString by ParcelInfoStringComputer
|
||||
|
||||
fun copyDataIgnoringDatabase(data: ParcelData) {
|
||||
this.data = data
|
||||
@@ -48,14 +32,19 @@ class Parcel(val world: ParcelWorld, val pos: Vec2i) : ParcelData {
|
||||
|
||||
fun copyData(data: ParcelData) {
|
||||
world.storage.setParcelData(this, data)
|
||||
this.data = data
|
||||
copyDataIgnoringDatabase(data)
|
||||
}
|
||||
|
||||
override val added: Map<UUID, AddedStatus> get() = data.added
|
||||
override val addedMap: Map<UUID, AddedStatus> get() = data.addedMap
|
||||
override fun getAddedStatus(uuid: UUID) = data.getAddedStatus(uuid)
|
||||
override fun isBanned(uuid: UUID) = data.isBanned(uuid)
|
||||
override fun isAllowed(uuid: UUID) = data.isAllowed(uuid)
|
||||
override fun canBuild(player: OfflinePlayer, checkAdmin: Boolean, checkGlobal: Boolean) = data.canBuild(player)
|
||||
override fun canBuild(player: OfflinePlayer, checkAdmin: Boolean, checkGlobal: Boolean): Boolean {
|
||||
return (data.canBuild(player, checkAdmin, false))
|
||||
|| checkGlobal && world.globalAddedData[owner ?: return false].isAllowed(player)
|
||||
}
|
||||
|
||||
val globalAddedMap: Map<UUID, AddedStatus>? get() = owner?.let { world.globalAddedData[it].addedMap }
|
||||
|
||||
override val since: DateTime? get() = data.since
|
||||
|
||||
@@ -93,7 +82,22 @@ class Parcel(val world: ParcelWorld, val pos: Vec2i) : ParcelData {
|
||||
var hasBlockVisitors: Boolean = false; private set
|
||||
}
|
||||
|
||||
interface ParcelData : AddedData {
|
||||
var owner: ParcelOwner?
|
||||
val since: DateTime?
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
class ParcelDataHolder : AddedDataHolder(), ParcelData {
|
||||
|
||||
override var owner: ParcelOwner? = null
|
||||
override var since: DateTime? = null
|
||||
override fun canBuild(player: OfflinePlayer, checkAdmin: Boolean, checkGlobal: Boolean) = isAllowed(player.uniqueId)
|
||||
@@ -104,3 +108,59 @@ class ParcelDataHolder : AddedDataHolder(), ParcelData {
|
||||
override var allowInteractInventory = true
|
||||
}
|
||||
|
||||
private object ParcelInfoStringComputer {
|
||||
val infoStringColor1 = Formatting.GREEN
|
||||
val infoStringColor2 = Formatting.AQUA
|
||||
|
||||
private inline fun StringBuilder.appendField(name: String, value: StringBuilder.() -> Unit) {
|
||||
append(infoStringColor1)
|
||||
append(name)
|
||||
append(": ")
|
||||
append(infoStringColor2)
|
||||
value()
|
||||
append(' ')
|
||||
}
|
||||
|
||||
operator fun getValue(parcel: Parcel, property: KProperty<*>): String = buildString {
|
||||
appendField("ID") {
|
||||
append(parcel.pos.x)
|
||||
append(':')
|
||||
append(parcel.pos.z)
|
||||
}
|
||||
|
||||
appendField("Owner") {
|
||||
val owner = parcel.owner
|
||||
if (owner == null) {
|
||||
append(infoStringColor1)
|
||||
append("none")
|
||||
} else {
|
||||
append(owner.notNullName)
|
||||
}
|
||||
}
|
||||
|
||||
// plotme appends biome here
|
||||
|
||||
append('\n')
|
||||
|
||||
val allowedMap = parcel.addedMap.filterValues { it.isAllowed }
|
||||
if (allowedMap.isNotEmpty()) appendField("Allowed") {
|
||||
allowedMap.keys.map(::getPlayerName).joinTo(this)
|
||||
}
|
||||
|
||||
val bannedMap = parcel.addedMap.filterValues { it.isBanned }
|
||||
if (bannedMap.isNotEmpty()) appendField("Banned") {
|
||||
bannedMap.keys.map(::getPlayerName).joinTo(this)
|
||||
}
|
||||
|
||||
if (!parcel.allowInteractInputs || !parcel.allowInteractInventory) {
|
||||
appendField("Options") {
|
||||
append("(")
|
||||
appendField("inputs") { append(parcel.allowInteractInputs)}
|
||||
append(", ")
|
||||
appendField("inventory") { append(parcel.allowInteractInventory) }
|
||||
append(")")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
@file:Suppress("unused")
|
||||
|
||||
package io.dico.parcels2
|
||||
|
||||
import io.dico.parcels2.util.getPlayerNameOrDefault
|
||||
@@ -10,10 +12,8 @@ import java.util.*
|
||||
|
||||
@Suppress("UsePropertyAccessSyntax")
|
||||
class ParcelOwner private constructor(val uuid: UUID?,
|
||||
name: String?) {
|
||||
var name: String? = name
|
||||
get() = field ?: getPlayerNameOrDefault(uuid!!).also { field = it }
|
||||
private set
|
||||
val name: String?) {
|
||||
val notNullName: String by lazy { name ?: getPlayerNameOrDefault(uuid!!) }
|
||||
|
||||
constructor(name: String) : this(null, name)
|
||||
constructor(uuid: UUID) : this(uuid, null)
|
||||
@@ -24,13 +24,13 @@ class ParcelOwner private constructor(val uuid: UUID?,
|
||||
}
|
||||
|
||||
inline val hasUUID: Boolean get() = uuid != null
|
||||
val onlinePlayer: Player? get() = uuid?.let { Bukkit.getPlayer(uuid) }
|
||||
val onlinePlayerAllowingNameMatch: Player? get() = onlinePlayer ?: name?.let { Bukkit.getPlayer(name) }
|
||||
|
||||
val onlinePlayer: Player? get() = uuid?.let { Bukkit.getPlayer(uuid) }
|
||||
@Suppress("DEPRECATION")
|
||||
val offlinePlayer
|
||||
get() = (uuid?.let { Bukkit.getOfflinePlayer(it) } ?: Bukkit.getOfflinePlayer(name))
|
||||
?.takeIf { it.isValid }
|
||||
val onlinePlayerAllowingNameMatch: Player? get() = onlinePlayer ?: name?.let { Bukkit.getPlayerExact(name) }
|
||||
val offlinePlayer: OfflinePlayer? get() = uuid?.let { Bukkit.getOfflinePlayer(it).takeIf { it.isValid } }
|
||||
@Suppress("DEPRECATION")
|
||||
val offlinePlayerAllowingNameMatch: OfflinePlayer? get() = offlinePlayer ?: Bukkit.getOfflinePlayer(name).takeIf { it.isValid }
|
||||
|
||||
fun matches(player: OfflinePlayer, allowNameMatch: Boolean = false): Boolean {
|
||||
return uuid?.let { it == player.uniqueId } ?: false
|
||||
|
||||
@@ -64,7 +64,8 @@ class Worlds(val plugin: ParcelsPlugin) {
|
||||
worldName,
|
||||
worldOptions,
|
||||
worldOptions.generator.getGenerator(this, worldName),
|
||||
plugin.storage)
|
||||
plugin.storage,
|
||||
plugin.globalAddedData)
|
||||
|
||||
} catch (ex: Exception) {
|
||||
ex.printStackTrace()
|
||||
@@ -117,7 +118,8 @@ interface ParcelProvider {
|
||||
class ParcelWorld constructor(val name: String,
|
||||
val options: WorldOptions,
|
||||
val generator: ParcelGenerator,
|
||||
val storage: Storage) : ParcelProvider by generator, ParcelContainer {
|
||||
val storage: Storage,
|
||||
val globalAddedData: GlobalAddedDataManager) : ParcelProvider by generator, ParcelContainer {
|
||||
val world: World by lazy {
|
||||
Bukkit.getWorld(name) ?: throw NullPointerException("World $name does not appear to be loaded")
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ abstract class ParcelGenerator : ChunkGenerator(), ParcelProvider {
|
||||
|
||||
abstract val factory: GeneratorFactory
|
||||
|
||||
abstract fun parcelIDAt(x: Int, z: Int): Vec2i?
|
||||
|
||||
abstract override fun generateChunkData(world: World?, random: Random?, chunkX: Int, chunkZ: Int, biome: BiomeGrid?): ChunkData
|
||||
|
||||
abstract fun populate(world: World?, random: Random?, chunk: Chunk?)
|
||||
@@ -171,19 +173,29 @@ class DefaultParcelGenerator(val worlds: Worlds, val name: String, private val o
|
||||
return Location(world, o.offsetX + fix, o.floorHeight + 1.0, o.offsetZ + fix)
|
||||
}
|
||||
|
||||
override fun parcelAt(x: Int, z: Int): Parcel? {
|
||||
private inline fun <T> convertBlockLocationToID(x: Int, z: Int, mapper: (Int, Int) -> T): T? {
|
||||
val sectionSize = sectionSize
|
||||
val parcelSize = o.parcelSize
|
||||
val absX = x - o.offsetX - pathOffset
|
||||
val absZ = z - o.offsetZ - pathOffset
|
||||
val modX = absX umod sectionSize
|
||||
val modZ = absZ umod sectionSize
|
||||
if (0 <= modX && modX < parcelSize && 0 <= modZ && modZ < parcelSize) {
|
||||
return world.parcelByID((absX - modX) / sectionSize, (absZ - modZ) / sectionSize)
|
||||
if (modX in 0 until parcelSize && modZ in 0 until parcelSize) {
|
||||
return mapper((absX - modX) / sectionSize, (absZ - modZ) / sectionSize)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun parcelIDAt(x: Int, z: Int): Vec2i? {
|
||||
return convertBlockLocationToID(x, z) { idx, idz -> Vec2i(idx, idz) }
|
||||
}
|
||||
|
||||
override fun parcelAt(x: Int, z: Int): Parcel? {
|
||||
return convertBlockLocationToID(x, z) { idx, idz ->
|
||||
world.parcelByID(idx, idz)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getBottomCoord(parcel: Parcel): Vec2i = Vec2i(sectionSize * parcel.pos.x + pathOffset + o.offsetX,
|
||||
sectionSize * parcel.pos.z + pathOffset + o.offsetZ)
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import io.dico.dicore.command.annotation.RequireParameters
|
||||
import io.dico.parcels2.ParcelOwner
|
||||
import io.dico.parcels2.ParcelsPlugin
|
||||
import io.dico.parcels2.blockvisitor.RegionTraversal
|
||||
import io.dico.parcels2.command.NamedParcelDefaultValue.FIRST_OWNED
|
||||
import io.dico.parcels2.storage.getParcelBySerializedValue
|
||||
import io.dico.parcels2.util.hasAdminManage
|
||||
import io.dico.parcels2.util.hasParcelHomeOthers
|
||||
@@ -49,18 +48,17 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||
"more than one parcel",
|
||||
shortVersion = "teleports you to parcels")
|
||||
@RequireParameters(0)
|
||||
suspend fun cmdHome(player: Player,
|
||||
@NamedParcelDefault(FIRST_OWNED) target: NamedParcelTarget): Any? {
|
||||
if (player !== target.player && !player.hasParcelHomeOthers) {
|
||||
suspend fun cmdHome(player: Player, @ParcelTarget.Kind(ParcelTarget.OWNER_REAL) target: ParcelTarget): Any? {
|
||||
val ownerTarget = target as ParcelTarget.ByOwner
|
||||
if (!ownerTarget.owner.matches(player) && !player.hasParcelHomeOthers) {
|
||||
error("You do not have permission to teleport to other people's parcels")
|
||||
}
|
||||
|
||||
val ownedParcelsResult = plugin.storage.getOwnedParcels(ParcelOwner(uuid = target.player.uuid)).await()
|
||||
val ownedParcelsResult = plugin.storage.getOwnedParcels(ownerTarget.owner).await()
|
||||
|
||||
val uuid = target.player.uuid
|
||||
val ownedParcels = ownedParcelsResult
|
||||
.map { worlds.getParcelBySerializedValue(it) }
|
||||
.filter { it != null && it.world == target.world && it.owner?.uuid == uuid }
|
||||
.filter { it != null && ownerTarget.world == it.world && ownerTarget.owner == it.owner }
|
||||
|
||||
val targetMatch = ownedParcels.getOrNull(target.index)
|
||||
?: error("The specified parcel could not be matched")
|
||||
@@ -79,7 +77,7 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||
}
|
||||
|
||||
checkParcelLimit(player)
|
||||
parcel.owner = ParcelOwner(uuid = player.uuid, name = player.name)
|
||||
parcel.owner = ParcelOwner(player)
|
||||
return "Enjoy your new parcel!"
|
||||
}
|
||||
|
||||
@@ -100,7 +98,7 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||
|
||||
@Cmd("swap")
|
||||
fun ParcelScope.cmdSwap(context: ExecutionContext, @Flag sure: Boolean): Any? {
|
||||
|
||||
TODO()
|
||||
}
|
||||
|
||||
@Cmd("make_mess")
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package io.dico.parcels2.command
|
||||
|
||||
import io.dico.parcels2.Parcel
|
||||
import io.dico.parcels2.ParcelWorld
|
||||
import io.dico.parcels2.ParcelsPlugin
|
||||
import kotlinx.coroutines.experimental.Deferred
|
||||
|
||||
interface ParcelTarget {
|
||||
val world: ParcelWorld
|
||||
val isByID: Boolean
|
||||
val isByOwner: Boolean get() = !isByID
|
||||
suspend fun ParcelsPlugin.await(): Parcel?
|
||||
fun ParcelsPlugin.get(): Deferred<Parcel?> =
|
||||
}
|
||||
|
||||
class ParcelTargetByOwner : ParcelTarget {
|
||||
override val isByID get() = false
|
||||
}
|
||||
|
||||
class ParcelTargetByID : ParcelTarget {
|
||||
override val isByID get() = true
|
||||
|
||||
}
|
||||
@@ -49,75 +49,3 @@ class ParcelParameterType(val worlds: Worlds) : ParameterType<Parcel, Void>(Parc
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class NamedParcelTarget(val world: ParcelWorld, val player: OfflinePlayer, val index: Int)
|
||||
|
||||
@Target(AnnotationTarget.VALUE_PARAMETER)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class NamedParcelDefault(val value: NamedParcelDefaultValue)
|
||||
|
||||
enum class NamedParcelDefaultValue {
|
||||
FIRST_OWNED,
|
||||
NULL
|
||||
}
|
||||
|
||||
class NamedParcelTargetConfig : ParameterConfig<NamedParcelDefault,
|
||||
NamedParcelDefaultValue>(NamedParcelDefault::class.java) {
|
||||
|
||||
override fun toParameterInfo(annotation: NamedParcelDefault): NamedParcelDefaultValue {
|
||||
return annotation.value
|
||||
}
|
||||
}
|
||||
|
||||
class ParcelHomeParameterType(val worlds: Worlds) : ParameterType<NamedParcelTarget,
|
||||
NamedParcelDefaultValue>(NamedParcelTarget::class.java, NamedParcelTargetConfig()) {
|
||||
|
||||
val regex = Regex.fromLiteral("((.+)->)?(.+)|((.+):([0-9]+))")
|
||||
|
||||
private fun requirePlayer(sender: CommandSender, parameter: Parameter<*, *>): Player {
|
||||
if (sender !is Player) invalidInput(parameter, "console cannot omit the player name")
|
||||
return sender
|
||||
}
|
||||
|
||||
@Suppress("UsePropertyAccessSyntax")
|
||||
private fun getOfflinePlayer(input: String, parameter: Parameter<*, *>) = Bukkit.getOfflinePlayer(input)
|
||||
?.takeIf { it.isValid }
|
||||
?: invalidInput(parameter, "do not know who $input is")
|
||||
|
||||
override fun parse(parameter: Parameter<NamedParcelTarget, NamedParcelDefaultValue>,
|
||||
sender: CommandSender, buffer: ArgumentBuffer): NamedParcelTarget {
|
||||
val matchResult = regex.matchEntire(buffer.next())
|
||||
?: invalidInput(parameter, "must be a player, index, or player:index (/${regex.pattern}/)")
|
||||
|
||||
val world = worlds.getTargetWorld(matchResult.groupValues[2], sender, parameter)
|
||||
|
||||
matchResult.groupValues[3].takeUnless { it.isEmpty() }?.let {
|
||||
// first group was matched, it's a player or an int
|
||||
it.toIntOrNull()?.let {
|
||||
requirePlayer(sender, parameter)
|
||||
return NamedParcelTarget(world, sender as Player, it)
|
||||
}
|
||||
|
||||
return NamedParcelTarget(world, getOfflinePlayer(it, parameter), 0)
|
||||
}
|
||||
|
||||
val player = getOfflinePlayer(matchResult.groupValues[5], parameter)
|
||||
val index = matchResult.groupValues[6].toIntOrNull()
|
||||
?: invalidInput(parameter, "couldn't parse int")
|
||||
|
||||
return NamedParcelTarget(world, player, index)
|
||||
}
|
||||
|
||||
override fun getDefaultValue(parameter: Parameter<NamedParcelTarget, NamedParcelDefaultValue>,
|
||||
sender: CommandSender, buffer: ArgumentBuffer): NamedParcelTarget? {
|
||||
if (parameter.paramInfo == NamedParcelDefaultValue.NULL) {
|
||||
return null
|
||||
}
|
||||
|
||||
val world = worlds.getTargetWorld(null, sender, parameter)
|
||||
val player = requirePlayer(sender, parameter)
|
||||
return NamedParcelTarget(world, player, 0)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
163
src/main/kotlin/io/dico/parcels2/command/ParcelTarget.kt
Normal file
163
src/main/kotlin/io/dico/parcels2/command/ParcelTarget.kt
Normal file
@@ -0,0 +1,163 @@
|
||||
package io.dico.parcels2.command
|
||||
|
||||
import io.dico.dicore.command.parameter.ArgumentBuffer
|
||||
import io.dico.dicore.command.parameter.Parameter
|
||||
import io.dico.dicore.command.parameter.type.ParameterConfig
|
||||
import io.dico.dicore.command.parameter.type.ParameterType
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.storage.getParcelBySerializedValue
|
||||
import io.dico.parcels2.util.Vec2i
|
||||
import io.dico.parcels2.util.floor
|
||||
import io.dico.parcels2.util.isValid
|
||||
import kotlinx.coroutines.experimental.Deferred
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
sealed class ParcelTarget(val world: ParcelWorld, val isDefault: Boolean) {
|
||||
abstract suspend fun ParcelsPlugin.getParcelSuspend(): Parcel?
|
||||
fun ParcelsPlugin.getParcelDeferred(): Deferred<Parcel?> = functionHelper.deferUndispatchedOnMainThread { getParcelSuspend() }
|
||||
|
||||
class ByID(world: ParcelWorld, val id: Vec2i?, isDefault: Boolean) : ParcelTarget(world, isDefault) {
|
||||
override suspend fun ParcelsPlugin.getParcelSuspend(): Parcel? = getParcel()
|
||||
fun getParcel() = id?.let { world.parcelByID(it) }
|
||||
val isPath: Boolean get() = id == null
|
||||
}
|
||||
|
||||
class ByOwner(world: ParcelWorld, val owner: ParcelOwner, val index: Int, isDefault: Boolean) : ParcelTarget(world, isDefault) {
|
||||
init {
|
||||
if (index < 0) throw IllegalArgumentException("Invalid parcel home index: $index")
|
||||
}
|
||||
|
||||
override suspend fun ParcelsPlugin.getParcelSuspend(): Parcel? {
|
||||
val ownedParcelsSerialized = storage.getOwnedParcels(owner).await()
|
||||
val ownedParcels = ownedParcelsSerialized
|
||||
.map { worlds.getParcelBySerializedValue(it) }
|
||||
.filter { it != null && world == it.world && owner == it.owner }
|
||||
return ownedParcels.getOrNull(index)
|
||||
}
|
||||
}
|
||||
|
||||
annotation class Kind(val kind: Int)
|
||||
|
||||
companion object Config : ParameterConfig<Kind, Int>(Kind::class.java) {
|
||||
override fun toParameterInfo(annotation: Kind): Int {
|
||||
return annotation.kind
|
||||
}
|
||||
|
||||
const val ID = 1 // ID
|
||||
const val OWNER_REAL = 2 // an owner backed by a UUID
|
||||
const val OWNER_FAKE = 3 // an owner not backed by a UUID
|
||||
|
||||
const val OWNER = OWNER_REAL or OWNER_FAKE // any owner
|
||||
const val ANY = ID or OWNER_REAL or OWNER_FAKE // any
|
||||
const val REAL = ID or OWNER_REAL // no owner not backed by a UUID
|
||||
|
||||
const val DEFAULT_KIND = REAL
|
||||
|
||||
const val PREFER_OWNED_FOR_DEFAULT = 4 // if the kind can be ID and OWNER_REAL, prefer OWNER_REAL for default
|
||||
// instead of parcel that the player is in
|
||||
}
|
||||
|
||||
class PType(val worlds: Worlds) : ParameterType<ParcelTarget, Int>(ParcelTarget::class.java, ParcelTarget.Config) {
|
||||
|
||||
override fun parse(parameter: Parameter<ParcelTarget, Int>, sender: CommandSender, buffer: ArgumentBuffer): ParcelTarget {
|
||||
var input = buffer.next()
|
||||
val worldString = input.substringBefore("->", missingDelimiterValue = "")
|
||||
input = input.substringAfter("->")
|
||||
|
||||
val world = if (worldString.isEmpty()) {
|
||||
val player = requirePlayer(sender, parameter, "the world")
|
||||
worlds.getWorld(player.world)
|
||||
?: invalidInput(parameter, "You cannot omit the world if you're not in a parcel world")
|
||||
} else {
|
||||
worlds.getWorld(worldString) ?: invalidInput(parameter, "$worldString is not a parcel world")
|
||||
}
|
||||
|
||||
val kind = parameter.paramInfo ?: DEFAULT_KIND
|
||||
if (input.contains(',')) {
|
||||
if (kind and ID == 0) invalidInput(parameter, "You must specify a parcel by ID, that is, the x and z component separated by a comma")
|
||||
return ByID(world, getId(parameter, input), false)
|
||||
}
|
||||
|
||||
if (kind and OWNER == 0) invalidInput(parameter, "You must specify a parcel by OWNER, that is, an owner and index")
|
||||
val (owner, index) = getHomeIndex(parameter, sender, input)
|
||||
return ByOwner(world, owner, index, false)
|
||||
}
|
||||
|
||||
private fun getId(parameter: Parameter<*, *>, input: String): Vec2i {
|
||||
val x = input.substringBefore(',').run {
|
||||
toIntOrNull() ?: invalidInput(parameter, "ID(x) must be an integer, $this is not an integer")
|
||||
}
|
||||
val z = input.substringAfter(',').run {
|
||||
toIntOrNull() ?: invalidInput(parameter, "ID(z) must be an integer, $this is not an integer")
|
||||
}
|
||||
return Vec2i(x, z)
|
||||
}
|
||||
|
||||
private fun getHomeIndex(parameter: Parameter<*, Int>, sender: CommandSender, input: String): Pair<ParcelOwner, Int> {
|
||||
val splitIdx = input.indexOf(':')
|
||||
val ownerString: String
|
||||
val indexString: String
|
||||
|
||||
if (splitIdx == -1) {
|
||||
// just the index.
|
||||
ownerString = ""
|
||||
indexString = input
|
||||
} else {
|
||||
ownerString = input.substring(0, splitIdx)
|
||||
indexString = input.substring(0, splitIdx + 1)
|
||||
}
|
||||
|
||||
val owner = if (ownerString.isEmpty())
|
||||
ParcelOwner(requirePlayer(sender, parameter, "the player"))
|
||||
else
|
||||
inputAsOwner(parameter, ownerString)
|
||||
|
||||
val index = if (indexString.isEmpty()) 0 else indexString.toIntOrNull()
|
||||
?: invalidInput(parameter, "The home index must be an integer, $indexString is not an integer")
|
||||
|
||||
return owner to index
|
||||
}
|
||||
|
||||
private fun requirePlayer(sender: CommandSender, parameter: Parameter<*, *>, objName: String): Player {
|
||||
if (sender !is Player) invalidInput(parameter, "console cannot omit the $objName")
|
||||
return sender
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private fun inputAsOwner(parameter: Parameter<*, Int>, input: String): ParcelOwner {
|
||||
val kind = parameter.paramInfo ?: DEFAULT_KIND
|
||||
if (kind and OWNER_REAL == 0) {
|
||||
return ParcelOwner(input)
|
||||
}
|
||||
|
||||
val player = Bukkit.getOfflinePlayer(input).takeIf { it.isValid }
|
||||
if (player == null) {
|
||||
if (kind and OWNER_FAKE == 0) invalidInput(parameter, "The player $input does not exist")
|
||||
return ParcelOwner(input)
|
||||
}
|
||||
|
||||
return ParcelOwner(player)
|
||||
}
|
||||
|
||||
override fun getDefaultValue(parameter: Parameter<ParcelTarget, Int>, sender: CommandSender, buffer: ArgumentBuffer): ParcelTarget? {
|
||||
val kind = parameter.paramInfo ?: DEFAULT_KIND
|
||||
val useLocation = when {
|
||||
kind and REAL == REAL -> kind and PREFER_OWNED_FOR_DEFAULT == 0
|
||||
kind and ID != 0 -> true
|
||||
kind and OWNER_REAL != 0 -> false
|
||||
else -> return null
|
||||
}
|
||||
|
||||
val player = requirePlayer(sender, parameter, "the parcel")
|
||||
val world = worlds.getWorld(player.world) ?: invalidInput(parameter, "You must be in a parcel world to omit the parcel")
|
||||
if (useLocation) {
|
||||
val id = player.location.let { world.generator.parcelIDAt(it.x.floor(), it.z.floor()) }
|
||||
return ByID(world, id, true)
|
||||
}
|
||||
|
||||
return ByOwner(world, ParcelOwner(player), 0, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -107,7 +107,7 @@ class ExposedBacking(private val dataSourceFactory: suspend () -> DataSource) :
|
||||
|
||||
setParcelOwner(parcelFor, data.owner)
|
||||
|
||||
for ((uuid, status) in data.added) {
|
||||
for ((uuid, status) in data.addedMap) {
|
||||
setLocalPlayerStatus(parcelFor, uuid, status)
|
||||
}
|
||||
|
||||
@@ -168,7 +168,7 @@ class ExposedBacking(private val dataSourceFactory: suspend () -> DataSource) :
|
||||
since = row[ParcelsT.claim_time]
|
||||
|
||||
val parcelId = row[ParcelsT.id]
|
||||
added = AddedLocalT.readAddedData(parcelId)
|
||||
addedMap = AddedLocalT.readAddedData(parcelId)
|
||||
|
||||
AddedLocalT.select { AddedLocalT.attach_id eq parcelId }.forEach {
|
||||
val uuid = it[AddedLocalT.player_uuid].toUUID()
|
||||
|
||||
@@ -32,7 +32,7 @@ sealed class IdTransactionsTable<TableT : IdTransactionsTable<TableT, QueryObj,
|
||||
return table.insert(body)[id] ?: insertError(objName)
|
||||
}
|
||||
|
||||
private inline fun insertError(obj: String): Nothing = throw ExposedDatabaseException("This should not happen - failed to insert $obj and get its id")
|
||||
private inline fun insertError(obj: String): Nothing = throw ExposedDatabaseException("This should not happen - failed to insert $obj and getParcelDeferred its id")
|
||||
|
||||
abstract fun getId(obj: QueryObj): Int?
|
||||
abstract fun getOrInitId(obj: QueryObj): Int
|
||||
@@ -91,31 +91,32 @@ object ParcelsT : IdTransactionsTable<ParcelsT, Parcel, SerializableParcel>("par
|
||||
|
||||
object OwnersT : IdTransactionsTable<OwnersT, ParcelOwner, ParcelOwner>("parcel_owners", "owner_id") {
|
||||
val uuid = binary("uuid", 2).nullable()
|
||||
val name = varchar("name", 32).nullable()
|
||||
val name = varchar("name", 32)
|
||||
val index_pair = uniqueIndexR("index_pair", uuid, name)
|
||||
|
||||
private inline fun getId(binaryUuid: ByteArray) = getId { uuid eq binaryUuid }
|
||||
private inline fun getId(uuid: UUID) = getId(uuid.toByteArray())
|
||||
private inline fun getId(name: String) = getId { OwnersT.name eq name }
|
||||
private inline fun getId(nameIn: String) = getId { uuid.isNull() and (name eq nameIn) }
|
||||
|
||||
private inline fun getOrInitId(uuid: UUID) = uuid.toByteArray().let { binaryUuid ->
|
||||
getId(binaryUuid)
|
||||
?: insertAndGetId("owner(uuid = $uuid)") { it[OwnersT.uuid] = binaryUuid }
|
||||
private inline fun getOrInitId(uuid: UUID, name: String) = uuid.toByteArray().let { binaryUuid ->
|
||||
getId(binaryUuid) ?: insertAndGetId("owner(uuid = $uuid)") {
|
||||
it[this@OwnersT.uuid] = binaryUuid
|
||||
it[this@OwnersT.name] = name
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun getOrInitId(name: String) =
|
||||
getId(name)
|
||||
?: insertAndGetId("owner(name = $name)") { it[OwnersT.name] = name }
|
||||
getId(name) ?: insertAndGetId("owner(name = $name)") { it[OwnersT.name] = name }
|
||||
|
||||
override fun getId(owner: ParcelOwner): Int? =
|
||||
if (owner.hasUUID) getId(owner.uuid!!)
|
||||
else getId(owner.name!!)
|
||||
|
||||
override fun getOrInitId(owner: ParcelOwner): Int =
|
||||
if (owner.hasUUID) getOrInitId(owner.uuid!!)
|
||||
if (owner.hasUUID) getOrInitId(owner.uuid!!, owner.notNullName)
|
||||
else getOrInitId(owner.name!!)
|
||||
|
||||
override fun getSerializable(row: ResultRow): ParcelOwner {
|
||||
return row[uuid]?.toUUID()?.let { ParcelOwner(it) } ?: ParcelOwner(row[name]!!)
|
||||
return row[uuid]?.toUUID()?.let { ParcelOwner(it) } ?: ParcelOwner(row[name])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ object AddedGlobalT : AddedTable<ParcelOwner, ParcelOwner>("parcels_added_global
|
||||
|
||||
object ParcelOptionsT : Table("parcel_options") {
|
||||
val parcel_id = integer("parcel_id").primaryKey().references(ParcelsT.id, ReferenceOption.CASCADE)
|
||||
val interact_inventory = bool("interact_inventory").default(false)
|
||||
val interact_inputs = bool("interact_inputs").default(false)
|
||||
val interact_inventory = bool("interact_inventory").default(true)
|
||||
val interact_inputs = bool("interact_inputs").default(true)
|
||||
}
|
||||
|
||||
typealias AddedStatusSendChannel<AttachT> = SendChannel<Pair<AttachT, MutableMap<UUID, AddedStatus>>>
|
||||
|
||||
@@ -19,7 +19,7 @@ data class Vec3i(
|
||||
inline operator fun World.get(vec: Vec3i): Block = getBlockAt(vec.x, vec.y, vec.z)
|
||||
|
||||
/*
|
||||
inline class IVec3i(private val data: Long) {
|
||||
private /*inline */class IVec3i(private val data: Long) {
|
||||
|
||||
private companion object {
|
||||
const val mask = 0x001F_FFFF
|
||||
@@ -34,7 +34,8 @@ inline class IVec3i(private val data: Long) {
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun Long.extractInt(offset: Int): Int {
|
||||
return ushr(offset).toInt().and(mask)
|
||||
val result = ushr(offset).toInt().and(mask)
|
||||
return if (result > max) result or mask.inv() else result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user