Archived
0

Work on commands. Implemented helper functions, among others to handle asynchronous commands

This commit is contained in:
Dico200
2018-07-24 01:14:23 +01:00
parent 42026191ec
commit d15d1b767b
24 changed files with 426 additions and 104 deletions

19
.editorconfig Normal file
View File

@@ -0,0 +1,19 @@
[*]
charset=utf-8
end_of_line=lf
insert_final_newline=false
indent_style=space
indent_size=4
[{.babelrc,.stylelintrc,jest.config,.eslintrc,*.bowerrc,*.jsb3,*.jsb2,*.json}]
indent_style=space
indent_size=2
[{*.ddl,*.sql}]
indent_style=space
indent_size=2
[{*.yml,*.yaml}]
indent_style=space
indent_size=2

View File

@@ -28,7 +28,7 @@ dependencies {
compile("org.jetbrains.exposed:exposed:0.10.3") compile("org.jetbrains.exposed:exposed:0.10.3")
compile("org.jetbrains.kotlinx:kotlinx-coroutines-core:0.23.4") compile("org.jetbrains.kotlinx:kotlinx-coroutines-core:0.23.4")
compile("com.zaxxer:HikariCP:3.2.0") compile("com.zaxxer:HikariCP:3.2.0")
compile(files("../h2/bin/h2-client-1.4.197.jar")) compile(files("../h2/bin/h2-1.4.197.jar"))
val jacksonVersion = "2.9.6" val jacksonVersion = "2.9.6"
compile("com.fasterxml.jackson.core:jackson-core:$jacksonVersion") compile("com.fasterxml.jackson.core:jackson-core:$jacksonVersion")
@@ -44,9 +44,12 @@ dependencies {
} }
tasks { tasks {
val jar by getting(Jar::class) val jar by getting(Jar::class) {
group = "artifacts"
}
val fatJar by creating(Jar::class) { val fatJar by creating(Jar::class) {
group = "artifacts"
destinationDir = file("$rootDir/debug/plugins") destinationDir = file("$rootDir/debug/plugins")
baseName = "parcels2-all" baseName = "parcels2-all"
from(*configurations.compile.map(::zipTree).toTypedArray()) from(*configurations.compile.map(::zipTree).toTypedArray())
@@ -54,6 +57,7 @@ tasks {
} }
val shadowJar by getting(ShadowJar::class) { val shadowJar by getting(ShadowJar::class) {
group = "artifacts"
destinationDir = file("$rootDir/debug/plugins") destinationDir = file("$rootDir/debug/plugins")
baseName = "parcels2-shaded" baseName = "parcels2-shaded"
@@ -72,6 +76,7 @@ tasks {
} }
val relocateSnakeyamlJar by creating(ShadowJar::class) { val relocateSnakeyamlJar by creating(ShadowJar::class) {
group = "artifacts"
destinationDir = file("$rootDir/debug/plugins") destinationDir = file("$rootDir/debug/plugins")
baseName = "parcels2-shaded" baseName = "parcels2-shaded"
relocate("org.yaml", "shadow.org.yaml") relocate("org.yaml", "shadow.org.yaml")

View File

@@ -5,7 +5,6 @@ import com.fasterxml.jackson.annotation.JsonIgnore
import io.dico.parcels2.storage.Storage import io.dico.parcels2.storage.Storage
import io.dico.parcels2.storage.StorageFactory import io.dico.parcels2.storage.StorageFactory
import io.dico.parcels2.storage.yamlObjectMapper import io.dico.parcels2.storage.yamlObjectMapper
import org.bukkit.Bukkit
import org.bukkit.Bukkit.createBlockData import org.bukkit.Bukkit.createBlockData
import org.bukkit.GameMode import org.bukkit.GameMode
import org.bukkit.Material import org.bukkit.Material

View File

@@ -19,6 +19,15 @@ interface ParcelData {
var allowInteractInputs: Boolean var allowInteractInputs: Boolean
var allowInteractInventory: Boolean var allowInteractInventory: Boolean
fun isOwner(uuid: UUID): Boolean {
return owner?.uuid == uuid
}
val infoString: String
get() {
TODO()
}
} }
/** /**

View File

@@ -1,8 +1,8 @@
package io.dico.parcels2 package io.dico.parcels2
import io.dico.dicore.command.CommandBuilder
import io.dico.dicore.command.EOverridePolicy import io.dico.dicore.command.EOverridePolicy
import io.dico.dicore.command.ICommandDispatcher import io.dico.dicore.command.ICommandDispatcher
import io.dico.parcels2.command.getParcelCommands
import io.dico.parcels2.storage.Storage import io.dico.parcels2.storage.Storage
import io.dico.parcels2.storage.yamlObjectMapper import io.dico.parcels2.storage.yamlObjectMapper
import io.dico.parcels2.util.tryCreate import io.dico.parcels2.util.tryCreate
@@ -14,6 +14,7 @@ import java.io.File
val logger = LoggerFactory.getLogger("ParcelsPlugin") val logger = LoggerFactory.getLogger("ParcelsPlugin")
private inline val plogger get() = logger private inline val plogger get() = logger
const val debugging = true
class ParcelsPlugin : JavaPlugin() { class ParcelsPlugin : JavaPlugin() {
lateinit var optionsFile: File lateinit var optionsFile: File
@@ -73,15 +74,9 @@ class ParcelsPlugin : JavaPlugin() {
} }
private fun registerCommands() { private fun registerCommands() {
//@formatting:off cmdDispatcher = getParcelCommands(this).apply {
cmdDispatcher = CommandBuilder() registerToCommandMap("parcels:", EOverridePolicy.FALLBACK_ONLY)
.group("parcel", "plot", "plots", "p") }
.registerCommands(PlotCommands(this))
.parent()
.getDispatcher()
//@formatting:on
cmdDispatcher!!.registerToCommandMap("parcels:", EOverridePolicy.FALLBACK_ONLY)
} }
} }

View File

@@ -0,0 +1,83 @@
package io.dico.parcels2.command
import io.dico.dicore.command.CommandException
import io.dico.dicore.command.CommandResult
import io.dico.dicore.command.EMessageType
import io.dico.dicore.command.ExecutionContext
import io.dico.dicore.command.chat.IChatController
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.logger
import kotlinx.coroutines.experimental.*
import org.bukkit.command.CommandSender
import kotlin.coroutines.experimental.Continuation
import kotlin.coroutines.experimental.suspendCoroutine
/*
* Interface to implicitly access plugin by creating extension functions for it
*/
interface HasPlugin {
val plugin: ParcelsPlugin
}
class CommandAsyncScope {
suspend fun <T> HasPlugin.awaitSynchronousTask(delay: Int = 0, task: () -> T): T {
return suspendCoroutine { cont: Continuation<T> ->
plugin.server.scheduler.runTaskLater(plugin, l@ {
val result = try {
task()
} catch (ex: CommandException) {
cont.resumeWithException(ex)
return@l
} catch (ex: Throwable) {
cont.context.cancel(ex)
return@l
}
cont.resume(result)
}, delay.toLong())
}
}
fun <T> HasPlugin.synchronousTask(delay: Int = 0, task: () -> T): Deferred<T> {
return async { awaitSynchronousTask(delay, task) }
}
}
fun <T : Any?> HasPlugin.delegateCommandAsync(context: ExecutionContext,
block: suspend CommandAsyncScope.() -> T) {
val job: Deferred<Any?> = async(/*context = plugin.storage.asyncDispatcher, */start = CoroutineStart.ATOMIC) {
CommandAsyncScope().block()
}
fun Job.invokeOnCompletionSynchronously(block: (Throwable?) -> Unit) = invokeOnCompletion {
plugin.server.scheduler.runTask(plugin) { block(it) }
}
job.invokeOnCompletionSynchronously l@{ exception: Throwable? ->
exception?.let {
context.address.chatController.handleCoroutineException(context.sender, context, it)
return@l
}
val result = job.getCompleted()
val message = when (result) {
is String -> result
is CommandResult -> result.message
else -> null
}
context.address.chatController.sendMessage(context.sender, EMessageType.RESULT, message)
}
}
fun IChatController.handleCoroutineException(sender: CommandSender, context: ExecutionContext, exception: Throwable) {
if (exception is CancellationException) {
sendMessage(sender, EMessageType.EXCEPTION, "The command was cancelled unexpectedly (see console)")
logger.warn("An asynchronously dispatched command was cancelled unexpectedly", exception)
} else {
handleException(sender, context, exception)
}
}

View File

@@ -0,0 +1,63 @@
@file:Suppress("NOTHING_TO_INLINE")
package io.dico.parcels2.command
import io.dico.dicore.command.CommandException
import io.dico.dicore.command.Validate
import io.dico.parcels2.Parcel
import io.dico.parcels2.ParcelWorld
import io.dico.parcels2.Worlds
import io.dico.parcels2.util.hasAdminManage
import io.dico.parcels2.util.uuid
import org.bukkit.entity.Player
/*
* Scope types for extension lambdas
*/
sealed class BaseScope
class WorldOnlyScope(val world: ParcelWorld) : BaseScope()
class ParcelScope(val world: ParcelWorld, val parcel: Parcel) : BaseScope()
/*
* Interface to implicitly access worlds object by creating extension functions for it
*/
interface HasWorlds {
val worlds: Worlds
}
/*
* Functions to be used by command implementations
*/
inline fun <T> HasWorlds.requireInWorld(player: Player,
admin: Boolean = false,
block: WorldOnlyScope.() -> T): T {
return WorldOnlyScope(worlds.getWorldRequired(player, admin = admin)).block()
}
inline fun <T> HasWorlds.requireInParcel(player: Player,
admin: Boolean = false,
own: Boolean = false,
block: ParcelScope.() -> T): T {
val parcel = worlds.getParcelRequired(player, admin = admin, own = own)
return ParcelScope(parcel.world, parcel).block()
}
/*
* Functions for checking
*/
fun Worlds.getWorldRequired(player: Player, admin: Boolean = false): ParcelWorld {
if (admin) Validate.isTrue(player.hasAdminManage, "You must have admin rights to use that command")
return getWorld(player.world)
?: throw CommandException("You must be in a parcel world to use that command")
}
fun Worlds.getParcelRequired(player: Player, admin: Boolean = false, own: Boolean = false): Parcel {
val parcel = getWorldRequired(player, admin = admin).parcelAt(player)
?: throw CommandException("You must be in a parcel to use that command")
if (own) Validate.isTrue(parcel.isOwner(player.uuid) || player.hasAdminManage,
"You must own this parcel to use that command")
return parcel
}

View File

@@ -1,11 +1,12 @@
package io.dico.parcels2 package io.dico.parcels2.command
import io.dico.dicore.command.CommandException import io.dico.dicore.command.CommandException
import io.dico.dicore.command.annotation.Cmd import io.dico.dicore.command.annotation.Cmd
import io.dico.parcels2.ParcelsPlugin
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.entity.Player import org.bukkit.entity.Player
class DebugCommands(val plugin: ParcelsPlugin) {
class PlotCommands(val plugin: ParcelsPlugin) {
@Cmd("reloadoptions") @Cmd("reloadoptions")
fun reloadOptions() { fun reloadOptions() {

View File

@@ -0,0 +1,68 @@
package io.dico.parcels2.command
import io.dico.dicore.command.CommandBuilder
import io.dico.dicore.command.CommandException
import io.dico.dicore.command.ICommandDispatcher
import io.dico.dicore.command.parameter.ArgumentBuffer
import io.dico.dicore.command.parameter.IParameter
import io.dico.dicore.command.parameter.type.ParameterType
import io.dico.parcels2.Parcel
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.Worlds
import io.dico.parcels2.debugging
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
@Suppress("UsePropertyAccessSyntax")
fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher {
//@formatter:off
return CommandBuilder()
.addParameterType(false, ParcelParameterType(plugin.worlds))
.group("parcel", "plot", "plots", "p")
.registerCommands(ParcelCommands(plugin))
.putDebugCommands(plugin)
.parent()
.getDispatcher()
//@formatter:on
}
private fun CommandBuilder.putDebugCommands(plugin: ParcelsPlugin): CommandBuilder {
if (!debugging) return this
//@formatter:off
return group("debug", "d")
.registerCommands(DebugCommands(plugin))
.parent()
//@formatter:on
}
private val regex = Regex.fromLiteral("((.+)->)?([0-9]+):([0-9]+)")
private class ParcelParameterType(val worlds: Worlds) : ParameterType<Parcel, Unit>(Parcel::class.java) {
private fun invalidInput(parameter: IParameter<*>, message: String): Nothing {
throw CommandException("invalid input for ${parameter.name}: $message")
}
override fun parse(parameter: IParameter<Parcel>, sender: CommandSender, buffer: ArgumentBuffer): Parcel {
val matchResult = regex.matchEntire(buffer.next())
?: invalidInput(parameter, "must match (w->)?a:b (/${regex.pattern}/)")
val worldName = matchResult.groupValues[2]
.takeUnless { it.isEmpty() }
?: (sender as? Player)?.world?.name
?: invalidInput(parameter, "console cannot omit the world name")
val world = worlds.getWorld(worldName)
?: invalidInput(parameter, "$worldName is not a parcel world")
val x = matchResult.groupValues[3].toIntOrNull()
?: invalidInput(parameter, "couldn't parse int")
val z = matchResult.groupValues[4].toIntOrNull()
?: invalidInput(parameter, "couldn't parse int")
return world.parcelByID(x, z)
?: invalidInput(parameter, "parcel id is out of range")
}
}

View File

@@ -0,0 +1,51 @@
package io.dico.parcels2.command
import io.dico.dicore.command.CommandException
import io.dico.dicore.command.ExecutionContext
import io.dico.dicore.command.annotation.Cmd
import io.dico.dicore.command.annotation.Desc
import io.dico.parcels2.ParcelOwner
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.util.parcelLimit
import io.dico.parcels2.util.uuid
import org.bukkit.entity.Player
class ParcelCommands(override val plugin: ParcelsPlugin) : HasWorlds, HasPlugin {
override val worlds = plugin.worlds
private fun error(message: String): Nothing {
throw CommandException(message)
}
@Cmd("auto")
@Desc("Finds the unclaimed parcel nearest to origin,",
"and gives it to you",
shortVersion = "sets you up with a fresh, unclaimed parcel")
fun cmdAuto(player: Player, context: ExecutionContext) = requireInWorld(player) {
delegateCommandAsync(context) {
val numOwnedParcels = plugin.storage.getNumParcels(ParcelOwner(uuid = player.uuid)).await()
awaitSynchronousTask {
val limit = player.parcelLimit
if (numOwnedParcels >= limit) {
error("You have enough plots for now")
}
val parcel = world.nextEmptyParcel()
?: error("This world is full, please ask an admin to upsize it")
parcel.owner = ParcelOwner(uuid = player.uuid)
player.teleport(world.generator.getHomeLocation(parcel))
"Enjoy your new parcel!"
}
}
}
@Cmd("info", aliases = ["i"])
@Desc("Displays general information",
"about the parcel you're on",
shortVersion = "displays information about this parcel")
fun cmdInfo(player: Player) = requireInParcel(player) { parcel.infoString }
}

View File

@@ -3,7 +3,7 @@ package io.dico.parcels2.math
fun Double.floor(): Int { fun Double.floor(): Int {
val down = toInt() val down = toInt()
if (down.toDouble() != this && (java.lang.Double.doubleToRawLongBits(this).ushr(63).toInt()) == 1) { if (down.toDouble() != this && (java.lang.Double.doubleToRawLongBits(this).ushr(63).toInt()) == 1) {
return down-1 return down - 1
} }
return down return down
} }

View File

@@ -10,6 +10,8 @@ interface Backing {
val name: String val name: String
val isConnected: Boolean
suspend fun init() suspend fun init()
suspend fun shutdown() suspend fun shutdown()
@@ -25,6 +27,8 @@ interface Backing {
suspend fun getOwnedParcels(user: ParcelOwner): List<SerializableParcel> suspend fun getOwnedParcels(user: ParcelOwner): List<SerializableParcel>
suspend fun getNumParcels(user: ParcelOwner): Int = getOwnedParcels(user).size
suspend fun setParcelData(parcelFor: Parcel, data: ParcelData?) suspend fun setParcelData(parcelFor: Parcel, data: ParcelData?)

View File

@@ -3,6 +3,7 @@ package io.dico.parcels2.storage
import com.zaxxer.hikari.HikariDataSource import com.zaxxer.hikari.HikariDataSource
import io.dico.parcels2.* import io.dico.parcels2.*
import io.dico.parcels2.math.Vec2i import io.dico.parcels2.math.Vec2i
import io.dico.parcels2.util.synchronized
import io.dico.parcels2.util.toByteArray import io.dico.parcels2.util.toByteArray
import io.dico.parcels2.util.toUUID import io.dico.parcels2.util.toUUID
import kotlinx.coroutines.experimental.channels.ProducerScope import kotlinx.coroutines.experimental.channels.ProducerScope
@@ -58,19 +59,30 @@ private class ExposedDatabaseException(message: String? = null) : Exception(mess
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
class ExposedBacking(val dataSource: DataSource) : Backing { class ExposedBacking(val dataSource: DataSource) : Backing {
override val name get() = "Exposed" override val name get() = "Exposed"
lateinit var database: Database private var database: Database? = null
private var isShutdown: Boolean = false
override val isConnected get() = database != null
override suspend fun init() { override suspend fun init() {
synchronized {
if (isShutdown) throw IllegalStateException()
database = Database.connect(dataSource) database = Database.connect(dataSource)
transaction(database) { transaction(database) {
create(ParcelsT, AddedLocalT) create(WorldsT, ParcelsT, AddedLocalT, ParcelOptionsT)
}
} }
} }
override suspend fun shutdown() { override suspend fun shutdown() {
synchronized {
if (isShutdown) throw IllegalStateException()
if (dataSource is HikariDataSource) { if (dataSource is HikariDataSource) {
dataSource.close() dataSource.close()
} }
database = null
isShutdown = true
}
} }
private fun <T> transaction(statement: Transaction.() -> T) = transaction(database, statement) private fun <T> transaction(statement: Transaction.() -> T) = transaction(database, statement)

View File

@@ -31,7 +31,7 @@ fun getHikariDataSource(dialectName: String,
dataSourceProperties.remove("serverName") dataSourceProperties.remove("serverName")
dataSourceProperties.remove("port") dataSourceProperties.remove("port")
dataSourceProperties.remove("databaseName") dataSourceProperties.remove("databaseName")
addDataSourceProperty("url", "jdbc:h2:tcp://$address/~/${dco.database}") addDataSourceProperty("url", "jdbc:h2:${if (address.isBlank()) "" else "tcp://$address/"}~/${dco.database}")
} else { } else {
// doesn't exist on the MariaDB driver // doesn't exist on the MariaDB driver
addDataSourceProperty("cachePrepStmts", "true") addDataSourceProperty("cachePrepStmts", "true")

View File

@@ -8,10 +8,11 @@ import com.fasterxml.jackson.databind.ser.BeanSerializerModifier
import com.fasterxml.jackson.databind.ser.std.StdSerializer import com.fasterxml.jackson.databind.ser.std.StdSerializer
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
import com.fasterxml.jackson.module.kotlin.KotlinModule import com.fasterxml.jackson.module.kotlin.KotlinModule
import io.dico.parcels2.* import io.dico.parcels2.GeneratorFactory
import io.dico.parcels2.GeneratorOptions
import io.dico.parcels2.StorageOptions
import org.bukkit.Bukkit import org.bukkit.Bukkit
import org.bukkit.block.data.BlockData import org.bukkit.block.data.BlockData
import kotlin.reflect.KClass
import kotlin.reflect.full.isSuperclassOf import kotlin.reflect.full.isSuperclassOf
val yamlObjectMapper = ObjectMapper(YAMLFactory()).apply { val yamlObjectMapper = ObjectMapper(YAMLFactory()).apply {

View File

@@ -14,10 +14,11 @@ interface Storage {
val name: String val name: String
val syncDispatcher: CoroutineDispatcher val syncDispatcher: CoroutineDispatcher
val asyncDispatcher: CoroutineDispatcher val asyncDispatcher: CoroutineDispatcher
val isConnected: Boolean
fun init(): Deferred<Unit> fun init(): Job
fun shutdown(): Deferred<Unit> fun shutdown(): Job
fun readParcelData(parcelFor: Parcel): Deferred<ParcelData?> fun readParcelData(parcelFor: Parcel): Deferred<ParcelData?>
@@ -26,16 +27,18 @@ interface Storage {
fun getOwnedParcels(user: ParcelOwner): Deferred<List<SerializableParcel>> fun getOwnedParcels(user: ParcelOwner): Deferred<List<SerializableParcel>>
fun getNumParcels(user: ParcelOwner): Deferred<Int>
fun setParcelData(parcelFor: Parcel, data: ParcelData?): Deferred<Unit>
fun setParcelOwner(parcelFor: Parcel, owner: ParcelOwner?): Deferred<Unit> fun setParcelData(parcelFor: Parcel, data: ParcelData?): Job
fun setParcelPlayerState(parcelFor: Parcel, player: UUID, state: Boolean?): Deferred<Unit> fun setParcelOwner(parcelFor: Parcel, owner: ParcelOwner?): Job
fun setParcelAllowsInteractInventory(parcel: Parcel, value: Boolean): Deferred<Unit> fun setParcelPlayerState(parcelFor: Parcel, player: UUID, state: Boolean?): Job
fun setParcelAllowsInteractInputs(parcel: Parcel, value: Boolean): Deferred<Unit> fun setParcelAllowsInteractInventory(parcel: Parcel, value: Boolean): Job
fun setParcelAllowsInteractInputs(parcel: Parcel, value: Boolean): Job
} }
@@ -44,15 +47,21 @@ class StorageWithCoroutineBacking internal constructor(val backing: Backing) : S
override val syncDispatcher = Executor { it.run() }.asCoroutineDispatcher() override val syncDispatcher = Executor { it.run() }.asCoroutineDispatcher()
val poolSize: Int get() = 4 val poolSize: Int get() = 4
override val asyncDispatcher = Executors.newFixedThreadPool(poolSize) { Thread(it, "Parcels2_StorageThread") }.asCoroutineDispatcher() override val asyncDispatcher = Executors.newFixedThreadPool(poolSize) { Thread(it, "Parcels2_StorageThread") }.asCoroutineDispatcher()
override val isConnected get() = backing.isConnected
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
private inline fun <T> defer(noinline block: suspend CoroutineScope.() -> T): Deferred<T> { private inline fun <T> defer(noinline block: suspend CoroutineScope.() -> T): Deferred<T> {
return async(context = asyncDispatcher, start = CoroutineStart.ATOMIC, block = block) return async(context = asyncDispatcher, start = CoroutineStart.ATOMIC, block = block)
} }
override fun init() = defer { backing.init() } @Suppress("NOTHING_TO_INLINE")
private inline fun job(noinline block: suspend CoroutineScope.() -> Unit): Job {
return launch(context = asyncDispatcher, start = CoroutineStart.ATOMIC, block = block)
}
override fun shutdown() = defer { backing.shutdown() } override fun init() = job { backing.init() }
override fun shutdown() = job { backing.shutdown() }
override fun readParcelData(parcelFor: Parcel) = defer { backing.readParcelData(parcelFor) } override fun readParcelData(parcelFor: Parcel) = defer { backing.readParcelData(parcelFor) }
@@ -61,16 +70,17 @@ class StorageWithCoroutineBacking internal constructor(val backing: Backing) : S
with(backing) { produceParcelData(parcelsFor) } with(backing) { produceParcelData(parcelsFor) }
} }
override fun setParcelData(parcelFor: Parcel, data: ParcelData?) = defer { backing.setParcelData(parcelFor, data) }
override fun getOwnedParcels(user: ParcelOwner) = defer { backing.getOwnedParcels(user) } override fun getOwnedParcels(user: ParcelOwner) = defer { backing.getOwnedParcels(user) }
override fun setParcelOwner(parcelFor: Parcel, owner: ParcelOwner?) = defer { backing.setParcelOwner(parcelFor, owner) } override fun getNumParcels(user: ParcelOwner) = defer { backing.getNumParcels(user) }
override fun setParcelPlayerState(parcelFor: Parcel, player: UUID, state: Boolean?) = defer { backing.setParcelPlayerState(parcelFor, player, state) } override fun setParcelData(parcelFor: Parcel, data: ParcelData?) = job { backing.setParcelData(parcelFor, data) }
override fun setParcelAllowsInteractInventory(parcel: Parcel, value: Boolean) = defer { backing.setParcelAllowsInteractInventory(parcel, value) } override fun setParcelOwner(parcelFor: Parcel, owner: ParcelOwner?) = job { backing.setParcelOwner(parcelFor, owner) }
override fun setParcelAllowsInteractInputs(parcel: Parcel, value: Boolean) = defer { backing.setParcelAllowsInteractInputs(parcel, value) } override fun setParcelPlayerState(parcelFor: Parcel, player: UUID, state: Boolean?) = job { backing.setParcelPlayerState(parcelFor, player, state) }
override fun setParcelAllowsInteractInventory(parcel: Parcel, value: Boolean) = job { backing.setParcelAllowsInteractInventory(parcel, value) }
override fun setParcelAllowsInteractInputs(parcel: Parcel, value: Boolean) = job { backing.setParcelAllowsInteractInputs(parcel, value) }
} }

View File

@@ -1,7 +1,6 @@
package io.dico.parcels2.storage package io.dico.parcels2.storage
import io.dico.parcels2.DataConnectionOptions import io.dico.parcels2.DataConnectionOptions
import net.minecraft.server.v1_13_R1.WorldType.types
import kotlin.reflect.KClass import kotlin.reflect.KClass
interface StorageFactory { interface StorageFactory {

View File

@@ -1,9 +1,7 @@
package io.dico.parcels2.util package io.dico.parcels2.util
import io.dico.parcels2.logger import io.dico.parcels2.logger
import org.slf4j.Logger
import java.io.File import java.io.File
import java.io.PrintWriter
fun File.tryCreate(): Boolean { fun File.tryCreate(): Boolean {
val parent = parentFile val parent = parentFile
@@ -13,3 +11,7 @@ fun File.tryCreate(): Boolean {
} }
return true return true
} }
inline fun <R> Any.synchronized(block: () -> R): R {
return synchronized(this, block)
}

View File

@@ -6,18 +6,19 @@ import io.dico.parcels2.logger
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.plugin.java.JavaPlugin import org.bukkit.plugin.java.JavaPlugin
inline val Player.hasBanBypass get() = hasPermission("plots.admin.bypass.ban") inline val Player.uuid get() = uniqueId
inline val Player.hasBuildAnywhere get() = hasPermission("plots.admin.bypass.build") inline val Player.hasBanBypass get() = hasPermission("parcels.admin.bypass.ban")
inline val Player.hasGamemodeBypass get() = hasPermission("plots.admin.bypass.gamemode") inline val Player.hasBuildAnywhere get() = hasPermission("parcels.admin.bypass.build")
inline val Player.hasAdminManage get() = hasPermission("plots.admin.manage") inline val Player.hasGamemodeBypass get() = hasPermission("parcels.admin.bypass.gamemode")
inline val Player.hasPlotHomeOthers get() = hasPermission("plots.command.home.others") inline val Player.hasAdminManage get() = hasPermission("parcels.admin.manage")
inline val Player.hasRandomSpecific get() = hasPermission("plots.command.random.specific") inline val Player.hasParcelHomeOthers get() = hasPermission("parcels.command.home.others")
val Player.plotLimit: Int inline val Player.hasRandomSpecific get() = hasPermission("parcels.command.random.specific")
val Player.parcelLimit: Int
get() { get() {
for (info in effectivePermissions) { for (info in effectivePermissions) {
val perm = info.permission val perm = info.permission
if (perm.startsWith("plots.limit.")) { if (perm.startsWith("parcels.limit.")) {
val limitString = perm.substring("plots.limit.".length) val limitString = perm.substring("parcels.limit.".length)
if (limitString == "*") { if (limitString == "*") {
return Int.MAX_VALUE return Int.MAX_VALUE
} }
@@ -32,7 +33,7 @@ val Player.plotLimit: Int
private const val DEFAULT_LIMIT = 1 private const val DEFAULT_LIMIT = 1
private val prefix = Formatting.translateChars('&', "&4[&c${JavaPlugin.getPlugin(ParcelsPlugin::class.java).name}&4] &a") private val prefix = Formatting.translateChars('&', "&4[&c${JavaPlugin.getPlugin(ParcelsPlugin::class.java).name}&4] &a")
fun Player.sendPlotMessage(except: Boolean = false, nopermit: Boolean = false, message: String) { fun Player.sendParcelMessage(except: Boolean = false, nopermit: Boolean = false, message: String) {
if (except) { if (except) {
sendMessage(prefix + Formatting.YELLOW + Formatting.translateChars('&', message)) sendMessage(prefix + Formatting.YELLOW + Formatting.translateChars('&', message))
} else if (nopermit) { } else if (nopermit) {