Archived
0

Tweaks and fixes

This commit is contained in:
Dico Karssiens
2018-07-29 01:03:31 +01:00
parent 547ffcb0ba
commit d425a1e977
19 changed files with 504 additions and 203 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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