Fixes n tweaks
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
package io.dico.parcels2
|
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 io.dico.parcels2.util.ext.getMaterialsWithWoodTypePrefix
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import java.util.EnumMap
|
import java.util.EnumMap
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
import io.dico.parcels2.util.Vec2i
|
import io.dico.parcels2.util.math.Vec2i
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
import io.dico.parcels2.blockvisitor.*
|
import io.dico.parcels2.blockvisitor.*
|
||||||
import io.dico.parcels2.util.Region
|
import io.dico.parcels2.util.math.Region
|
||||||
import io.dico.parcels2.util.Vec2i
|
import io.dico.parcels2.util.math.Vec2i
|
||||||
import io.dico.parcels2.util.get
|
import io.dico.parcels2.util.math.get
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import org.bukkit.Chunk
|
import org.bukkit.Chunk
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
@@ -37,12 +37,12 @@ abstract class ParcelGenerator : ChunkGenerator() {
|
|||||||
abstract fun makeParcelLocatorAndBlockManager(worldId: ParcelWorldId,
|
abstract fun makeParcelLocatorAndBlockManager(worldId: ParcelWorldId,
|
||||||
container: ParcelContainer,
|
container: ParcelContainer,
|
||||||
coroutineScope: CoroutineScope,
|
coroutineScope: CoroutineScope,
|
||||||
workDispatcher: WorkDispatcher): Pair<ParcelLocator, ParcelBlockManager>
|
jobDispatcher: JobDispatcher): Pair<ParcelLocator, ParcelBlockManager>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ParcelBlockManager {
|
interface ParcelBlockManager {
|
||||||
val world: World
|
val world: World
|
||||||
val workDispatcher: WorkDispatcher
|
val jobDispatcher: JobDispatcher
|
||||||
val parcelTraverser: RegionTraverser
|
val parcelTraverser: RegionTraverser
|
||||||
|
|
||||||
// fun getBottomBlock(parcel: ParcelId): Vec2i
|
// fun getBottomBlock(parcel: ParcelId): Vec2i
|
||||||
@@ -55,13 +55,13 @@ interface ParcelBlockManager {
|
|||||||
|
|
||||||
fun setOwnerBlock(parcel: ParcelId, owner: PlayerProfile?)
|
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
|
* Used to update owner blocks in the corner of the parcel
|
||||||
@@ -71,7 +71,7 @@ interface ParcelBlockManager {
|
|||||||
|
|
||||||
inline fun ParcelBlockManager.doBlockOperation(parcel: ParcelId,
|
inline fun ParcelBlockManager.doBlockOperation(parcel: ParcelId,
|
||||||
traverser: RegionTraverser,
|
traverser: RegionTraverser,
|
||||||
crossinline operation: suspend WorkerScope.(Block) -> Unit) = submitBlockVisitor(parcel) {
|
crossinline operation: suspend JobScope.(Block) -> Unit) = submitBlockVisitor(parcel) {
|
||||||
val region = getRegion(parcel)
|
val region = getRegion(parcel)
|
||||||
val blockCount = region.blockCount.toDouble()
|
val blockCount = region.blockCount.toDouble()
|
||||||
val blocks = traverser.traverseRegion(region)
|
val blocks = traverser.traverseRegion(region)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
import io.dico.parcels2.util.Vec2i
|
import io.dico.parcels2.util.math.Vec2i
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ package io.dico.parcels2
|
|||||||
|
|
||||||
import io.dico.parcels2.options.RuntimeWorldOptions
|
import io.dico.parcels2.options.RuntimeWorldOptions
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import io.dico.parcels2.util.Vec2i
|
import io.dico.parcels2.util.math.Vec2i
|
||||||
import io.dico.parcels2.util.ext.floor
|
import io.dico.parcels2.util.math.ext.floor
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
import org.bukkit.block.Block
|
import org.bukkit.block.Block
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package io.dico.parcels2
|
|||||||
import io.dico.dicore.Registrator
|
import io.dico.dicore.Registrator
|
||||||
import io.dico.dicore.command.EOverridePolicy
|
import io.dico.dicore.command.EOverridePolicy
|
||||||
import io.dico.dicore.command.ICommandDispatcher
|
import io.dico.dicore.command.ICommandDispatcher
|
||||||
import io.dico.parcels2.blockvisitor.BukkitWorkDispatcher
|
import io.dico.parcels2.blockvisitor.BukkitJobDispatcher
|
||||||
import io.dico.parcels2.blockvisitor.WorkDispatcher
|
import io.dico.parcels2.blockvisitor.JobDispatcher
|
||||||
import io.dico.parcels2.command.getParcelCommands
|
import io.dico.parcels2.command.getParcelCommands
|
||||||
import io.dico.parcels2.defaultimpl.GlobalPrivilegesManagerImpl
|
import io.dico.parcels2.defaultimpl.GlobalPrivilegesManagerImpl
|
||||||
import io.dico.parcels2.defaultimpl.ParcelProviderImpl
|
import io.dico.parcels2.defaultimpl.ParcelProviderImpl
|
||||||
@@ -44,7 +44,7 @@ class ParcelsPlugin : JavaPlugin(), CoroutineScope, PluginScheduler {
|
|||||||
|
|
||||||
override val coroutineContext: CoroutineContext = MainThreadDispatcher(this)
|
override val coroutineContext: CoroutineContext = MainThreadDispatcher(this)
|
||||||
override val plugin: Plugin get() = 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() {
|
override fun onEnable() {
|
||||||
plogger.info("Debug enabled: ${plogger.isDebugEnabled}")
|
plogger.info("Debug enabled: ${plogger.isDebugEnabled}")
|
||||||
@@ -55,11 +55,11 @@ class ParcelsPlugin : JavaPlugin(), CoroutineScope, PluginScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onDisable() {
|
override fun onDisable() {
|
||||||
val hasWorkers = workDispatcher.workers.isNotEmpty()
|
val hasWorkers = jobDispatcher.jobs.isNotEmpty()
|
||||||
if (hasWorkers) {
|
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) {
|
if (hasWorkers) {
|
||||||
plogger.info("Parcels has completed the remaining jobs.")
|
plogger.info("Parcels has completed the remaining jobs.")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ interface RawPrivileges {
|
|||||||
open class PrivilegesHolder(override var privilegeMap: MutablePrivilegeMap = EmptyPrivilegeMap) : RawPrivileges {
|
open class PrivilegesHolder(override var privilegeMap: MutablePrivilegeMap = EmptyPrivilegeMap) : RawPrivileges {
|
||||||
private var _privilegeOfStar: Privilege = DEFAULT
|
private var _privilegeOfStar: Privilege = DEFAULT
|
||||||
|
|
||||||
override var privilegeOfStar: Privilege
|
override /*open*/ var privilegeOfStar: Privilege
|
||||||
get() = _privilegeOfStar
|
get() = _privilegeOfStar
|
||||||
set(value) = run { _privilegeOfStar = value }
|
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
|
return if (privilege == DEFAULT) privilegeMap.remove(key) != null
|
||||||
else privilegeMap.put(key, privilege) != privilege
|
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
|
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.getMaterialsWithWoodTypePrefix
|
||||||
import io.dico.parcels2.util.ext.getMaterialsWithWoolColorPrefix
|
import io.dico.parcels2.util.ext.getMaterialsWithWoolColorPrefix
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ package io.dico.parcels2.blockvisitor
|
|||||||
|
|
||||||
import io.dico.parcels2.ParcelsPlugin
|
import io.dico.parcels2.ParcelsPlugin
|
||||||
import io.dico.parcels2.logger
|
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.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.CoroutineStart.LAZY
|
import kotlinx.coroutines.CoroutineStart.LAZY
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job as CoroutineJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.bukkit.scheduler.BukkitTask
|
import org.bukkit.scheduler.BukkitTask
|
||||||
import java.lang.System.currentTimeMillis
|
import java.lang.System.currentTimeMillis
|
||||||
@@ -16,21 +16,21 @@ import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
|
|||||||
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
|
import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
|
||||||
import kotlin.coroutines.resume
|
import kotlin.coroutines.resume
|
||||||
|
|
||||||
typealias WorkerTask = suspend WorkerScope.() -> Unit
|
typealias JobFunction = suspend JobScope.() -> Unit
|
||||||
typealias WorkerUpdateLister = Worker.(Double, Long) -> 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
|
* 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.
|
* Attempts to complete any remaining tasks immediately, without suspension.
|
||||||
@@ -38,27 +38,27 @@ interface WorkDispatcher {
|
|||||||
fun completeAllTasks()
|
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
|
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.
|
* with no guarantees to its accuracy.
|
||||||
*/
|
*/
|
||||||
val progress: Double
|
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
|
val isComplete: Boolean
|
||||||
|
|
||||||
@@ -69,28 +69,28 @@ interface Worker : WorkerAndScopeMembersUnion {
|
|||||||
val completionException: Throwable?
|
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.
|
* if [minInterval] milliseconds expired since the last call.
|
||||||
* The first call occurs after at least [minDelay] milliseconds in a likewise manner.
|
* The first call occurs after at least [minDelay] milliseconds in a likewise manner.
|
||||||
* Repeated invocations of this method result in an [IllegalStateException]
|
* Repeated invocations of this method result in an [IllegalStateException]
|
||||||
*
|
*
|
||||||
* if [asCompletionListener] is true, [onCompleted] is called with the same [block]
|
* 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.
|
* 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()
|
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.
|
* 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)
|
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
|
* 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 {
|
inline fun <T> JobScope.delegateWork(portion: Double = -1.0, block: JobScope.() -> T): T {
|
||||||
delegateWork(portion).apply {
|
delegateProgress(portion).apply {
|
||||||
val result = block()
|
val result = block()
|
||||||
markComplete()
|
markComplete()
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WorkerInternal : Worker, WorkerScope {
|
interface JobInternal : Job, JobScope {
|
||||||
/**
|
/**
|
||||||
* Start or resumes the execution of this worker
|
* Start or resumes the execution of this job
|
||||||
* and returns true if the worker completed
|
* and returns true if the job completed
|
||||||
*
|
*
|
||||||
* [worktime] is the maximum amount of time, in milliseconds,
|
* [worktime] is the maximum amount of time, in milliseconds,
|
||||||
* that this job may run for until suspension.
|
* 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.
|
* without suspension and this method will always return true.
|
||||||
*/
|
*/
|
||||||
fun resume(worktime: Long): Boolean
|
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.
|
* 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
|
* 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
|
// The currently registered bukkit scheduler task
|
||||||
private var bukkitTask: BukkitTask? = null
|
private var bukkitTask: BukkitTask? = null
|
||||||
// The workers.
|
// The jobs.
|
||||||
private val _workers = LinkedList<WorkerInternal>()
|
private val _jobs = LinkedList<JobInternal>()
|
||||||
override val workers: List<Worker> = _workers
|
override val jobs: List<Job> = _jobs
|
||||||
|
|
||||||
override fun dispatch(task: WorkerTask): Worker {
|
override fun dispatch(task: JobFunction): Job {
|
||||||
val worker: WorkerInternal = WorkerImpl(plugin, task)
|
val job: JobInternal = JobImpl(plugin, task)
|
||||||
|
|
||||||
if (bukkitTask == null) {
|
if (bukkitTask == null) {
|
||||||
val completed = worker.resume(options.workTime.toLong())
|
val completed = job.resume(options.jobTime.toLong())
|
||||||
if (completed) return worker
|
if (completed) return job
|
||||||
bukkitTask = plugin.scheduleRepeating(0, options.tickInterval) { tickJobs() }
|
bukkitTask = plugin.scheduleRepeating(0, options.tickInterval) { tickCoroutineJobs() }
|
||||||
}
|
}
|
||||||
_workers.addFirst(worker)
|
_jobs.addFirst(job)
|
||||||
return worker
|
return job
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun tickJobs() {
|
private fun tickCoroutineJobs() {
|
||||||
val workers = _workers
|
val jobs = _jobs
|
||||||
if (workers.isEmpty()) return
|
if (jobs.isEmpty()) return
|
||||||
val tickStartTime = System.currentTimeMillis()
|
val tickStartTime = System.currentTimeMillis()
|
||||||
|
|
||||||
val iterator = workers.listIterator(index = 0)
|
val iterator = jobs.listIterator(index = 0)
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
val time = System.currentTimeMillis()
|
val time = System.currentTimeMillis()
|
||||||
val timeElapsed = time - tickStartTime
|
val timeElapsed = time - tickStartTime
|
||||||
val timeLeft = options.workTime - timeElapsed
|
val timeLeft = options.jobTime - timeElapsed
|
||||||
if (timeLeft <= 0) return
|
if (timeLeft <= 0) return
|
||||||
|
|
||||||
val count = workers.size - iterator.nextIndex()
|
val count = jobs.size - iterator.nextIndex()
|
||||||
val timePerJob = (timeLeft + count - 1) / count
|
val timePerJob = (timeLeft + count - 1) / count
|
||||||
val worker = iterator.next()
|
val job = iterator.next()
|
||||||
val completed = worker.resume(timePerJob)
|
val completed = job.resume(timePerJob)
|
||||||
if (completed) {
|
if (completed) {
|
||||||
iterator.remove()
|
iterator.remove()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (workers.isEmpty()) {
|
if (jobs.isEmpty()) {
|
||||||
bukkitTask?.cancel()
|
bukkitTask?.cancel()
|
||||||
bukkitTask = null
|
bukkitTask = null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun completeAllTasks() {
|
override fun completeAllTasks() {
|
||||||
_workers.forEach {
|
_jobs.forEach {
|
||||||
it.resume(-1)
|
it.resume(-1)
|
||||||
}
|
}
|
||||||
_workers.clear()
|
_jobs.clear()
|
||||||
bukkitTask?.cancel()
|
bukkitTask?.cancel()
|
||||||
bukkitTask = null
|
bukkitTask = null
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class WorkerImpl(scope: CoroutineScope, task: WorkerTask) : WorkerInternal {
|
private class JobImpl(scope: CoroutineScope, task: JobFunction) : JobInternal {
|
||||||
override val job: Job = scope.launch(start = LAZY) { task() }
|
override val job: CoroutineJob = scope.launch(start = LAZY) { task() }
|
||||||
|
|
||||||
private var continuation: Continuation<Unit>? = null
|
private var continuation: Continuation<Unit>? = null
|
||||||
private var nextSuspensionTime: Long = 0L
|
private var nextSuspensionTime: Long = 0L
|
||||||
@@ -217,17 +217,17 @@ private class WorkerImpl(scope: CoroutineScope, task: WorkerTask) : WorkerIntern
|
|||||||
override var completionException: Throwable? = null; private set
|
override var completionException: Throwable? = null; private set
|
||||||
|
|
||||||
private var startTimeOrElapsedTime: Long = 0L // startTime before completed, elapsed time otherwise
|
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 progressUpdateInterval: Int = 0
|
||||||
private var lastUpdateTime: Long = 0L
|
private var lastUpdateTime: Long = 0L
|
||||||
private var onCompleted: WorkerUpdateLister? = null
|
private var onCompleted: JobUpdateLister? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
job.invokeOnCompletion { exception ->
|
job.invokeOnCompletion { exception ->
|
||||||
// report any error that occurred
|
// report any error that occurred
|
||||||
completionException = exception?.also {
|
completionException = exception?.also {
|
||||||
if (it !is CancellationException)
|
if (it !is CancellationException)
|
||||||
logger.error("WorkerTask generated an exception", it)
|
logger.error("JobFunction generated an exception", it)
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert to elapsed time here
|
// 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() }
|
onProgressUpdate?.let { throw IllegalStateException() }
|
||||||
if (asCompletionListener) onCompleted(block)
|
if (asCompletionListener) onCompleted(block)
|
||||||
if (isComplete) return this
|
if (isComplete) return this
|
||||||
@@ -250,7 +250,7 @@ private class WorkerImpl(scope: CoroutineScope, task: WorkerTask) : WorkerIntern
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCompleted(block: WorkerUpdateLister): Worker {
|
override fun onCompleted(block: JobUpdateLister): Job {
|
||||||
if (isComplete) {
|
if (isComplete) {
|
||||||
block(1.0, startTimeOrElapsedTime)
|
block(1.0, startTimeOrElapsedTime)
|
||||||
return this
|
return this
|
||||||
@@ -260,7 +260,7 @@ private class WorkerImpl(scope: CoroutineScope, task: WorkerTask) : WorkerIntern
|
|||||||
onCompleted = if (cur == null) {
|
onCompleted = if (cur == null) {
|
||||||
block
|
block
|
||||||
} else {
|
} else {
|
||||||
fun Worker.(prog: Double, el: Long) {
|
fun Job.(prog: Double, el: Long) {
|
||||||
cur(prog, el)
|
cur(prog, el)
|
||||||
block(prog, el)
|
block(prog, el)
|
||||||
}
|
}
|
||||||
@@ -315,25 +315,25 @@ private class WorkerImpl(scope: CoroutineScope, task: WorkerTask) : WorkerIntern
|
|||||||
job.join()
|
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))
|
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
|
override val elapsedTime: Long
|
||||||
get() = this@WorkerImpl.elapsedTime
|
get() = this@JobImpl.elapsedTime
|
||||||
|
|
||||||
override suspend fun markSuspensionPoint() =
|
override suspend fun markSuspensionPoint() =
|
||||||
this@WorkerImpl.markSuspensionPoint()
|
this@JobImpl.markSuspensionPoint()
|
||||||
|
|
||||||
override val progress: Double
|
override val progress: Double
|
||||||
get() = (this@WorkerImpl.progress - progressStart) / portion
|
get() = (this@JobImpl.progress - progressStart) / portion
|
||||||
|
|
||||||
override fun setProgress(progress: Double) =
|
override fun setProgress(progress: Double) =
|
||||||
this@WorkerImpl.setProgress(progressStart + progress * portion)
|
this@JobImpl.setProgress(progressStart + progress * portion)
|
||||||
|
|
||||||
override fun delegateWork(portion: Double): WorkerScope =
|
override fun delegateProgress(portion: Double): JobScope =
|
||||||
this@WorkerImpl.delegateWork(this.portion, portion)
|
this@JobImpl.delegateProgress(this.portion, portion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package io.dico.parcels2.blockvisitor
|
package io.dico.parcels2.blockvisitor
|
||||||
|
|
||||||
import io.dico.parcels2.util.Region
|
import io.dico.parcels2.util.math.Dimension
|
||||||
import io.dico.parcels2.util.Vec3i
|
import io.dico.parcels2.util.math.Region
|
||||||
import io.dico.parcels2.util.ext.clampMax
|
import io.dico.parcels2.util.math.Vec3i
|
||||||
|
import io.dico.parcels2.util.math.ext.clampMax
|
||||||
|
|
||||||
private typealias Scope = SequenceScope<Vec3i>
|
private typealias Scope = SequenceScope<Vec3i>
|
||||||
|
|
||||||
@@ -54,9 +55,9 @@ sealed class RegionTraverser {
|
|||||||
val (primary, secondary, tertiary) = order.toArray()
|
val (primary, secondary, tertiary) = order.toArray()
|
||||||
val (origin, size) = region
|
val (origin, size) = region
|
||||||
|
|
||||||
val maxOfPrimary = primary.extract(size) - 1
|
val maxOfPrimary = size[primary] - 1
|
||||||
val maxOfSecondary = secondary.extract(size) - 1
|
val maxOfSecondary = size[secondary] - 1
|
||||||
val maxOfTertiary = tertiary.extract(size) - 1
|
val maxOfTertiary = size[tertiary] - 1
|
||||||
|
|
||||||
val isPrimaryIncreasing = direction.isIncreasing(primary)
|
val isPrimaryIncreasing = direction.isIncreasing(primary)
|
||||||
val isSecondaryIncreasing = direction.isIncreasing(secondary)
|
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 {
|
object TraverseOrderFactory {
|
||||||
private fun isSwap(primary: Dimension, secondary: Dimension) = secondary.ordinal != (primary.ordinal + 1) % 3
|
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 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
|
// optimize this, will be called lots
|
||||||
when (orderNum) {
|
when (orderNum) {
|
||||||
0 -> vec.add(dp, ds, dt) // xyz
|
0 -> vec.add(p, s, t) // xyz
|
||||||
1 -> vec.add(dt, dp, ds) // yzx
|
1 -> vec.add(t, p, s) // yzx
|
||||||
2 -> vec.add(ds, dt, dp) // zxy
|
2 -> vec.add(s, t, p) // zxy
|
||||||
3 -> vec.add(dp, dt, ds) // xzy
|
3 -> vec.add(p, t, s) // xzy
|
||||||
4 -> vec.add(ds, dp, dt) // yxz
|
4 -> vec.add(s, p, t) // yxz
|
||||||
5 -> vec.add(dt, ds, dp) // zyx
|
5 -> vec.add(t, s, p) // zyx
|
||||||
else -> error("Invalid orderNum $orderNum")
|
else -> error("Invalid orderNum $orderNum")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -212,9 +195,9 @@ inline class TraverseDirection(val bits: Int) {
|
|||||||
|
|
||||||
fun comesFirst(current: Vec3i, block: Vec3i, dimension: Dimension): Boolean =
|
fun comesFirst(current: Vec3i, block: Vec3i, dimension: Dimension): Boolean =
|
||||||
if (isIncreasing(dimension))
|
if (isIncreasing(dimension))
|
||||||
dimension.extract(block) <= dimension.extract(current)
|
block[dimension] <= current[dimension]
|
||||||
else
|
else
|
||||||
dimension.extract(block) >= dimension.extract(current)
|
block[dimension] >= current[dimension]
|
||||||
|
|
||||||
fun comesFirst(current: Vec3i, block: Vec3i) =
|
fun comesFirst(current: Vec3i, block: Vec3i) =
|
||||||
comesFirst(current, block, Dimension.X)
|
comesFirst(current, block, Dimension.X)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package io.dico.parcels2.blockvisitor
|
package io.dico.parcels2.blockvisitor
|
||||||
|
|
||||||
import io.dico.parcels2.util.Region
|
import io.dico.parcels2.util.math.Region
|
||||||
import io.dico.parcels2.util.Vec3i
|
import io.dico.parcels2.util.math.Vec3i
|
||||||
import io.dico.parcels2.util.get
|
import io.dico.parcels2.util.math.get
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
@@ -24,7 +24,7 @@ class Schematic {
|
|||||||
private var isLoaded = false; private set
|
private var isLoaded = false; private set
|
||||||
private val traverser: RegionTraverser = RegionTraverser.upward
|
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
|
_size = region.size
|
||||||
|
|
||||||
val data = arrayOfNulls<BlockData>(region.blockCount).also { blockDatas = it }
|
val data = arrayOfNulls<BlockData>(region.blockCount).also { blockDatas = it }
|
||||||
@@ -52,7 +52,7 @@ class Schematic {
|
|||||||
isLoaded = true
|
isLoaded = true
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun WorkerScope.paste(world: World, position: Vec3i) {
|
suspend fun JobScope.paste(world: World, position: Vec3i) {
|
||||||
if (!isLoaded) throw IllegalStateException()
|
if (!isLoaded) throw IllegalStateException()
|
||||||
|
|
||||||
val region = Region(position, _size!!)
|
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)
|
load(world, region)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPasteTask(world: World, position: Vec3i): WorkerTask = {
|
fun getPasteTask(world: World, position: Vec3i): JobFunction = {
|
||||||
paste(world, position)
|
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.PlayerProfile.*
|
import io.dico.parcels2.PlayerProfile.*
|
||||||
import io.dico.parcels2.PrivilegeKey
|
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.hasPermAdminManage
|
||||||
import io.dico.parcels2.util.ext.parcelLimit
|
import io.dico.parcels2.util.ext.parcelLimit
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
@@ -50,7 +50,7 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei
|
|||||||
world.blockManager.clearParcel(parcel.id)
|
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 ->
|
onProgressUpdate(1000, 1000) { progress, elapsedTime ->
|
||||||
val alt = context.getFormat(EMessageType.NUMBER)
|
val alt = context.getFormat(EMessageType.NUMBER)
|
||||||
val main = context.getFormat(EMessageType.INFORMATIVE)
|
val main = context.getFormat(EMessageType.INFORMATIVE)
|
||||||
|
|||||||
@@ -81,14 +81,14 @@ class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
|
|
||||||
@Cmd("jobs")
|
@Cmd("jobs")
|
||||||
fun cmdJobs(): Any? {
|
fun cmdJobs(): Any? {
|
||||||
val workers = plugin.workDispatcher.workers
|
val workers = plugin.jobDispatcher.jobs
|
||||||
println(workers.map { it.job }.joinToString(separator = "\n"))
|
println(workers.map { it.job }.joinToString(separator = "\n"))
|
||||||
return "Task count: ${workers.size}"
|
return "Task count: ${workers.size}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Cmd("complete_jobs")
|
@Cmd("complete_jobs")
|
||||||
fun cmdCompleteJobs(): Any? = cmdJobs().also {
|
fun cmdCompleteJobs(): Any? = cmdJobs().also {
|
||||||
plugin.launch { plugin.workDispatcher.completeAllTasks() }
|
plugin.launch { plugin.jobDispatcher.completeAllTasks() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Cmd("message")
|
@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.PREFER_OWNED_FOR_DEFAULT
|
||||||
import io.dico.parcels2.command.ParcelTarget.TargetKind.Companion.REAL
|
import io.dico.parcels2.command.ParcelTarget.TargetKind.Companion.REAL
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import io.dico.parcels2.util.Vec2i
|
import io.dico.parcels2.util.math.Vec2i
|
||||||
import io.dico.parcels2.util.ext.floor
|
import io.dico.parcels2.util.math.ext.floor
|
||||||
import org.bukkit.command.CommandSender
|
import org.bukkit.command.CommandSender
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ package io.dico.parcels2.defaultimpl
|
|||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.blockvisitor.*
|
import io.dico.parcels2.blockvisitor.*
|
||||||
import io.dico.parcels2.options.DefaultGeneratorOptions
|
import io.dico.parcels2.options.DefaultGeneratorOptions
|
||||||
import io.dico.parcels2.util.Region
|
import io.dico.parcels2.util.math.Region
|
||||||
import io.dico.parcels2.util.Vec2i
|
import io.dico.parcels2.util.math.Vec2i
|
||||||
import io.dico.parcels2.util.Vec3i
|
import io.dico.parcels2.util.math.Vec3i
|
||||||
import io.dico.parcels2.util.ext.even
|
import io.dico.parcels2.util.math.ext.even
|
||||||
import io.dico.parcels2.util.ext.umod
|
import io.dico.parcels2.util.math.ext.umod
|
||||||
import io.dico.parcels2.util.get
|
import io.dico.parcels2.util.math.get
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
|
import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -121,9 +121,9 @@ class DefaultParcelGenerator(
|
|||||||
worldId: ParcelWorldId,
|
worldId: ParcelWorldId,
|
||||||
container: ParcelContainer,
|
container: ParcelContainer,
|
||||||
coroutineScope: CoroutineScope,
|
coroutineScope: CoroutineScope,
|
||||||
workDispatcher: WorkDispatcher
|
jobDispatcher: JobDispatcher
|
||||||
): Pair<ParcelLocator, ParcelBlockManager> {
|
): 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? {
|
private inline fun <T> convertBlockLocationToId(x: Int, z: Int, mapper: (Int, Int) -> T): T? {
|
||||||
@@ -158,7 +158,7 @@ class DefaultParcelGenerator(
|
|||||||
private inner class ParcelBlockManagerImpl(
|
private inner class ParcelBlockManagerImpl(
|
||||||
val worldId: ParcelWorldId,
|
val worldId: ParcelWorldId,
|
||||||
coroutineScope: CoroutineScope,
|
coroutineScope: CoroutineScope,
|
||||||
override val workDispatcher: WorkDispatcher
|
override val jobDispatcher: JobDispatcher
|
||||||
) : ParcelBlockManagerBase(), CoroutineScope by coroutineScope {
|
) : ParcelBlockManagerBase(), CoroutineScope by coroutineScope {
|
||||||
override val world: World = this@DefaultParcelGenerator.world
|
override val world: World = this@DefaultParcelGenerator.world
|
||||||
override val parcelTraverser: RegionTraverser = RegionTraverser.convergingTo(o.floorHeight)
|
override val parcelTraverser: RegionTraverser = RegionTraverser.convergingTo(o.floorHeight)
|
||||||
@@ -177,7 +177,10 @@ class DefaultParcelGenerator(
|
|||||||
|
|
||||||
override fun getRegion(parcel: ParcelId): Region {
|
override fun getRegion(parcel: ParcelId): Region {
|
||||||
val bottom = getBottomBlock(parcel)
|
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 {
|
private fun getRegionConsideringWorld(parcel: ParcelId): Region {
|
||||||
@@ -234,12 +237,12 @@ class DefaultParcelGenerator(
|
|||||||
return world.getParcelById(parcelId)
|
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) }
|
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")
|
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) {
|
for (parcel in parcels) {
|
||||||
launch(start = UNDISPATCHED) {
|
launch(start = UNDISPATCHED) {
|
||||||
@@ -252,7 +255,7 @@ class DefaultParcelGenerator(
|
|||||||
return worker
|
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 world = world
|
||||||
val b = getBottomBlock(parcel)
|
val b = getBottomBlock(parcel)
|
||||||
val parcelSize = o.parcelSize
|
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 region = getRegion(parcel)
|
||||||
val blocks = parcelTraverser.traverseRegion(region)
|
val blocks = parcelTraverser.traverseRegion(region)
|
||||||
val blockCount = region.blockCount.toDouble()
|
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 region1 = getRegionConsideringWorld(parcel1)
|
||||||
var region2 = getRegionConsideringWorld(parcel2)
|
var region2 = getRegionConsideringWorld(parcel2)
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package io.dico.parcels2.defaultimpl
|
|||||||
import io.dico.dicore.Formatting
|
import io.dico.dicore.Formatting
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.Privilege.*
|
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 io.dico.parcels2.util.ext.alsoIfTrue
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
|
|||||||
@@ -58,8 +58,10 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
|||||||
if (worldExists) Bukkit.getWorld(worldName)!!
|
if (worldExists) Bukkit.getWorld(worldName)!!
|
||||||
else WorldCreator(worldName).generator(generator).createWorld().also { logger.info("Creating world $worldName") }
|
else WorldCreator(worldName).generator(generator).createWorld().also { logger.info("Creating world $worldName") }
|
||||||
|
|
||||||
parcelWorld = ParcelWorldImpl(bukkitWorld, generator, worldOptions.runtime, plugin.storage,
|
parcelWorld = ParcelWorldImpl(
|
||||||
plugin.globalPrivileges, ::DefaultParcelContainer, plugin, plugin.workDispatcher)
|
bukkitWorld, generator, worldOptions.runtime, plugin.storage,
|
||||||
|
plugin.globalPrivileges, ::DefaultParcelContainer, plugin, plugin.jobDispatcher
|
||||||
|
)
|
||||||
|
|
||||||
if (!worldExists) {
|
if (!worldExists) {
|
||||||
val time = DateTime.now()
|
val time = DateTime.now()
|
||||||
@@ -95,11 +97,18 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
|||||||
|
|
||||||
logger.info("Loading all parcel data...")
|
logger.info("Loading all parcel data...")
|
||||||
val channel = plugin.storage.transmitAllParcelData()
|
val channel = plugin.storage.transmitAllParcelData()
|
||||||
do {
|
while (true) {
|
||||||
val pair = channel.receiveOrNull() ?: break
|
val (id, data) = channel.receiveOrNull() ?: break
|
||||||
val parcel = getParcelById(pair.first) ?: continue
|
val parcel = getParcelById(id) ?: continue
|
||||||
pair.second?.let { parcel.copyDataIgnoringDatabase(it) }
|
data?.let { parcel.copyDataIgnoringDatabase(it) }
|
||||||
} while (true)
|
}
|
||||||
|
|
||||||
|
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")
|
logger.info("Loading data completed")
|
||||||
_dataIsLoaded = true
|
_dataIsLoaded = true
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
package io.dico.parcels2.defaultimpl
|
package io.dico.parcels2.defaultimpl
|
||||||
|
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.blockvisitor.WorkDispatcher
|
import io.dico.parcels2.blockvisitor.JobDispatcher
|
||||||
import io.dico.parcels2.options.RuntimeWorldOptions
|
import io.dico.parcels2.options.RuntimeWorldOptions
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -18,7 +18,7 @@ class ParcelWorldImpl(override val world: World,
|
|||||||
override val globalPrivileges: GlobalPrivilegesManager,
|
override val globalPrivileges: GlobalPrivilegesManager,
|
||||||
containerFactory: ParcelContainerFactory,
|
containerFactory: ParcelContainerFactory,
|
||||||
coroutineScope: CoroutineScope,
|
coroutineScope: CoroutineScope,
|
||||||
workDispatcher: WorkDispatcher)
|
jobDispatcher: JobDispatcher)
|
||||||
: ParcelWorld,
|
: ParcelWorld,
|
||||||
ParcelWorldId,
|
ParcelWorldId,
|
||||||
ParcelContainer, /* missing delegation */
|
ParcelContainer, /* missing delegation */
|
||||||
@@ -39,7 +39,7 @@ class ParcelWorldImpl(override val world: World,
|
|||||||
override val blockManager: ParcelBlockManager
|
override val blockManager: ParcelBlockManager
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val pair = generator.makeParcelLocatorAndBlockManager(id, container, coroutineScope, workDispatcher)
|
val pair = generator.makeParcelLocatorAndBlockManager(id, container, coroutineScope, jobDispatcher)
|
||||||
locator = pair.first
|
locator = pair.first
|
||||||
blockManager = pair.second
|
blockManager = pair.second
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ import io.dico.dicore.RegistratorListener
|
|||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import io.dico.parcels2.util.ext.*
|
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.Material.*
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
import org.bukkit.block.Biome
|
import org.bukkit.block.Biome
|
||||||
@@ -52,6 +58,7 @@ class ParcelListeners(
|
|||||||
return world to world.getParcelAt(block)
|
return world to world.getParcelAt(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prevents players from entering plots they are banned from
|
* Prevents players from entering plots they are banned from
|
||||||
*/
|
*/
|
||||||
@@ -59,12 +66,36 @@ class ParcelListeners(
|
|||||||
val onPlayerMoveEvent = RegistratorListener<PlayerMoveEvent> l@{ event ->
|
val onPlayerMoveEvent = RegistratorListener<PlayerMoveEvent> l@{ event ->
|
||||||
val user = event.player
|
val user = event.player
|
||||||
if (user.hasPermBanBypass) return@l
|
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)) {
|
if (!parcel.canEnterFast(user)) {
|
||||||
parcelProvider.getParcelAt(event.from)?.also {
|
val region = parcel.world.blockManager.getRegion(parcel.id)
|
||||||
user.teleport(it.homeLocation)
|
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")
|
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
|
package io.dico.parcels2.options
|
||||||
|
|
||||||
import io.dico.parcels2.blockvisitor.TickWorktimeOptions
|
import io.dico.parcels2.blockvisitor.TickJobtimeOptions
|
||||||
import org.bukkit.GameMode
|
import org.bukkit.GameMode
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
@@ -11,7 +11,7 @@ class Options {
|
|||||||
var worlds: Map<String, WorldOptions> = hashMapOf()
|
var worlds: Map<String, WorldOptions> = hashMapOf()
|
||||||
private set
|
private set
|
||||||
var storage: StorageOptions = StorageOptions()
|
var storage: StorageOptions = StorageOptions()
|
||||||
var tickWorktime: TickWorktimeOptions = TickWorktimeOptions(20, 1)
|
var tickJobtime: TickJobtimeOptions = TickJobtimeOptions(20, 1)
|
||||||
var migration = MigrationOptionsHolder()
|
var migration = MigrationOptionsHolder()
|
||||||
|
|
||||||
fun addWorld(name: String,
|
fun addWorld(name: String,
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ interface Backing {
|
|||||||
fun setParcelOptionsInteractConfig(parcel: ParcelId, config: InteractableConfiguration)
|
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)
|
fun setGlobalPrivilege(owner: PlayerProfile, player: PlayerProfile, privilege: Privilege)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import java.util.UUID
|
|||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
typealias DataPair = Pair<ParcelId, ParcelData?>
|
typealias DataPair = Pair<ParcelId, ParcelData?>
|
||||||
typealias AddedDataPair<TAttach> = Pair<TAttach, MutablePrivilegeMap>
|
typealias PrivilegePair<TAttach> = Pair<TAttach, PrivilegesHolder>
|
||||||
|
|
||||||
interface Storage {
|
interface Storage {
|
||||||
val name: String
|
val name: String
|
||||||
@@ -55,9 +55,9 @@ interface Storage {
|
|||||||
fun setParcelOptionsInteractConfig(parcel: ParcelId, config: InteractableConfiguration): Job
|
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
|
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 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) }
|
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.*
|
||||||
import io.dico.parcels2.PlayerProfile.Star.name
|
import io.dico.parcels2.PlayerProfile.Star.name
|
||||||
import io.dico.parcels2.storage.*
|
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 io.dico.parcels2.util.ext.synchronized
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import kotlinx.coroutines.channels.ArrayChannel
|
import kotlinx.coroutines.channels.ArrayChannel
|
||||||
@@ -193,6 +193,10 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
|
|||||||
PrivilegesLocalT.setPrivilege(parcel, profile, privilege)
|
PrivilegesLocalT.setPrivilege(parcel, profile, privilege)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data.privilegeOfStar.takeIf { it != Privilege.DEFAULT }?.let { privilege ->
|
||||||
|
PrivilegesLocalT.setPrivilege(parcel, PlayerProfile.Star, privilege)
|
||||||
|
}
|
||||||
|
|
||||||
setParcelOptionsInteractConfig(parcel, data.interactableConfig)
|
setParcelOptionsInteractConfig(parcel, data.interactableConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,13 +246,13 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun transmitAllGlobalAddedData(channel: SendChannel<AddedDataPair<PlayerProfile>>) {
|
override fun transmitAllGlobalPrivileges(channel: SendChannel<PrivilegePair<PlayerProfile>>) {
|
||||||
PrivilegesGlobalT.sendAllAddedData(channel)
|
PrivilegesGlobalT.sendAllPrivilegesH(channel)
|
||||||
channel.close()
|
channel.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun readGlobalPrivileges(owner: PlayerProfile): MutablePrivilegeMap {
|
override fun readGlobalPrivileges(owner: PlayerProfile): PrivilegesHolder? {
|
||||||
return PrivilegesGlobalT.readPrivileges(ProfilesT.getId(owner.toOwnerProfile()) ?: return hashMapOf())
|
return PrivilegesGlobalT.readPrivileges(ProfilesT.getId(owner.toOwnerProfile()) ?: return null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setGlobalPrivilege(owner: PlayerProfile, player: PlayerProfile, privilege: Privilege) {
|
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))
|
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)
|
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) {
|
sealed class PrivilegesTable<AttachT>(name: String, val idTable: IdTransactionsTable<*, AttachT>) : Table(name) {
|
||||||
val attach_id = integer("attach_id").references(idTable.id, ReferenceOption.CASCADE)
|
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 list = slice(profile_id, privilege).select { attach_id eq id }
|
||||||
val result = MutablePrivilegeMap()
|
val result = PrivilegesHolder()
|
||||||
for (row in list) {
|
for (row in list) {
|
||||||
val profile = ProfilesT.getRealItem(row[profile_id]) ?: continue
|
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
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendAllAddedData(channel: PrivilegesSendChannel<AttachT>) {
|
fun sendAllPrivilegesH(channel: PrivilegesSendChannel<AttachT>) {
|
||||||
val iterator = selectAll().orderBy(attach_id).iterator()
|
val iterator = selectAll().orderBy(attach_id).iterator()
|
||||||
|
|
||||||
if (iterator.hasNext()) {
|
if (iterator.hasNext()) {
|
||||||
val firstRow = iterator.next()
|
val firstRow = iterator.next()
|
||||||
var id: Int = firstRow[attach_id]
|
var id: Int = firstRow[attach_id]
|
||||||
var attach: AttachT? = null
|
var attach: AttachT? = null
|
||||||
var map: MutablePrivilegeMap? = null
|
var map: PrivilegesHolder? = null
|
||||||
|
|
||||||
fun initAttachAndMap() {
|
fun initAttachAndMap() {
|
||||||
attach = idTable.getItem(id)
|
attach = idTable.getItem(id)
|
||||||
map = attach?.let { mutableMapOf() }
|
map = attach?.let { PrivilegesHolder() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun sendIfPresent() {
|
fun sendIfPresent() {
|
||||||
if (attach != null && map != null && map!!.isNotEmpty()) {
|
if (attach != null && map != null) {
|
||||||
channel.offer(attach!! to map!!)
|
channel.offer(attach!! to map!!)
|
||||||
}
|
}
|
||||||
attach = null
|
attach = null
|
||||||
@@ -91,7 +91,7 @@ sealed class PrivilegesTable<AttachT>(name: String, val idTable: IdTransactionsT
|
|||||||
|
|
||||||
val profile = ProfilesT.getRealItem(row[profile_id]) ?: continue
|
val profile = ProfilesT.getRealItem(row[profile_id]) ?: continue
|
||||||
val privilege = Privilege.getByNumber(row[privilege]) ?: continue
|
val privilege = Privilege.getByNumber(row[privilege]) ?: continue
|
||||||
map!![profile] = privilege
|
map!!.setRawStoredPrivilege(profile, privilege)
|
||||||
}
|
}
|
||||||
|
|
||||||
sendIfPresent()
|
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: Formatting) = toString() + other
|
||||||
operator fun Formatting.plus(other: String) = 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.World
|
||||||
import org.bukkit.block.Block
|
import org.bukkit.block.Block
|
||||||
import org.bukkit.block.BlockFace
|
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(
|
data class Vec3i(
|
||||||
val x: Int,
|
val x: Int,
|
||||||
val y: Int,
|
val y: Int,
|
||||||
val z: 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 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)
|
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)
|
infix fun addX(o: Int) = Vec3i(x + o, y, z)
|
||||||
@@ -38,6 +25,27 @@ data class Vec3i(
|
|||||||
fun neg() = Vec3i(-x, -y, -z)
|
fun neg() = Vec3i(-x, -y, -z)
|
||||||
fun clampMax(o: Vec3i) = Vec3i(x.clampMax(o.x), y.clampMax(o.y), z.clampMax(o.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 {
|
companion object {
|
||||||
private operator fun invoke(face: BlockFace) = Vec3i(face.modX, face.modY, face.modZ)
|
private operator fun invoke(face: BlockFace) = Vec3i(face.modX, face.modY, face.modZ)
|
||||||
val down = Vec3i(BlockFace.DOWN)
|
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 {
|
fun Double.floor(): Int {
|
||||||
val down = toInt()
|
val down = toInt()
|
||||||
@@ -34,6 +34,7 @@ fun IntRange.clamp(min: Int, max: Int): IntRange {
|
|||||||
// the name coerceAtMost is bad
|
// the name coerceAtMost is bad
|
||||||
fun Int.clampMax(max: Int) = coerceAtMost(max)
|
fun Int.clampMax(max: Int) = coerceAtMost(max)
|
||||||
fun Double.clampMin(min: Double) = coerceAtLeast(min)
|
fun Double.clampMin(min: Double) = coerceAtLeast(min)
|
||||||
|
fun Double.clampMax(max: Double) = coerceAtMost(max)
|
||||||
|
|
||||||
// Why does this not exist?
|
// Why does this not exist?
|
||||||
infix fun Int.ceilDiv(divisor: Int): Int {
|
infix fun Int.ceilDiv(divisor: Int): Int {
|
||||||
Reference in New Issue
Block a user