summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDico <dico.karssiens@gmail.com>2018-09-23 06:34:03 +0100
committerDico <dico.karssiens@gmail.com>2018-09-23 06:34:03 +0100
commit038e698a1421e95d1dc96117cd9a2ae0cfdddf6a (patch)
tree9a9a44bb20869ab8a7ab2287d14c6558a495614b
parentf499555f8bff9d3c77340a0aa852cb418e81e6f7 (diff)
Work down some todo items, update to kotlin 1.3-rc
-rw-r--r--build.gradle.kts19
-rw-r--r--dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java9
-rw-r--r--dicore3/command/src/main/java/io/dico/dicore/command/ICommandReceiver.java5
-rw-r--r--dicore3/command/src/main/kotlin/io/dico/dicore/command/registration/reflect/KotlinReflectiveRegistration.kt37
-rw-r--r--gradle.properties1
-rw-r--r--settings.gradle.kts6
-rw-r--r--src/main/kotlin/io/dico/parcels2/Interactable.kt5
-rw-r--r--src/main/kotlin/io/dico/parcels2/Parcel.kt4
-rw-r--r--src/main/kotlin/io/dico/parcels2/ParcelGenerator.kt2
-rw-r--r--src/main/kotlin/io/dico/parcels2/ParcelId.kt13
-rw-r--r--src/main/kotlin/io/dico/parcels2/ParcelWorld.kt5
-rw-r--r--src/main/kotlin/io/dico/parcels2/ParcelsPlugin.kt22
-rw-r--r--src/main/kotlin/io/dico/parcels2/PlayerProfile.kt23
-rw-r--r--src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt14
-rw-r--r--src/main/kotlin/io/dico/parcels2/blockvisitor/WorktimeLimiter.kt84
-rw-r--r--src/main/kotlin/io/dico/parcels2/command/AbstractParcelCommands.kt27
-rw-r--r--src/main/kotlin/io/dico/parcels2/command/CommandsAddedStatusLocal.kt2
-rw-r--r--src/main/kotlin/io/dico/parcels2/command/CommandsAdmin.kt36
-rw-r--r--src/main/kotlin/io/dico/parcels2/command/CommandsGeneral.kt45
-rw-r--r--src/main/kotlin/io/dico/parcels2/command/ParcelCommandReceivers.kt4
-rw-r--r--src/main/kotlin/io/dico/parcels2/command/ParcelTarget.kt41
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelContainer.kt15
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt82
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/GlobalAddedDataManagerImpl.kt2
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt22
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt15
-rw-r--r--src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelWorldImpl.kt6
-rw-r--r--src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt4
-rw-r--r--src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt2
-rw-r--r--src/main/kotlin/io/dico/parcels2/listener/WorldEditListener.kt80
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/Backing.kt10
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/Storage.kt10
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt12
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/exposed/IdTables.kt7
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/exposed/ListTables.kt2
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/migration/Migration.kt2
-rw-r--r--src/main/kotlin/io/dico/parcels2/storage/migration/plotme/PlotmeMigration.kt6
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/FunctionHelper.kt53
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/MainThreadDispatcher.kt31
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/PluginScheduler.kt20
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/UUIDUtil.kt9
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/ext/Material.kt (renamed from src/main/kotlin/io/dico/parcels2/util/MaterialExtensions.kt)2
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/ext/Math.kt (renamed from src/main/kotlin/io/dico/parcels2/util/NumberExtensions.kt)2
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/ext/Misc.kt (renamed from src/main/kotlin/io/dico/parcels2/util/MiscExtensions.kt)2
-rw-r--r--src/main/kotlin/io/dico/parcels2/util/ext/Player.kt (renamed from src/main/kotlin/io/dico/parcels2/util/PlayerExtensions.kt)3
-rw-r--r--todo.md14
46 files changed, 553 insertions, 264 deletions
diff --git a/build.gradle.kts b/build.gradle.kts
index fa4eb09..34a9737 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -14,12 +14,10 @@ version = "0.2"
plugins {
java
- kotlin("jvm") version "1.2.51"
+ kotlin("jvm") version "1.3.0-rc-57"
id("com.github.johnrengelman.plugin-shadow") version "2.0.3"
}
-kotlin.experimental.coroutines = ENABLE
-
allprojects {
apply<JavaPlugin>()
@@ -28,6 +26,8 @@ allprojects {
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots")
maven("https://hub.spigotmc.org/nexus/content/repositories/sonatype-nexus-snapshots")
maven("https://dl.bintray.com/kotlin/exposed")
+ maven("https://dl.bintray.com/kotlin/kotlin-eap")
+ maven("https://dl.bintray.com/kotlin/kotlinx/")
}
dependencies {
@@ -51,7 +51,7 @@ project(":dicore3:dicore3-command") {
dependencies {
c.kotlinStd(kotlin("stdlib-jdk8"))
c.kotlinStd(kotlin("reflect"))
- c.kotlinStd(kotlinx("coroutines-core:0.24.0"))
+ c.kotlinStd(kotlinx("coroutines-core:0.26.1-eap13"))
compile(project(":dicore3:dicore3-core"))
compile("com.thoughtworks.paranamer:paranamer:2.8")
@@ -59,17 +59,19 @@ project(":dicore3:dicore3-command") {
}
}
-
dependencies {
compile(project(":dicore3:dicore3-core"))
compile(project(":dicore3:dicore3-command"))
c.kotlinStd(kotlin("stdlib-jdk8"))
c.kotlinStd(kotlin("reflect"))
- c.kotlinStd(kotlinx("coroutines-core:0.23.4"))
- c.kotlinStd("org.jetbrains.kotlinx:atomicfu-common:0.11.0")
+ c.kotlinStd(kotlinx("coroutines-core:0.26.1-eap13"))
+ c.kotlinStd("org.jetbrains.kotlinx:atomicfu-common:0.11.7-rc-conf")
+
+ // not on sk89q maven repo yet
+ compileClasspath(files("$rootDir/debug/plugins/worldedit-bukkit-7.0.0-beta-01.jar"))
- compile("org.jetbrains.exposed:exposed:0.10.3") { isTransitive = false }
+ compile("org.jetbrains.exposed:exposed:0.10.5") { isTransitive = false }
compile("joda-time:joda-time:2.10")
compile("com.zaxxer:HikariCP:3.2.0")
compile("ch.qos.logback:logback-classic:1.2.3") { isTransitive = false }
@@ -131,6 +133,7 @@ tasks {
}
val createDebugServer by creating {
+ // todo
val jarUrl = URL("https://yivesmirror.com/files/spigot/spigot-latest.jar")
val serverJarFile = file("$serverDir/lib/spigot.jar")
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java b/dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java
index 4c014fb..4450a92 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/ExecutionContext.java
@@ -200,6 +200,15 @@ public class ExecutionContext {
return originalBuffer.getArrayFromIndex(cursorStart);
}
+ /**
+ * The path used to access this address.
+ *
+ * @return the path used to access this address.
+ */
+ public String[] getRoute() {
+ return Arrays.copyOf(originalBuffer.toArray(), address.getDepth());
+ }
+
public Formatting getFormat(EMessageType type) {
return address.getChatController().getChatFormatForType(type);
}
diff --git a/dicore3/command/src/main/java/io/dico/dicore/command/ICommandReceiver.java b/dicore3/command/src/main/java/io/dico/dicore/command/ICommandReceiver.java
index 88b0d50..6660bf8 100644
--- a/dicore3/command/src/main/java/io/dico/dicore/command/ICommandReceiver.java
+++ b/dicore3/command/src/main/java/io/dico/dicore/command/ICommandReceiver.java
@@ -12,6 +12,11 @@ public interface ICommandReceiver {
Plugin getPlugin();
+ // type is CoroutineContext, but we avoid referring to Kotlin runtime here
+ default Object getCoroutineContext() {
+ return null;
+ }
+
}
}
diff --git a/dicore3/command/src/main/kotlin/io/dico/dicore/command/registration/reflect/KotlinReflectiveRegistration.kt b/dicore3/command/src/main/kotlin/io/dico/dicore/command/registration/reflect/KotlinReflectiveRegistration.kt
index 9d23ee6..c09088e 100644
--- a/dicore3/command/src/main/kotlin/io/dico/dicore/command/registration/reflect/KotlinReflectiveRegistration.kt
+++ b/dicore3/command/src/main/kotlin/io/dico/dicore/command/registration/reflect/KotlinReflectiveRegistration.kt
@@ -4,15 +4,15 @@ import io.dico.dicore.command.CommandException
import io.dico.dicore.command.EMessageType
import io.dico.dicore.command.ExecutionContext
import io.dico.dicore.command.ICommandReceiver
-import kotlinx.coroutines.experimental.CoroutineStart.UNDISPATCHED
-import kotlinx.coroutines.experimental.Deferred
-import kotlinx.coroutines.experimental.asCoroutineDispatcher
-import kotlinx.coroutines.experimental.async
+import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.async
import java.lang.reflect.Method
-import java.util.*
import java.util.concurrent.CancellationException
-import java.util.concurrent.Executor
-import kotlin.coroutines.experimental.intrinsics.suspendCoroutineOrReturn
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.intrinsics.intercepted
+import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
import kotlin.reflect.jvm.kotlinFunction
fun isSuspendFunction(method: Method): Boolean {
@@ -20,16 +20,21 @@ fun isSuspendFunction(method: Method): Boolean {
return func.isSuspend
}
-fun callAsCoroutine(command: ReflectiveCommand,
- factory: ICommandReceiver.Factory,
- context: ExecutionContext,
- args: Array<Any?>): String? {
- val dispatcher = Executor { task -> factory.plugin.server.scheduler.runTask(factory.plugin, task) }.asCoroutineDispatcher()
+fun callAsCoroutine(
+ command: ReflectiveCommand,
+ factory: ICommandReceiver.Factory,
+ context: ExecutionContext,
+ args: Array<Any?>
+): String? {
// UNDISPATCHED causes the handler to run until the first suspension point on the current thread,
// meaning command handlers that don't have suspension points will run completely synchronously.
// Tasks that take time to compute should suspend the coroutine and resume on another thread.
- val job = async(context = dispatcher, start = UNDISPATCHED) { command.method.invokeSuspend(command.instance, args) }
+ val job = GlobalScope.async(context = factory.coroutineContext as CoroutineContext, start = UNDISPATCHED) {
+ suspendCoroutineUninterceptedOrReturn<Any?> { cont ->
+ command.method.invoke(command.instance, *args, cont.intercepted())
+ }
+ }
if (job.isCompleted) {
return job.getResult()
@@ -48,12 +53,6 @@ fun callAsCoroutine(command: ReflectiveCommand,
return null
}
-private suspend fun Method.invokeSuspend(instance: Any?, args: Array<Any?>): Any? {
- return suspendCoroutineOrReturn { cont ->
- invoke(instance, *args, cont)
- }
-}
-
@Throws(CommandException::class)
private fun Deferred<Any?>.getResult(): String? {
getCompletionExceptionOrNull()?.let { ex ->
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..29e08e8
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1 @@
+kotlin.code.style=official \ No newline at end of file
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 020ed4e..2977cab 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,3 +1,9 @@
+pluginManagement.repositories {
+ maven("http://dl.bintray.com/kotlin/kotlin-eap")
+ mavenCentral()
+ maven("https://plugins.gradle.org/m2/")
+}
+
rootProject.name = "parcels2"
include("dicore3:core")
diff --git a/src/main/kotlin/io/dico/parcels2/Interactable.kt b/src/main/kotlin/io/dico/parcels2/Interactable.kt
index 36a8bdd..f1beac5 100644
--- a/src/main/kotlin/io/dico/parcels2/Interactable.kt
+++ b/src/main/kotlin/io/dico/parcels2/Interactable.kt
@@ -1,6 +1,6 @@
package io.dico.parcels2
-import io.dico.parcels2.util.findWoodKindPrefixedMaterials
+import io.dico.parcels2.util.ext.findWoodKindPrefixedMaterials
import org.bukkit.Material
import java.util.EnumMap
@@ -28,7 +28,8 @@ private constructor(val id: Int,
arrayOf(
Interactables(id++, "button", true,
Material.STONE_BUTTON,
- *findWoodKindPrefixedMaterials("BUTTON")),
+ *findWoodKindPrefixedMaterials("BUTTON")
+ ),
Interactables(id++, "lever", true,
Material.LEVER),
diff --git a/src/main/kotlin/io/dico/parcels2/Parcel.kt b/src/main/kotlin/io/dico/parcels2/Parcel.kt
index 6d8a1ca..bdf4ff9 100644
--- a/src/main/kotlin/io/dico/parcels2/Parcel.kt
+++ b/src/main/kotlin/io/dico/parcels2/Parcel.kt
@@ -1,7 +1,7 @@
package io.dico.parcels2
import io.dico.parcels2.util.Vec2i
-import io.dico.parcels2.util.hasBuildAnywhere
+import io.dico.parcels2.util.ext.hasBuildAnywhere
import org.bukkit.Location
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
@@ -32,6 +32,8 @@ interface Parcel : ParcelData {
fun dispose()
+ suspend fun withBlockVisitorPermit(block: suspend () -> Unit)
+
val homeLocation: Location get() = world.blockManager.getHomeLocation(id)
}
diff --git a/src/main/kotlin/io/dico/parcels2/ParcelGenerator.kt b/src/main/kotlin/io/dico/parcels2/ParcelGenerator.kt
index f8e4fd0..8e7a5df 100644
--- a/src/main/kotlin/io/dico/parcels2/ParcelGenerator.kt
+++ b/src/main/kotlin/io/dico/parcels2/ParcelGenerator.kt
@@ -7,6 +7,7 @@ import io.dico.parcels2.blockvisitor.WorktimeLimiter
import io.dico.parcels2.util.Region
import io.dico.parcels2.util.Vec2i
import io.dico.parcels2.util.get
+import kotlinx.coroutines.CoroutineScope
import org.bukkit.Chunk
import org.bukkit.Location
import org.bukkit.World
@@ -38,6 +39,7 @@ abstract class ParcelGenerator : ChunkGenerator() {
abstract fun makeParcelLocatorAndBlockManager(worldId: ParcelWorldId,
container: ParcelContainer,
+ coroutineScope: CoroutineScope,
worktimeLimiter: WorktimeLimiter): Pair<ParcelLocator, ParcelBlockManager>
}
diff --git a/src/main/kotlin/io/dico/parcels2/ParcelId.kt b/src/main/kotlin/io/dico/parcels2/ParcelId.kt
index 20d4cc8..72eceb9 100644
--- a/src/main/kotlin/io/dico/parcels2/ParcelId.kt
+++ b/src/main/kotlin/io/dico/parcels2/ParcelId.kt
@@ -22,6 +22,8 @@ interface ParcelWorldId {
}
}
+fun ParcelWorldId.toStringExt() = "ParcelWorld($name)"
+
/**
* Used by storage backing options to encompass the location of a parcel
* Does NOT support equality operator.
@@ -31,6 +33,7 @@ interface ParcelId {
val x: Int
val z: Int
val pos: Vec2i get() = Vec2i(x, z)
+ val idString get() = "$x,$z"
fun equals(id: ParcelId): Boolean = x == id.x && z == id.z && worldId.equals(id.worldId)
companion object {
@@ -41,9 +44,15 @@ interface ParcelId {
}
}
+fun ParcelId.toStringExt() = "Parcel(${worldId.name},$idString)"
+
private class ParcelWorldIdImpl(override val name: String,
- override val uid: UUID?) : ParcelWorldId
+ override val uid: UUID?) : ParcelWorldId {
+ override fun toString() = toStringExt()
+}
private class ParcelIdImpl(override val worldId: ParcelWorldId,
override val x: Int,
- override val z: Int) : ParcelId
+ override val z: Int) : ParcelId {
+ override fun toString() = toStringExt()
+}
diff --git a/src/main/kotlin/io/dico/parcels2/ParcelWorld.kt b/src/main/kotlin/io/dico/parcels2/ParcelWorld.kt
index d307947..d70368f 100644
--- a/src/main/kotlin/io/dico/parcels2/ParcelWorld.kt
+++ b/src/main/kotlin/io/dico/parcels2/ParcelWorld.kt
@@ -3,8 +3,7 @@ package io.dico.parcels2
import io.dico.parcels2.options.RuntimeWorldOptions
import io.dico.parcels2.storage.Storage
import io.dico.parcels2.util.Vec2i
-import io.dico.parcels2.util.floor
-import org.bukkit.Chunk
+import io.dico.parcels2.util.ext.floor
import org.bukkit.Location
import org.bukkit.World
import org.bukkit.block.Block
@@ -70,6 +69,8 @@ interface ParcelContainer {
fun getParcelById(id: Vec2i): Parcel? = getParcelById(id.x, id.z)
+ fun getParcelById(id: ParcelId): Parcel? = getParcelById(id.x, id.z)
+
fun nextEmptyParcel(): Parcel?
}
diff --git a/src/main/kotlin/io/dico/parcels2/ParcelsPlugin.kt b/src/main/kotlin/io/dico/parcels2/ParcelsPlugin.kt
index 01ee857..c863716 100644
--- a/src/main/kotlin/io/dico/parcels2/ParcelsPlugin.kt
+++ b/src/main/kotlin/io/dico/parcels2/ParcelsPlugin.kt
@@ -10,23 +10,27 @@ import io.dico.parcels2.defaultimpl.GlobalAddedDataManagerImpl
import io.dico.parcels2.defaultimpl.ParcelProviderImpl
import io.dico.parcels2.listener.ParcelEntityTracker
import io.dico.parcels2.listener.ParcelListeners
+import io.dico.parcels2.listener.WorldEditListener
import io.dico.parcels2.options.Options
import io.dico.parcels2.options.optionsMapper
import io.dico.parcels2.storage.Storage
-import io.dico.parcels2.util.FunctionHelper
-import io.dico.parcels2.util.tryCreate
+import io.dico.parcels2.util.MainThreadDispatcher
+import io.dico.parcels2.util.PluginScheduler
+import io.dico.parcels2.util.ext.tryCreate
+import kotlinx.coroutines.CoroutineScope
import org.bukkit.Bukkit
import org.bukkit.generator.ChunkGenerator
+import org.bukkit.plugin.Plugin
import org.bukkit.plugin.java.JavaPlugin
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.File
-import java.util.Random
+import kotlin.coroutines.CoroutineContext
val logger: Logger = LoggerFactory.getLogger("ParcelsPlugin")
private inline val plogger get() = logger
-class ParcelsPlugin : JavaPlugin() {
+class ParcelsPlugin : JavaPlugin(), CoroutineScope, PluginScheduler {
lateinit var optionsFile: File; private set
lateinit var options: Options; private set
lateinit var parcelProvider: ParcelProvider; private set
@@ -38,7 +42,8 @@ class ParcelsPlugin : JavaPlugin() {
private var listeners: ParcelListeners? = null
private var cmdDispatcher: ICommandDispatcher? = null
- val functionHelper: FunctionHelper = FunctionHelper(this)
+ override val coroutineContext: CoroutineContext = MainThreadDispatcher(this)
+ override val plugin: Plugin get() = this
val worktimeLimiter: WorktimeLimiter by lazy { TickWorktimeLimiter(this, options.tickWorktime) }
override fun onEnable() {
@@ -135,9 +140,14 @@ class ParcelsPlugin : JavaPlugin() {
if (listeners == null) {
listeners = ParcelListeners(parcelProvider, entityTracker, storage)
registrator.registerListeners(listeners!!)
+
+ val worldEditPlugin = server.pluginManager.getPlugin("WorldEdit")
+ if (worldEditPlugin != null) {
+ WorldEditListener.register(this, worldEditPlugin)
+ }
}
- functionHelper.scheduleRepeating(100, 5, entityTracker::tick)
+ scheduleRepeating(100, 5, entityTracker::tick)
}
} \ No newline at end of file
diff --git a/src/main/kotlin/io/dico/parcels2/PlayerProfile.kt b/src/main/kotlin/io/dico/parcels2/PlayerProfile.kt
index c735c68..0ef9f9d 100644
--- a/src/main/kotlin/io/dico/parcels2/PlayerProfile.kt
+++ b/src/main/kotlin/io/dico/parcels2/PlayerProfile.kt
@@ -3,12 +3,13 @@
package io.dico.parcels2
import io.dico.parcels2.storage.Storage
-import io.dico.parcels2.util.getPlayerNameOrDefault
-import io.dico.parcels2.util.isValid
-import io.dico.parcels2.util.uuid
-import kotlinx.coroutines.experimental.Deferred
-import kotlinx.coroutines.experimental.Unconfined
-import kotlinx.coroutines.experimental.async
+import io.dico.parcels2.util.PLAYER_NAME_PLACEHOLDER
+import io.dico.parcels2.util.getPlayerName
+import io.dico.parcels2.util.ext.isValid
+import io.dico.parcels2.util.ext.uuid
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.Unconfined
+import kotlinx.coroutines.async
import org.bukkit.Bukkit
import org.bukkit.OfflinePlayer
import java.util.UUID
@@ -18,7 +19,7 @@ interface PlayerProfile {
val name: String?
val nameOrBukkitName: String?
val notNullName: String
- val isStar: Boolean get() = false
+ val isStar: Boolean get() = this is Star
val exists: Boolean get() = this is RealImpl
fun matches(player: OfflinePlayer, allowNameMatch: Boolean = false): Boolean
@@ -78,9 +79,9 @@ interface PlayerProfile {
override val uuid: UUID
override val nameOrBukkitName: String?
// If a player is online, their name is prioritized to get name changes right immediately
- get() = Bukkit.getPlayer(uuid)?.name ?: name ?: Bukkit.getOfflinePlayer(uuid).takeIf { it.isValid }?.name
+ get() = Bukkit.getPlayer(uuid)?.name ?: name ?: getPlayerName(uuid)
override val notNullName: String
- get() = name ?: getPlayerNameOrDefault(uuid)
+ get() = nameOrBukkitName ?: PLAYER_NAME_PLACEHOLDER
val player: OfflinePlayer? get() = Bukkit.getOfflinePlayer(uuid).takeIf { it.isValid }
val playerUnchecked: OfflinePlayer get() = Bukkit.getOfflinePlayer(uuid)
@@ -115,8 +116,8 @@ interface PlayerProfile {
object Star : BaseImpl(), Real {
override val name: String = "*"
+ // hopefully nobody will have this random UUID :)
override val uuid: UUID = UUID.fromString("7d09c4c6-117d-4f36-9778-c4d24618cee1")
- override val isStar: Boolean get() = true
override fun matches(player: OfflinePlayer, allowNameMatch: Boolean): Boolean {
return true
@@ -148,7 +149,7 @@ interface PlayerProfile {
}
suspend fun tryResolveSuspendedly(storage: Storage): Real? {
- return storage.getPlayerUuidForName(name).await()?.let { RealImpl(it, name) }
+ return storage.getPlayerUuidForName(name).await()?.let { resolve(it) }
}
fun resolve(uuid: UUID): Real {
diff --git a/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt b/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt
index 1cac5f9..3899db9 100644
--- a/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt
+++ b/src/main/kotlin/io/dico/parcels2/blockvisitor/RegionTraverser.kt
@@ -2,13 +2,11 @@ package io.dico.parcels2.blockvisitor
import io.dico.parcels2.util.Region
import io.dico.parcels2.util.Vec3i
-import kotlin.coroutines.experimental.SequenceBuilder
-import kotlin.coroutines.experimental.buildIterator
abstract class RegionTraverser {
- fun traverseRegion(region: Region): Iterable<Vec3i> = Iterable { buildIterator { build(region) } }
+ fun traverseRegion(region: Region): Iterable<Vec3i> = Iterable { iterator<Vec3i> { build(region) } }
- protected abstract suspend fun SequenceBuilder<Vec3i>.build(region: Region)
+ protected abstract suspend fun SequenceScope<Vec3i>.build(region: Region)
companion object {
val upward = create { traverseUpward(it) }
@@ -16,13 +14,13 @@ abstract class RegionTraverser {
val forClearing get() = downward
val forFilling get() = upward
- inline fun create(crossinline builder: suspend SequenceBuilder<Vec3i>.(Region) -> Unit) = object : RegionTraverser() {
- override suspend fun SequenceBuilder<Vec3i>.build(region: Region) {
+ inline fun create(crossinline builder: suspend SequenceScope<Vec3i>.(Region) -> Unit) = object : RegionTraverser() {
+ override suspend fun SequenceScope<Vec3i>.build(region: Region) {
builder(region)
}
}
- private suspend fun SequenceBuilder<Vec3i>.traverseDownward(region: Region) {
+ private suspend fun SequenceScope<Vec3i>.traverseDownward(region: Region) {
val origin = region.origin
val size = region.size
repeat(size.y) { y ->
@@ -34,7 +32,7 @@ abstract class RegionTraverser {
}
}
- private suspend fun SequenceBuilder<Vec3i>.traverseUpward(region: Region) {
+ private suspend fun SequenceScope<Vec3i>.traverseUpward(region: Region) {
val origin = region.origin
val size = region.size
repeat(size.y) { y ->
diff --git a/src/main/kotlin/io/dico/parcels2/blockvisitor/WorktimeLimiter.kt b/src/main/kotlin/io/dico/parcels2/blockvisitor/WorktimeLimiter.kt
index ea4db62..f735903 100644
--- a/src/main/kotlin/io/dico/parcels2/blockvisitor/WorktimeLimiter.kt
+++ b/src/main/kotlin/io/dico/parcels2/blockvisitor/WorktimeLimiter.kt
@@ -1,38 +1,42 @@
package io.dico.parcels2.blockvisitor
import io.dico.parcels2.ParcelsPlugin
-import io.dico.parcels2.util.FunctionHelper
-import kotlinx.coroutines.experimental.CancellationException
-import kotlinx.coroutines.experimental.Job
+import io.dico.parcels2.logger
+import kotlinx.coroutines.CancellationException
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart.LAZY
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
import org.bukkit.scheduler.BukkitTask
import java.lang.System.currentTimeMillis
import java.util.LinkedList
-import java.util.logging.Level
-import kotlin.coroutines.experimental.Continuation
-import kotlin.coroutines.experimental.intrinsics.COROUTINE_SUSPENDED
-import kotlin.coroutines.experimental.intrinsics.suspendCoroutineUninterceptedOrReturn
+import kotlin.coroutines.Continuation
+import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
+import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
+import kotlin.coroutines.resume
+import kotlin.coroutines.suspendCoroutine
typealias TimeLimitedTask = suspend WorkerScope.() -> Unit
typealias WorkerUpdateLister = Worker.(Double, Long) -> Unit
data class TickWorktimeOptions(var workTime: Int, var tickInterval: Int)
-sealed class WorktimeLimiter {
+interface WorktimeLimiter {
/**
* Submit a [task] that should be run synchronously, but limited such that it does not stall the server
* a bunch
*/
- abstract fun submit(task: TimeLimitedTask): Worker
+ fun submit(task: TimeLimitedTask): Worker
/**
* Get a list of all workers
*/
- abstract val workers: List<Worker>
+ val workers: List<Worker>
/**
* Attempts to complete any remaining tasks immediately, without suspension.
*/
- abstract fun completeAllTasks()
+ fun completeAllTasks()
}
interface Timed {
@@ -77,9 +81,14 @@ interface Worker : Timed {
/**
* Calls the given [block] when this worker completes, with the progress value 1.0.
- * Repeated invocations of this method result in an [IllegalStateException]
+ * Multiple listeners may be registered to this function.
*/
fun onCompleted(block: WorkerUpdateLister): Worker
+
+ /**
+ * Await completion of this worker
+ */
+ suspend fun awaitCompletion()
}
interface WorkerScope : Timed {
@@ -113,7 +122,7 @@ private interface WorkerContinuation : Worker, WorkerScope {
* There is a configurable maxiumum amount of milliseconds that can be allocated to all workers together in each server tick
* This object attempts to split that maximum amount of milliseconds equally between all jobs
*/
-class TickWorktimeLimiter(private val plugin: ParcelsPlugin, var options: TickWorktimeOptions) : WorktimeLimiter() {
+class TickWorktimeLimiter(private val plugin: ParcelsPlugin, var options: TickWorktimeOptions) : WorktimeLimiter {
// The currently registered bukkit scheduler task
private var bukkitTask: BukkitTask? = null
// The workers.
@@ -121,12 +130,12 @@ class TickWorktimeLimiter(private val plugin: ParcelsPlugin, var options: TickWo
override val workers: List<Worker> = _workers
override fun submit(task: TimeLimitedTask): Worker {
- val worker: WorkerContinuation = WorkerImpl(plugin.functionHelper, task)
+ val worker: WorkerContinuation = WorkerImpl(plugin, task)
if (bukkitTask == null) {
val completed = worker.resume(options.workTime.toLong())
if (completed) return worker
- bukkitTask = plugin.functionHelper.scheduleRepeating(0, options.tickInterval) { tickJobs() }
+ bukkitTask = plugin.scheduleRepeating(0, options.tickInterval) { tickJobs() }
}
_workers.addFirst(worker)
@@ -171,8 +180,10 @@ class TickWorktimeLimiter(private val plugin: ParcelsPlugin, var options: TickWo
}
-private class WorkerImpl(val functionHelper: FunctionHelper,
- val task: TimeLimitedTask) : WorkerContinuation {
+private class WorkerImpl(
+ val scope: CoroutineScope,
+ val task: TimeLimitedTask
+) : WorkerContinuation, CoroutineScope by scope {
override var job: Job? = null; private set
override val elapsedTime
@@ -204,27 +215,44 @@ private class WorkerImpl(val functionHelper: FunctionHelper,
// report any error that occurred
completionException = exception?.also {
if (it !is CancellationException)
- functionHelper.plugin.logger.log(Level.SEVERE, "TimeLimitedTask for plugin ${functionHelper.plugin.name} generated an exception", it)
+ logger.error("TimeLimitedTask generated an exception", it)
}
// convert to elapsed time here
startTimeOrElapsedTime = System.currentTimeMillis() - startTimeOrElapsedTime
onCompleted?.let { it(1.0, elapsedTime) }
+
+ onCompleted = null
+ onProgressUpdate = { prog, el -> }
}
}
override fun onProgressUpdate(minDelay: Int, minInterval: Int, asCompletionListener: Boolean, block: WorkerUpdateLister): Worker {
onProgressUpdate?.let { throw IllegalStateException() }
+ if (asCompletionListener) onCompleted(block)
+ if (isComplete) return this
onProgressUpdate = block
progressUpdateInterval = minInterval
lastUpdateTime = System.currentTimeMillis() + minDelay - minInterval
- if (asCompletionListener) onCompleted(block)
+
return this
}
override fun onCompleted(block: WorkerUpdateLister): Worker {
- onCompleted?.let { throw IllegalStateException() }
- onCompleted = block
+ if (isComplete) {
+ block(1.0, startTimeOrElapsedTime)
+ return this
+ }
+
+ val cur = onCompleted
+ onCompleted = if (cur == null) {
+ block
+ } else {
+ fun Worker.(prog: Double, el: Long) {
+ cur(prog, el)
+ block(prog, el)
+ }
+ }
return this
}
@@ -265,7 +293,7 @@ private class WorkerImpl(val functionHelper: FunctionHelper,
}
try {
- val job = functionHelper.launchLazilyOnMainThread { task() }
+ val job = launch(start = LAZY) { task() }
initJob(job = job)
job.start()
} catch (t: Throwable) {
@@ -275,6 +303,18 @@ private class WorkerImpl(val functionHelper: FunctionHelper,
return continuation == null
}
+ override suspend fun awaitCompletion() {
+ if (isComplete) return
+
+ // easy path - if the job was initialized already
+ job?.apply { join(); return }
+
+ // other way.
+ return suspendCoroutine { cont ->
+ onCompleted { prog, el -> cont.resume(Unit) }
+ }
+ }
+
}
/*
diff --git a/src/main/kotlin/io/dico/parcels2/command/AbstractParcelCommands.kt b/src/main/kotlin/io/dico/parcels2/command/AbstractParcelCommands.kt
index 31a551a..bd27fe7 100644
--- a/src/main/kotlin/io/dico/parcels2/command/AbstractParcelCommands.kt
+++ b/src/main/kotlin/io/dico/parcels2/command/AbstractParcelCommands.kt
@@ -1,26 +1,25 @@
package io.dico.parcels2.command
import io.dico.dicore.command.CommandException
+import io.dico.dicore.command.EMessageType
import io.dico.dicore.command.ExecutionContext
import io.dico.dicore.command.ICommandReceiver
-import io.dico.parcels2.PlayerProfile
import io.dico.parcels2.ParcelWorld
import io.dico.parcels2.ParcelsPlugin
-import io.dico.parcels2.util.hasAdminManage
-import io.dico.parcels2.util.parcelLimit
+import io.dico.parcels2.PlayerProfile
+import io.dico.parcels2.util.ext.hasAdminManage
+import io.dico.parcels2.util.ext.parcelLimit
import org.bukkit.entity.Player
import org.bukkit.plugin.Plugin
import java.lang.reflect.Method
abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandReceiver.Factory {
-
override fun getPlugin(): Plugin = plugin
+
override fun getReceiver(context: ExecutionContext, target: Method, cmdName: String): ICommandReceiver {
return getParcelCommandReceiver(plugin.parcelProvider, context, target, cmdName)
}
- protected inline val worlds get() = plugin.parcelProvider
-
protected fun error(message: String): Nothing {
throw CommandException(message)
}
@@ -40,5 +39,21 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei
}
}
+ protected fun areYouSureMessage(context: ExecutionContext) = "Are you sure? You cannot undo this action!\n" +
+ "Run \"/${context.route.joinToString(" ")} -sure\" if you want to go through with this."
+
+ protected fun ParcelScope.clearWithProgressUpdates(context: ExecutionContext, action: String) {
+ world.blockManager.clearParcel(parcel.id)
+ .onProgressUpdate(1000, 1000) { progress, elapsedTime ->
+ val alt = context.getFormat(EMessageType.NUMBER)
+ val main = context.getFormat(EMessageType.INFORMATIVE)
+ context.sendMessage(
+ EMessageType.INFORMATIVE, false, "$action progress: $alt%.02f$main%%, $alt%.2f${main}s elapsed"
+ .format(progress * 100, elapsedTime / 1000.0)
+ )
+ }
+ }
+
+ override fun getCoroutineContext() = plugin.coroutineContext
}
diff --git a/src/main/kotlin/io/dico/parcels2/command/CommandsAddedStatusLocal.kt b/src/main/kotlin/io/dico/parcels2/command/CommandsAddedStatusLocal.kt
index 69da341..223e504 100644
--- a/src/main/kotlin/io/dico/parcels2/command/CommandsAddedStatusLocal.kt
+++ b/src/main/kotlin/io/dico/parcels2/command/CommandsAddedStatusLocal.kt
@@ -4,7 +4,7 @@ import io.dico.dicore.command.Validate
import io.dico.dicore.command.annotation.Cmd
import io.dico.dicore.command.annotation.Desc
import io.dico.parcels2.ParcelsPlugin
-import io.dico.parcels2.util.hasAdminManage
+import io.dico.parcels2.util.ext.hasAdminManage
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
diff --git a/src/main/kotlin/io/dico/parcels2/command/CommandsAdmin.kt b/src/main/kotlin/io/dico/parcels2/command/CommandsAdmin.kt
index 2fe18ed..35ede71 100644
--- a/src/main/kotlin/io/dico/parcels2/command/CommandsAdmin.kt
+++ b/src/main/kotlin/io/dico/parcels2/command/CommandsAdmin.kt
@@ -1,7 +1,43 @@
package io.dico.parcels2.command
+import io.dico.dicore.command.ExecutionContext
+import io.dico.dicore.command.annotation.Cmd
+import io.dico.dicore.command.annotation.Flag
import io.dico.parcels2.ParcelsPlugin
+import io.dico.parcels2.PlayerProfile
class CommandsAdmin(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
+ @Cmd("setowner")
+ @ParcelRequire(admin = true)
+ fun ParcelScope.cmdSetowner(target: PlayerProfile): Any? {
+ parcel.owner = target
+
+ val fakeString = if (target.isFake) " (fake)" else ""
+ return "${target.notNullName}$fakeString is the new owner of (${parcel.id.idString})"
+ }
+
+ @Cmd("dispose")
+ @ParcelRequire(admin = true)
+ fun ParcelScope.cmdDispose(): Any? {
+ parcel.dispose()
+ return "Data of (${parcel.id.idString}) has been disposed"
+ }
+
+ @Cmd("reset")
+ @ParcelRequire(admin = true)
+ fun ParcelScope.cmdReset(context: ExecutionContext, @Flag sure: Boolean): Any? {
+ if (!sure) return areYouSureMessage(context)
+ parcel.dispose()
+ clearWithProgressUpdates(context, "Reset")
+ return null
+ }
+
+ @Cmd("swap")
+ fun ParcelScope.cmdSwap(context: ExecutionContext, @Flag sure: Boolean): Any? {
+ if (!sure) return areYouSureMessage(context)
+ TODO()
+ }
+
+
} \ No newline at end of file
diff --git a/src/main/kotlin/io/dico/parcels2/command/CommandsGeneral.kt b/src/main/kotlin/io/dico/parcels2/command/CommandsGeneral.kt
index d02c974..95083b6 100644
--- a/src/main/kotlin/io/dico/parcels2/command/CommandsGeneral.kt
+++ b/src/main/kotlin/io/dico/parcels2/command/CommandsGeneral.kt
@@ -1,16 +1,18 @@
package io.dico.parcels2.command
-import io.dico.dicore.command.EMessageType
import io.dico.dicore.command.ExecutionContext
+import io.dico.dicore.command.Validate
import io.dico.dicore.command.annotation.Cmd
import io.dico.dicore.command.annotation.Desc
import io.dico.dicore.command.annotation.Flag
import io.dico.dicore.command.annotation.RequireParameters
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.PlayerProfile
-import io.dico.parcels2.util.hasAdminManage
-import io.dico.parcels2.util.hasParcelHomeOthers
-import io.dico.parcels2.util.uuid
+import io.dico.parcels2.command.ParcelTarget.Kind
+import io.dico.parcels2.util.ext.hasAdminManage
+import io.dico.parcels2.util.ext.hasParcelHomeOthers
+import io.dico.parcels2.util.ext.uuid
+import org.bukkit.block.Biome
import org.bukkit.entity.Player
class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
@@ -43,17 +45,20 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
"more than one parcel",
shortVersion = "teleports you to parcels")
@RequireParameters(0)
- suspend fun cmdHome(player: Player, @ParcelTarget.Kind(ParcelTarget.OWNER_REAL) target: ParcelTarget): Any? {
+ suspend fun cmdHome(player: Player,
+ @Kind(ParcelTarget.OWNER_REAL) target: ParcelTarget): Any? {
return cmdGoto(player, target)
}
@Cmd("tp", aliases = ["teleport"])
- suspend fun cmdTp(player: Player, @ParcelTarget.Kind(ParcelTarget.ID) target: ParcelTarget): Any? {
+ suspend fun cmdTp(player: Player,
+ @Kind(ParcelTarget.ID) target: ParcelTarget): Any? {
return cmdGoto(player, target)
}
@Cmd("goto")
- suspend fun cmdGoto(player: Player, @ParcelTarget.Kind(ParcelTarget.ANY) target: ParcelTarget): Any? {
+ suspend fun cmdGoto(player: Player,
+ @Kind(ParcelTarget.ANY) target: ParcelTarget): Any? {
if (target is ParcelTarget.ByOwner) {
target.resolveOwner(plugin.storage)
if (!target.owner.matches(player) && !player.hasParcelHomeOthers) {
@@ -64,11 +69,12 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
val match = target.getParcelSuspend(plugin.storage)
?: error("The specified parcel could not be matched")
player.teleport(match.homeLocation)
- return ""
+ return null
}
@Cmd("goto_fake")
- suspend fun cmdGotoFake(player: Player, @ParcelTarget.Kind(ParcelTarget.OWNER_FAKE) target: ParcelTarget): Any? {
+ suspend fun cmdGotoFake(player: Player,
+ @Kind(ParcelTarget.OWNER_FAKE) target: ParcelTarget): Any? {
return cmdGoto(player, target)
}
@@ -97,23 +103,18 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
@Cmd("clear")
@ParcelRequire(owner = true)
fun ParcelScope.cmdClear(context: ExecutionContext, @Flag sure: Boolean): Any? {
- if (!sure) return "Are you sure? You cannot undo this action!\n" +
- "Run \"/${context.rawInput} -sure\" if you want to go through with this."
-
- world.blockManager.clearParcel(parcel.id)
- .onProgressUpdate(1000, 1000) { progress, elapsedTime ->
- val alt = context.getFormat(EMessageType.NUMBER)
- val main = context.getFormat(EMessageType.INFORMATIVE)
- context.sendMessage(EMessageType.INFORMATIVE, false, "Clear progress: $alt%.02f$main%%, $alt%.2f${main}s elapsed"
- .format(progress * 100, elapsedTime / 1000.0))
- }
+ if (!sure) return areYouSureMessage(context)
+ clearWithProgressUpdates(context, "Clear")
return null
}
- @Cmd("swap")
- fun ParcelScope.cmdSwap(context: ExecutionContext, @Flag sure: Boolean): Any? {
- TODO()
+ @Cmd("setbiome")
+ @ParcelRequire(owner = true)
+ fun ParcelScope.cmdSetbiome(context: ExecutionContext, biome: Biome): Any? {
+ Validate.isTrue(!parcel.hasBlockVisitors, "A process is already running in this parcel")
+ world.blockManager.setBiome(parcel.id, biome)
+ return "Biome has been set to $biome"
}
} \ No newline at end of file
diff --git a/src/main/kotlin/io/dico/parcels2/command/ParcelCommandReceivers.kt b/src/main/kotlin/io/dico/parcels2/command/ParcelCommandReceivers.kt
index eab02c4..488148d 100644
--- a/src/main/kotlin/io/dico/parcels2/command/ParcelCommandReceivers.kt
+++ b/src/main/kotlin/io/dico/parcels2/command/ParcelCommandReceivers.kt
@@ -7,8 +7,8 @@ import io.dico.dicore.command.Validate
import io.dico.parcels2.Parcel
import io.dico.parcels2.ParcelProvider
import io.dico.parcels2.ParcelWorld
-import io.dico.parcels2.util.hasAdminManage
-import io.dico.parcels2.util.uuid
+import io.dico.parcels2.util.ext.hasAdminManage
+import io.dico.parcels2.util.ext.uuid
import org.bukkit.entity.Player
import java.lang.reflect.Method
import kotlin.reflect.full.extensionReceiverParameter
diff --git a/src/main/kotlin/io/dico/parcels2/command/ParcelTarget.kt b/src/main/kotlin/io/dico/parcels2/command/ParcelTarget.kt
index bbdcdb8..abf7d40 100644
--- a/src/main/kotlin/io/dico/parcels2/command/ParcelTarget.kt
+++ b/src/main/kotlin/io/dico/parcels2/command/ParcelTarget.kt
@@ -7,8 +7,10 @@ import io.dico.dicore.command.parameter.type.ParameterType
import io.dico.parcels2.*
import io.dico.parcels2.storage.Storage
import io.dico.parcels2.util.Vec2i
-import io.dico.parcels2.util.floor
-import kotlinx.coroutines.experimental.Deferred
+import io.dico.parcels2.util.ext.floor
+import kotlinx.coroutines.CoroutineStart.*
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.async
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
@@ -16,7 +18,7 @@ sealed class ParcelTarget(val world: ParcelWorld, val parsedKind: Int, val isDef
abstract suspend fun getParcelSuspend(storage: Storage): Parcel?
- fun ParcelsPlugin.getParcelDeferred(): Deferred<Parcel?> = functionHelper.deferUndispatchedOnMainThread { getParcelSuspend(storage) }
+ fun ParcelsPlugin.getParcelDeferred(): Deferred<Parcel?> = async(start = UNDISPATCHED) { getParcelSuspend(storage) }
class ByID(world: ParcelWorld, val id: Vec2i?, parsedKind: Int, isDefault: Boolean) : ParcelTarget(world, parsedKind, isDefault) {
override suspend fun getParcelSuspend(storage: Storage): Parcel? = getParcel()
@@ -57,13 +59,7 @@ sealed class ParcelTarget(val world: ParcelWorld, val parsedKind: Int, val isDef
}
}
- annotation class Kind(val kind: Int)
-
- companion object Config : ParameterConfig<Kind, Int>(Kind::class.java) {
- override fun toParameterInfo(annotation: Kind): Int {
- return annotation.kind
- }
-
+ companion object {
const val ID = 1 // ID
const val OWNER_REAL = 2 // an owner backed by a UUID
const val OWNER_FAKE = 4 // an owner not backed by a UUID
@@ -78,7 +74,14 @@ sealed class ParcelTarget(val world: ParcelWorld, val parsedKind: Int, val isDef
// instead of parcel that the player is in
}
- class PType(val parcelProvider: ParcelProvider) : ParameterType<ParcelTarget, Int>(ParcelTarget::class.java, ParcelTarget.Config) {
+ annotation class Kind(val kind: Int)
+ private object Config : ParameterConfig<Kind, Int>(Kind::class.java) {
+ override fun toParameterInfo(annotation: Kind): Int {
+ return annotation.kind
+ }
+ }
+
+ class PType(val parcelProvider: ParcelProvider) : ParameterType<ParcelTarget, Int>(ParcelTarget::class.java, Config) {
override fun parse(parameter: Parameter<ParcelTarget, Int>, sender: CommandSender, buffer: ArgumentBuffer): ParcelTarget {
var input = buffer.next()
@@ -117,15 +120,18 @@ sealed class ParcelTarget(val world: ParcelWorld, val parsedKind: Int, val isDef
private fun getHomeIndex(parameter: Parameter<*, *>, kind: Int, sender: CommandSender, input: String): Pair<PlayerProfile, Int> {
val splitIdx = input.indexOf(':')
val ownerString: String
- val indexString: String
+ val index: Int?
if (splitIdx == -1) {
// just the index.
- ownerString = ""
- indexString = input
+ index = input.toIntOrNull()
+ ownerString = if (index == null) input else ""
} else {
ownerString = input.substring(0, splitIdx)
- indexString = input.substring(splitIdx + 1)
+
+ val indexString = input.substring(splitIdx + 1)
+ index = indexString.toIntOrNull()
+ ?: invalidInput(parameter, "The home index must be an integer, $indexString is not an integer")
}
val owner = if (ownerString.isEmpty())
@@ -133,10 +139,7 @@ sealed class ParcelTarget(val world: ParcelWorld, val parsedKind: Int, val isDef
else
PlayerProfile.byName(ownerString, allowReal = kind and OWNER_REAL != 0, allowFake = kind and OWNER_FAKE != 0)
- 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
+ return owner to (index ?: 0)
}
private fun requirePlayer(sender: CommandSender, parameter: Parameter<*, *>, objName: String): Player {
diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelContainer.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelContainer.kt
index 0597a9f..e6d29f4 100644
--- a/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelContainer.kt
+++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelContainer.kt
@@ -2,9 +2,8 @@ package io.dico.parcels2.defaultimpl
import io.dico.parcels2.Parcel
import io.dico.parcels2.ParcelContainer
+import io.dico.parcels2.ParcelId
import io.dico.parcels2.ParcelWorld
-import kotlin.coroutines.experimental.buildIterator
-import kotlin.coroutines.experimental.buildSequence
class DefaultParcelContainer(val world: ParcelWorld) : ParcelContainer {
private var parcels: Array<Array<Parcel>>
@@ -38,12 +37,20 @@ class DefaultParcelContainer(val world: ParcelWorld) : ParcelContainer {
return parcels.getOrNull(x + world.options.axisLimit)?.getOrNull(z + world.options.axisLimit)
}
+ override fun getParcelById(id: ParcelId): Parcel? {
+ if (!world.id.equals(id.worldId)) throw IllegalArgumentException()
+ return when (id) {
+ is Parcel -> id
+ else -> getParcelById(id.x, id.z)
+ }
+ }
+
override fun nextEmptyParcel(): Parcel? {
return walkInCircle().find { it.owner == null }
}
private fun walkInCircle(): Iterable<Parcel> = Iterable {
- buildIterator {
+ iterator {
val center = world.options.axisLimit
for (radius in 0..center) {
var x = center - radius;
@@ -56,7 +63,7 @@ class DefaultParcelContainer(val world: ParcelWorld) : ParcelContainer {
}
}
- fun allParcels(): Sequence<Parcel> = buildSequence {
+ fun allParcels(): Sequence<Parcel> = sequence {
for (array in parcels) {
yieldAll(array.iterator())
}
diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt
index 244d38c..44ecc6c 100644
--- a/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt
+++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/DefaultParcelGenerator.kt
@@ -2,10 +2,19 @@ package io.dico.parcels2.defaultimpl
import io.dico.parcels2.*
import io.dico.parcels2.blockvisitor.RegionTraverser
+import io.dico.parcels2.blockvisitor.TimeLimitedTask
import io.dico.parcels2.blockvisitor.Worker
import io.dico.parcels2.blockvisitor.WorktimeLimiter
import io.dico.parcels2.options.DefaultGeneratorOptions
-import io.dico.parcels2.util.*
+import io.dico.parcels2.util.Region
+import io.dico.parcels2.util.Vec2i
+import io.dico.parcels2.util.Vec3i
+import io.dico.parcels2.util.ext.even
+import io.dico.parcels2.util.ext.umod
+import io.dico.parcels2.util.get
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
+import kotlinx.coroutines.launch
import org.bukkit.*
import org.bukkit.block.Biome
import org.bukkit.block.BlockFace
@@ -13,13 +22,17 @@ import org.bukkit.block.Skull
import org.bukkit.block.data.BlockData
import org.bukkit.block.data.type.Sign
import org.bukkit.block.data.type.Slab
+import java.lang.IllegalArgumentException
import java.util.Random
private val airType = Bukkit.createBlockData(Material.AIR)
private const val chunkSize = 16
-class DefaultParcelGenerator(override val worldName: String, private val o: DefaultGeneratorOptions) : ParcelGenerator() {
+class DefaultParcelGenerator(
+ override val worldName: String,
+ private val o: DefaultGeneratorOptions
+) : ParcelGenerator() {
private var _world: World? = null
override val world: World
get() {
@@ -36,13 +49,15 @@ class DefaultParcelGenerator(override val worldName: String, private val o: Defa
val makePathMain = o.pathSize > 2
val makePathAlt = o.pathSize > 4
- private inline fun <T> generate(chunkX: Int,
- chunkZ: Int,
- floor: T, wall:
- T, pathMain: T,
- pathAlt: T,
- fill: T,
- setter: (Int, Int, Int, T) -> Unit) {
+ private inline fun <T> generate(
+ chunkX: Int,
+ chunkZ: Int,
+ floor: T, wall:
+ T, pathMain: T,
+ pathAlt: T,
+ fill: T,
+ setter: (Int, Int, Int, T) -> Unit
+ ) {
val floorHeight = o.floorHeight
val parcelSize = o.parcelSize
@@ -104,10 +119,13 @@ class DefaultParcelGenerator(override val worldName: String, private val o: Defa
return Location(world, o.offsetX + fix, o.floorHeight + 1.0, o.offsetZ + fix)
}
- override fun makeParcelLocatorAndBlockManager(worldId: ParcelWorldId,
- container: ParcelContainer,
- worktimeLimiter: WorktimeLimiter): Pair<ParcelLocator, ParcelBlockManager> {
- return ParcelLocatorImpl(worldId, container) to ParcelBlockManagerImpl(worldId, worktimeLimiter)
+ override fun makeParcelLocatorAndBlockManager(
+ worldId: ParcelWorldId,
+ container: ParcelContainer,
+ coroutineScope: CoroutineScope,
+ worktimeLimiter: WorktimeLimiter
+ ): Pair<ParcelLocator, ParcelBlockManager> {
+ return ParcelLocatorImpl(worldId, container) to ParcelBlockManagerImpl(worldId, coroutineScope, worktimeLimiter)
}
private inline fun <T> convertBlockLocationToId(x: Int, z: Int, mapper: (Int, Int) -> T): T? {
@@ -123,8 +141,10 @@ class DefaultParcelGenerator(override val worldName: String, private val o: Defa
return null
}
- private inner class ParcelLocatorImpl(val worldId: ParcelWorldId,
- val container: ParcelContainer) : ParcelLocator {
+ private inner class ParcelLocatorImpl(
+ val worldId: ParcelWorldId,
+ val container: ParcelContainer
+ ) : ParcelLocator {
override val world: World = this@DefaultParcelGenerator.world
override fun getParcelAt(x: Int, z: Int): Parcel? {
@@ -137,8 +157,11 @@ class DefaultParcelGenerator(override val worldName: String, private val o: Defa
}
@Suppress("DEPRECATION")
- private inner class ParcelBlockManagerImpl(val worldId: ParcelWorldId,
- override val worktimeLimiter: WorktimeLimiter) : ParcelBlockManagerBase() {
+ private inner class ParcelBlockManagerImpl(
+ val worldId: ParcelWorldId,
+ coroutineScope: CoroutineScope,
+ override val worktimeLimiter: WorktimeLimiter
+ ) : ParcelBlockManagerBase(), CoroutineScope by coroutineScope {
override val world: World = this@DefaultParcelGenerator.world
override val parcelTraverser: RegionTraverser = RegionTraverser.upToAndDownUntil(o.floorHeight)
@@ -198,7 +221,28 @@ class DefaultParcelGenerator(override val worldName: String, private val o: Defa
}
}
- override fun setBiome(parcel: ParcelId, biome: Biome): Worker = worktimeLimiter.submit {
+ private fun getParcel(parcelId: ParcelId): Parcel? {
+ // todo dont rely on this cast
+ val world = worldId as? ParcelWorld ?: return null
+ return world.getParcelById(parcelId)
+ }
+
+ private fun submitBlockVisitor(parcelId: ParcelId, task: TimeLimitedTask): Worker {
+ val parcel = getParcel(parcelId) ?: return worktimeLimiter.submit(task)
+ if (parcel.hasBlockVisitors) throw IllegalArgumentException("This parcel already has a block visitor")
+
+ val worker = worktimeLimiter.submit(task)
+
+ launch(start = UNDISPATCHED) {
+ parcel.withBlockVisitorPermit {
+ worker.awaitCompletion()
+ }
+ }
+
+ return worker
+ }
+
+ override fun setBiome(parcel: ParcelId, biome: Biome): Worker = submitBlockVisitor(parcel) {
val world = world
val b = getBottomBlock(parcel)
val parcelSize = o.parcelSize
@@ -210,7 +254,7 @@ class DefaultParcelGenerator(override val worldName: String, private val o: Defa
}
}
- override fun clearParcel(parcel: ParcelId): Worker = worktimeLimiter.submit {
+ override fun clearParcel(parcel: ParcelId): Worker = submitBlockVisitor(parcel) {
val region = getRegion(parcel)
val blocks = parcelTraverser.traverseRegion(region)
val blockCount = region.blockCount.toDouble()
diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/GlobalAddedDataManagerImpl.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/GlobalAddedDataManagerImpl.kt
index ba54375..49ab71f 100644
--- a/src/main/kotlin/io/dico/parcels2/defaultimpl/GlobalAddedDataManagerImpl.kt
+++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/GlobalAddedDataManagerImpl.kt
@@ -3,7 +3,7 @@
package io.dico.parcels2.defaultimpl
import io.dico.parcels2.*
-import io.dico.parcels2.util.alsoIfTrue
+import io.dico.parcels2.util.ext.alsoIfTrue
import java.util.Collections
class GlobalAddedDataManagerImpl(val plugin: ParcelsPlugin) : GlobalAddedDataManager {
diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt
index dd3c121..59e84f4 100644
--- a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt
+++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt
@@ -3,11 +3,11 @@ package io.dico.parcels2.defaultimpl
import io.dico.dicore.Formatting
import io.dico.parcels2.*
import io.dico.parcels2.util.Vec2i
-import io.dico.parcels2.util.alsoIfTrue
+import io.dico.parcels2.util.ext.alsoIfTrue
import org.bukkit.Material
import org.bukkit.OfflinePlayer
import org.joda.time.DateTime
-import kotlin.reflect.KProperty
+import java.util.concurrent.atomic.AtomicInteger
class ParcelImpl(override val world: ParcelWorld,
override val x: Int,
@@ -15,8 +15,8 @@ class ParcelImpl(override val world: ParcelWorld,
override val id: ParcelId = this
override val pos get() = Vec2i(x, z)
override var data: ParcelDataHolder = ParcelDataHolder(); private set
- override val infoString by ParcelInfoStringComputer
- override var hasBlockVisitors: Boolean = false; private set
+ override val infoString get() = ParcelInfoStringComputer.getInfoString(this)
+ override val hasBlockVisitors get() = blockVisitors.get() > 0
override val worldId: ParcelWorldId get() = world.id
override fun copyDataIgnoringDatabase(data: ParcelData) {
@@ -115,6 +115,18 @@ class ParcelImpl(override val world: ParcelWorld,
// TODO update storage
}
+ private var blockVisitors = AtomicInteger(0)
+
+ override suspend fun withBlockVisitorPermit(block: suspend () -> Unit) {
+ try {
+ blockVisitors.getAndIncrement()
+ block()
+ } finally {
+ blockVisitors.getAndDecrement()
+ }
+ }
+
+ override fun toString() = toStringExt()
}
private object ParcelInfoStringComputer {
@@ -159,7 +171,7 @@ private object ParcelInfoStringComputer {
}
}
- operator fun getValue(parcel: Parcel, property: KProperty<*>): String = buildString {
+ fun getInfoString(parcel: Parcel): String = buildString {
appendField("ID") {
append(parcel.x)
append(',')
diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt
index c9f4613..8920e2e 100644
--- a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt
+++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelProviderImpl.kt
@@ -1,8 +1,11 @@
package io.dico.parcels2.defaultimpl
import io.dico.parcels2.*
-import kotlinx.coroutines.experimental.Unconfined
-import kotlinx.coroutines.experimental.launch
+import io.dico.parcels2.util.schedule
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.CoroutineStart.*
+import kotlinx.coroutines.Unconfined
+import kotlinx.coroutines.launch
import org.bukkit.Bukkit
import org.bukkit.WorldCreator
import org.joda.time.DateTime
@@ -42,7 +45,7 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
private fun loadWorlds0() {
if (Bukkit.getWorlds().isEmpty()) {
- plugin.functionHelper.schedule(::loadWorlds0)
+ plugin.schedule(::loadWorlds0)
plugin.logger.warning("Scheduling to load worlds in the next tick, \nbecause no bukkit worlds are loaded yet")
return
}
@@ -58,7 +61,7 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
else WorldCreator(worldName).generator(generator).createWorld().also { logger.info("Creating world $worldName") }
parcelWorld = ParcelWorldImpl(bukkitWorld, generator, worldOptions.runtime, plugin.storage,
- plugin.globalAddedData, ::DefaultParcelContainer, plugin.worktimeLimiter)
+ plugin.globalAddedData, ::DefaultParcelContainer, plugin, plugin.worktimeLimiter)
if (!worldExists) {
val time = DateTime.now()
@@ -77,7 +80,7 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
}
private fun loadStoredData() {
- plugin.functionHelper.launchLazilyOnMainThread {
+ plugin.launch {
val migration = plugin.options.migration
if (migration.enabled) {
migration.instance?.newInstance()?.apply {
@@ -102,7 +105,7 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
logger.info("Loading data completed")
_dataIsLoaded = true
- }.start()
+ }
}
/*
diff --git a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelWorldImpl.kt b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelWorldImpl.kt
index a54e519..9f96a8c 100644
--- a/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelWorldImpl.kt
+++ b/src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelWorldImpl.kt
@@ -6,6 +6,7 @@ import io.dico.parcels2.*
import io.dico.parcels2.blockvisitor.WorktimeLimiter
import io.dico.parcels2.options.RuntimeWorldOptions
import io.dico.parcels2.storage.Storage
+import kotlinx.coroutines.CoroutineScope
import org.bukkit.World
import org.joda.time.DateTime
import java.util.UUID
@@ -16,6 +17,7 @@ class ParcelWorldImpl(override val world: World,
override val storage: Storage,
override val globalAddedData: GlobalAddedDataManager,
containerFactory: ParcelContainerFactory,
+ coroutineScope: CoroutineScope,
worktimeLimiter: WorktimeLimiter)
: ParcelWorld,
ParcelWorldId,
@@ -37,7 +39,7 @@ class ParcelWorldImpl(override val world: World,
override val blockManager: ParcelBlockManager
init {
- val pair = generator.makeParcelLocatorAndBlockManager(id, container, worktimeLimiter)
+ val pair = generator.makeParcelLocatorAndBlockManager(id, container, coroutineScope, worktimeLimiter)
locator = pair.first
blockManager = pair.second
@@ -84,5 +86,5 @@ class ParcelWorldImpl(override val world: World,
return container.nextEmptyParcel()
}
-
+ override fun toString() = toStringExt()
}
diff --git a/src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt b/src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt
index edb48b5..eaacf93 100644
--- a/src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt
+++ b/src/main/kotlin/io/dico/parcels2/listener/ParcelEntityTracker.kt
@@ -2,8 +2,8 @@ package io.dico.parcels2.listener
import io.dico.parcels2.Parcel
import io.dico.parcels2.ParcelProvider
-import io.dico.parcels2.util.editLoop
-import io.dico.parcels2.util.isPresentAnd
+import io.dico.parcels2.util.ext.editLoop
+import io.dico.parcels2.util.ext.isPresentAnd
import org.bukkit.entity.Entity
class ParcelEntityTracker(val parcelProvider: ParcelProvider) {
diff --git a/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt b/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt
index eedc416..6d89ee6 100644
--- a/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt
+++ b/src/main/kotlin/io/dico/parcels2/listener/ParcelListeners.kt
@@ -8,7 +8,7 @@ import io.dico.parcels2.ParcelProvider
import io.dico.parcels2.ParcelWorld
import io.dico.parcels2.statusKey
import io.dico.parcels2.storage.Storage
-import io.dico.parcels2.util.*
+import io.dico.parcels2.util.ext.*
import org.bukkit.Material.*
import org.bukkit.World
import org.bukkit.block.Biome
diff --git a/src/main/kotlin/io/dico/parcels2/listener/WorldEditListener.kt b/src/main/kotlin/io/dico/parcels2/listener/WorldEditListener.kt
new file mode 100644
index 0000000..b68f7c2
--- /dev/null
+++ b/src/main/kotlin/io/dico/parcels2/listener/WorldEditListener.kt
@@ -0,0 +1,80 @@
+package io.dico.parcels2.listener
+
+import com.sk89q.worldedit.EditSession.Stage.BEFORE_REORDER
+import com.sk89q.worldedit.Vector
+import com.sk89q.worldedit.Vector2D
+import com.sk89q.worldedit.WorldEdit
+import com.sk89q.worldedit.WorldEditException
+import com.sk89q.worldedit.bukkit.WorldEditPlugin
+import com.sk89q.worldedit.event.extent.EditSessionEvent
+import com.sk89q.worldedit.extent.AbstractDelegateExtent
+import com.sk89q.worldedit.extent.Extent
+import com.sk89q.worldedit.util.eventbus.EventHandler.Priority.VERY_EARLY
+import com.sk89q.worldedit.util.eventbus.Subscribe
+import com.sk89q.worldedit.world.biome.BaseBiome
+import com.sk89q.worldedit.world.block.BaseBlock
+import com.sk89q.worldedit.world.block.BlockStateHolder
+import io.dico.parcels2.ParcelWorld
+import io.dico.parcels2.ParcelsPlugin
+import io.dico.parcels2.util.ext.hasBuildAnywhere
+import io.dico.parcels2.util.ext.sendParcelMessage
+import org.bukkit.entity.Player
+import org.bukkit.plugin.Plugin
+
+class WorldEditListener(val parcels: ParcelsPlugin, val worldEdit: WorldEdit) {
+
+ @Subscribe(priority = VERY_EARLY)
+ fun onEditSession(event: EditSessionEvent) {
+ val worldName = event.world?.name ?: return
+ val world = parcels.parcelProvider.getWorld(worldName) ?: return
+ if (event.stage == BEFORE_REORDER) return
+
+ val actor = event.actor
+ if (actor == null || !actor.isPlayer) return
+
+ val player = parcels.server.getPlayer(actor.uniqueId)
+ if (player.hasBuildAnywhere) return
+
+ event.extent = ParcelsExtent(event.extent, world, player)
+ }
+
+ private class ParcelsExtent(extent: Extent,
+ val world: ParcelWorld,
+ val player: Player) : AbstractDelegateExtent(extent) {
+ private var messageSent = false
+
+ private fun canBuild(x: Int, z: Int): Boolean {
+ world.getParcelAt(x, z)?.let { parcel ->
+ if (parcel.canBuild(player, checkAdmin = false)) {
+ return true
+ }
+ }
+
+ if (!messageSent) {
+ messageSent = true
+ player.sendParcelMessage(except = true, message = "You can't use WorldEdit there")
+ }
+
+ return false
+ }
+
+ override fun setBlock(location: Vector, block: BlockStateHolder<*>): Boolean {
+ return canBuild(location.blockX, location.blockZ) && super.setBlock(location, block)
+ }
+
+ override fun setBiome(coord: Vector2D, biome: BaseBiome): Boolean {
+ return canBuild(coord.blockX, coord.blockZ) && super.setBiome(coord, biome)
+ }
+
+ }
+
+ companion object {
+ fun register(parcels: ParcelsPlugin, worldEditPlugin: Plugin) {
+ if (worldEditPlugin !is WorldEditPlugin) return
+ val worldEdit = worldEditPlugin.worldEdit
+ val listener = WorldEditListener(parcels, worldEdit)
+ worldEdit.eventBus.register(listener)
+ }
+ }
+
+} \ No newline at end of file
diff --git a/src/main/kotlin/io/dico/parcels2/storage/Backing.kt b/src/main/kotlin/io/dico/parcels2/storage/Backing.kt
index 6bef483..3875467 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/Backing.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/Backing.kt
@@ -1,11 +1,11 @@
package io.dico.parcels2.storage
import io.dico.parcels2.*
-import kotlinx.coroutines.experimental.CoroutineDispatcher
-import kotlinx.coroutines.experimental.Deferred
-import kotlinx.coroutines.experimental.Job
-import kotlinx.coroutines.experimental.channels.ReceiveChannel
-import kotlinx.coroutines.experimental.channels.SendChannel
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.channels.ReceiveChannel
+import kotlinx.coroutines.channels.SendChannel
import org.joda.time.DateTime
import java.util.UUID
diff --git a/src/main/kotlin/io/dico/parcels2/storage/Storage.kt b/src/main/kotlin/io/dico/parcels2/storage/Storage.kt
index a0e94e0..7b04bce 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/Storage.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/Storage.kt
@@ -3,11 +3,11 @@
package io.dico.parcels2.storage
import io.dico.parcels2.*
-import kotlinx.coroutines.experimental.Deferred
-import kotlinx.coroutines.experimental.Job
-import kotlinx.coroutines.experimental.channels.ReceiveChannel
-import kotlinx.coroutines.experimental.channels.SendChannel
-import kotlinx.coroutines.experimental.launch
+import kotlinx.coroutines.Deferred
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.channels.ReceiveChannel
+import kotlinx.coroutines.channels.SendChannel
+import kotlinx.coroutines.launch
import org.joda.time.DateTime
import java.util.UUID
diff --git a/src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt b/src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt
index 8cd2804..39a32e0 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/exposed/ExposedBacking.kt
@@ -8,14 +8,14 @@ import io.dico.parcels2.PlayerProfile.Star.name
import io.dico.parcels2.storage.AddedDataPair
import io.dico.parcels2.storage.Backing
import io.dico.parcels2.storage.DataPair
-import io.dico.parcels2.util.synchronized
+import io.dico.parcels2.util.ext.synchronized
import io.dico.parcels2.util.toByteArray
import io.dico.parcels2.util.toUUID
-import kotlinx.coroutines.experimental.*
-import kotlinx.coroutines.experimental.channels.ArrayChannel
-import kotlinx.coroutines.experimental.channels.LinkedListChannel
-import kotlinx.coroutines.experimental.channels.ReceiveChannel
-import kotlinx.coroutines.experimental.channels.SendChannel
+import kotlinx.coroutines.*
+import kotlinx.coroutines.channels.ArrayChannel
+import kotlinx.coroutines.channels.LinkedListChannel
+import kotlinx.coroutines.channels.ReceiveChannel
+import kotlinx.coroutines.channels.SendChannel
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SchemaUtils.create
import org.jetbrains.exposed.sql.transactions.transaction
diff --git a/src/main/kotlin/io/dico/parcels2/storage/exposed/IdTables.kt b/src/main/kotlin/io/dico/parcels2/storage/exposed/IdTables.kt
index d8315fd..afbaa6e 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/exposed/IdTables.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/exposed/IdTables.kt
@@ -153,6 +153,13 @@ object ProfilesT : IdTransactionsTable<ProfilesT, PlayerProfile>("parcels_profil
return getItem(id) as? PlayerProfile.Real
}
+ /*
+ fun updatePlayerProfile(profile: PlayerProfile.Real) {
+ update({ uuid eq profile.uuid.toByteArray() }) {
+ it[name] = profile.nameOrBukkitName
+ }
+ }*/
+
}
// val ParcelsWithOptionsT = ParcelsT.join(ParcelOptionsT, JoinType.INNER, onColumn = ParcelsT.id, otherColumn = ParcelOptionsT.parcel_id) \ No newline at end of file
diff --git a/src/main/kotlin/io/dico/parcels2/storage/exposed/ListTables.kt b/src/main/kotlin/io/dico/parcels2/storage/exposed/ListTables.kt
index bbf6872..c976f69 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/exposed/ListTables.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/exposed/ListTables.kt
@@ -3,7 +3,7 @@
package io.dico.parcels2.storage.exposed
import io.dico.parcels2.*
-import kotlinx.coroutines.experimental.channels.SendChannel
+import kotlinx.coroutines.channels.SendChannel
import org.jetbrains.exposed.sql.*
import java.util.UUID
diff --git a/src/main/kotlin/io/dico/parcels2/storage/migration/Migration.kt b/src/main/kotlin/io/dico/parcels2/storage/migration/Migration.kt
index 0db669a..acc7c5e 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/migration/Migration.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/migration/Migration.kt
@@ -1,7 +1,7 @@
package io.dico.parcels2.storage.migration
import io.dico.parcels2.storage.Storage
-import kotlinx.coroutines.experimental.Job
+import kotlinx.coroutines.Job
interface Migration {
fun migrateTo(storage: Storage): Job
diff --git a/src/main/kotlin/io/dico/parcels2/storage/migration/plotme/PlotmeMigration.kt b/src/main/kotlin/io/dico/parcels2/storage/migration/plotme/PlotmeMigration.kt
index 9921268..3fae57f 100644
--- a/src/main/kotlin/io/dico/parcels2/storage/migration/plotme/PlotmeMigration.kt
+++ b/src/main/kotlin/io/dico/parcels2/storage/migration/plotme/PlotmeMigration.kt
@@ -10,9 +10,9 @@ import io.dico.parcels2.storage.exposed.abs
import io.dico.parcels2.storage.exposed.greater
import io.dico.parcels2.storage.migration.Migration
import io.dico.parcels2.util.toUUID
-import kotlinx.coroutines.experimental.Job
-import kotlinx.coroutines.experimental.launch
-import kotlinx.coroutines.experimental.newFixedThreadPoolContext
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.newFixedThreadPoolContext
import org.jetbrains.exposed.sql.*
import org.slf4j.LoggerFactory
import java.sql.Blob
diff --git a/src/main/kotlin/io/dico/parcels2/util/FunctionHelper.kt b/src/main/kotlin/io/dico/parcels2/util/FunctionHelper.kt
deleted file mode 100644
index ea16652..0000000
--- a/src/main/kotlin/io/dico/parcels2/util/FunctionHelper.kt
+++ /dev/null
@@ -1,53 +0,0 @@
-package io.dico.parcels2.util
-
-import io.dico.parcels2.ParcelsPlugin
-import kotlinx.coroutines.experimental.*
-import org.bukkit.scheduler.BukkitTask
-import kotlin.coroutines.experimental.CoroutineContext
-
-@Suppress("NOTHING_TO_INLINE")
-class FunctionHelper(val plugin: ParcelsPlugin) {
- val mainThreadDispatcher: MainThreadDispatcher = MainThreadDispatcherImpl()
-
- fun <T> deferLazilyOnMainThread(block: suspend CoroutineScope.() -> T): Deferred<T> {
- return async(context = mainThreadDispatcher, start = CoroutineStart.LAZY, block = block)
- }
-
- fun <T> deferUndispatchedOnMainThread(block: suspend CoroutineScope.() -> T): Deferred<T> {
- return async(context = mainThreadDispatcher, start = CoroutineStart.UNDISPATCHED, block = block)
- }
-
- fun launchLazilyOnMainThread(block: suspend CoroutineScope.() -> Unit): Job {
- return launch(context = mainThreadDispatcher, start = CoroutineStart.LAZY, block = block)
- }
-
- inline fun schedule(noinline task: () -> Unit) = schedule(0, task)
-
- fun schedule(delay: Int, task: () -> Unit): BukkitTask {
- return plugin.server.scheduler.runTaskLater(plugin, task, delay.toLong())
- }
-
- fun scheduleRepeating(delay: Int, interval: Int, task: () -> Unit): BukkitTask {
- return plugin.server.scheduler.runTaskTimer(plugin, task, delay.toLong(), interval.toLong())
- }
-
- abstract class MainThreadDispatcher : CoroutineDispatcher() {
- abstract val mainThread: Thread
- abstract fun runOnMainThread(task: Runnable)
- }
-
- private inner class MainThreadDispatcherImpl : MainThreadDispatcher() {
- override val mainThread: Thread = Thread.currentThread()
-
- override fun dispatch(context: CoroutineContext, block: Runnable) {
- runOnMainThread(block)
- }
-
- @Suppress("OVERRIDE_BY_INLINE")
- override inline fun runOnMainThread(task: Runnable) {
- if (Thread.currentThread() === mainThread) task.run()
- else plugin.server.scheduler.runTaskLater(plugin, task, 0)
- }
- }
-
-}
diff --git a/src/main/kotlin/io/dico/parcels2/util/MainThreadDispatcher.kt b/src/main/kotlin/io/dico/parcels2/util/MainThreadDispatcher.kt
new file mode 100644
index 0000000..b1d18ab
--- /dev/null
+++ b/src/main/kotlin/io/dico/parcels2/util/MainThreadDispatcher.kt
@@ -0,0 +1,31 @@
+package io.dico.parcels2.util
+
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Runnable
+import org.bukkit.plugin.Plugin
+import kotlin.coroutines.CoroutineContext
+
+abstract class MainThreadDispatcher : CoroutineDispatcher() {
+ abstract val mainThread: Thread
+ abstract fun runOnMainThread(task: Runnable)
+}
+
+@Suppress("FunctionName")
+fun MainThreadDispatcher(plugin: Plugin): MainThreadDispatcher {
+ return object : MainThreadDispatcher() {
+ override val mainThread: Thread = Thread.currentThread()
+
+ override fun dispatch(context: CoroutineContext, block: Runnable) {
+ doDispatch(block)
+ }
+
+ override fun runOnMainThread(task: Runnable) {
+ doDispatch(task)
+ }
+
+ private fun doDispatch(task: Runnable) {
+ if (Thread.currentThread() === mainThread) task.run()
+ else plugin.server.scheduler.runTaskLater(plugin, task, 0)
+ }
+ }
+} \ No newline at end of file
diff --git a/src/main/kotlin/io/dico/parcels2/util/PluginScheduler.kt b/src/main/kotlin/io/dico/parcels2/util/PluginScheduler.kt
new file mode 100644
index 0000000..f29ba2b
--- /dev/null
+++ b/src/main/kotlin/io/dico/parcels2/util/PluginScheduler.kt
@@ -0,0 +1,20 @@
+package io.dico.parcels2.util
+
+import org.bukkit.plugin.Plugin
+import org.bukkit.scheduler.BukkitTask
+
+interface PluginScheduler {
+ val plugin: Plugin
+
+ fun schedule(delay: Int, task: () -> Unit): BukkitTask {
+ return plugin.server.scheduler.runTaskLater(plugin, task, delay.toLong())
+ }
+
+ fun scheduleRepeating(delay: Int, interval: Int, task: () -> Unit): BukkitTask {
+ return plugin.server.scheduler.runTaskTimer(plugin, task, delay.toLong(), interval.toLong())
+ }
+}
+
+@Suppress("NOTHING_TO_INLINE")
+inline fun PluginScheduler.schedule(noinline task: () -> Unit) = schedule(0, task)
+
diff --git a/src/main/kotlin/io/dico/parcels2/util/UUIDUtil.kt b/src/main/kotlin/io/dico/parcels2/util/UUIDUtil.kt
index bca2428..268c1b9 100644
--- a/src/main/kotlin/io/dico/parcels2/util/UUIDUtil.kt
+++ b/src/main/kotlin/io/dico/parcels2/util/UUIDUtil.kt
@@ -1,16 +1,11 @@
package io.dico.parcels2.util
+import io.dico.parcels2.util.ext.isValid
import org.bukkit.Bukkit
import java.nio.ByteBuffer
import java.util.UUID
-@Suppress("UsePropertyAccessSyntax")
-fun getPlayerNameOrDefault(uuid: UUID?, ifUnknown: String? = null): String {
- return uuid
- ?.let { getPlayerName(it) }
- ?: ifUnknown
- ?: ":unknown_name:"
-}
+const val PLAYER_NAME_PLACEHOLDER = ":unknown_name:"
fun getPlayerName(uuid: UUID): String? {
return Bukkit.getOfflinePlayer(uuid)?.takeIf { it.isValid }?.name
diff --git a/src/main/kotlin/io/dico/parcels2/util/MaterialExtensions.kt b/src/main/kotlin/io/dico/parcels2/util/ext/Material.kt
index fadd722..c375cb2 100644
--- a/src/main/kotlin/io/dico/parcels2/util/MaterialExtensions.kt
+++ b/src/main/kotlin/io/dico/parcels2/util/ext/Material.kt
@@ -1,4 +1,4 @@
-package io.dico.parcels2.util
+package io.dico.parcels2.util.ext
import org.bukkit.Material
import org.bukkit.Material.*
diff --git a/src/main/kotlin/io/dico/parcels2/util/NumberExtensions.kt b/src/main/kotlin/io/dico/parcels2/util/ext/Math.kt
index 214a797..32540fd 100644
--- a/src/main/kotlin/io/dico/parcels2/util/NumberExtensions.kt
+++ b/src/main/kotlin/io/dico/parcels2/util/ext/Math.kt
@@ -1,4 +1,4 @@
-package io.dico.parcels2.util
+package io.dico.parcels2.util.ext
fun Double.floor(): Int {
val down = toInt()
diff --git a/src/main/kotlin/io/dico/parcels2/util/MiscExtensions.kt b/src/main/kotlin/io/dico/parcels2/util/ext/Misc.kt
index 24f9401..d7feabf 100644
--- a/src/main/kotlin/io/dico/parcels2/util/MiscExtensions.kt
+++ b/src/main/kotlin/io/dico/parcels2/util/ext/Misc.kt
@@ -1,4 +1,4 @@
-package io.dico.parcels2.util
+package io.dico.parcels2.util.ext
import io.dico.parcels2.logger
import java.io.File
diff --git a/src/main/kotlin/io/dico/parcels2/util/PlayerExtensions.kt b/src/main/kotlin/io/dico/parcels2/util/ext/Player.kt
index 9604365..38402f0 100644
--- a/src/main/kotlin/io/dico/parcels2/util/PlayerExtensions.kt
+++ b/src/main/kotlin/io/dico/parcels2/util/ext/Player.kt
@@ -1,8 +1,7 @@
-package io.dico.parcels2.util
+package io.dico.parcels2.util.ext
import io.dico.dicore.Formatting
import io.dico.parcels2.ParcelsPlugin
-import io.dico.parcels2.PlayerProfile
import io.dico.parcels2.logger
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
diff --git a/todo.md b/todo.md
index 541aecf..c04937a 100644
--- a/todo.md
+++ b/todo.md
@@ -3,18 +3,18 @@
Commands
-
Basically all admin commands.
-* setowner
-* dispose
-* reset
+* ~~setowner~~
+* ~~dispose~~
+* ~~reset~~
* swap
* New admin commands that I can't think of right now.
Also
-* setbiome
+* ~~setbiome~~
* random
Modify home command:
-* Make `:` not be required if prior component cannot be parsed to an int
+* ~~Make `:` not be required if prior component cannot be parsed to an int~~
* Listen for command events that use plotme-style argument, and transform the command
~~Add permissions to commands (replace or fix `IContextFilter` from command lib
@@ -61,7 +61,7 @@ Prevent block spreading subject to conditions.
Scan through blocks that were added since original Parcels implementation,
that might introduce things that need to be checked or listened for.
-WorldEdit Listener.
+~~WorldEdit Listener.~~
Limit number of beacons in a parcel and/or avoid potion effects being applied outside the parcel.
@@ -77,6 +77,6 @@ Use an atomic GET OR INSERT query so that parallel execution doesn't cause probl
Implement a container that doesn't require loading all parcel data on startup (Complex).
-Update player profiles in the database on join to account for name changes.
+~~Update player profiles in the database on join to account for name changes.~~