Fixes n tweaks
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
package io.dico.parcels2
|
||||
|
||||
import io.dico.parcels2.util.ext.ceilDiv
|
||||
import io.dico.parcels2.util.math.ext.ceilDiv
|
||||
import io.dico.parcels2.util.ext.getMaterialsWithWoodTypePrefix
|
||||
import org.bukkit.Material
|
||||
import java.util.EnumMap
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.dico.parcels2
|
||||
|
||||
import io.dico.parcels2.util.Vec2i
|
||||
import io.dico.parcels2.util.math.Vec2i
|
||||
import org.bukkit.Location
|
||||
import org.joda.time.DateTime
|
||||
import java.util.UUID
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package io.dico.parcels2
|
||||
|
||||
import io.dico.parcels2.blockvisitor.*
|
||||
import io.dico.parcels2.util.Region
|
||||
import io.dico.parcels2.util.Vec2i
|
||||
import io.dico.parcels2.util.get
|
||||
import io.dico.parcels2.util.math.Region
|
||||
import io.dico.parcels2.util.math.Vec2i
|
||||
import io.dico.parcels2.util.math.get
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import org.bukkit.Chunk
|
||||
import org.bukkit.Location
|
||||
@@ -37,12 +37,12 @@ abstract class ParcelGenerator : ChunkGenerator() {
|
||||
abstract fun makeParcelLocatorAndBlockManager(worldId: ParcelWorldId,
|
||||
container: ParcelContainer,
|
||||
coroutineScope: CoroutineScope,
|
||||
workDispatcher: WorkDispatcher): Pair<ParcelLocator, ParcelBlockManager>
|
||||
jobDispatcher: JobDispatcher): Pair<ParcelLocator, ParcelBlockManager>
|
||||
}
|
||||
|
||||
interface ParcelBlockManager {
|
||||
val world: World
|
||||
val workDispatcher: WorkDispatcher
|
||||
val jobDispatcher: JobDispatcher
|
||||
val parcelTraverser: RegionTraverser
|
||||
|
||||
// fun getBottomBlock(parcel: ParcelId): Vec2i
|
||||
@@ -55,13 +55,13 @@ interface ParcelBlockManager {
|
||||
|
||||
fun setOwnerBlock(parcel: ParcelId, owner: PlayerProfile?)
|
||||
|
||||
fun setBiome(parcel: ParcelId, biome: Biome): Worker
|
||||
fun setBiome(parcel: ParcelId, biome: Biome): Job
|
||||
|
||||
fun clearParcel(parcel: ParcelId): Worker
|
||||
fun clearParcel(parcel: ParcelId): Job
|
||||
|
||||
fun swapParcels(parcel1: ParcelId, parcel2: ParcelId): Worker
|
||||
fun swapParcels(parcel1: ParcelId, parcel2: ParcelId): Job
|
||||
|
||||
fun submitBlockVisitor(vararg parcelIds: ParcelId, task: WorkerTask): Worker
|
||||
fun submitBlockVisitor(vararg parcelIds: ParcelId, task: JobFunction): Job
|
||||
|
||||
/**
|
||||
* Used to update owner blocks in the corner of the parcel
|
||||
@@ -71,7 +71,7 @@ interface ParcelBlockManager {
|
||||
|
||||
inline fun ParcelBlockManager.doBlockOperation(parcel: ParcelId,
|
||||
traverser: RegionTraverser,
|
||||
crossinline operation: suspend WorkerScope.(Block) -> Unit) = submitBlockVisitor(parcel) {
|
||||
crossinline operation: suspend JobScope.(Block) -> Unit) = submitBlockVisitor(parcel) {
|
||||
val region = getRegion(parcel)
|
||||
val blockCount = region.blockCount.toDouble()
|
||||
val blocks = traverser.traverseRegion(region)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.dico.parcels2
|
||||
|
||||
import io.dico.parcels2.util.Vec2i
|
||||
import io.dico.parcels2.util.math.Vec2i
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.World
|
||||
import java.util.UUID
|
||||
|
||||
@@ -2,8 +2,8 @@ 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.ext.floor
|
||||
import io.dico.parcels2.util.math.Vec2i
|
||||
import io.dico.parcels2.util.math.ext.floor
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.World
|
||||
import org.bukkit.block.Block
|
||||
|
||||
@@ -3,8 +3,8 @@ package io.dico.parcels2
|
||||
import io.dico.dicore.Registrator
|
||||
import io.dico.dicore.command.EOverridePolicy
|
||||
import io.dico.dicore.command.ICommandDispatcher
|
||||
import io.dico.parcels2.blockvisitor.BukkitWorkDispatcher
|
||||
import io.dico.parcels2.blockvisitor.WorkDispatcher
|
||||
import io.dico.parcels2.blockvisitor.BukkitJobDispatcher
|
||||
import io.dico.parcels2.blockvisitor.JobDispatcher
|
||||
import io.dico.parcels2.command.getParcelCommands
|
||||
import io.dico.parcels2.defaultimpl.GlobalPrivilegesManagerImpl
|
||||
import io.dico.parcels2.defaultimpl.ParcelProviderImpl
|
||||
@@ -44,7 +44,7 @@ class ParcelsPlugin : JavaPlugin(), CoroutineScope, PluginScheduler {
|
||||
|
||||
override val coroutineContext: CoroutineContext = MainThreadDispatcher(this)
|
||||
override val plugin: Plugin get() = this
|
||||
val workDispatcher: WorkDispatcher by lazy { BukkitWorkDispatcher(this, options.tickWorktime) }
|
||||
val jobDispatcher: JobDispatcher by lazy { BukkitJobDispatcher(this, options.tickJobtime) }
|
||||
|
||||
override fun onEnable() {
|
||||
plogger.info("Debug enabled: ${plogger.isDebugEnabled}")
|
||||
@@ -55,11 +55,11 @@ class ParcelsPlugin : JavaPlugin(), CoroutineScope, PluginScheduler {
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
val hasWorkers = workDispatcher.workers.isNotEmpty()
|
||||
val hasWorkers = jobDispatcher.jobs.isNotEmpty()
|
||||
if (hasWorkers) {
|
||||
plogger.warn("Parcels is attempting to complete all ${workDispatcher.workers.size} remaining jobs before shutdown...")
|
||||
plogger.warn("Parcels is attempting to complete all ${jobDispatcher.jobs.size} remaining jobs before shutdown...")
|
||||
}
|
||||
workDispatcher.completeAllTasks()
|
||||
jobDispatcher.completeAllTasks()
|
||||
if (hasWorkers) {
|
||||
plogger.info("Parcels has completed the remaining jobs.")
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ interface RawPrivileges {
|
||||
open class PrivilegesHolder(override var privilegeMap: MutablePrivilegeMap = EmptyPrivilegeMap) : RawPrivileges {
|
||||
private var _privilegeOfStar: Privilege = DEFAULT
|
||||
|
||||
override var privilegeOfStar: Privilege
|
||||
override /*open*/ var privilegeOfStar: Privilege
|
||||
get() = _privilegeOfStar
|
||||
set(value) = run { _privilegeOfStar = value }
|
||||
|
||||
@@ -94,5 +94,10 @@ open class PrivilegesHolder(override var privilegeMap: MutablePrivilegeMap = Emp
|
||||
return if (privilege == DEFAULT) privilegeMap.remove(key) != null
|
||||
else privilegeMap.put(key, privilege) != privilege
|
||||
}
|
||||
|
||||
fun copyPrivilegesFrom(other: PrivilegesHolder) {
|
||||
privilegeMap = other.privilegeMap
|
||||
privilegeOfStar = other.privilegeOfStar
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.dico.parcels2.blockvisitor
|
||||
|
||||
import io.dico.parcels2.util.Vec3i
|
||||
import io.dico.parcels2.util.math.Vec3i
|
||||
import io.dico.parcels2.util.ext.getMaterialsWithWoodTypePrefix
|
||||
import io.dico.parcels2.util.ext.getMaterialsWithWoolColorPrefix
|
||||
import org.bukkit.Material
|
||||
|
||||
@@ -2,11 +2,11 @@ package io.dico.parcels2.blockvisitor
|
||||
|
||||
import io.dico.parcels2.ParcelsPlugin
|
||||
import io.dico.parcels2.logger
|
||||
import io.dico.parcels2.util.ext.clampMin
|
||||
import io.dico.parcels2.util.math.ext.clampMin
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.CoroutineStart.LAZY
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.Job as CoroutineJob
|
||||
import kotlinx.coroutines.launch
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
import java.lang.System.currentTimeMillis
|
||||
@@ -16,21 +16,21 @@ import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
|
||||
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
typealias WorkerTask = suspend WorkerScope.() -> Unit
|
||||
typealias WorkerUpdateLister = Worker.(Double, Long) -> Unit
|
||||
typealias JobFunction = suspend JobScope.() -> Unit
|
||||
typealias JobUpdateLister = Job.(Double, Long) -> Unit
|
||||
|
||||
data class TickWorktimeOptions(var workTime: Int, var tickInterval: Int)
|
||||
data class TickJobtimeOptions(var jobTime: Int, var tickInterval: Int)
|
||||
|
||||
interface WorkDispatcher {
|
||||
interface JobDispatcher {
|
||||
/**
|
||||
* Submit a [task] that should be run synchronously, but limited such that it does not stall the server
|
||||
*/
|
||||
fun dispatch(task: WorkerTask): Worker
|
||||
fun dispatch(task: JobFunction): Job
|
||||
|
||||
/**
|
||||
* Get a list of all workers
|
||||
* Get a list of all jobs
|
||||
*/
|
||||
val workers: List<Worker>
|
||||
val jobs: List<Job>
|
||||
|
||||
/**
|
||||
* Attempts to complete any remaining tasks immediately, without suspension.
|
||||
@@ -38,27 +38,27 @@ interface WorkDispatcher {
|
||||
fun completeAllTasks()
|
||||
}
|
||||
|
||||
interface WorkerAndScopeMembersUnion {
|
||||
interface JobAndScopeMembersUnion {
|
||||
/**
|
||||
* The time that elapsed since this worker was dispatched, in milliseconds
|
||||
* The time that elapsed since this job was dispatched, in milliseconds
|
||||
*/
|
||||
val elapsedTime: Long
|
||||
|
||||
/**
|
||||
* A value indicating the progress of this worker, in the range 0.0 <= progress <= 1.0
|
||||
* A value indicating the progress of this job, in the range 0.0 <= progress <= 1.0
|
||||
* with no guarantees to its accuracy.
|
||||
*/
|
||||
val progress: Double
|
||||
}
|
||||
|
||||
interface Worker : WorkerAndScopeMembersUnion {
|
||||
interface Job : JobAndScopeMembersUnion {
|
||||
/**
|
||||
* The coroutine associated with this worker
|
||||
* The coroutine associated with this job
|
||||
*/
|
||||
val job: Job
|
||||
val job: CoroutineJob
|
||||
|
||||
/**
|
||||
* true if this worker has completed
|
||||
* true if this job has completed
|
||||
*/
|
||||
val isComplete: Boolean
|
||||
|
||||
@@ -69,28 +69,28 @@ interface Worker : WorkerAndScopeMembersUnion {
|
||||
val completionException: Throwable?
|
||||
|
||||
/**
|
||||
* Calls the given [block] whenever the progress of this worker is updated,
|
||||
* Calls the given [block] whenever the progress of this job is updated,
|
||||
* if [minInterval] milliseconds expired since the last call.
|
||||
* The first call occurs after at least [minDelay] milliseconds in a likewise manner.
|
||||
* Repeated invocations of this method result in an [IllegalStateException]
|
||||
*
|
||||
* if [asCompletionListener] is true, [onCompleted] is called with the same [block]
|
||||
*/
|
||||
fun onProgressUpdate(minDelay: Int, minInterval: Int, asCompletionListener: Boolean = true, block: WorkerUpdateLister): Worker
|
||||
fun onProgressUpdate(minDelay: Int, minInterval: Int, asCompletionListener: Boolean = true, block: JobUpdateLister): Job
|
||||
|
||||
/**
|
||||
* Calls the given [block] when this worker completes, with the progress value 1.0.
|
||||
* Calls the given [block] when this job completes, with the progress value 1.0.
|
||||
* Multiple listeners may be registered to this function.
|
||||
*/
|
||||
fun onCompleted(block: WorkerUpdateLister): Worker
|
||||
fun onCompleted(block: JobUpdateLister): Job
|
||||
|
||||
/**
|
||||
* Await completion of this worker
|
||||
* Await completion of this job
|
||||
*/
|
||||
suspend fun awaitCompletion()
|
||||
}
|
||||
|
||||
interface WorkerScope : WorkerAndScopeMembersUnion {
|
||||
interface JobScope : JobAndScopeMembersUnion {
|
||||
/**
|
||||
* A task should call this frequently during its execution, such that the timer can suspend it when necessary.
|
||||
*/
|
||||
@@ -107,29 +107,29 @@ interface WorkerScope : WorkerAndScopeMembersUnion {
|
||||
fun markComplete() = setProgress(1.0)
|
||||
|
||||
/**
|
||||
* Get a [WorkerScope] that is responsible for [portion] part of the progress
|
||||
* Get a [JobScope] that is responsible for [portion] part of the progress
|
||||
* If [portion] is negative, the remaining progress is used
|
||||
*/
|
||||
fun delegateWork(portion: Double = -1.0): WorkerScope
|
||||
fun delegateProgress(portion: Double = -1.0): JobScope
|
||||
}
|
||||
|
||||
inline fun <T> WorkerScope.delegateWork(portion: Double = -1.0, block: WorkerScope.() -> T): T {
|
||||
delegateWork(portion).apply {
|
||||
inline fun <T> JobScope.delegateWork(portion: Double = -1.0, block: JobScope.() -> T): T {
|
||||
delegateProgress(portion).apply {
|
||||
val result = block()
|
||||
markComplete()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
interface WorkerInternal : Worker, WorkerScope {
|
||||
interface JobInternal : Job, JobScope {
|
||||
/**
|
||||
* Start or resumes the execution of this worker
|
||||
* and returns true if the worker completed
|
||||
* Start or resumes the execution of this job
|
||||
* and returns true if the job completed
|
||||
*
|
||||
* [worktime] is the maximum amount of time, in milliseconds,
|
||||
* that this job may run for until suspension.
|
||||
*
|
||||
* If [worktime] is not positive, the worker will complete
|
||||
* If [worktime] is not positive, the job will complete
|
||||
* without suspension and this method will always return true.
|
||||
*/
|
||||
fun resume(worktime: Long): Boolean
|
||||
@@ -137,68 +137,68 @@ interface WorkerInternal : Worker, WorkerScope {
|
||||
|
||||
/**
|
||||
* An object that controls one or more jobs, ensuring that they don't stall the server too much.
|
||||
* 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 jobs together in each server tick
|
||||
* This object attempts to split that maximum amount of milliseconds equally between all jobs
|
||||
*/
|
||||
class BukkitWorkDispatcher(private val plugin: ParcelsPlugin, var options: TickWorktimeOptions) : WorkDispatcher {
|
||||
class BukkitJobDispatcher(private val plugin: ParcelsPlugin, var options: TickJobtimeOptions) : JobDispatcher {
|
||||
// The currently registered bukkit scheduler task
|
||||
private var bukkitTask: BukkitTask? = null
|
||||
// The workers.
|
||||
private val _workers = LinkedList<WorkerInternal>()
|
||||
override val workers: List<Worker> = _workers
|
||||
// The jobs.
|
||||
private val _jobs = LinkedList<JobInternal>()
|
||||
override val jobs: List<Job> = _jobs
|
||||
|
||||
override fun dispatch(task: WorkerTask): Worker {
|
||||
val worker: WorkerInternal = WorkerImpl(plugin, task)
|
||||
override fun dispatch(task: JobFunction): Job {
|
||||
val job: JobInternal = JobImpl(plugin, task)
|
||||
|
||||
if (bukkitTask == null) {
|
||||
val completed = worker.resume(options.workTime.toLong())
|
||||
if (completed) return worker
|
||||
bukkitTask = plugin.scheduleRepeating(0, options.tickInterval) { tickJobs() }
|
||||
val completed = job.resume(options.jobTime.toLong())
|
||||
if (completed) return job
|
||||
bukkitTask = plugin.scheduleRepeating(0, options.tickInterval) { tickCoroutineJobs() }
|
||||
}
|
||||
_workers.addFirst(worker)
|
||||
return worker
|
||||
_jobs.addFirst(job)
|
||||
return job
|
||||
}
|
||||
|
||||
private fun tickJobs() {
|
||||
val workers = _workers
|
||||
if (workers.isEmpty()) return
|
||||
private fun tickCoroutineJobs() {
|
||||
val jobs = _jobs
|
||||
if (jobs.isEmpty()) return
|
||||
val tickStartTime = System.currentTimeMillis()
|
||||
|
||||
val iterator = workers.listIterator(index = 0)
|
||||
val iterator = jobs.listIterator(index = 0)
|
||||
while (iterator.hasNext()) {
|
||||
val time = System.currentTimeMillis()
|
||||
val timeElapsed = time - tickStartTime
|
||||
val timeLeft = options.workTime - timeElapsed
|
||||
val timeLeft = options.jobTime - timeElapsed
|
||||
if (timeLeft <= 0) return
|
||||
|
||||
val count = workers.size - iterator.nextIndex()
|
||||
val count = jobs.size - iterator.nextIndex()
|
||||
val timePerJob = (timeLeft + count - 1) / count
|
||||
val worker = iterator.next()
|
||||
val completed = worker.resume(timePerJob)
|
||||
val job = iterator.next()
|
||||
val completed = job.resume(timePerJob)
|
||||
if (completed) {
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
|
||||
if (workers.isEmpty()) {
|
||||
if (jobs.isEmpty()) {
|
||||
bukkitTask?.cancel()
|
||||
bukkitTask = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun completeAllTasks() {
|
||||
_workers.forEach {
|
||||
_jobs.forEach {
|
||||
it.resume(-1)
|
||||
}
|
||||
_workers.clear()
|
||||
_jobs.clear()
|
||||
bukkitTask?.cancel()
|
||||
bukkitTask = null
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class WorkerImpl(scope: CoroutineScope, task: WorkerTask) : WorkerInternal {
|
||||
override val job: Job = scope.launch(start = LAZY) { task() }
|
||||
private class JobImpl(scope: CoroutineScope, task: JobFunction) : JobInternal {
|
||||
override val job: CoroutineJob = scope.launch(start = LAZY) { task() }
|
||||
|
||||
private var continuation: Continuation<Unit>? = null
|
||||
private var nextSuspensionTime: Long = 0L
|
||||
@@ -217,17 +217,17 @@ private class WorkerImpl(scope: CoroutineScope, task: WorkerTask) : WorkerIntern
|
||||
override var completionException: Throwable? = null; private set
|
||||
|
||||
private var startTimeOrElapsedTime: Long = 0L // startTime before completed, elapsed time otherwise
|
||||
private var onProgressUpdate: WorkerUpdateLister? = null
|
||||
private var onProgressUpdate: JobUpdateLister? = null
|
||||
private var progressUpdateInterval: Int = 0
|
||||
private var lastUpdateTime: Long = 0L
|
||||
private var onCompleted: WorkerUpdateLister? = null
|
||||
private var onCompleted: JobUpdateLister? = null
|
||||
|
||||
init {
|
||||
job.invokeOnCompletion { exception ->
|
||||
// report any error that occurred
|
||||
completionException = exception?.also {
|
||||
if (it !is CancellationException)
|
||||
logger.error("WorkerTask generated an exception", it)
|
||||
logger.error("JobFunction generated an exception", it)
|
||||
}
|
||||
|
||||
// convert to elapsed time here
|
||||
@@ -239,7 +239,7 @@ private class WorkerImpl(scope: CoroutineScope, task: WorkerTask) : WorkerIntern
|
||||
}
|
||||
}
|
||||
|
||||
override fun onProgressUpdate(minDelay: Int, minInterval: Int, asCompletionListener: Boolean, block: WorkerUpdateLister): Worker {
|
||||
override fun onProgressUpdate(minDelay: Int, minInterval: Int, asCompletionListener: Boolean, block: JobUpdateLister): Job {
|
||||
onProgressUpdate?.let { throw IllegalStateException() }
|
||||
if (asCompletionListener) onCompleted(block)
|
||||
if (isComplete) return this
|
||||
@@ -250,7 +250,7 @@ private class WorkerImpl(scope: CoroutineScope, task: WorkerTask) : WorkerIntern
|
||||
return this
|
||||
}
|
||||
|
||||
override fun onCompleted(block: WorkerUpdateLister): Worker {
|
||||
override fun onCompleted(block: JobUpdateLister): Job {
|
||||
if (isComplete) {
|
||||
block(1.0, startTimeOrElapsedTime)
|
||||
return this
|
||||
@@ -260,7 +260,7 @@ private class WorkerImpl(scope: CoroutineScope, task: WorkerTask) : WorkerIntern
|
||||
onCompleted = if (cur == null) {
|
||||
block
|
||||
} else {
|
||||
fun Worker.(prog: Double, el: Long) {
|
||||
fun Job.(prog: Double, el: Long) {
|
||||
cur(prog, el)
|
||||
block(prog, el)
|
||||
}
|
||||
@@ -315,25 +315,25 @@ private class WorkerImpl(scope: CoroutineScope, task: WorkerTask) : WorkerIntern
|
||||
job.join()
|
||||
}
|
||||
|
||||
private fun delegateWork(curPortion: Double, portion: Double): WorkerScope =
|
||||
private fun delegateProgress(curPortion: Double, portion: Double): JobScope =
|
||||
DelegateScope(progress, curPortion * (if (portion < 0) 1.0 - progress else portion).clampMin(0.0))
|
||||
|
||||
override fun delegateWork(portion: Double): WorkerScope = delegateWork(1.0, portion)
|
||||
override fun delegateProgress(portion: Double): JobScope = delegateProgress(1.0, portion)
|
||||
|
||||
private inner class DelegateScope(val progressStart: Double, val portion: Double) : WorkerScope {
|
||||
private inner class DelegateScope(val progressStart: Double, val portion: Double) : JobScope {
|
||||
override val elapsedTime: Long
|
||||
get() = this@WorkerImpl.elapsedTime
|
||||
get() = this@JobImpl.elapsedTime
|
||||
|
||||
override suspend fun markSuspensionPoint() =
|
||||
this@WorkerImpl.markSuspensionPoint()
|
||||
this@JobImpl.markSuspensionPoint()
|
||||
|
||||
override val progress: Double
|
||||
get() = (this@WorkerImpl.progress - progressStart) / portion
|
||||
get() = (this@JobImpl.progress - progressStart) / portion
|
||||
|
||||
override fun setProgress(progress: Double) =
|
||||
this@WorkerImpl.setProgress(progressStart + progress * portion)
|
||||
this@JobImpl.setProgress(progressStart + progress * portion)
|
||||
|
||||
override fun delegateWork(portion: Double): WorkerScope =
|
||||
this@WorkerImpl.delegateWork(this.portion, portion)
|
||||
override fun delegateProgress(portion: Double): JobScope =
|
||||
this@JobImpl.delegateProgress(this.portion, portion)
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
package io.dico.parcels2.blockvisitor
|
||||
|
||||
import io.dico.parcels2.util.Region
|
||||
import io.dico.parcels2.util.Vec3i
|
||||
import io.dico.parcels2.util.ext.clampMax
|
||||
import io.dico.parcels2.util.math.Dimension
|
||||
import io.dico.parcels2.util.math.Region
|
||||
import io.dico.parcels2.util.math.Vec3i
|
||||
import io.dico.parcels2.util.math.ext.clampMax
|
||||
|
||||
private typealias Scope = SequenceScope<Vec3i>
|
||||
|
||||
@@ -54,9 +55,9 @@ sealed class RegionTraverser {
|
||||
val (primary, secondary, tertiary) = order.toArray()
|
||||
val (origin, size) = region
|
||||
|
||||
val maxOfPrimary = primary.extract(size) - 1
|
||||
val maxOfSecondary = secondary.extract(size) - 1
|
||||
val maxOfTertiary = tertiary.extract(size) - 1
|
||||
val maxOfPrimary = size[primary] - 1
|
||||
val maxOfSecondary = size[secondary] - 1
|
||||
val maxOfTertiary = size[tertiary] - 1
|
||||
|
||||
val isPrimaryIncreasing = direction.isIncreasing(primary)
|
||||
val isSecondaryIncreasing = direction.isIncreasing(secondary)
|
||||
@@ -137,24 +138,6 @@ sealed class RegionTraverser {
|
||||
|
||||
}
|
||||
|
||||
enum class Dimension {
|
||||
X,
|
||||
Y,
|
||||
Z;
|
||||
|
||||
fun extract(block: Vec3i) =
|
||||
when (this) {
|
||||
X -> block.x
|
||||
Y -> block.y
|
||||
Z -> block.z
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val values = values()
|
||||
operator fun get(ordinal: Int) = values[ordinal]
|
||||
}
|
||||
}
|
||||
|
||||
object TraverseOrderFactory {
|
||||
private fun isSwap(primary: Dimension, secondary: Dimension) = secondary.ordinal != (primary.ordinal + 1) % 3
|
||||
|
||||
@@ -194,15 +177,15 @@ inline class TraverseOrder(val orderNum: Int) {
|
||||
*/
|
||||
fun toArray() = arrayOf(primary, secondary, tertiary)
|
||||
|
||||
fun add(vec: Vec3i, dp: Int, ds: Int, dt: Int): Vec3i =
|
||||
fun add(vec: Vec3i, p: Int, s: Int, t: Int): Vec3i =
|
||||
// optimize this, will be called lots
|
||||
when (orderNum) {
|
||||
0 -> vec.add(dp, ds, dt) // xyz
|
||||
1 -> vec.add(dt, dp, ds) // yzx
|
||||
2 -> vec.add(ds, dt, dp) // zxy
|
||||
3 -> vec.add(dp, dt, ds) // xzy
|
||||
4 -> vec.add(ds, dp, dt) // yxz
|
||||
5 -> vec.add(dt, ds, dp) // zyx
|
||||
0 -> vec.add(p, s, t) // xyz
|
||||
1 -> vec.add(t, p, s) // yzx
|
||||
2 -> vec.add(s, t, p) // zxy
|
||||
3 -> vec.add(p, t, s) // xzy
|
||||
4 -> vec.add(s, p, t) // yxz
|
||||
5 -> vec.add(t, s, p) // zyx
|
||||
else -> error("Invalid orderNum $orderNum")
|
||||
}
|
||||
}
|
||||
@@ -212,9 +195,9 @@ inline class TraverseDirection(val bits: Int) {
|
||||
|
||||
fun comesFirst(current: Vec3i, block: Vec3i, dimension: Dimension): Boolean =
|
||||
if (isIncreasing(dimension))
|
||||
dimension.extract(block) <= dimension.extract(current)
|
||||
block[dimension] <= current[dimension]
|
||||
else
|
||||
dimension.extract(block) >= dimension.extract(current)
|
||||
block[dimension] >= current[dimension]
|
||||
|
||||
fun comesFirst(current: Vec3i, block: Vec3i) =
|
||||
comesFirst(current, block, Dimension.X)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.dico.parcels2.blockvisitor
|
||||
|
||||
import io.dico.parcels2.util.Region
|
||||
import io.dico.parcels2.util.Vec3i
|
||||
import io.dico.parcels2.util.get
|
||||
import io.dico.parcels2.util.math.Region
|
||||
import io.dico.parcels2.util.math.Vec3i
|
||||
import io.dico.parcels2.util.math.get
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.World
|
||||
@@ -24,7 +24,7 @@ class Schematic {
|
||||
private var isLoaded = false; private set
|
||||
private val traverser: RegionTraverser = RegionTraverser.upward
|
||||
|
||||
suspend fun WorkerScope.load(world: World, region: Region) {
|
||||
suspend fun JobScope.load(world: World, region: Region) {
|
||||
_size = region.size
|
||||
|
||||
val data = arrayOfNulls<BlockData>(region.blockCount).also { blockDatas = it }
|
||||
@@ -52,7 +52,7 @@ class Schematic {
|
||||
isLoaded = true
|
||||
}
|
||||
|
||||
suspend fun WorkerScope.paste(world: World, position: Vec3i) {
|
||||
suspend fun JobScope.paste(world: World, position: Vec3i) {
|
||||
if (!isLoaded) throw IllegalStateException()
|
||||
|
||||
val region = Region(position, _size!!)
|
||||
@@ -108,11 +108,11 @@ class Schematic {
|
||||
}
|
||||
}
|
||||
|
||||
fun getLoadTask(world: World, region: Region): WorkerTask = {
|
||||
fun getLoadTask(world: World, region: Region): JobFunction = {
|
||||
load(world, region)
|
||||
}
|
||||
|
||||
fun getPasteTask(world: World, position: Vec3i): WorkerTask = {
|
||||
fun getPasteTask(world: World, position: Vec3i): JobFunction = {
|
||||
paste(world, position)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import io.dico.parcels2.ParcelsPlugin
|
||||
import io.dico.parcels2.PlayerProfile
|
||||
import io.dico.parcels2.PlayerProfile.*
|
||||
import io.dico.parcels2.PrivilegeKey
|
||||
import io.dico.parcels2.blockvisitor.Worker
|
||||
import io.dico.parcels2.blockvisitor.Job
|
||||
import io.dico.parcels2.util.ext.hasPermAdminManage
|
||||
import io.dico.parcels2.util.ext.parcelLimit
|
||||
import org.bukkit.entity.Player
|
||||
@@ -50,7 +50,7 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei
|
||||
world.blockManager.clearParcel(parcel.id)
|
||||
}
|
||||
|
||||
protected fun Worker.reportProgressUpdates(context: ExecutionContext, action: String) {
|
||||
protected fun Job.reportProgressUpdates(context: ExecutionContext, action: String) {
|
||||
onProgressUpdate(1000, 1000) { progress, elapsedTime ->
|
||||
val alt = context.getFormat(EMessageType.NUMBER)
|
||||
val main = context.getFormat(EMessageType.INFORMATIVE)
|
||||
|
||||
@@ -81,14 +81,14 @@ class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||
|
||||
@Cmd("jobs")
|
||||
fun cmdJobs(): Any? {
|
||||
val workers = plugin.workDispatcher.workers
|
||||
val workers = plugin.jobDispatcher.jobs
|
||||
println(workers.map { it.job }.joinToString(separator = "\n"))
|
||||
return "Task count: ${workers.size}"
|
||||
}
|
||||
|
||||
@Cmd("complete_jobs")
|
||||
fun cmdCompleteJobs(): Any? = cmdJobs().also {
|
||||
plugin.launch { plugin.workDispatcher.completeAllTasks() }
|
||||
plugin.launch { plugin.jobDispatcher.completeAllTasks() }
|
||||
}
|
||||
|
||||
@Cmd("message")
|
||||
|
||||
@@ -16,8 +16,8 @@ import io.dico.parcels2.command.ParcelTarget.TargetKind.Companion.OWNER_REAL
|
||||
import io.dico.parcels2.command.ParcelTarget.TargetKind.Companion.PREFER_OWNED_FOR_DEFAULT
|
||||
import io.dico.parcels2.command.ParcelTarget.TargetKind.Companion.REAL
|
||||
import io.dico.parcels2.storage.Storage
|
||||
import io.dico.parcels2.util.Vec2i
|
||||
import io.dico.parcels2.util.ext.floor
|
||||
import io.dico.parcels2.util.math.Vec2i
|
||||
import io.dico.parcels2.util.math.ext.floor
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@ package io.dico.parcels2.defaultimpl
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.blockvisitor.*
|
||||
import io.dico.parcels2.options.DefaultGeneratorOptions
|
||||
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 io.dico.parcels2.util.math.Region
|
||||
import io.dico.parcels2.util.math.Vec2i
|
||||
import io.dico.parcels2.util.math.Vec3i
|
||||
import io.dico.parcels2.util.math.ext.even
|
||||
import io.dico.parcels2.util.math.ext.umod
|
||||
import io.dico.parcels2.util.math.get
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -121,9 +121,9 @@ class DefaultParcelGenerator(
|
||||
worldId: ParcelWorldId,
|
||||
container: ParcelContainer,
|
||||
coroutineScope: CoroutineScope,
|
||||
workDispatcher: WorkDispatcher
|
||||
jobDispatcher: JobDispatcher
|
||||
): Pair<ParcelLocator, ParcelBlockManager> {
|
||||
return ParcelLocatorImpl(worldId, container) to ParcelBlockManagerImpl(worldId, coroutineScope, workDispatcher)
|
||||
return ParcelLocatorImpl(worldId, container) to ParcelBlockManagerImpl(worldId, coroutineScope, jobDispatcher)
|
||||
}
|
||||
|
||||
private inline fun <T> convertBlockLocationToId(x: Int, z: Int, mapper: (Int, Int) -> T): T? {
|
||||
@@ -158,7 +158,7 @@ class DefaultParcelGenerator(
|
||||
private inner class ParcelBlockManagerImpl(
|
||||
val worldId: ParcelWorldId,
|
||||
coroutineScope: CoroutineScope,
|
||||
override val workDispatcher: WorkDispatcher
|
||||
override val jobDispatcher: JobDispatcher
|
||||
) : ParcelBlockManagerBase(), CoroutineScope by coroutineScope {
|
||||
override val world: World = this@DefaultParcelGenerator.world
|
||||
override val parcelTraverser: RegionTraverser = RegionTraverser.convergingTo(o.floorHeight)
|
||||
@@ -177,7 +177,10 @@ class DefaultParcelGenerator(
|
||||
|
||||
override fun getRegion(parcel: ParcelId): Region {
|
||||
val bottom = getBottomBlock(parcel)
|
||||
return Region(Vec3i(bottom.x, 0, bottom.z), Vec3i(o.parcelSize, maxHeight, o.parcelSize))
|
||||
return Region(
|
||||
Vec3i(bottom.x, 0, bottom.z),
|
||||
Vec3i(o.parcelSize, maxHeight, o.parcelSize)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getRegionConsideringWorld(parcel: ParcelId): Region {
|
||||
@@ -234,12 +237,12 @@ class DefaultParcelGenerator(
|
||||
return world.getParcelById(parcelId)
|
||||
}
|
||||
|
||||
override fun submitBlockVisitor(vararg parcelIds: ParcelId, task: WorkerTask): Worker {
|
||||
override fun submitBlockVisitor(vararg parcelIds: ParcelId, task: JobFunction): Job {
|
||||
val parcels = parcelIds.mapNotNull { getParcel(it) }
|
||||
if (parcels.isEmpty()) return workDispatcher.dispatch(task)
|
||||
if (parcels.isEmpty()) return jobDispatcher.dispatch(task)
|
||||
if (parcels.any { it.hasBlockVisitors }) throw IllegalArgumentException("This parcel already has a block visitor")
|
||||
|
||||
val worker = workDispatcher.dispatch(task)
|
||||
val worker = jobDispatcher.dispatch(task)
|
||||
|
||||
for (parcel in parcels) {
|
||||
launch(start = UNDISPATCHED) {
|
||||
@@ -252,7 +255,7 @@ class DefaultParcelGenerator(
|
||||
return worker
|
||||
}
|
||||
|
||||
override fun setBiome(parcel: ParcelId, biome: Biome): Worker = submitBlockVisitor(parcel) {
|
||||
override fun setBiome(parcel: ParcelId, biome: Biome): Job = submitBlockVisitor(parcel) {
|
||||
val world = world
|
||||
val b = getBottomBlock(parcel)
|
||||
val parcelSize = o.parcelSize
|
||||
@@ -264,7 +267,7 @@ class DefaultParcelGenerator(
|
||||
}
|
||||
}
|
||||
|
||||
override fun clearParcel(parcel: ParcelId): Worker = submitBlockVisitor(parcel) {
|
||||
override fun clearParcel(parcel: ParcelId): Job = submitBlockVisitor(parcel) {
|
||||
val region = getRegion(parcel)
|
||||
val blocks = parcelTraverser.traverseRegion(region)
|
||||
val blockCount = region.blockCount.toDouble()
|
||||
@@ -288,7 +291,7 @@ class DefaultParcelGenerator(
|
||||
}
|
||||
}
|
||||
|
||||
override fun swapParcels(parcel1: ParcelId, parcel2: ParcelId): Worker = submitBlockVisitor(parcel1, parcel2) {
|
||||
override fun swapParcels(parcel1: ParcelId, parcel2: ParcelId): Job = submitBlockVisitor(parcel1, parcel2) {
|
||||
var region1 = getRegionConsideringWorld(parcel1)
|
||||
var region2 = getRegionConsideringWorld(parcel2)
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package io.dico.parcels2.defaultimpl
|
||||
import io.dico.dicore.Formatting
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.Privilege.*
|
||||
import io.dico.parcels2.util.Vec2i
|
||||
import io.dico.parcels2.util.math.Vec2i
|
||||
import io.dico.parcels2.util.ext.alsoIfTrue
|
||||
import org.bukkit.Material
|
||||
import org.joda.time.DateTime
|
||||
|
||||
@@ -58,8 +58,10 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
||||
if (worldExists) Bukkit.getWorld(worldName)!!
|
||||
else WorldCreator(worldName).generator(generator).createWorld().also { logger.info("Creating world $worldName") }
|
||||
|
||||
parcelWorld = ParcelWorldImpl(bukkitWorld, generator, worldOptions.runtime, plugin.storage,
|
||||
plugin.globalPrivileges, ::DefaultParcelContainer, plugin, plugin.workDispatcher)
|
||||
parcelWorld = ParcelWorldImpl(
|
||||
bukkitWorld, generator, worldOptions.runtime, plugin.storage,
|
||||
plugin.globalPrivileges, ::DefaultParcelContainer, plugin, plugin.jobDispatcher
|
||||
)
|
||||
|
||||
if (!worldExists) {
|
||||
val time = DateTime.now()
|
||||
@@ -95,11 +97,18 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
||||
|
||||
logger.info("Loading all parcel data...")
|
||||
val channel = plugin.storage.transmitAllParcelData()
|
||||
do {
|
||||
val pair = channel.receiveOrNull() ?: break
|
||||
val parcel = getParcelById(pair.first) ?: continue
|
||||
pair.second?.let { parcel.copyDataIgnoringDatabase(it) }
|
||||
} while (true)
|
||||
while (true) {
|
||||
val (id, data) = channel.receiveOrNull() ?: break
|
||||
val parcel = getParcelById(id) ?: continue
|
||||
data?.let { parcel.copyDataIgnoringDatabase(it) }
|
||||
}
|
||||
|
||||
val channel2 = plugin.storage.transmitAllGlobalPrivileges()
|
||||
while (true) {
|
||||
val (profile, data) = channel2.receiveOrNull() ?: break
|
||||
val key = profile as? PrivilegeKey ?: continue
|
||||
(plugin.globalPrivileges[key] as PrivilegesHolder).copyPrivilegesFrom(data)
|
||||
}
|
||||
|
||||
logger.info("Loading data completed")
|
||||
_dataIsLoaded = true
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
package io.dico.parcels2.defaultimpl
|
||||
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.blockvisitor.WorkDispatcher
|
||||
import io.dico.parcels2.blockvisitor.JobDispatcher
|
||||
import io.dico.parcels2.options.RuntimeWorldOptions
|
||||
import io.dico.parcels2.storage.Storage
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
@@ -18,7 +18,7 @@ class ParcelWorldImpl(override val world: World,
|
||||
override val globalPrivileges: GlobalPrivilegesManager,
|
||||
containerFactory: ParcelContainerFactory,
|
||||
coroutineScope: CoroutineScope,
|
||||
workDispatcher: WorkDispatcher)
|
||||
jobDispatcher: JobDispatcher)
|
||||
: ParcelWorld,
|
||||
ParcelWorldId,
|
||||
ParcelContainer, /* missing delegation */
|
||||
@@ -39,7 +39,7 @@ class ParcelWorldImpl(override val world: World,
|
||||
override val blockManager: ParcelBlockManager
|
||||
|
||||
init {
|
||||
val pair = generator.makeParcelLocatorAndBlockManager(id, container, coroutineScope, workDispatcher)
|
||||
val pair = generator.makeParcelLocatorAndBlockManager(id, container, coroutineScope, jobDispatcher)
|
||||
locator = pair.first
|
||||
blockManager = pair.second
|
||||
|
||||
|
||||
@@ -7,6 +7,12 @@ import io.dico.dicore.RegistratorListener
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.storage.Storage
|
||||
import io.dico.parcels2.util.ext.*
|
||||
import io.dico.parcels2.util.math.Dimension
|
||||
import io.dico.parcels2.util.math.Vec3d
|
||||
import io.dico.parcels2.util.math.Vec3i
|
||||
import io.dico.parcels2.util.math.ext.clampMax
|
||||
import io.dico.parcels2.util.math.ext.clampMin
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.Material.*
|
||||
import org.bukkit.World
|
||||
import org.bukkit.block.Biome
|
||||
@@ -52,6 +58,7 @@ class ParcelListeners(
|
||||
return world to world.getParcelAt(block)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Prevents players from entering plots they are banned from
|
||||
*/
|
||||
@@ -59,12 +66,36 @@ class ParcelListeners(
|
||||
val onPlayerMoveEvent = RegistratorListener<PlayerMoveEvent> l@{ event ->
|
||||
val user = event.player
|
||||
if (user.hasPermBanBypass) return@l
|
||||
val parcel = parcelProvider.getParcelAt(event.to) ?: return@l
|
||||
val toLoc = event.to
|
||||
val parcel = parcelProvider.getParcelAt(toLoc) ?: return@l
|
||||
|
||||
if (!parcel.canEnterFast(user)) {
|
||||
parcelProvider.getParcelAt(event.from)?.also {
|
||||
user.teleport(it.homeLocation)
|
||||
val region = parcel.world.blockManager.getRegion(parcel.id)
|
||||
val dimension = region.getFirstUncontainedDimensionOf(Vec3i(event.from))
|
||||
|
||||
if (dimension == null) {
|
||||
user.teleport(parcel.homeLocation)
|
||||
user.sendParcelMessage(nopermit = true, message = "You are banned from this parcel")
|
||||
} ?: run { event.to = event.from }
|
||||
|
||||
} else {
|
||||
val speed = getPlayerSpeed(user)
|
||||
val from = Vec3d(event.from)
|
||||
val to = Vec3d(toLoc).with(dimension, from[dimension])
|
||||
|
||||
var newTo = to
|
||||
dimension.otherDimensions.forEach {
|
||||
val delta = to[it] - from[it]
|
||||
newTo = newTo.add(it, delta * 100 * if (it == Dimension.Y) 0.5 else speed)
|
||||
}
|
||||
|
||||
|
||||
|
||||
event.to = Location(
|
||||
toLoc.world,
|
||||
newTo.x, newTo.y.clampMin(0.0).clampMax(255.0), newTo.z,
|
||||
toLoc.yaw, toLoc.pitch
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -607,4 +638,16 @@ class ParcelListeners(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun getPlayerSpeed(player: Player): Double =
|
||||
if (player.isFlying) {
|
||||
player.flySpeed * if (player.isSprinting) 21.6 else 10.92
|
||||
} else {
|
||||
player.walkSpeed * when {
|
||||
player.isSprinting -> 5.612
|
||||
player.isSneaking -> 1.31
|
||||
else -> 4.317
|
||||
} / 1.5 //?
|
||||
} / 20.0
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.dico.parcels2.options
|
||||
|
||||
import io.dico.parcels2.blockvisitor.TickWorktimeOptions
|
||||
import io.dico.parcels2.blockvisitor.TickJobtimeOptions
|
||||
import org.bukkit.GameMode
|
||||
import org.bukkit.Material
|
||||
import java.io.Reader
|
||||
@@ -11,7 +11,7 @@ class Options {
|
||||
var worlds: Map<String, WorldOptions> = hashMapOf()
|
||||
private set
|
||||
var storage: StorageOptions = StorageOptions()
|
||||
var tickWorktime: TickWorktimeOptions = TickWorktimeOptions(20, 1)
|
||||
var tickJobtime: TickJobtimeOptions = TickJobtimeOptions(20, 1)
|
||||
var migration = MigrationOptionsHolder()
|
||||
|
||||
fun addWorld(name: String,
|
||||
|
||||
@@ -61,9 +61,9 @@ interface Backing {
|
||||
fun setParcelOptionsInteractConfig(parcel: ParcelId, config: InteractableConfiguration)
|
||||
|
||||
|
||||
fun transmitAllGlobalAddedData(channel: SendChannel<AddedDataPair<PlayerProfile>>)
|
||||
fun transmitAllGlobalPrivileges(channel: SendChannel<PrivilegePair<PlayerProfile>>)
|
||||
|
||||
fun readGlobalPrivileges(owner: PlayerProfile): MutablePrivilegeMap
|
||||
fun readGlobalPrivileges(owner: PlayerProfile): PrivilegesHolder?
|
||||
|
||||
fun setGlobalPrivilege(owner: PlayerProfile, player: PlayerProfile, privilege: Privilege)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import java.util.UUID
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
typealias DataPair = Pair<ParcelId, ParcelData?>
|
||||
typealias AddedDataPair<TAttach> = Pair<TAttach, MutablePrivilegeMap>
|
||||
typealias PrivilegePair<TAttach> = Pair<TAttach, PrivilegesHolder>
|
||||
|
||||
interface Storage {
|
||||
val name: String
|
||||
@@ -55,9 +55,9 @@ interface Storage {
|
||||
fun setParcelOptionsInteractConfig(parcel: ParcelId, config: InteractableConfiguration): Job
|
||||
|
||||
|
||||
fun transmitAllGlobalAddedData(): ReceiveChannel<AddedDataPair<PlayerProfile>>
|
||||
fun transmitAllGlobalPrivileges(): ReceiveChannel<PrivilegePair<PlayerProfile>>
|
||||
|
||||
fun readGlobalPrivileges(owner: PlayerProfile): Deferred<MutablePrivilegeMap?>
|
||||
fun readGlobalPrivileges(owner: PlayerProfile): Deferred<PrivilegesHolder?>
|
||||
|
||||
fun setGlobalPrivilege(owner: PlayerProfile, player: PlayerProfile, privilege: Privilege): Job
|
||||
|
||||
@@ -104,9 +104,9 @@ class BackedStorage internal constructor(val b: Backing) : Storage, CoroutineSco
|
||||
override fun setParcelOptionsInteractConfig(parcel: ParcelId, config: InteractableConfiguration) = b.launchJob { b.setParcelOptionsInteractConfig(parcel, config) }
|
||||
|
||||
|
||||
override fun transmitAllGlobalAddedData(): ReceiveChannel<AddedDataPair<PlayerProfile>> = b.openChannel { b.transmitAllGlobalAddedData(it) }
|
||||
override fun transmitAllGlobalPrivileges(): ReceiveChannel<PrivilegePair<PlayerProfile>> = b.openChannel { b.transmitAllGlobalPrivileges(it) }
|
||||
|
||||
override fun readGlobalPrivileges(owner: PlayerProfile): Deferred<MutablePrivilegeMap?> = b.launchFuture { b.readGlobalPrivileges(owner) }
|
||||
override fun readGlobalPrivileges(owner: PlayerProfile): Deferred<PrivilegesHolder?> = b.launchFuture { b.readGlobalPrivileges(owner) }
|
||||
|
||||
override fun setGlobalPrivilege(owner: PlayerProfile, player: PlayerProfile, privilege: Privilege) = b.launchJob { b.setGlobalPrivilege(owner, player, privilege) }
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.zaxxer.hikari.HikariDataSource
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.PlayerProfile.Star.name
|
||||
import io.dico.parcels2.storage.*
|
||||
import io.dico.parcels2.util.ext.clampMax
|
||||
import io.dico.parcels2.util.math.ext.clampMax
|
||||
import io.dico.parcels2.util.ext.synchronized
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.ArrayChannel
|
||||
@@ -193,6 +193,10 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
|
||||
PrivilegesLocalT.setPrivilege(parcel, profile, privilege)
|
||||
}
|
||||
|
||||
data.privilegeOfStar.takeIf { it != Privilege.DEFAULT }?.let { privilege ->
|
||||
PrivilegesLocalT.setPrivilege(parcel, PlayerProfile.Star, privilege)
|
||||
}
|
||||
|
||||
setParcelOptionsInteractConfig(parcel, data.interactableConfig)
|
||||
}
|
||||
|
||||
@@ -242,13 +246,13 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
|
||||
}
|
||||
}
|
||||
|
||||
override fun transmitAllGlobalAddedData(channel: SendChannel<AddedDataPair<PlayerProfile>>) {
|
||||
PrivilegesGlobalT.sendAllAddedData(channel)
|
||||
override fun transmitAllGlobalPrivileges(channel: SendChannel<PrivilegePair<PlayerProfile>>) {
|
||||
PrivilegesGlobalT.sendAllPrivilegesH(channel)
|
||||
channel.close()
|
||||
}
|
||||
|
||||
override fun readGlobalPrivileges(owner: PlayerProfile): MutablePrivilegeMap {
|
||||
return PrivilegesGlobalT.readPrivileges(ProfilesT.getId(owner.toOwnerProfile()) ?: return hashMapOf())
|
||||
override fun readGlobalPrivileges(owner: PlayerProfile): PrivilegesHolder? {
|
||||
return PrivilegesGlobalT.readPrivileges(ProfilesT.getId(owner.toOwnerProfile()) ?: return null)
|
||||
}
|
||||
|
||||
override fun setGlobalPrivilege(owner: PlayerProfile, player: PlayerProfile, privilege: Privilege) {
|
||||
@@ -267,7 +271,10 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
|
||||
System.arraycopy(source, 0, target, 0, source.size.clampMax(target.size))
|
||||
}
|
||||
|
||||
privilegeMap = PrivilegesLocalT.readPrivileges(id)
|
||||
val privileges = PrivilegesLocalT.readPrivileges(id)
|
||||
if (privileges != null) {
|
||||
copyPrivilegesFrom(privileges)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ object ParcelOptionsT : Table("parcel_options") {
|
||||
val interact_bitmask = binary("interact_bitmask", 4)
|
||||
}
|
||||
|
||||
typealias PrivilegesSendChannel<AttachT> = SendChannel<Pair<AttachT, MutablePrivilegeMap>>
|
||||
typealias PrivilegesSendChannel<AttachT> = SendChannel<Pair<AttachT, PrivilegesHolder>>
|
||||
|
||||
sealed class PrivilegesTable<AttachT>(name: String, val idTable: IdTransactionsTable<*, AttachT>) : Table(name) {
|
||||
val attach_id = integer("attach_id").references(idTable.id, ReferenceOption.CASCADE)
|
||||
@@ -43,32 +43,32 @@ sealed class PrivilegesTable<AttachT>(name: String, val idTable: IdTransactionsT
|
||||
}
|
||||
}
|
||||
|
||||
fun readPrivileges(id: Int): MutablePrivilegeMap {
|
||||
fun readPrivileges(id: Int): PrivilegesHolder? {
|
||||
val list = slice(profile_id, privilege).select { attach_id eq id }
|
||||
val result = MutablePrivilegeMap()
|
||||
val result = PrivilegesHolder()
|
||||
for (row in list) {
|
||||
val profile = ProfilesT.getRealItem(row[profile_id]) ?: continue
|
||||
result[profile] = Privilege.getByNumber(row[privilege]) ?: continue
|
||||
result.setRawStoredPrivilege(profile, Privilege.getByNumber(row[privilege]) ?: continue)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun sendAllAddedData(channel: PrivilegesSendChannel<AttachT>) {
|
||||
fun sendAllPrivilegesH(channel: PrivilegesSendChannel<AttachT>) {
|
||||
val iterator = selectAll().orderBy(attach_id).iterator()
|
||||
|
||||
if (iterator.hasNext()) {
|
||||
val firstRow = iterator.next()
|
||||
var id: Int = firstRow[attach_id]
|
||||
var attach: AttachT? = null
|
||||
var map: MutablePrivilegeMap? = null
|
||||
var map: PrivilegesHolder? = null
|
||||
|
||||
fun initAttachAndMap() {
|
||||
attach = idTable.getItem(id)
|
||||
map = attach?.let { mutableMapOf() }
|
||||
map = attach?.let { PrivilegesHolder() }
|
||||
}
|
||||
|
||||
fun sendIfPresent() {
|
||||
if (attach != null && map != null && map!!.isNotEmpty()) {
|
||||
if (attach != null && map != null) {
|
||||
channel.offer(attach!! to map!!)
|
||||
}
|
||||
attach = null
|
||||
@@ -91,7 +91,7 @@ sealed class PrivilegesTable<AttachT>(name: String, val idTable: IdTransactionsT
|
||||
|
||||
val profile = ProfilesT.getRealItem(row[profile_id]) ?: continue
|
||||
val privilege = Privilege.getByNumber(row[privilege]) ?: continue
|
||||
map!![profile] = privilege
|
||||
map!!.setRawStoredPrivilege(profile, privilege)
|
||||
}
|
||||
|
||||
sendIfPresent()
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
package io.dico.parcels2.util
|
||||
|
||||
data class Region(val origin: Vec3i, val size: Vec3i) {
|
||||
val blockCount: Int get() = size.x * size.y * size.z
|
||||
|
||||
val center: Vec3d
|
||||
get() {
|
||||
val x = (origin.x + size.x) / 2.0
|
||||
val y = (origin.y + size.y) / 2.0
|
||||
val z = (origin.z + size.z) / 2.0
|
||||
return Vec3d(x, y, z)
|
||||
}
|
||||
|
||||
fun withSize(size: Vec3i): Region {
|
||||
if (size == this.size) return this
|
||||
return Region(origin, size)
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package io.dico.parcels2.util
|
||||
|
||||
data class Vec2i(
|
||||
val x: Int,
|
||||
val z: Int
|
||||
)
|
||||
|
||||
data class Region2i(
|
||||
val bottom: Vec2i,
|
||||
val top: Vec2i
|
||||
)
|
||||
@@ -77,3 +77,8 @@ class EditLoopScope<T, U>(val _map: MutableMap<T, U>) {
|
||||
|
||||
operator fun Formatting.plus(other: Formatting) = toString() + other
|
||||
operator fun Formatting.plus(other: String) = toString() + other
|
||||
|
||||
inline fun <T> Pair<T, T>.forEach(block: (T) -> Unit) {
|
||||
block(first)
|
||||
block(second)
|
||||
}
|
||||
|
||||
19
src/main/kotlin/io/dico/parcels2/util/math/Dimension.kt
Normal file
19
src/main/kotlin/io/dico/parcels2/util/math/Dimension.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
package io.dico.parcels2.util.math
|
||||
|
||||
enum class Dimension {
|
||||
X,
|
||||
Y,
|
||||
Z;
|
||||
|
||||
val otherDimensions
|
||||
get() = when (this) {
|
||||
X -> Y to Z
|
||||
Y -> X to Z
|
||||
Z -> X to Y
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val values = values()
|
||||
operator fun get(ordinal: Int) = values[ordinal]
|
||||
}
|
||||
}
|
||||
37
src/main/kotlin/io/dico/parcels2/util/math/Region.kt
Normal file
37
src/main/kotlin/io/dico/parcels2/util/math/Region.kt
Normal file
@@ -0,0 +1,37 @@
|
||||
package io.dico.parcels2.util.math
|
||||
|
||||
data class Region(val origin: Vec3i, val size: Vec3i) {
|
||||
val blockCount: Int get() = size.x * size.y * size.z
|
||||
|
||||
val center: Vec3d
|
||||
get() {
|
||||
val x = (origin.x + size.x) / 2.0
|
||||
val y = (origin.y + size.y) / 2.0
|
||||
val z = (origin.z + size.z) / 2.0
|
||||
return Vec3d(x, y, z)
|
||||
}
|
||||
|
||||
val end: Vec3i
|
||||
get() = origin + size
|
||||
|
||||
val max: Vec3i
|
||||
get() = Vec3i(origin.x + size.x - 1, origin.y + size.y - 1, origin.z + size.z - 1)
|
||||
|
||||
fun withSize(size: Vec3i): Region {
|
||||
if (size == this.size) return this
|
||||
return Region(origin, size)
|
||||
}
|
||||
|
||||
operator fun contains(loc: Vec3i): Boolean = getFirstUncontainedDimensionOf(loc) == null
|
||||
|
||||
fun getFirstUncontainedDimensionOf(loc: Vec3i): Dimension? {
|
||||
val max = max
|
||||
return when {
|
||||
loc.x !in origin.x..max.x -> Dimension.X
|
||||
loc.z !in origin.z..max.z -> Dimension.Z
|
||||
loc.y !in origin.y..max.y -> Dimension.Y
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
6
src/main/kotlin/io/dico/parcels2/util/math/Vec2i.kt
Normal file
6
src/main/kotlin/io/dico/parcels2/util/math/Vec2i.kt
Normal file
@@ -0,0 +1,6 @@
|
||||
package io.dico.parcels2.util.math
|
||||
|
||||
data class Vec2i(
|
||||
val x: Int,
|
||||
val z: Int
|
||||
)
|
||||
54
src/main/kotlin/io/dico/parcels2/util/math/Vec3d.kt
Normal file
54
src/main/kotlin/io/dico/parcels2/util/math/Vec3d.kt
Normal file
@@ -0,0 +1,54 @@
|
||||
package io.dico.parcels2.util.math
|
||||
|
||||
import io.dico.parcels2.util.math.ext.floor
|
||||
import org.bukkit.Location
|
||||
import kotlin.math.sqrt
|
||||
|
||||
data class Vec3d(
|
||||
val x: Double,
|
||||
val y: Double,
|
||||
val z: Double
|
||||
) {
|
||||
constructor(loc: Location) : this(loc.x, loc.y, loc.z)
|
||||
|
||||
operator fun plus(o: Vec3d) = Vec3d(x + o.x, y + o.y, z + o.z)
|
||||
operator fun minus(o: Vec3i) = Vec3d(x - o.x, y - o.y, z - o.z)
|
||||
infix fun addX(o: Double) = Vec3d(x + o, y, z)
|
||||
infix fun addY(o: Double) = Vec3d(x, y + o, z)
|
||||
infix fun addZ(o: Double) = Vec3d(x, y, z + o)
|
||||
infix fun withX(o: Double) = Vec3d(o, y, z)
|
||||
infix fun withY(o: Double) = Vec3d(x, o, z)
|
||||
infix fun withZ(o: Double) = Vec3d(x, y, o)
|
||||
fun add(ox: Double, oy: Double, oz: Double) = Vec3d(x + ox, y + oy, z + oz)
|
||||
fun toVec3i() = Vec3i(x.floor(), y.floor(), z.floor())
|
||||
|
||||
fun distanceSquared(o: Vec3d): Double {
|
||||
val dx = o.x - x
|
||||
val dy = o.y - y
|
||||
val dz = o.z - z
|
||||
return dx * dx + dy * dy + dz * dz
|
||||
}
|
||||
|
||||
fun distance(o: Vec3d) = sqrt(distanceSquared(o))
|
||||
|
||||
operator fun get(dimension: Dimension) =
|
||||
when (dimension) {
|
||||
Dimension.X -> x
|
||||
Dimension.Y -> y
|
||||
Dimension.Z -> z
|
||||
}
|
||||
|
||||
fun with(dimension: Dimension, value: Double) =
|
||||
when (dimension) {
|
||||
Dimension.X -> withX(value)
|
||||
Dimension.Y -> withY(value)
|
||||
Dimension.Z -> withZ(value)
|
||||
}
|
||||
|
||||
fun add(dimension: Dimension, value: Double) =
|
||||
when (dimension) {
|
||||
Dimension.X -> addX(value)
|
||||
Dimension.Y -> addY(value)
|
||||
Dimension.Z -> addZ(value)
|
||||
}
|
||||
}
|
||||
@@ -1,31 +1,18 @@
|
||||
package io.dico.parcels2.util
|
||||
package io.dico.parcels2.util.math
|
||||
|
||||
import io.dico.parcels2.util.ext.clampMax
|
||||
import io.dico.parcels2.util.math.ext.clampMax
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.World
|
||||
import org.bukkit.block.Block
|
||||
import org.bukkit.block.BlockFace
|
||||
|
||||
data class Vec3d(
|
||||
val x: Double,
|
||||
val y: Double,
|
||||
val z: Double
|
||||
) {
|
||||
operator fun plus(o: Vec3d) = Vec3d(x + o.x, y + o.y, z + o.z)
|
||||
operator fun minus(o: Vec3i) = Vec3d(x - o.x, y - o.y, z - o.z)
|
||||
infix fun addX(o: Double) = Vec3d(x + o, y, z)
|
||||
infix fun addY(o: Double) = Vec3d(x, y + o, z)
|
||||
infix fun addZ(o: Double) = Vec3d(x, y, z + o)
|
||||
infix fun withX(o: Double) = Vec3d(o, y, z)
|
||||
infix fun withY(o: Double) = Vec3d(x, o, z)
|
||||
infix fun withZ(o: Double) = Vec3d(x, y, o)
|
||||
fun add(ox: Double, oy: Double, oz: Double) = Vec3d(x + ox, y + oy, z + oz)
|
||||
}
|
||||
|
||||
data class Vec3i(
|
||||
val x: Int,
|
||||
val y: Int,
|
||||
val z: Int
|
||||
) {
|
||||
constructor(loc: Location) : this(loc.blockX, loc.blockY, loc.blockZ)
|
||||
|
||||
operator fun plus(o: Vec3i) = Vec3i(x + o.x, y + o.y, z + o.z)
|
||||
operator fun minus(o: Vec3i) = Vec3i(x - o.x, y - o.y, z - o.z)
|
||||
infix fun addX(o: Int) = Vec3i(x + o, y, z)
|
||||
@@ -38,6 +25,27 @@ data class Vec3i(
|
||||
fun neg() = Vec3i(-x, -y, -z)
|
||||
fun clampMax(o: Vec3i) = Vec3i(x.clampMax(o.x), y.clampMax(o.y), z.clampMax(o.z))
|
||||
|
||||
operator fun get(dimension: Dimension) =
|
||||
when (dimension) {
|
||||
Dimension.X -> x
|
||||
Dimension.Y -> y
|
||||
Dimension.Z -> z
|
||||
}
|
||||
|
||||
fun with(dimension: Dimension, value: Int) =
|
||||
when (dimension) {
|
||||
Dimension.X -> withX(value)
|
||||
Dimension.Y -> withY(value)
|
||||
Dimension.Z -> withZ(value)
|
||||
}
|
||||
|
||||
fun add(dimension: Dimension, value: Int) =
|
||||
when (dimension) {
|
||||
Dimension.X -> addX(value)
|
||||
Dimension.Y -> addY(value)
|
||||
Dimension.Z -> addZ(value)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private operator fun invoke(face: BlockFace) = Vec3i(face.modX, face.modY, face.modZ)
|
||||
val down = Vec3i(BlockFace.DOWN)
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.dico.parcels2.util.ext
|
||||
package io.dico.parcels2.util.math.ext
|
||||
|
||||
fun Double.floor(): Int {
|
||||
val down = toInt()
|
||||
@@ -34,6 +34,7 @@ fun IntRange.clamp(min: Int, max: Int): IntRange {
|
||||
// the name coerceAtMost is bad
|
||||
fun Int.clampMax(max: Int) = coerceAtMost(max)
|
||||
fun Double.clampMin(min: Double) = coerceAtLeast(min)
|
||||
fun Double.clampMax(max: Double) = coerceAtMost(max)
|
||||
|
||||
// Why does this not exist?
|
||||
infix fun Int.ceilDiv(divisor: Int): Int {
|
||||
Reference in New Issue
Block a user