Archived
0

Improve (ParcelTarget)ing for commands, ParcelOwner things, various little bits

This commit is contained in:
Dico Karssiens
2018-08-02 01:16:38 +01:00
parent 472e700e04
commit 3917855a72
14 changed files with 307 additions and 165 deletions

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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(")")
}
}
}
}

View File

@@ -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

View File

@@ -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")
}

View File

@@ -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)

View File

@@ -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")

View File

@@ -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
}

View File

@@ -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)
}
}

View 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)
}
}
}

View File

@@ -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()

View File

@@ -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])
}
}

View File

@@ -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>>>

View File

@@ -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
}
}