Work down some todo items, update to kotlin 1.3-rc
This commit is contained in:
@@ -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")
|
||||
|
||||
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("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")
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 ->
|
||||
|
||||
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"
|
||||
|
||||
include("dicore3:core")
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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?
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 ->
|
||||
|
||||
@@ -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) }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(',')
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
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
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.dico.parcels2.util
|
||||
package io.dico.parcels2.util.ext
|
||||
|
||||
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 {
|
||||
val down = toInt()
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.dico.parcels2.util
|
||||
package io.dico.parcels2.util.ext
|
||||
|
||||
import io.dico.parcels2.logger
|
||||
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.parcels2.ParcelsPlugin
|
||||
import io.dico.parcels2.PlayerProfile
|
||||
import io.dico.parcels2.logger
|
||||
import org.bukkit.OfflinePlayer
|
||||
import org.bukkit.entity.Player
|
||||
14
todo.md
14
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.~~
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user