Work down some todo items, update to kotlin 1.3-rc
This commit is contained in:
@@ -14,12 +14,10 @@ version = "0.2"
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
java
|
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"
|
id("com.github.johnrengelman.plugin-shadow") version "2.0.3"
|
||||||
}
|
}
|
||||||
|
|
||||||
kotlin.experimental.coroutines = ENABLE
|
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
apply<JavaPlugin>()
|
apply<JavaPlugin>()
|
||||||
|
|
||||||
@@ -28,6 +26,8 @@ allprojects {
|
|||||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots")
|
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots")
|
||||||
maven("https://hub.spigotmc.org/nexus/content/repositories/sonatype-nexus-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/exposed")
|
||||||
|
maven("https://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
|
maven("https://dl.bintray.com/kotlin/kotlinx/")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@@ -51,7 +51,7 @@ project(":dicore3:dicore3-command") {
|
|||||||
dependencies {
|
dependencies {
|
||||||
c.kotlinStd(kotlin("stdlib-jdk8"))
|
c.kotlinStd(kotlin("stdlib-jdk8"))
|
||||||
c.kotlinStd(kotlin("reflect"))
|
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(project(":dicore3:dicore3-core"))
|
||||||
compile("com.thoughtworks.paranamer:paranamer:2.8")
|
compile("com.thoughtworks.paranamer:paranamer:2.8")
|
||||||
@@ -59,17 +59,19 @@ project(":dicore3:dicore3-command") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile(project(":dicore3:dicore3-core"))
|
compile(project(":dicore3:dicore3-core"))
|
||||||
compile(project(":dicore3:dicore3-command"))
|
compile(project(":dicore3:dicore3-command"))
|
||||||
|
|
||||||
c.kotlinStd(kotlin("stdlib-jdk8"))
|
c.kotlinStd(kotlin("stdlib-jdk8"))
|
||||||
c.kotlinStd(kotlin("reflect"))
|
c.kotlinStd(kotlin("reflect"))
|
||||||
c.kotlinStd(kotlinx("coroutines-core:0.23.4"))
|
c.kotlinStd(kotlinx("coroutines-core:0.26.1-eap13"))
|
||||||
c.kotlinStd("org.jetbrains.kotlinx:atomicfu-common:0.11.0")
|
c.kotlinStd("org.jetbrains.kotlinx:atomicfu-common:0.11.7-rc-conf")
|
||||||
|
|
||||||
compile("org.jetbrains.exposed:exposed:0.10.3") { isTransitive = false }
|
// 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.5") { isTransitive = false }
|
||||||
compile("joda-time:joda-time:2.10")
|
compile("joda-time:joda-time:2.10")
|
||||||
compile("com.zaxxer:HikariCP:3.2.0")
|
compile("com.zaxxer:HikariCP:3.2.0")
|
||||||
compile("ch.qos.logback:logback-classic:1.2.3") { isTransitive = false }
|
compile("ch.qos.logback:logback-classic:1.2.3") { isTransitive = false }
|
||||||
@@ -131,6 +133,7 @@ tasks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val createDebugServer by creating {
|
val createDebugServer by creating {
|
||||||
|
// todo
|
||||||
|
|
||||||
val jarUrl = URL("https://yivesmirror.com/files/spigot/spigot-latest.jar")
|
val jarUrl = URL("https://yivesmirror.com/files/spigot/spigot-latest.jar")
|
||||||
val serverJarFile = file("$serverDir/lib/spigot.jar")
|
val serverJarFile = file("$serverDir/lib/spigot.jar")
|
||||||
|
|||||||
@@ -200,6 +200,15 @@ public class ExecutionContext {
|
|||||||
return originalBuffer.getArrayFromIndex(cursorStart);
|
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) {
|
public Formatting getFormat(EMessageType type) {
|
||||||
return address.getChatController().getChatFormatForType(type);
|
return address.getChatController().getChatFormatForType(type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ public interface ICommandReceiver {
|
|||||||
|
|
||||||
Plugin getPlugin();
|
Plugin getPlugin();
|
||||||
|
|
||||||
|
// type is CoroutineContext, but we avoid referring to Kotlin runtime here
|
||||||
|
default Object getCoroutineContext() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,15 +4,15 @@ import io.dico.dicore.command.CommandException
|
|||||||
import io.dico.dicore.command.EMessageType
|
import io.dico.dicore.command.EMessageType
|
||||||
import io.dico.dicore.command.ExecutionContext
|
import io.dico.dicore.command.ExecutionContext
|
||||||
import io.dico.dicore.command.ICommandReceiver
|
import io.dico.dicore.command.ICommandReceiver
|
||||||
import kotlinx.coroutines.experimental.CoroutineStart.UNDISPATCHED
|
import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
|
||||||
import kotlinx.coroutines.experimental.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.experimental.asCoroutineDispatcher
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.experimental.async
|
import kotlinx.coroutines.async
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
import java.util.*
|
|
||||||
import java.util.concurrent.CancellationException
|
import java.util.concurrent.CancellationException
|
||||||
import java.util.concurrent.Executor
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.coroutines.experimental.intrinsics.suspendCoroutineOrReturn
|
import kotlin.coroutines.intrinsics.intercepted
|
||||||
|
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
|
||||||
import kotlin.reflect.jvm.kotlinFunction
|
import kotlin.reflect.jvm.kotlinFunction
|
||||||
|
|
||||||
fun isSuspendFunction(method: Method): Boolean {
|
fun isSuspendFunction(method: Method): Boolean {
|
||||||
@@ -20,16 +20,21 @@ fun isSuspendFunction(method: Method): Boolean {
|
|||||||
return func.isSuspend
|
return func.isSuspend
|
||||||
}
|
}
|
||||||
|
|
||||||
fun callAsCoroutine(command: ReflectiveCommand,
|
fun callAsCoroutine(
|
||||||
|
command: ReflectiveCommand,
|
||||||
factory: ICommandReceiver.Factory,
|
factory: ICommandReceiver.Factory,
|
||||||
context: ExecutionContext,
|
context: ExecutionContext,
|
||||||
args: Array<Any?>): String? {
|
args: Array<Any?>
|
||||||
val dispatcher = Executor { task -> factory.plugin.server.scheduler.runTask(factory.plugin, task) }.asCoroutineDispatcher()
|
): String? {
|
||||||
|
|
||||||
// UNDISPATCHED causes the handler to run until the first suspension point on the current thread,
|
// 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.
|
// 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.
|
// 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) {
|
if (job.isCompleted) {
|
||||||
return job.getResult()
|
return job.getResult()
|
||||||
@@ -48,12 +53,6 @@ fun callAsCoroutine(command: ReflectiveCommand,
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun Method.invokeSuspend(instance: Any?, args: Array<Any?>): Any? {
|
|
||||||
return suspendCoroutineOrReturn { cont ->
|
|
||||||
invoke(instance, *args, cont)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Throws(CommandException::class)
|
@Throws(CommandException::class)
|
||||||
private fun Deferred<Any?>.getResult(): String? {
|
private fun Deferred<Any?>.getResult(): String? {
|
||||||
getCompletionExceptionOrNull()?.let { ex ->
|
getCompletionExceptionOrNull()?.let { ex ->
|
||||||
|
|||||||
1
gradle.properties
Normal file
1
gradle.properties
Normal file
@@ -0,0 +1 @@
|
|||||||
|
kotlin.code.style=official
|
||||||
@@ -1,3 +1,9 @@
|
|||||||
|
pluginManagement.repositories {
|
||||||
|
maven("http://dl.bintray.com/kotlin/kotlin-eap")
|
||||||
|
mavenCentral()
|
||||||
|
maven("https://plugins.gradle.org/m2/")
|
||||||
|
}
|
||||||
|
|
||||||
rootProject.name = "parcels2"
|
rootProject.name = "parcels2"
|
||||||
|
|
||||||
include("dicore3:core")
|
include("dicore3:core")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
import io.dico.parcels2.util.findWoodKindPrefixedMaterials
|
import io.dico.parcels2.util.ext.findWoodKindPrefixedMaterials
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import java.util.EnumMap
|
import java.util.EnumMap
|
||||||
|
|
||||||
@@ -28,7 +28,8 @@ private constructor(val id: Int,
|
|||||||
arrayOf(
|
arrayOf(
|
||||||
Interactables(id++, "button", true,
|
Interactables(id++, "button", true,
|
||||||
Material.STONE_BUTTON,
|
Material.STONE_BUTTON,
|
||||||
*findWoodKindPrefixedMaterials("BUTTON")),
|
*findWoodKindPrefixedMaterials("BUTTON")
|
||||||
|
),
|
||||||
|
|
||||||
Interactables(id++, "lever", true,
|
Interactables(id++, "lever", true,
|
||||||
Material.LEVER),
|
Material.LEVER),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
import io.dico.parcels2.util.Vec2i
|
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.Location
|
||||||
import org.bukkit.OfflinePlayer
|
import org.bukkit.OfflinePlayer
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
@@ -32,6 +32,8 @@ interface Parcel : ParcelData {
|
|||||||
|
|
||||||
fun dispose()
|
fun dispose()
|
||||||
|
|
||||||
|
suspend fun withBlockVisitorPermit(block: suspend () -> Unit)
|
||||||
|
|
||||||
val homeLocation: Location get() = world.blockManager.getHomeLocation(id)
|
val homeLocation: Location get() = world.blockManager.getHomeLocation(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import io.dico.parcels2.blockvisitor.WorktimeLimiter
|
|||||||
import io.dico.parcels2.util.Region
|
import io.dico.parcels2.util.Region
|
||||||
import io.dico.parcels2.util.Vec2i
|
import io.dico.parcels2.util.Vec2i
|
||||||
import io.dico.parcels2.util.get
|
import io.dico.parcels2.util.get
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import org.bukkit.Chunk
|
import org.bukkit.Chunk
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
@@ -38,6 +39,7 @@ abstract class ParcelGenerator : ChunkGenerator() {
|
|||||||
|
|
||||||
abstract fun makeParcelLocatorAndBlockManager(worldId: ParcelWorldId,
|
abstract fun makeParcelLocatorAndBlockManager(worldId: ParcelWorldId,
|
||||||
container: ParcelContainer,
|
container: ParcelContainer,
|
||||||
|
coroutineScope: CoroutineScope,
|
||||||
worktimeLimiter: WorktimeLimiter): Pair<ParcelLocator, ParcelBlockManager>
|
worktimeLimiter: WorktimeLimiter): Pair<ParcelLocator, ParcelBlockManager>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ interface ParcelWorldId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ParcelWorldId.toStringExt() = "ParcelWorld($name)"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by storage backing options to encompass the location of a parcel
|
* Used by storage backing options to encompass the location of a parcel
|
||||||
* Does NOT support equality operator.
|
* Does NOT support equality operator.
|
||||||
@@ -31,6 +33,7 @@ interface ParcelId {
|
|||||||
val x: Int
|
val x: Int
|
||||||
val z: Int
|
val z: Int
|
||||||
val pos: Vec2i get() = Vec2i(x, z)
|
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)
|
fun equals(id: ParcelId): Boolean = x == id.x && z == id.z && worldId.equals(id.worldId)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -41,9 +44,15 @@ interface ParcelId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ParcelId.toStringExt() = "Parcel(${worldId.name},$idString)"
|
||||||
|
|
||||||
private class ParcelWorldIdImpl(override val name: String,
|
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,
|
private class ParcelIdImpl(override val worldId: ParcelWorldId,
|
||||||
override val x: Int,
|
override val x: Int,
|
||||||
override val z: Int) : ParcelId
|
override val z: Int) : ParcelId {
|
||||||
|
override fun toString() = toStringExt()
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ package io.dico.parcels2
|
|||||||
import io.dico.parcels2.options.RuntimeWorldOptions
|
import io.dico.parcels2.options.RuntimeWorldOptions
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import io.dico.parcels2.util.Vec2i
|
import io.dico.parcels2.util.Vec2i
|
||||||
import io.dico.parcels2.util.floor
|
import io.dico.parcels2.util.ext.floor
|
||||||
import org.bukkit.Chunk
|
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
import org.bukkit.block.Block
|
import org.bukkit.block.Block
|
||||||
@@ -70,6 +69,8 @@ interface ParcelContainer {
|
|||||||
|
|
||||||
fun getParcelById(id: Vec2i): Parcel? = getParcelById(id.x, id.z)
|
fun getParcelById(id: Vec2i): Parcel? = getParcelById(id.x, id.z)
|
||||||
|
|
||||||
|
fun getParcelById(id: ParcelId): Parcel? = getParcelById(id.x, id.z)
|
||||||
|
|
||||||
fun nextEmptyParcel(): Parcel?
|
fun nextEmptyParcel(): Parcel?
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,23 +10,27 @@ import io.dico.parcels2.defaultimpl.GlobalAddedDataManagerImpl
|
|||||||
import io.dico.parcels2.defaultimpl.ParcelProviderImpl
|
import io.dico.parcels2.defaultimpl.ParcelProviderImpl
|
||||||
import io.dico.parcels2.listener.ParcelEntityTracker
|
import io.dico.parcels2.listener.ParcelEntityTracker
|
||||||
import io.dico.parcels2.listener.ParcelListeners
|
import io.dico.parcels2.listener.ParcelListeners
|
||||||
|
import io.dico.parcels2.listener.WorldEditListener
|
||||||
import io.dico.parcels2.options.Options
|
import io.dico.parcels2.options.Options
|
||||||
import io.dico.parcels2.options.optionsMapper
|
import io.dico.parcels2.options.optionsMapper
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import io.dico.parcels2.util.FunctionHelper
|
import io.dico.parcels2.util.MainThreadDispatcher
|
||||||
import io.dico.parcels2.util.tryCreate
|
import io.dico.parcels2.util.PluginScheduler
|
||||||
|
import io.dico.parcels2.util.ext.tryCreate
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.generator.ChunkGenerator
|
import org.bukkit.generator.ChunkGenerator
|
||||||
|
import org.bukkit.plugin.Plugin
|
||||||
import org.bukkit.plugin.java.JavaPlugin
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Random
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
val logger: Logger = LoggerFactory.getLogger("ParcelsPlugin")
|
val logger: Logger = LoggerFactory.getLogger("ParcelsPlugin")
|
||||||
private inline val plogger get() = logger
|
private inline val plogger get() = logger
|
||||||
|
|
||||||
class ParcelsPlugin : JavaPlugin() {
|
class ParcelsPlugin : JavaPlugin(), CoroutineScope, PluginScheduler {
|
||||||
lateinit var optionsFile: File; private set
|
lateinit var optionsFile: File; private set
|
||||||
lateinit var options: Options; private set
|
lateinit var options: Options; private set
|
||||||
lateinit var parcelProvider: ParcelProvider; private set
|
lateinit var parcelProvider: ParcelProvider; private set
|
||||||
@@ -38,7 +42,8 @@ class ParcelsPlugin : JavaPlugin() {
|
|||||||
private var listeners: ParcelListeners? = null
|
private var listeners: ParcelListeners? = null
|
||||||
private var cmdDispatcher: ICommandDispatcher? = 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) }
|
val worktimeLimiter: WorktimeLimiter by lazy { TickWorktimeLimiter(this, options.tickWorktime) }
|
||||||
|
|
||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
@@ -135,9 +140,14 @@ class ParcelsPlugin : JavaPlugin() {
|
|||||||
if (listeners == null) {
|
if (listeners == null) {
|
||||||
listeners = ParcelListeners(parcelProvider, entityTracker, storage)
|
listeners = ParcelListeners(parcelProvider, entityTracker, storage)
|
||||||
registrator.registerListeners(listeners!!)
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,12 +3,13 @@
|
|||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import io.dico.parcels2.util.getPlayerNameOrDefault
|
import io.dico.parcels2.util.PLAYER_NAME_PLACEHOLDER
|
||||||
import io.dico.parcels2.util.isValid
|
import io.dico.parcels2.util.getPlayerName
|
||||||
import io.dico.parcels2.util.uuid
|
import io.dico.parcels2.util.ext.isValid
|
||||||
import kotlinx.coroutines.experimental.Deferred
|
import io.dico.parcels2.util.ext.uuid
|
||||||
import kotlinx.coroutines.experimental.Unconfined
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.experimental.async
|
import kotlinx.coroutines.Unconfined
|
||||||
|
import kotlinx.coroutines.async
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.OfflinePlayer
|
import org.bukkit.OfflinePlayer
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
@@ -18,7 +19,7 @@ interface PlayerProfile {
|
|||||||
val name: String?
|
val name: String?
|
||||||
val nameOrBukkitName: String?
|
val nameOrBukkitName: String?
|
||||||
val notNullName: String
|
val notNullName: String
|
||||||
val isStar: Boolean get() = false
|
val isStar: Boolean get() = this is Star
|
||||||
val exists: Boolean get() = this is RealImpl
|
val exists: Boolean get() = this is RealImpl
|
||||||
|
|
||||||
fun matches(player: OfflinePlayer, allowNameMatch: Boolean = false): Boolean
|
fun matches(player: OfflinePlayer, allowNameMatch: Boolean = false): Boolean
|
||||||
@@ -78,9 +79,9 @@ interface PlayerProfile {
|
|||||||
override val uuid: UUID
|
override val uuid: UUID
|
||||||
override val nameOrBukkitName: String?
|
override val nameOrBukkitName: String?
|
||||||
// If a player is online, their name is prioritized to get name changes right immediately
|
// 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
|
override val notNullName: String
|
||||||
get() = name ?: getPlayerNameOrDefault(uuid)
|
get() = nameOrBukkitName ?: PLAYER_NAME_PLACEHOLDER
|
||||||
|
|
||||||
val player: OfflinePlayer? get() = Bukkit.getOfflinePlayer(uuid).takeIf { it.isValid }
|
val player: OfflinePlayer? get() = Bukkit.getOfflinePlayer(uuid).takeIf { it.isValid }
|
||||||
val playerUnchecked: OfflinePlayer get() = Bukkit.getOfflinePlayer(uuid)
|
val playerUnchecked: OfflinePlayer get() = Bukkit.getOfflinePlayer(uuid)
|
||||||
@@ -115,8 +116,8 @@ interface PlayerProfile {
|
|||||||
|
|
||||||
object Star : BaseImpl(), Real {
|
object Star : BaseImpl(), Real {
|
||||||
override val name: String = "*"
|
override val name: String = "*"
|
||||||
|
// hopefully nobody will have this random UUID :)
|
||||||
override val uuid: UUID = UUID.fromString("7d09c4c6-117d-4f36-9778-c4d24618cee1")
|
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 {
|
override fun matches(player: OfflinePlayer, allowNameMatch: Boolean): Boolean {
|
||||||
return true
|
return true
|
||||||
@@ -148,7 +149,7 @@ interface PlayerProfile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
suspend fun tryResolveSuspendedly(storage: Storage): Real? {
|
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 {
|
fun resolve(uuid: UUID): Real {
|
||||||
|
|||||||
@@ -2,13 +2,11 @@ package io.dico.parcels2.blockvisitor
|
|||||||
|
|
||||||
import io.dico.parcels2.util.Region
|
import io.dico.parcels2.util.Region
|
||||||
import io.dico.parcels2.util.Vec3i
|
import io.dico.parcels2.util.Vec3i
|
||||||
import kotlin.coroutines.experimental.SequenceBuilder
|
|
||||||
import kotlin.coroutines.experimental.buildIterator
|
|
||||||
|
|
||||||
abstract class RegionTraverser {
|
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 {
|
companion object {
|
||||||
val upward = create { traverseUpward(it) }
|
val upward = create { traverseUpward(it) }
|
||||||
@@ -16,13 +14,13 @@ abstract class RegionTraverser {
|
|||||||
val forClearing get() = downward
|
val forClearing get() = downward
|
||||||
val forFilling get() = upward
|
val forFilling get() = upward
|
||||||
|
|
||||||
inline fun create(crossinline builder: suspend SequenceBuilder<Vec3i>.(Region) -> Unit) = object : RegionTraverser() {
|
inline fun create(crossinline builder: suspend SequenceScope<Vec3i>.(Region) -> Unit) = object : RegionTraverser() {
|
||||||
override suspend fun SequenceBuilder<Vec3i>.build(region: Region) {
|
override suspend fun SequenceScope<Vec3i>.build(region: Region) {
|
||||||
builder(region)
|
builder(region)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun SequenceBuilder<Vec3i>.traverseDownward(region: Region) {
|
private suspend fun SequenceScope<Vec3i>.traverseDownward(region: Region) {
|
||||||
val origin = region.origin
|
val origin = region.origin
|
||||||
val size = region.size
|
val size = region.size
|
||||||
repeat(size.y) { y ->
|
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 origin = region.origin
|
||||||
val size = region.size
|
val size = region.size
|
||||||
repeat(size.y) { y ->
|
repeat(size.y) { y ->
|
||||||
|
|||||||
@@ -1,38 +1,42 @@
|
|||||||
package io.dico.parcels2.blockvisitor
|
package io.dico.parcels2.blockvisitor
|
||||||
|
|
||||||
import io.dico.parcels2.ParcelsPlugin
|
import io.dico.parcels2.ParcelsPlugin
|
||||||
import io.dico.parcels2.util.FunctionHelper
|
import io.dico.parcels2.logger
|
||||||
import kotlinx.coroutines.experimental.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.experimental.Job
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.CoroutineStart.LAZY
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.bukkit.scheduler.BukkitTask
|
import org.bukkit.scheduler.BukkitTask
|
||||||
import java.lang.System.currentTimeMillis
|
import java.lang.System.currentTimeMillis
|
||||||
import java.util.LinkedList
|
import java.util.LinkedList
|
||||||
import java.util.logging.Level
|
import kotlin.coroutines.Continuation
|
||||||
import kotlin.coroutines.experimental.Continuation
|
import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
|
||||||
import kotlin.coroutines.experimental.intrinsics.COROUTINE_SUSPENDED
|
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
|
||||||
import kotlin.coroutines.experimental.intrinsics.suspendCoroutineUninterceptedOrReturn
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
typealias TimeLimitedTask = suspend WorkerScope.() -> Unit
|
typealias TimeLimitedTask = suspend WorkerScope.() -> Unit
|
||||||
typealias WorkerUpdateLister = Worker.(Double, Long) -> Unit
|
typealias WorkerUpdateLister = Worker.(Double, Long) -> Unit
|
||||||
|
|
||||||
data class TickWorktimeOptions(var workTime: Int, var tickInterval: Int)
|
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
|
* Submit a [task] that should be run synchronously, but limited such that it does not stall the server
|
||||||
* a bunch
|
* a bunch
|
||||||
*/
|
*/
|
||||||
abstract fun submit(task: TimeLimitedTask): Worker
|
fun submit(task: TimeLimitedTask): Worker
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of all workers
|
* Get a list of all workers
|
||||||
*/
|
*/
|
||||||
abstract val workers: List<Worker>
|
val workers: List<Worker>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts to complete any remaining tasks immediately, without suspension.
|
* Attempts to complete any remaining tasks immediately, without suspension.
|
||||||
*/
|
*/
|
||||||
abstract fun completeAllTasks()
|
fun completeAllTasks()
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Timed {
|
interface Timed {
|
||||||
@@ -77,9 +81,14 @@ interface Worker : Timed {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Calls the given [block] when this worker completes, with the progress value 1.0.
|
* 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
|
fun onCompleted(block: WorkerUpdateLister): Worker
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Await completion of this worker
|
||||||
|
*/
|
||||||
|
suspend fun awaitCompletion()
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WorkerScope : Timed {
|
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
|
* 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
|
* 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
|
// The currently registered bukkit scheduler task
|
||||||
private var bukkitTask: BukkitTask? = null
|
private var bukkitTask: BukkitTask? = null
|
||||||
// The workers.
|
// The workers.
|
||||||
@@ -121,12 +130,12 @@ class TickWorktimeLimiter(private val plugin: ParcelsPlugin, var options: TickWo
|
|||||||
override val workers: List<Worker> = _workers
|
override val workers: List<Worker> = _workers
|
||||||
|
|
||||||
override fun submit(task: TimeLimitedTask): Worker {
|
override fun submit(task: TimeLimitedTask): Worker {
|
||||||
val worker: WorkerContinuation = WorkerImpl(plugin.functionHelper, task)
|
val worker: WorkerContinuation = WorkerImpl(plugin, task)
|
||||||
|
|
||||||
if (bukkitTask == null) {
|
if (bukkitTask == null) {
|
||||||
val completed = worker.resume(options.workTime.toLong())
|
val completed = worker.resume(options.workTime.toLong())
|
||||||
if (completed) return worker
|
if (completed) return worker
|
||||||
bukkitTask = plugin.functionHelper.scheduleRepeating(0, options.tickInterval) { tickJobs() }
|
bukkitTask = plugin.scheduleRepeating(0, options.tickInterval) { tickJobs() }
|
||||||
}
|
}
|
||||||
|
|
||||||
_workers.addFirst(worker)
|
_workers.addFirst(worker)
|
||||||
@@ -171,8 +180,10 @@ class TickWorktimeLimiter(private val plugin: ParcelsPlugin, var options: TickWo
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class WorkerImpl(val functionHelper: FunctionHelper,
|
private class WorkerImpl(
|
||||||
val task: TimeLimitedTask) : WorkerContinuation {
|
val scope: CoroutineScope,
|
||||||
|
val task: TimeLimitedTask
|
||||||
|
) : WorkerContinuation, CoroutineScope by scope {
|
||||||
override var job: Job? = null; private set
|
override var job: Job? = null; private set
|
||||||
|
|
||||||
override val elapsedTime
|
override val elapsedTime
|
||||||
@@ -204,27 +215,44 @@ private class WorkerImpl(val functionHelper: FunctionHelper,
|
|||||||
// report any error that occurred
|
// report any error that occurred
|
||||||
completionException = exception?.also {
|
completionException = exception?.also {
|
||||||
if (it !is CancellationException)
|
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
|
// convert to elapsed time here
|
||||||
startTimeOrElapsedTime = System.currentTimeMillis() - startTimeOrElapsedTime
|
startTimeOrElapsedTime = System.currentTimeMillis() - startTimeOrElapsedTime
|
||||||
onCompleted?.let { it(1.0, elapsedTime) }
|
onCompleted?.let { it(1.0, elapsedTime) }
|
||||||
|
|
||||||
|
onCompleted = null
|
||||||
|
onProgressUpdate = { prog, el -> }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onProgressUpdate(minDelay: Int, minInterval: Int, asCompletionListener: Boolean, block: WorkerUpdateLister): Worker {
|
override fun onProgressUpdate(minDelay: Int, minInterval: Int, asCompletionListener: Boolean, block: WorkerUpdateLister): Worker {
|
||||||
onProgressUpdate?.let { throw IllegalStateException() }
|
onProgressUpdate?.let { throw IllegalStateException() }
|
||||||
|
if (asCompletionListener) onCompleted(block)
|
||||||
|
if (isComplete) return this
|
||||||
onProgressUpdate = block
|
onProgressUpdate = block
|
||||||
progressUpdateInterval = minInterval
|
progressUpdateInterval = minInterval
|
||||||
lastUpdateTime = System.currentTimeMillis() + minDelay - minInterval
|
lastUpdateTime = System.currentTimeMillis() + minDelay - minInterval
|
||||||
if (asCompletionListener) onCompleted(block)
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCompleted(block: WorkerUpdateLister): Worker {
|
override fun onCompleted(block: WorkerUpdateLister): Worker {
|
||||||
onCompleted?.let { throw IllegalStateException() }
|
if (isComplete) {
|
||||||
onCompleted = block
|
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
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,7 +293,7 @@ private class WorkerImpl(val functionHelper: FunctionHelper,
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val job = functionHelper.launchLazilyOnMainThread { task() }
|
val job = launch(start = LAZY) { task() }
|
||||||
initJob(job = job)
|
initJob(job = job)
|
||||||
job.start()
|
job.start()
|
||||||
} catch (t: Throwable) {
|
} catch (t: Throwable) {
|
||||||
@@ -275,6 +303,18 @@ private class WorkerImpl(val functionHelper: FunctionHelper,
|
|||||||
return continuation == null
|
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) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1,26 +1,25 @@
|
|||||||
package io.dico.parcels2.command
|
package io.dico.parcels2.command
|
||||||
|
|
||||||
import io.dico.dicore.command.CommandException
|
import io.dico.dicore.command.CommandException
|
||||||
|
import io.dico.dicore.command.EMessageType
|
||||||
import io.dico.dicore.command.ExecutionContext
|
import io.dico.dicore.command.ExecutionContext
|
||||||
import io.dico.dicore.command.ICommandReceiver
|
import io.dico.dicore.command.ICommandReceiver
|
||||||
import io.dico.parcels2.PlayerProfile
|
|
||||||
import io.dico.parcels2.ParcelWorld
|
import io.dico.parcels2.ParcelWorld
|
||||||
import io.dico.parcels2.ParcelsPlugin
|
import io.dico.parcels2.ParcelsPlugin
|
||||||
import io.dico.parcels2.util.hasAdminManage
|
import io.dico.parcels2.PlayerProfile
|
||||||
import io.dico.parcels2.util.parcelLimit
|
import io.dico.parcels2.util.ext.hasAdminManage
|
||||||
|
import io.dico.parcels2.util.ext.parcelLimit
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.plugin.Plugin
|
import org.bukkit.plugin.Plugin
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
|
|
||||||
abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandReceiver.Factory {
|
abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandReceiver.Factory {
|
||||||
|
|
||||||
override fun getPlugin(): Plugin = plugin
|
override fun getPlugin(): Plugin = plugin
|
||||||
|
|
||||||
override fun getReceiver(context: ExecutionContext, target: Method, cmdName: String): ICommandReceiver {
|
override fun getReceiver(context: ExecutionContext, target: Method, cmdName: String): ICommandReceiver {
|
||||||
return getParcelCommandReceiver(plugin.parcelProvider, context, target, cmdName)
|
return getParcelCommandReceiver(plugin.parcelProvider, context, target, cmdName)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected inline val worlds get() = plugin.parcelProvider
|
|
||||||
|
|
||||||
protected fun error(message: String): Nothing {
|
protected fun error(message: String): Nothing {
|
||||||
throw CommandException(message)
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import io.dico.dicore.command.Validate
|
|||||||
import io.dico.dicore.command.annotation.Cmd
|
import io.dico.dicore.command.annotation.Cmd
|
||||||
import io.dico.dicore.command.annotation.Desc
|
import io.dico.dicore.command.annotation.Desc
|
||||||
import io.dico.parcels2.ParcelsPlugin
|
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.OfflinePlayer
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,43 @@
|
|||||||
package io.dico.parcels2.command
|
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.ParcelsPlugin
|
||||||
|
import io.dico.parcels2.PlayerProfile
|
||||||
|
|
||||||
class CommandsAdmin(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
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()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,16 +1,18 @@
|
|||||||
package io.dico.parcels2.command
|
package io.dico.parcels2.command
|
||||||
|
|
||||||
import io.dico.dicore.command.EMessageType
|
|
||||||
import io.dico.dicore.command.ExecutionContext
|
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.Cmd
|
||||||
import io.dico.dicore.command.annotation.Desc
|
import io.dico.dicore.command.annotation.Desc
|
||||||
import io.dico.dicore.command.annotation.Flag
|
import io.dico.dicore.command.annotation.Flag
|
||||||
import io.dico.dicore.command.annotation.RequireParameters
|
import io.dico.dicore.command.annotation.RequireParameters
|
||||||
import io.dico.parcels2.ParcelsPlugin
|
import io.dico.parcels2.ParcelsPlugin
|
||||||
import io.dico.parcels2.PlayerProfile
|
import io.dico.parcels2.PlayerProfile
|
||||||
import io.dico.parcels2.util.hasAdminManage
|
import io.dico.parcels2.command.ParcelTarget.Kind
|
||||||
import io.dico.parcels2.util.hasParcelHomeOthers
|
import io.dico.parcels2.util.ext.hasAdminManage
|
||||||
import io.dico.parcels2.util.uuid
|
import io.dico.parcels2.util.ext.hasParcelHomeOthers
|
||||||
|
import io.dico.parcels2.util.ext.uuid
|
||||||
|
import org.bukkit.block.Biome
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||||
@@ -43,17 +45,20 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
"more than one parcel",
|
"more than one parcel",
|
||||||
shortVersion = "teleports you to parcels")
|
shortVersion = "teleports you to parcels")
|
||||||
@RequireParameters(0)
|
@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)
|
return cmdGoto(player, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Cmd("tp", aliases = ["teleport"])
|
@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)
|
return cmdGoto(player, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Cmd("goto")
|
@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) {
|
if (target is ParcelTarget.ByOwner) {
|
||||||
target.resolveOwner(plugin.storage)
|
target.resolveOwner(plugin.storage)
|
||||||
if (!target.owner.matches(player) && !player.hasParcelHomeOthers) {
|
if (!target.owner.matches(player) && !player.hasParcelHomeOthers) {
|
||||||
@@ -64,11 +69,12 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
val match = target.getParcelSuspend(plugin.storage)
|
val match = target.getParcelSuspend(plugin.storage)
|
||||||
?: error("The specified parcel could not be matched")
|
?: error("The specified parcel could not be matched")
|
||||||
player.teleport(match.homeLocation)
|
player.teleport(match.homeLocation)
|
||||||
return ""
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@Cmd("goto_fake")
|
@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)
|
return cmdGoto(player, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,23 +103,18 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
@Cmd("clear")
|
@Cmd("clear")
|
||||||
@ParcelRequire(owner = true)
|
@ParcelRequire(owner = true)
|
||||||
fun ParcelScope.cmdClear(context: ExecutionContext, @Flag sure: Boolean): Any? {
|
fun ParcelScope.cmdClear(context: ExecutionContext, @Flag sure: Boolean): Any? {
|
||||||
if (!sure) return "Are you sure? You cannot undo this action!\n" +
|
if (!sure) return areYouSureMessage(context)
|
||||||
"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))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
clearWithProgressUpdates(context, "Clear")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@Cmd("swap")
|
@Cmd("setbiome")
|
||||||
fun ParcelScope.cmdSwap(context: ExecutionContext, @Flag sure: Boolean): Any? {
|
@ParcelRequire(owner = true)
|
||||||
TODO()
|
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"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -7,8 +7,8 @@ import io.dico.dicore.command.Validate
|
|||||||
import io.dico.parcels2.Parcel
|
import io.dico.parcels2.Parcel
|
||||||
import io.dico.parcels2.ParcelProvider
|
import io.dico.parcels2.ParcelProvider
|
||||||
import io.dico.parcels2.ParcelWorld
|
import io.dico.parcels2.ParcelWorld
|
||||||
import io.dico.parcels2.util.hasAdminManage
|
import io.dico.parcels2.util.ext.hasAdminManage
|
||||||
import io.dico.parcels2.util.uuid
|
import io.dico.parcels2.util.ext.uuid
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import java.lang.reflect.Method
|
import java.lang.reflect.Method
|
||||||
import kotlin.reflect.full.extensionReceiverParameter
|
import kotlin.reflect.full.extensionReceiverParameter
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ import io.dico.dicore.command.parameter.type.ParameterType
|
|||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import io.dico.parcels2.util.Vec2i
|
import io.dico.parcels2.util.Vec2i
|
||||||
import io.dico.parcels2.util.floor
|
import io.dico.parcels2.util.ext.floor
|
||||||
import kotlinx.coroutines.experimental.Deferred
|
import kotlinx.coroutines.CoroutineStart.*
|
||||||
|
import kotlinx.coroutines.Deferred
|
||||||
|
import kotlinx.coroutines.async
|
||||||
import org.bukkit.command.CommandSender
|
import org.bukkit.command.CommandSender
|
||||||
import org.bukkit.entity.Player
|
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?
|
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) {
|
class ByID(world: ParcelWorld, val id: Vec2i?, parsedKind: Int, isDefault: Boolean) : ParcelTarget(world, parsedKind, isDefault) {
|
||||||
override suspend fun getParcelSuspend(storage: Storage): Parcel? = getParcel()
|
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 {
|
||||||
|
|
||||||
companion object Config : ParameterConfig<Kind, Int>(Kind::class.java) {
|
|
||||||
override fun toParameterInfo(annotation: Kind): Int {
|
|
||||||
return annotation.kind
|
|
||||||
}
|
|
||||||
|
|
||||||
const val ID = 1 // ID
|
const val ID = 1 // ID
|
||||||
const val OWNER_REAL = 2 // an owner backed by a UUID
|
const val OWNER_REAL = 2 // an owner backed by a UUID
|
||||||
const val OWNER_FAKE = 4 // an owner not 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
|
// 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 {
|
override fun parse(parameter: Parameter<ParcelTarget, Int>, sender: CommandSender, buffer: ArgumentBuffer): ParcelTarget {
|
||||||
var input = buffer.next()
|
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> {
|
private fun getHomeIndex(parameter: Parameter<*, *>, kind: Int, sender: CommandSender, input: String): Pair<PlayerProfile, Int> {
|
||||||
val splitIdx = input.indexOf(':')
|
val splitIdx = input.indexOf(':')
|
||||||
val ownerString: String
|
val ownerString: String
|
||||||
val indexString: String
|
val index: Int?
|
||||||
|
|
||||||
if (splitIdx == -1) {
|
if (splitIdx == -1) {
|
||||||
// just the index.
|
// just the index.
|
||||||
ownerString = ""
|
index = input.toIntOrNull()
|
||||||
indexString = input
|
ownerString = if (index == null) input else ""
|
||||||
} else {
|
} else {
|
||||||
ownerString = input.substring(0, splitIdx)
|
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())
|
val owner = if (ownerString.isEmpty())
|
||||||
@@ -133,10 +139,7 @@ sealed class ParcelTarget(val world: ParcelWorld, val parsedKind: Int, val isDef
|
|||||||
else
|
else
|
||||||
PlayerProfile.byName(ownerString, allowReal = kind and OWNER_REAL != 0, allowFake = kind and OWNER_FAKE != 0)
|
PlayerProfile.byName(ownerString, allowReal = kind and OWNER_REAL != 0, allowFake = kind and OWNER_FAKE != 0)
|
||||||
|
|
||||||
val index = if (indexString.isEmpty()) 0 else indexString.toIntOrNull()
|
return owner to (index ?: 0)
|
||||||
?: invalidInput(parameter, "The home index must be an integer, $indexString is not an integer")
|
|
||||||
|
|
||||||
return owner to index
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun requirePlayer(sender: CommandSender, parameter: Parameter<*, *>, objName: String): Player {
|
private fun requirePlayer(sender: CommandSender, parameter: Parameter<*, *>, objName: String): Player {
|
||||||
|
|||||||
@@ -2,9 +2,8 @@ package io.dico.parcels2.defaultimpl
|
|||||||
|
|
||||||
import io.dico.parcels2.Parcel
|
import io.dico.parcels2.Parcel
|
||||||
import io.dico.parcels2.ParcelContainer
|
import io.dico.parcels2.ParcelContainer
|
||||||
|
import io.dico.parcels2.ParcelId
|
||||||
import io.dico.parcels2.ParcelWorld
|
import io.dico.parcels2.ParcelWorld
|
||||||
import kotlin.coroutines.experimental.buildIterator
|
|
||||||
import kotlin.coroutines.experimental.buildSequence
|
|
||||||
|
|
||||||
class DefaultParcelContainer(val world: ParcelWorld) : ParcelContainer {
|
class DefaultParcelContainer(val world: ParcelWorld) : ParcelContainer {
|
||||||
private var parcels: Array<Array<Parcel>>
|
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)
|
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? {
|
override fun nextEmptyParcel(): Parcel? {
|
||||||
return walkInCircle().find { it.owner == null }
|
return walkInCircle().find { it.owner == null }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun walkInCircle(): Iterable<Parcel> = Iterable {
|
private fun walkInCircle(): Iterable<Parcel> = Iterable {
|
||||||
buildIterator {
|
iterator {
|
||||||
val center = world.options.axisLimit
|
val center = world.options.axisLimit
|
||||||
for (radius in 0..center) {
|
for (radius in 0..center) {
|
||||||
var x = center - radius;
|
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) {
|
for (array in parcels) {
|
||||||
yieldAll(array.iterator())
|
yieldAll(array.iterator())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,19 @@ package io.dico.parcels2.defaultimpl
|
|||||||
|
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.blockvisitor.RegionTraverser
|
import io.dico.parcels2.blockvisitor.RegionTraverser
|
||||||
|
import io.dico.parcels2.blockvisitor.TimeLimitedTask
|
||||||
import io.dico.parcels2.blockvisitor.Worker
|
import io.dico.parcels2.blockvisitor.Worker
|
||||||
import io.dico.parcels2.blockvisitor.WorktimeLimiter
|
import io.dico.parcels2.blockvisitor.WorktimeLimiter
|
||||||
import io.dico.parcels2.options.DefaultGeneratorOptions
|
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.*
|
||||||
import org.bukkit.block.Biome
|
import org.bukkit.block.Biome
|
||||||
import org.bukkit.block.BlockFace
|
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.BlockData
|
||||||
import org.bukkit.block.data.type.Sign
|
import org.bukkit.block.data.type.Sign
|
||||||
import org.bukkit.block.data.type.Slab
|
import org.bukkit.block.data.type.Slab
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
import java.util.Random
|
import java.util.Random
|
||||||
|
|
||||||
private val airType = Bukkit.createBlockData(Material.AIR)
|
private val airType = Bukkit.createBlockData(Material.AIR)
|
||||||
|
|
||||||
private const val chunkSize = 16
|
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
|
private var _world: World? = null
|
||||||
override val world: World
|
override val world: World
|
||||||
get() {
|
get() {
|
||||||
@@ -36,13 +49,15 @@ class DefaultParcelGenerator(override val worldName: String, private val o: Defa
|
|||||||
val makePathMain = o.pathSize > 2
|
val makePathMain = o.pathSize > 2
|
||||||
val makePathAlt = o.pathSize > 4
|
val makePathAlt = o.pathSize > 4
|
||||||
|
|
||||||
private inline fun <T> generate(chunkX: Int,
|
private inline fun <T> generate(
|
||||||
|
chunkX: Int,
|
||||||
chunkZ: Int,
|
chunkZ: Int,
|
||||||
floor: T, wall:
|
floor: T, wall:
|
||||||
T, pathMain: T,
|
T, pathMain: T,
|
||||||
pathAlt: T,
|
pathAlt: T,
|
||||||
fill: T,
|
fill: T,
|
||||||
setter: (Int, Int, Int, T) -> Unit) {
|
setter: (Int, Int, Int, T) -> Unit
|
||||||
|
) {
|
||||||
|
|
||||||
val floorHeight = o.floorHeight
|
val floorHeight = o.floorHeight
|
||||||
val parcelSize = o.parcelSize
|
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)
|
return Location(world, o.offsetX + fix, o.floorHeight + 1.0, o.offsetZ + fix)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun makeParcelLocatorAndBlockManager(worldId: ParcelWorldId,
|
override fun makeParcelLocatorAndBlockManager(
|
||||||
|
worldId: ParcelWorldId,
|
||||||
container: ParcelContainer,
|
container: ParcelContainer,
|
||||||
worktimeLimiter: WorktimeLimiter): Pair<ParcelLocator, ParcelBlockManager> {
|
coroutineScope: CoroutineScope,
|
||||||
return ParcelLocatorImpl(worldId, container) to ParcelBlockManagerImpl(worldId, worktimeLimiter)
|
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? {
|
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
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class ParcelLocatorImpl(val worldId: ParcelWorldId,
|
private inner class ParcelLocatorImpl(
|
||||||
val container: ParcelContainer) : ParcelLocator {
|
val worldId: ParcelWorldId,
|
||||||
|
val container: ParcelContainer
|
||||||
|
) : ParcelLocator {
|
||||||
override val world: World = this@DefaultParcelGenerator.world
|
override val world: World = this@DefaultParcelGenerator.world
|
||||||
|
|
||||||
override fun getParcelAt(x: Int, z: Int): Parcel? {
|
override fun getParcelAt(x: Int, z: Int): Parcel? {
|
||||||
@@ -137,8 +157,11 @@ class DefaultParcelGenerator(override val worldName: String, private val o: Defa
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
private inner class ParcelBlockManagerImpl(val worldId: ParcelWorldId,
|
private inner class ParcelBlockManagerImpl(
|
||||||
override val worktimeLimiter: WorktimeLimiter) : ParcelBlockManagerBase() {
|
val worldId: ParcelWorldId,
|
||||||
|
coroutineScope: CoroutineScope,
|
||||||
|
override val worktimeLimiter: WorktimeLimiter
|
||||||
|
) : ParcelBlockManagerBase(), CoroutineScope by coroutineScope {
|
||||||
override val world: World = this@DefaultParcelGenerator.world
|
override val world: World = this@DefaultParcelGenerator.world
|
||||||
override val parcelTraverser: RegionTraverser = RegionTraverser.upToAndDownUntil(o.floorHeight)
|
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 world = world
|
||||||
val b = getBottomBlock(parcel)
|
val b = getBottomBlock(parcel)
|
||||||
val parcelSize = o.parcelSize
|
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 region = getRegion(parcel)
|
||||||
val blocks = parcelTraverser.traverseRegion(region)
|
val blocks = parcelTraverser.traverseRegion(region)
|
||||||
val blockCount = region.blockCount.toDouble()
|
val blockCount = region.blockCount.toDouble()
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
package io.dico.parcels2.defaultimpl
|
package io.dico.parcels2.defaultimpl
|
||||||
|
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.util.alsoIfTrue
|
import io.dico.parcels2.util.ext.alsoIfTrue
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
|
|
||||||
class GlobalAddedDataManagerImpl(val plugin: ParcelsPlugin) : GlobalAddedDataManager {
|
class GlobalAddedDataManagerImpl(val plugin: ParcelsPlugin) : GlobalAddedDataManager {
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package io.dico.parcels2.defaultimpl
|
|||||||
import io.dico.dicore.Formatting
|
import io.dico.dicore.Formatting
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.util.Vec2i
|
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.Material
|
||||||
import org.bukkit.OfflinePlayer
|
import org.bukkit.OfflinePlayer
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import kotlin.reflect.KProperty
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
class ParcelImpl(override val world: ParcelWorld,
|
class ParcelImpl(override val world: ParcelWorld,
|
||||||
override val x: Int,
|
override val x: Int,
|
||||||
@@ -15,8 +15,8 @@ class ParcelImpl(override val world: ParcelWorld,
|
|||||||
override val id: ParcelId = this
|
override val id: ParcelId = this
|
||||||
override val pos get() = Vec2i(x, z)
|
override val pos get() = Vec2i(x, z)
|
||||||
override var data: ParcelDataHolder = ParcelDataHolder(); private set
|
override var data: ParcelDataHolder = ParcelDataHolder(); private set
|
||||||
override val infoString by ParcelInfoStringComputer
|
override val infoString get() = ParcelInfoStringComputer.getInfoString(this)
|
||||||
override var hasBlockVisitors: Boolean = false; private set
|
override val hasBlockVisitors get() = blockVisitors.get() > 0
|
||||||
override val worldId: ParcelWorldId get() = world.id
|
override val worldId: ParcelWorldId get() = world.id
|
||||||
|
|
||||||
override fun copyDataIgnoringDatabase(data: ParcelData) {
|
override fun copyDataIgnoringDatabase(data: ParcelData) {
|
||||||
@@ -115,6 +115,18 @@ class ParcelImpl(override val world: ParcelWorld,
|
|||||||
// TODO update storage
|
// 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 {
|
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") {
|
appendField("ID") {
|
||||||
append(parcel.x)
|
append(parcel.x)
|
||||||
append(',')
|
append(',')
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
package io.dico.parcels2.defaultimpl
|
package io.dico.parcels2.defaultimpl
|
||||||
|
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import kotlinx.coroutines.experimental.Unconfined
|
import io.dico.parcels2.util.schedule
|
||||||
import kotlinx.coroutines.experimental.launch
|
import kotlinx.coroutines.CoroutineStart
|
||||||
|
import kotlinx.coroutines.CoroutineStart.*
|
||||||
|
import kotlinx.coroutines.Unconfined
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.WorldCreator
|
import org.bukkit.WorldCreator
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
@@ -42,7 +45,7 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
|||||||
|
|
||||||
private fun loadWorlds0() {
|
private fun loadWorlds0() {
|
||||||
if (Bukkit.getWorlds().isEmpty()) {
|
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")
|
plugin.logger.warning("Scheduling to load worlds in the next tick, \nbecause no bukkit worlds are loaded yet")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -58,7 +61,7 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
|||||||
else WorldCreator(worldName).generator(generator).createWorld().also { logger.info("Creating world $worldName") }
|
else WorldCreator(worldName).generator(generator).createWorld().also { logger.info("Creating world $worldName") }
|
||||||
|
|
||||||
parcelWorld = ParcelWorldImpl(bukkitWorld, generator, worldOptions.runtime, plugin.storage,
|
parcelWorld = ParcelWorldImpl(bukkitWorld, generator, worldOptions.runtime, plugin.storage,
|
||||||
plugin.globalAddedData, ::DefaultParcelContainer, plugin.worktimeLimiter)
|
plugin.globalAddedData, ::DefaultParcelContainer, plugin, plugin.worktimeLimiter)
|
||||||
|
|
||||||
if (!worldExists) {
|
if (!worldExists) {
|
||||||
val time = DateTime.now()
|
val time = DateTime.now()
|
||||||
@@ -77,7 +80,7 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun loadStoredData() {
|
private fun loadStoredData() {
|
||||||
plugin.functionHelper.launchLazilyOnMainThread {
|
plugin.launch {
|
||||||
val migration = plugin.options.migration
|
val migration = plugin.options.migration
|
||||||
if (migration.enabled) {
|
if (migration.enabled) {
|
||||||
migration.instance?.newInstance()?.apply {
|
migration.instance?.newInstance()?.apply {
|
||||||
@@ -102,7 +105,7 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
|||||||
|
|
||||||
logger.info("Loading data completed")
|
logger.info("Loading data completed")
|
||||||
_dataIsLoaded = true
|
_dataIsLoaded = true
|
||||||
}.start()
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import io.dico.parcels2.*
|
|||||||
import io.dico.parcels2.blockvisitor.WorktimeLimiter
|
import io.dico.parcels2.blockvisitor.WorktimeLimiter
|
||||||
import io.dico.parcels2.options.RuntimeWorldOptions
|
import io.dico.parcels2.options.RuntimeWorldOptions
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
@@ -16,6 +17,7 @@ class ParcelWorldImpl(override val world: World,
|
|||||||
override val storage: Storage,
|
override val storage: Storage,
|
||||||
override val globalAddedData: GlobalAddedDataManager,
|
override val globalAddedData: GlobalAddedDataManager,
|
||||||
containerFactory: ParcelContainerFactory,
|
containerFactory: ParcelContainerFactory,
|
||||||
|
coroutineScope: CoroutineScope,
|
||||||
worktimeLimiter: WorktimeLimiter)
|
worktimeLimiter: WorktimeLimiter)
|
||||||
: ParcelWorld,
|
: ParcelWorld,
|
||||||
ParcelWorldId,
|
ParcelWorldId,
|
||||||
@@ -37,7 +39,7 @@ class ParcelWorldImpl(override val world: World,
|
|||||||
override val blockManager: ParcelBlockManager
|
override val blockManager: ParcelBlockManager
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val pair = generator.makeParcelLocatorAndBlockManager(id, container, worktimeLimiter)
|
val pair = generator.makeParcelLocatorAndBlockManager(id, container, coroutineScope, worktimeLimiter)
|
||||||
locator = pair.first
|
locator = pair.first
|
||||||
blockManager = pair.second
|
blockManager = pair.second
|
||||||
|
|
||||||
@@ -84,5 +86,5 @@ class ParcelWorldImpl(override val world: World,
|
|||||||
return container.nextEmptyParcel()
|
return container.nextEmptyParcel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun toString() = toStringExt()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package io.dico.parcels2.listener
|
|||||||
|
|
||||||
import io.dico.parcels2.Parcel
|
import io.dico.parcels2.Parcel
|
||||||
import io.dico.parcels2.ParcelProvider
|
import io.dico.parcels2.ParcelProvider
|
||||||
import io.dico.parcels2.util.editLoop
|
import io.dico.parcels2.util.ext.editLoop
|
||||||
import io.dico.parcels2.util.isPresentAnd
|
import io.dico.parcels2.util.ext.isPresentAnd
|
||||||
import org.bukkit.entity.Entity
|
import org.bukkit.entity.Entity
|
||||||
|
|
||||||
class ParcelEntityTracker(val parcelProvider: ParcelProvider) {
|
class ParcelEntityTracker(val parcelProvider: ParcelProvider) {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import io.dico.parcels2.ParcelProvider
|
|||||||
import io.dico.parcels2.ParcelWorld
|
import io.dico.parcels2.ParcelWorld
|
||||||
import io.dico.parcels2.statusKey
|
import io.dico.parcels2.statusKey
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import io.dico.parcels2.util.*
|
import io.dico.parcels2.util.ext.*
|
||||||
import org.bukkit.Material.*
|
import org.bukkit.Material.*
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
import org.bukkit.block.Biome
|
import org.bukkit.block.Biome
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
package io.dico.parcels2.storage
|
package io.dico.parcels2.storage
|
||||||
|
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import kotlinx.coroutines.experimental.CoroutineDispatcher
|
import kotlinx.coroutines.CoroutineDispatcher
|
||||||
import kotlinx.coroutines.experimental.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.experimental.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.experimental.channels.ReceiveChannel
|
import kotlinx.coroutines.channels.ReceiveChannel
|
||||||
import kotlinx.coroutines.experimental.channels.SendChannel
|
import kotlinx.coroutines.channels.SendChannel
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,11 @@
|
|||||||
package io.dico.parcels2.storage
|
package io.dico.parcels2.storage
|
||||||
|
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import kotlinx.coroutines.experimental.Deferred
|
import kotlinx.coroutines.Deferred
|
||||||
import kotlinx.coroutines.experimental.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.experimental.channels.ReceiveChannel
|
import kotlinx.coroutines.channels.ReceiveChannel
|
||||||
import kotlinx.coroutines.experimental.channels.SendChannel
|
import kotlinx.coroutines.channels.SendChannel
|
||||||
import kotlinx.coroutines.experimental.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ import io.dico.parcels2.PlayerProfile.Star.name
|
|||||||
import io.dico.parcels2.storage.AddedDataPair
|
import io.dico.parcels2.storage.AddedDataPair
|
||||||
import io.dico.parcels2.storage.Backing
|
import io.dico.parcels2.storage.Backing
|
||||||
import io.dico.parcels2.storage.DataPair
|
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.toByteArray
|
||||||
import io.dico.parcels2.util.toUUID
|
import io.dico.parcels2.util.toUUID
|
||||||
import kotlinx.coroutines.experimental.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.experimental.channels.ArrayChannel
|
import kotlinx.coroutines.channels.ArrayChannel
|
||||||
import kotlinx.coroutines.experimental.channels.LinkedListChannel
|
import kotlinx.coroutines.channels.LinkedListChannel
|
||||||
import kotlinx.coroutines.experimental.channels.ReceiveChannel
|
import kotlinx.coroutines.channels.ReceiveChannel
|
||||||
import kotlinx.coroutines.experimental.channels.SendChannel
|
import kotlinx.coroutines.channels.SendChannel
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.SchemaUtils.create
|
import org.jetbrains.exposed.sql.SchemaUtils.create
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
|||||||
@@ -153,6 +153,13 @@ object ProfilesT : IdTransactionsTable<ProfilesT, PlayerProfile>("parcels_profil
|
|||||||
return getItem(id) as? PlayerProfile.Real
|
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)
|
// val ParcelsWithOptionsT = ParcelsT.join(ParcelOptionsT, JoinType.INNER, onColumn = ParcelsT.id, otherColumn = ParcelOptionsT.parcel_id)
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
package io.dico.parcels2.storage.exposed
|
package io.dico.parcels2.storage.exposed
|
||||||
|
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import kotlinx.coroutines.experimental.channels.SendChannel
|
import kotlinx.coroutines.channels.SendChannel
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package io.dico.parcels2.storage.migration
|
package io.dico.parcels2.storage.migration
|
||||||
|
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import kotlinx.coroutines.experimental.Job
|
import kotlinx.coroutines.Job
|
||||||
|
|
||||||
interface Migration {
|
interface Migration {
|
||||||
fun migrateTo(storage: Storage): Job
|
fun migrateTo(storage: Storage): Job
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import io.dico.parcels2.storage.exposed.abs
|
|||||||
import io.dico.parcels2.storage.exposed.greater
|
import io.dico.parcels2.storage.exposed.greater
|
||||||
import io.dico.parcels2.storage.migration.Migration
|
import io.dico.parcels2.storage.migration.Migration
|
||||||
import io.dico.parcels2.util.toUUID
|
import io.dico.parcels2.util.toUUID
|
||||||
import kotlinx.coroutines.experimental.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.experimental.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.experimental.newFixedThreadPoolContext
|
import kotlinx.coroutines.newFixedThreadPoolContext
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
import java.sql.Blob
|
import java.sql.Blob
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
src/main/kotlin/io/dico/parcels2/util/PluginScheduler.kt
Normal file
20
src/main/kotlin/io/dico/parcels2/util/PluginScheduler.kt
Normal file
@@ -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)
|
||||||
|
|
||||||
@@ -1,16 +1,11 @@
|
|||||||
package io.dico.parcels2.util
|
package io.dico.parcels2.util
|
||||||
|
|
||||||
|
import io.dico.parcels2.util.ext.isValid
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
@Suppress("UsePropertyAccessSyntax")
|
const val PLAYER_NAME_PLACEHOLDER = ":unknown_name:"
|
||||||
fun getPlayerNameOrDefault(uuid: UUID?, ifUnknown: String? = null): String {
|
|
||||||
return uuid
|
|
||||||
?.let { getPlayerName(it) }
|
|
||||||
?: ifUnknown
|
|
||||||
?: ":unknown_name:"
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getPlayerName(uuid: UUID): String? {
|
fun getPlayerName(uuid: UUID): String? {
|
||||||
return Bukkit.getOfflinePlayer(uuid)?.takeIf { it.isValid }?.name
|
return Bukkit.getOfflinePlayer(uuid)?.takeIf { it.isValid }?.name
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package io.dico.parcels2.util
|
package io.dico.parcels2.util.ext
|
||||||
|
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.Material.*
|
import org.bukkit.Material.*
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package io.dico.parcels2.util
|
package io.dico.parcels2.util.ext
|
||||||
|
|
||||||
fun Double.floor(): Int {
|
fun Double.floor(): Int {
|
||||||
val down = toInt()
|
val down = toInt()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package io.dico.parcels2.util
|
package io.dico.parcels2.util.ext
|
||||||
|
|
||||||
import io.dico.parcels2.logger
|
import io.dico.parcels2.logger
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
package io.dico.parcels2.util
|
package io.dico.parcels2.util.ext
|
||||||
|
|
||||||
import io.dico.dicore.Formatting
|
import io.dico.dicore.Formatting
|
||||||
import io.dico.parcels2.ParcelsPlugin
|
import io.dico.parcels2.ParcelsPlugin
|
||||||
import io.dico.parcels2.PlayerProfile
|
|
||||||
import io.dico.parcels2.logger
|
import io.dico.parcels2.logger
|
||||||
import org.bukkit.OfflinePlayer
|
import org.bukkit.OfflinePlayer
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
14
todo.md
14
todo.md
@@ -3,18 +3,18 @@
|
|||||||
Commands
|
Commands
|
||||||
-
|
-
|
||||||
Basically all admin commands.
|
Basically all admin commands.
|
||||||
* setowner
|
* ~~setowner~~
|
||||||
* dispose
|
* ~~dispose~~
|
||||||
* reset
|
* ~~reset~~
|
||||||
* swap
|
* swap
|
||||||
* New admin commands that I can't think of right now.
|
* New admin commands that I can't think of right now.
|
||||||
|
|
||||||
Also
|
Also
|
||||||
* setbiome
|
* ~~setbiome~~
|
||||||
* random
|
* random
|
||||||
|
|
||||||
Modify home command:
|
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
|
* Listen for command events that use plotme-style argument, and transform the command
|
||||||
|
|
||||||
~~Add permissions to commands (replace or fix `IContextFilter` from command lib
|
~~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,
|
Scan through blocks that were added since original Parcels implementation,
|
||||||
that might introduce things that need to be checked or listened for.
|
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.
|
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).
|
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.~~
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user