Tweaks and fixes
This commit is contained in:
@@ -15,6 +15,7 @@ import org.bukkit.block.Block
|
||||
import org.bukkit.entity.Entity
|
||||
import org.bukkit.entity.Player
|
||||
import java.util.*
|
||||
import kotlin.coroutines.experimental.buildIterator
|
||||
import kotlin.coroutines.experimental.buildSequence
|
||||
import kotlin.reflect.jvm.javaMethod
|
||||
import kotlin.reflect.jvm.kotlinFunction
|
||||
@@ -117,7 +118,9 @@ class ParcelWorld constructor(val name: String,
|
||||
val options: WorldOptions,
|
||||
val generator: ParcelGenerator,
|
||||
val storage: Storage) : ParcelProvider by generator, ParcelContainer {
|
||||
val world: World by lazy { Bukkit.getWorld(name) ?: throw NullPointerException("World $name does not appear to be loaded") }
|
||||
val world: World by lazy {
|
||||
Bukkit.getWorld(name) ?: throw NullPointerException("World $name does not appear to be loaded")
|
||||
}
|
||||
val container: ParcelContainer = DefaultParcelContainer(this, storage)
|
||||
|
||||
override fun parcelByID(x: Int, z: Int): Parcel? {
|
||||
@@ -189,12 +192,24 @@ class DefaultParcelContainer(private val world: ParcelWorld,
|
||||
}
|
||||
|
||||
override fun parcelByID(x: Int, z: Int): Parcel? {
|
||||
return parcels.getOrNull(x)?.getOrNull(z)
|
||||
return parcels.getOrNull(x + world.options.axisLimit)?.getOrNull(z + world.options.axisLimit)
|
||||
}
|
||||
|
||||
override fun nextEmptyParcel(): Parcel? {
|
||||
return parcels[0][0]
|
||||
TODO()
|
||||
return walkInCircle().find { it.owner == null }
|
||||
}
|
||||
|
||||
private fun walkInCircle(): Iterable<Parcel> = Iterable {
|
||||
buildIterator {
|
||||
val center = world.options.axisLimit
|
||||
for (radius in 0..center) {
|
||||
var x = center - radius; var z = center - radius
|
||||
repeat(radius * 2) { yield(parcels[x++][z]) }
|
||||
repeat(radius * 2) { yield(parcels[x][z++]) }
|
||||
repeat(radius * 2) { yield(parcels[x--][z]) }
|
||||
repeat(radius * 2) { yield(parcels[x][z--]) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun allParcels(): Sequence<Parcel> = buildSequence {
|
||||
|
||||
@@ -194,7 +194,7 @@ class DefaultParcelGenerator(val worlds: Worlds, val name: String, private val o
|
||||
val signBlock = world.getBlockAt(b.x - 2, o.floorHeight + 1, b.z - 1)
|
||||
val skullBlock = world.getBlockAt(b.x - 1, o.floorHeight + 2, b.z - 1)
|
||||
|
||||
val owner = parcel.data?.owner
|
||||
val owner = parcel.owner
|
||||
if (owner == null) {
|
||||
wallBlock.blockData = o.wallType
|
||||
signBlock.type = Material.AIR
|
||||
|
||||
@@ -25,6 +25,7 @@ class CommandsParcelOptions(plugin: ParcelsPlugin) : AbstractParcelCommands(plug
|
||||
@Desc("Sets whether players who are not allowed to",
|
||||
"build here can interact with inventories",
|
||||
shortVersion = "allows editing inventories")
|
||||
@RequireParameters(0)
|
||||
fun ParcelScope.cmdInventory(player: Player, enabled: Boolean?): Any? {
|
||||
return runOptionCommand(player, Parcel::allowInteractInventory, enabled, "interaction with inventories")
|
||||
}
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package io.dico.parcels2.command
|
||||
|
||||
import io.dico.dicore.command.CommandBuilder
|
||||
import io.dico.dicore.command.ICommandAddress
|
||||
import io.dico.dicore.command.ICommandDispatcher
|
||||
import io.dico.dicore.command.predef.PredefinedCommand
|
||||
import io.dico.dicore.command.registration.reflect.ReflectiveRegistration
|
||||
import io.dico.parcels2.ParcelsPlugin
|
||||
import io.dico.parcels2.logger
|
||||
import java.util.*
|
||||
|
||||
@Suppress("UsePropertyAccessSyntax")
|
||||
fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher {
|
||||
@@ -18,7 +22,7 @@ fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher {
|
||||
.registerCommands(CommandsAddedStatus(plugin))
|
||||
|
||||
.group("option")
|
||||
.apply { CommandsParcelOptions.setGroupDescription(this) }
|
||||
//.apply { CommandsParcelOptions.setGroupDescription(this) }
|
||||
.registerCommands(CommandsParcelOptions(plugin))
|
||||
.parent()
|
||||
|
||||
@@ -29,15 +33,34 @@ fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher {
|
||||
.putDebugCommands(plugin)
|
||||
|
||||
.parent()
|
||||
.generateHelpAndSyntaxCommands()
|
||||
.getDispatcher()
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
private fun CommandBuilder.putDebugCommands(plugin: ParcelsPlugin): CommandBuilder {
|
||||
if (!logger.isDebugEnabled) return this
|
||||
//if (!logger.isDebugEnabled) return this
|
||||
//@formatter:off
|
||||
return group("debug", "d")
|
||||
.registerCommands(CommandsDebug(plugin))
|
||||
.parent()
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
private fun CommandBuilder.generateHelpAndSyntaxCommands(): CommandBuilder {
|
||||
generateCommands(dispatcher as ICommandAddress, "help", "syntax")
|
||||
return this
|
||||
}
|
||||
|
||||
private fun generateCommands(address: ICommandAddress, vararg names: String) {
|
||||
val addresses: Queue<ICommandAddress> = LinkedList()
|
||||
addresses.offer(address)
|
||||
|
||||
while (addresses.isNotEmpty()) {
|
||||
val cur = addresses.poll()
|
||||
addresses.addAll(cur.children.values.distinct())
|
||||
if (cur.hasCommand()) {
|
||||
ReflectiveRegistration.generateCommands(cur, names)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,42 +17,39 @@ object WorldsT : Table("worlds") {
|
||||
val id = integer("world_id").autoIncrement().primaryKey()
|
||||
val name = varchar("name", 50)
|
||||
val uid = binary("uid", 16)
|
||||
.also { uniqueIndex("index_uid", it) }
|
||||
val index_uid = uniqueIndexR("index_uid", uid)
|
||||
}
|
||||
|
||||
object ParcelsT : Table("parcels") {
|
||||
val id = integer("parcel_id").autoIncrement().primaryKey()
|
||||
val px = integer("px")
|
||||
val pz = integer("pz")
|
||||
val world_id = integer("id")
|
||||
.also { uniqueIndex("index_location", it, px, pz) }
|
||||
.references(WorldsT.id)
|
||||
val world_id = integer("world_id").references(WorldsT.id)
|
||||
val owner_uuid = binary("owner_uuid", 16).nullable()
|
||||
val owner_name = varchar("owner_name", 16).nullable()
|
||||
val claim_time = datetime("claim_time").nullable()
|
||||
val index_location = uniqueIndexR("index_location", world_id, px, pz)
|
||||
}
|
||||
|
||||
object AddedLocalT : Table("parcels_added_local") {
|
||||
val parcel_id = integer("parcel_id")
|
||||
.references(ParcelsT.id, ReferenceOption.CASCADE)
|
||||
val parcel_id = integer("parcel_id").references(ParcelsT.id, ReferenceOption.CASCADE)
|
||||
val player_uuid = binary("player_uuid", 16)
|
||||
.also { uniqueIndex("index_pair", parcel_id, it) }
|
||||
val allowed_flag = bool("allowed_flag")
|
||||
val index_pair = uniqueIndexR("index_pair", parcel_id, player_uuid)
|
||||
}
|
||||
|
||||
object AddedGlobalT : Table("parcels_added_global") {
|
||||
val owner_uuid = binary("owner_uuid", 16)
|
||||
val player_uuid = binary("player_uuid", 16)
|
||||
.also { uniqueIndex("index_pair", owner_uuid, it) }
|
||||
val allowed_flag = bool("allowed_flag")
|
||||
val index_pair = uniqueIndexR("index_pair", owner_uuid, player_uuid)
|
||||
}
|
||||
|
||||
object ParcelOptionsT : Table("parcel_options") {
|
||||
val parcel_id = integer("parcel_id")
|
||||
.also { uniqueIndex("index_parcel_id", it) }
|
||||
.references(ParcelsT.id, ReferenceOption.CASCADE)
|
||||
val parcel_id = integer("parcel_id").references(ParcelsT.id, ReferenceOption.CASCADE)
|
||||
val interact_inventory = bool("interact_inventory").default(false)
|
||||
val interact_inputs = bool("interact_inputs").default(false)
|
||||
val index_parcel_id = uniqueIndexR("index_parcel_id", parcel_id)
|
||||
}
|
||||
|
||||
private class ExposedDatabaseException(message: String? = null) : Exception(message)
|
||||
@@ -163,7 +160,6 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource) : Backing
|
||||
rowToParcelData(row)
|
||||
}
|
||||
|
||||
// TODO order by some new column
|
||||
override suspend fun getOwnedParcels(user: ParcelOwner): List<SerializableParcel> = transaction {
|
||||
val where: SqlExpressionBuilder.() -> Op<Boolean>
|
||||
|
||||
@@ -175,7 +171,8 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource) : Backing
|
||||
where = { ParcelsT.owner_name eq name }
|
||||
}
|
||||
|
||||
ParcelsT.select(where).orderBy(ParcelsT.claim_time, isAsc = true)
|
||||
ParcelsT.select(where)
|
||||
.orderBy(ParcelsT.claim_time, isAsc = true)
|
||||
.mapNotNull(::rowToSerializableParcel)
|
||||
.toList()
|
||||
}
|
||||
@@ -243,7 +240,7 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource) : Backing
|
||||
}
|
||||
|
||||
val id = getOrInitParcelId(parcelFor)
|
||||
AddedLocalT.insertOrUpdate(AddedLocalT.allowed_flag) {
|
||||
AddedLocalT.upsert(AddedLocalT.parcel_id) {
|
||||
it[AddedLocalT.parcel_id] = id
|
||||
it[AddedLocalT.player_uuid] = binaryUuid
|
||||
}
|
||||
@@ -251,7 +248,7 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource) : Backing
|
||||
|
||||
override suspend fun setParcelAllowsInteractInventory(parcel: Parcel, value: Boolean): Unit = transaction {
|
||||
val id = getOrInitParcelId(parcel)
|
||||
ParcelOptionsT.insertOrUpdate(ParcelOptionsT.interact_inventory) {
|
||||
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
|
||||
it[ParcelOptionsT.parcel_id] = id
|
||||
it[ParcelOptionsT.interact_inventory] = value
|
||||
}
|
||||
@@ -259,7 +256,7 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource) : Backing
|
||||
|
||||
override suspend fun setParcelAllowsInteractInputs(parcel: Parcel, value: Boolean): Unit = transaction {
|
||||
val id = getOrInitParcelId(parcel)
|
||||
ParcelOptionsT.insertOrUpdate(ParcelOptionsT.interact_inputs) {
|
||||
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
|
||||
it[ParcelOptionsT.parcel_id] = id
|
||||
it[ParcelOptionsT.interact_inputs] = value
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package io.dico.parcels2.storage
|
||||
|
||||
import org.jetbrains.exposed.sql.Column
|
||||
import org.jetbrains.exposed.sql.Table
|
||||
import org.jetbrains.exposed.sql.Transaction
|
||||
import org.jetbrains.exposed.sql.*
|
||||
import org.jetbrains.exposed.sql.statements.InsertStatement
|
||||
import org.jetbrains.exposed.sql.statements.UpdateStatement
|
||||
import org.jetbrains.exposed.sql.transactions.TransactionManager
|
||||
|
||||
/*
|
||||
@@ -29,8 +28,82 @@ class InsertOrUpdate<Key : Any>(
|
||||
}
|
||||
|
||||
|
||||
class UpsertStatement<Key : Any>(table: Table, conflictColumn: Column<*>? = null, conflictIndex: Index? = null)
|
||||
: InsertStatement<Key>(table, false) {
|
||||
val indexName: String
|
||||
val indexColumns: List<Column<*>>
|
||||
|
||||
init {
|
||||
if (conflictIndex != null) {
|
||||
indexName = conflictIndex.indexName
|
||||
indexColumns = conflictIndex.columns
|
||||
} else if (conflictColumn != null) {
|
||||
indexName = conflictColumn.name
|
||||
indexColumns = listOf(conflictColumn)
|
||||
} else {
|
||||
throw IllegalArgumentException()
|
||||
}
|
||||
}
|
||||
|
||||
override fun prepareSQL(transaction: Transaction): String {
|
||||
val insertSQL = super.prepareSQL(transaction)
|
||||
val args = arguments!!.first()
|
||||
val map = mutableMapOf<Column<Any?>, Any?>().apply { args.forEach { put(it.first.castUnchecked(), it.second) } }
|
||||
|
||||
val updateSQL = updateBody(table, UpdateStatement(table, null, combineAsConjunctions(indexColumns.castUnchecked(), map))) {
|
||||
map.forEach { col, value ->
|
||||
if (col !in columns) {
|
||||
it[col] = value
|
||||
}
|
||||
}
|
||||
}.prepareSQL(transaction)
|
||||
|
||||
val builder = StringBuilder().apply {
|
||||
append(insertSQL)
|
||||
append(" ON CONFLICT(")
|
||||
append(indexName)
|
||||
append(") DO UPDATE ")
|
||||
append(updateSQL)
|
||||
}
|
||||
|
||||
return builder.toString().also { println(it) }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
inline fun <T : Table> updateBody(table: T, updateStatement: UpdateStatement,
|
||||
body: T.(UpdateStatement) -> Unit): UpdateStatement {
|
||||
table.body(updateStatement)
|
||||
return updateStatement
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST", "NOTHING_TO_INLINE")
|
||||
inline fun <T> Any.castUnchecked() = this as T
|
||||
|
||||
private val absent = Any() // marker object
|
||||
fun combineAsConjunctions(columns: Iterable<Column<Any?>>, map: Map<Column<Any?>, Any?>): Op<Boolean>? {
|
||||
return with(SqlExpressionBuilder) {
|
||||
columns.fold<Column<Any?>, Op<Boolean>?>(null) { op, col ->
|
||||
val arg = map.getOrDefault(col, absent)
|
||||
if (arg === absent) return@fold op
|
||||
op?.let { it and (col eq arg) } ?: col eq arg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <T : Table> T.upsert(conflictColumn: Column<*>? = null, conflictIndex: Index? = null, body: T.(UpsertStatement<Number>) -> Unit) =
|
||||
UpsertStatement<Number>(this, conflictColumn, conflictIndex).apply {
|
||||
body(this)
|
||||
execute(TransactionManager.current())
|
||||
}
|
||||
|
||||
fun Table.indexR(customIndexName:String? = null, isUnique: Boolean = false, vararg columns: Column<*>): Index {
|
||||
val index = Index(columns.toList(), isUnique, customIndexName)
|
||||
indices.add(index)
|
||||
return index
|
||||
}
|
||||
|
||||
fun Table.uniqueIndexR(customIndexName:String? = null, vararg columns: Column<*>): Index = indexR(customIndexName, true, *columns)
|
||||
|
||||
Reference in New Issue
Block a user