10/10 commit messages btw
This commit is contained in:
@@ -77,7 +77,7 @@ dependencies {
|
|||||||
|
|
||||||
// not on sk89q maven repo yet
|
// not on sk89q maven repo yet
|
||||||
compileClasspath(files("$rootDir/debug/plugins/worldedit-bukkit-7.0.0-beta-01.jar"))
|
compileClasspath(files("$rootDir/debug/plugins/worldedit-bukkit-7.0.0-beta-01.jar"))
|
||||||
//compileClasspath(files("$rootDir/debug/lib/spigot-1.13.1.jar"))
|
compileClasspath(files("$rootDir/debug/lib/spigot-1.13.1.jar"))
|
||||||
|
|
||||||
compile("org.jetbrains.exposed:exposed:0.10.5") { isTransitive = false }
|
compile("org.jetbrains.exposed:exposed:0.10.5") { isTransitive = false }
|
||||||
compile("joda-time:joda-time:2.10")
|
compile("joda-time:joda-time:2.10")
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package io.dico.parcels2.blockvisitor
|
package io.dico.parcels2
|
||||||
|
|
||||||
import io.dico.parcels2.ParcelsPlugin
|
|
||||||
import io.dico.parcels2.logger
|
|
||||||
import io.dico.parcels2.util.math.clampMin
|
import io.dico.parcels2.util.math.clampMin
|
||||||
import kotlinx.coroutines.CancellationException
|
import kotlinx.coroutines.CancellationException
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@@ -23,9 +21,9 @@ data class TickJobtimeOptions(var jobTime: Int, var tickInterval: Int)
|
|||||||
|
|
||||||
interface JobDispatcher {
|
interface JobDispatcher {
|
||||||
/**
|
/**
|
||||||
* Submit a [task] that should be run synchronously, but limited such that it does not stall the server
|
* Submit a [function] that should be run synchronously, but limited such that it does not stall the server
|
||||||
*/
|
*/
|
||||||
fun dispatch(task: JobFunction): Job
|
fun dispatch(function: JobFunction): Job
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a list of all jobs
|
* Get a list of all jobs
|
||||||
@@ -55,7 +53,7 @@ interface Job : JobAndScopeMembersUnion {
|
|||||||
/**
|
/**
|
||||||
* The coroutine associated with this job
|
* The coroutine associated with this job
|
||||||
*/
|
*/
|
||||||
val job: CoroutineJob
|
val coroutine: CoroutineJob
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* true if this job has completed
|
* true if this job has completed
|
||||||
@@ -147,8 +145,8 @@ class BukkitJobDispatcher(private val plugin: ParcelsPlugin, var options: TickJo
|
|||||||
private val _jobs = LinkedList<JobInternal>()
|
private val _jobs = LinkedList<JobInternal>()
|
||||||
override val jobs: List<Job> = _jobs
|
override val jobs: List<Job> = _jobs
|
||||||
|
|
||||||
override fun dispatch(task: JobFunction): Job {
|
override fun dispatch(function: JobFunction): Job {
|
||||||
val job: JobInternal = JobImpl(plugin, task)
|
val job: JobInternal = JobImpl(plugin, function)
|
||||||
|
|
||||||
if (bukkitTask == null) {
|
if (bukkitTask == null) {
|
||||||
val completed = job.resume(options.jobTime.toLong())
|
val completed = job.resume(options.jobTime.toLong())
|
||||||
@@ -198,7 +196,7 @@ class BukkitJobDispatcher(private val plugin: ParcelsPlugin, var options: TickJo
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class JobImpl(scope: CoroutineScope, task: JobFunction) : JobInternal {
|
private class JobImpl(scope: CoroutineScope, task: JobFunction) : JobInternal {
|
||||||
override val job: CoroutineJob = scope.launch(start = LAZY) { task() }
|
override val coroutine: 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
|
||||||
@@ -207,10 +205,10 @@ private class JobImpl(scope: CoroutineScope, task: JobFunction) : JobInternal {
|
|||||||
|
|
||||||
override val elapsedTime
|
override val elapsedTime
|
||||||
get() =
|
get() =
|
||||||
if (job.isCompleted) startTimeOrElapsedTime
|
if (coroutine.isCompleted) startTimeOrElapsedTime
|
||||||
else currentTimeMillis() - startTimeOrElapsedTime
|
else currentTimeMillis() - startTimeOrElapsedTime
|
||||||
|
|
||||||
override val isComplete get() = job.isCompleted
|
override val isComplete get() = coroutine.isCompleted
|
||||||
|
|
||||||
private var _progress = 0.0
|
private var _progress = 0.0
|
||||||
override val progress get() = _progress
|
override val progress get() = _progress
|
||||||
@@ -223,7 +221,7 @@ private class JobImpl(scope: CoroutineScope, task: JobFunction) : JobInternal {
|
|||||||
private var onCompleted: JobUpdateLister? = null
|
private var onCompleted: JobUpdateLister? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
job.invokeOnCompletion { exception ->
|
coroutine.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)
|
||||||
@@ -306,13 +304,13 @@ private class JobImpl(scope: CoroutineScope, task: JobFunction) : JobInternal {
|
|||||||
|
|
||||||
isStarted = true
|
isStarted = true
|
||||||
startTimeOrElapsedTime = System.currentTimeMillis()
|
startTimeOrElapsedTime = System.currentTimeMillis()
|
||||||
job.start()
|
coroutine.start()
|
||||||
|
|
||||||
return continuation == null
|
return continuation == null
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun awaitCompletion() {
|
override suspend fun awaitCompletion() {
|
||||||
job.join()
|
coroutine.join()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun delegateProgress(curPortion: Double, portion: Double): JobScope =
|
private fun delegateProgress(curPortion: Double, portion: Double): JobScope =
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
import io.dico.parcels2.util.math.Vec2i
|
import io.dico.parcels2.util.math.Vec2i
|
||||||
|
import io.dico.parcels2.util.math.Vec3i
|
||||||
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
|
||||||
@@ -19,7 +20,7 @@ interface Parcel : ParcelData, Privileges {
|
|||||||
val pos: Vec2i
|
val pos: Vec2i
|
||||||
val x: Int
|
val x: Int
|
||||||
val z: Int
|
val z: Int
|
||||||
val data: ParcelData
|
val data: ParcelDataHolder
|
||||||
val infoString: String
|
val infoString: String
|
||||||
val hasBlockVisitors: Boolean
|
val hasBlockVisitors: Boolean
|
||||||
val globalPrivileges: GlobalPrivileges?
|
val globalPrivileges: GlobalPrivileges?
|
||||||
@@ -27,21 +28,21 @@ interface Parcel : ParcelData, Privileges {
|
|||||||
override val keyOfOwner: PlayerProfile.Real?
|
override val keyOfOwner: PlayerProfile.Real?
|
||||||
get() = owner as? PlayerProfile.Real
|
get() = owner as? PlayerProfile.Real
|
||||||
|
|
||||||
fun copyDataIgnoringDatabase(data: ParcelData)
|
fun copyData(newData: ParcelDataHolder, callerIsDatabase: Boolean = false)
|
||||||
|
|
||||||
fun copyData(data: ParcelData)
|
fun dispose() = copyData(ParcelDataHolder())
|
||||||
|
|
||||||
fun dispose()
|
fun updateOwnerSign(force: Boolean = false)
|
||||||
|
|
||||||
suspend fun withBlockVisitorPermit(block: suspend () -> Unit)
|
|
||||||
|
|
||||||
val homeLocation: Location get() = world.blockManager.getHomeLocation(id)
|
val homeLocation: Location get() = world.blockManager.getHomeLocation(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface ParcelData : RawPrivileges {
|
interface ParcelData : RawPrivileges {
|
||||||
var owner: PlayerProfile?
|
var owner: PlayerProfile?
|
||||||
val lastClaimTime: DateTime?
|
val lastClaimTime: DateTime?
|
||||||
var ownerSignOutdated: Boolean
|
var isOwnerSignOutdated: Boolean
|
||||||
var interactableConfig: InteractableConfiguration
|
var interactableConfig: InteractableConfiguration
|
||||||
|
|
||||||
//fun canBuild(player: OfflinePlayer, checkAdmin: Boolean = true, checkGlobal: Boolean = true): Boolean
|
//fun canBuild(player: OfflinePlayer, checkAdmin: Boolean = true, checkGlobal: Boolean = true): Boolean
|
||||||
@@ -59,7 +60,7 @@ class ParcelDataHolder(addedMap: MutablePrivilegeMap = mutableMapOf())
|
|||||||
: ParcelData, PrivilegesHolder(addedMap) {
|
: ParcelData, PrivilegesHolder(addedMap) {
|
||||||
override var owner: PlayerProfile? = null
|
override var owner: PlayerProfile? = null
|
||||||
override var lastClaimTime: DateTime? = null
|
override var lastClaimTime: DateTime? = null
|
||||||
override var ownerSignOutdated = false
|
override var isOwnerSignOutdated = false
|
||||||
override var interactableConfig: InteractableConfiguration = BitmaskInteractableConfiguration()
|
override var interactableConfig: InteractableConfiguration = BitmaskInteractableConfiguration()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
import io.dico.parcels2.blockvisitor.*
|
import io.dico.parcels2.blockvisitor.RegionTraverser
|
||||||
import io.dico.parcels2.util.math.Region
|
import io.dico.parcels2.util.math.Region
|
||||||
import io.dico.parcels2.util.math.Vec2i
|
import io.dico.parcels2.util.math.Vec2i
|
||||||
|
import io.dico.parcels2.util.math.Vec3i
|
||||||
import io.dico.parcels2.util.math.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
|
||||||
|
import org.bukkit.Material
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
import org.bukkit.block.Biome
|
import org.bukkit.block.Biome
|
||||||
import org.bukkit.block.Block
|
import org.bukkit.block.Block
|
||||||
|
import org.bukkit.block.BlockFace
|
||||||
import org.bukkit.entity.Entity
|
import org.bukkit.entity.Entity
|
||||||
import org.bukkit.generator.BlockPopulator
|
import org.bukkit.generator.BlockPopulator
|
||||||
import org.bukkit.generator.ChunkGenerator
|
import org.bukkit.generator.ChunkGenerator
|
||||||
@@ -34,10 +37,12 @@ abstract class ParcelGenerator : ChunkGenerator() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract fun makeParcelLocatorAndBlockManager(worldId: ParcelWorldId,
|
abstract fun makeParcelLocatorAndBlockManager(
|
||||||
container: ParcelContainer,
|
parcelProvider: ParcelProvider,
|
||||||
coroutineScope: CoroutineScope,
|
container: ParcelContainer,
|
||||||
jobDispatcher: JobDispatcher): Pair<ParcelLocator, ParcelBlockManager>
|
coroutineScope: CoroutineScope,
|
||||||
|
jobDispatcher: JobDispatcher
|
||||||
|
): Pair<ParcelLocator, ParcelBlockManager>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ParcelBlockManager {
|
interface ParcelBlockManager {
|
||||||
@@ -45,7 +50,7 @@ interface ParcelBlockManager {
|
|||||||
val jobDispatcher: JobDispatcher
|
val jobDispatcher: JobDispatcher
|
||||||
val parcelTraverser: RegionTraverser
|
val parcelTraverser: RegionTraverser
|
||||||
|
|
||||||
// fun getBottomBlock(parcel: ParcelId): Vec2i
|
fun getRegionOrigin(parcel: ParcelId) = getRegion(parcel).origin.toVec2i()
|
||||||
|
|
||||||
fun getHomeLocation(parcel: ParcelId): Location
|
fun getHomeLocation(parcel: ParcelId): Location
|
||||||
|
|
||||||
@@ -53,15 +58,15 @@ interface ParcelBlockManager {
|
|||||||
|
|
||||||
fun getEntities(parcel: ParcelId): Collection<Entity>
|
fun getEntities(parcel: ParcelId): Collection<Entity>
|
||||||
|
|
||||||
fun setOwnerBlock(parcel: ParcelId, owner: PlayerProfile?)
|
fun isParcelInfoSectionLoaded(parcel: ParcelId): Boolean
|
||||||
|
|
||||||
fun setBiome(parcel: ParcelId, biome: Biome): Job
|
fun updateParcelInfo(parcel: ParcelId, owner: PlayerProfile?)
|
||||||
|
|
||||||
fun clearParcel(parcel: ParcelId): Job
|
fun getParcelForInfoBlockInteraction(block: Vec3i, type: Material, face: BlockFace): Parcel?
|
||||||
|
|
||||||
fun swapParcels(parcel1: ParcelId, parcel2: ParcelId): Job
|
fun setBiome(parcel: ParcelId, biome: Biome): Job?
|
||||||
|
|
||||||
fun submitBlockVisitor(vararg parcelIds: ParcelId, task: JobFunction): Job
|
fun clearParcel(parcel: ParcelId): Job?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to update owner blocks in the corner of the parcel
|
* Used to update owner blocks in the corner of the parcel
|
||||||
@@ -69,9 +74,12 @@ interface ParcelBlockManager {
|
|||||||
fun getParcelsWithOwnerBlockIn(chunk: Chunk): Collection<Vec2i>
|
fun getParcelsWithOwnerBlockIn(chunk: Chunk): Collection<Vec2i>
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun ParcelBlockManager.doBlockOperation(parcel: ParcelId,
|
inline fun ParcelBlockManager.tryDoBlockOperation(
|
||||||
traverser: RegionTraverser,
|
parcelProvider: ParcelProvider,
|
||||||
crossinline operation: suspend JobScope.(Block) -> Unit) = submitBlockVisitor(parcel) {
|
parcel: ParcelId,
|
||||||
|
traverser: RegionTraverser,
|
||||||
|
crossinline operation: suspend JobScope.(Block) -> Unit
|
||||||
|
) = parcelProvider.trySubmitBlockVisitor(Permit(), arrayOf(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,3 +1,5 @@
|
|||||||
|
@file:Suppress("FunctionName")
|
||||||
|
|
||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
import io.dico.parcels2.util.math.Vec2i
|
import io.dico.parcels2.util.math.Vec2i
|
||||||
@@ -15,14 +17,12 @@ interface ParcelWorldId {
|
|||||||
fun equals(id: ParcelWorldId): Boolean = name == id.name || (uid != null && uid == id.uid)
|
fun equals(id: ParcelWorldId): Boolean = name == id.name || (uid != null && uid == id.uid)
|
||||||
|
|
||||||
val bukkitWorld: World? get() = Bukkit.getWorld(name) ?: uid?.let { Bukkit.getWorld(it) }
|
val bukkitWorld: World? get() = Bukkit.getWorld(name) ?: uid?.let { Bukkit.getWorld(it) }
|
||||||
|
|
||||||
companion object {
|
|
||||||
operator fun invoke(worldName: String, worldUid: UUID?): ParcelWorldId = ParcelWorldIdImpl(worldName, worldUid)
|
|
||||||
operator fun invoke(worldName: String): ParcelWorldId = ParcelWorldIdImpl(worldName, null)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ParcelWorldId.toStringExt() = "ParcelWorld($name)"
|
fun ParcelWorldId.parcelWorldIdToString() = "ParcelWorld($name)"
|
||||||
|
|
||||||
|
fun ParcelWorldId(worldName: String, worldUid: UUID? = null): ParcelWorldId = ParcelWorldIdImpl(worldName, worldUid)
|
||||||
|
fun ParcelWorldId(world: World) = ParcelWorldId(world.name, world.uid)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by storage backing options to encompass the location of a parcel
|
* Used by storage backing options to encompass the location of a parcel
|
||||||
@@ -35,24 +35,22 @@ interface ParcelId {
|
|||||||
val pos: Vec2i get() = Vec2i(x, z)
|
val pos: Vec2i get() = Vec2i(x, z)
|
||||||
val idString get() = "$x,$z"
|
val idString get() = "$x,$z"
|
||||||
fun equals(id: ParcelId): Boolean = x == id.x && z == id.z && worldId.equals(id.worldId)
|
fun equals(id: ParcelId): Boolean = x == id.x && z == id.z && worldId.equals(id.worldId)
|
||||||
|
|
||||||
companion object {
|
|
||||||
operator fun invoke(worldId: ParcelWorldId, pos: Vec2i) = invoke(worldId, pos.x, pos.z)
|
|
||||||
operator fun invoke(worldName: String, worldUid: UUID?, pos: Vec2i) = invoke(worldName, worldUid, pos.x, pos.z)
|
|
||||||
operator fun invoke(worldName: String, worldUid: UUID?, x: Int, z: Int) = invoke(ParcelWorldId(worldName, worldUid), x, z)
|
|
||||||
operator fun invoke(worldId: ParcelWorldId, x: Int, z: Int): ParcelId = ParcelIdImpl(worldId, x, z)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ParcelId.toStringExt() = "Parcel(${worldId.name},$idString)"
|
fun ParcelId.parcelIdToString() = "Parcel(${worldId.name},$idString)"
|
||||||
|
|
||||||
|
fun ParcelId(worldId: ParcelWorldId, pos: Vec2i) = ParcelId(worldId, pos.x, pos.z)
|
||||||
|
fun ParcelId(worldName: String, worldUid: UUID?, pos: Vec2i) = ParcelId(worldName, worldUid, pos.x, pos.z)
|
||||||
|
fun ParcelId(worldName: String, worldUid: UUID?, x: Int, z: Int) = ParcelId(ParcelWorldId(worldName, worldUid), x, z)
|
||||||
|
fun ParcelId(worldId: ParcelWorldId, x: Int, z: Int): ParcelId = ParcelIdImpl(worldId, x, z)
|
||||||
|
|
||||||
private class ParcelWorldIdImpl(override val name: String,
|
private class ParcelWorldIdImpl(override val name: String,
|
||||||
override val uid: UUID?) : ParcelWorldId {
|
override val uid: UUID?) : ParcelWorldId {
|
||||||
override fun toString() = toStringExt()
|
override fun toString() = parcelWorldIdToString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ParcelIdImpl(override val worldId: ParcelWorldId,
|
private class ParcelIdImpl(override val worldId: ParcelWorldId,
|
||||||
override val x: Int,
|
override val x: Int,
|
||||||
override val z: Int) : ParcelId {
|
override val z: Int) : ParcelId {
|
||||||
override fun toString() = toStringExt()
|
override fun toString() = parcelIdToString()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,11 @@ import org.bukkit.World
|
|||||||
import org.bukkit.block.Block
|
import org.bukkit.block.Block
|
||||||
import org.bukkit.entity.Entity
|
import org.bukkit.entity.Entity
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
|
import java.lang.IllegalStateException
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
|
class Permit
|
||||||
|
|
||||||
interface ParcelProvider {
|
interface ParcelProvider {
|
||||||
val worlds: Map<String, ParcelWorld>
|
val worlds: Map<String, ParcelWorld>
|
||||||
|
|
||||||
@@ -43,6 +46,15 @@ interface ParcelProvider {
|
|||||||
fun getWorldGenerator(worldName: String): ParcelGenerator?
|
fun getWorldGenerator(worldName: String): ParcelGenerator?
|
||||||
|
|
||||||
fun loadWorlds()
|
fun loadWorlds()
|
||||||
|
|
||||||
|
fun acquireBlockVisitorPermit(parcelId: ParcelId, with: Permit): Boolean
|
||||||
|
|
||||||
|
@Throws(IllegalStateException::class)
|
||||||
|
fun releaseBlockVisitorPermit(parcelId: ParcelId, with: Permit)
|
||||||
|
|
||||||
|
fun trySubmitBlockVisitor(permit: Permit, parcelIds: Array<out ParcelId>, function: JobFunction): Job?
|
||||||
|
|
||||||
|
fun swapParcels(parcelId1: ParcelId, parcelId2: ParcelId): Job?
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ParcelLocator {
|
interface ParcelLocator {
|
||||||
@@ -69,7 +81,7 @@ interface ParcelContainer {
|
|||||||
|
|
||||||
fun getParcelById(id: Vec2i): Parcel? = getParcelById(id.x, id.z)
|
fun getParcelById(id: Vec2i): Parcel? = getParcelById(id.x, id.z)
|
||||||
|
|
||||||
fun getParcelById(id: ParcelId): Parcel? = getParcelById(id.x, id.z)
|
fun getParcelById(id: ParcelId): Parcel?
|
||||||
|
|
||||||
fun nextEmptyParcel(): Parcel?
|
fun nextEmptyParcel(): Parcel?
|
||||||
|
|
||||||
@@ -88,5 +100,4 @@ interface ParcelWorld : ParcelLocator, ParcelContainer {
|
|||||||
val globalPrivileges: GlobalPrivilegesManager
|
val globalPrivileges: GlobalPrivilegesManager
|
||||||
|
|
||||||
val creationTime: DateTime?
|
val creationTime: DateTime?
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ 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.BukkitJobDispatcher
|
|
||||||
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
|
||||||
@@ -17,6 +15,7 @@ import io.dico.parcels2.storage.Storage
|
|||||||
import io.dico.parcels2.util.MainThreadDispatcher
|
import io.dico.parcels2.util.MainThreadDispatcher
|
||||||
import io.dico.parcels2.util.PluginScheduler
|
import io.dico.parcels2.util.PluginScheduler
|
||||||
import io.dico.parcels2.util.ext.tryCreate
|
import io.dico.parcels2.util.ext.tryCreate
|
||||||
|
import io.dico.parcels2.util.isServerThread
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.generator.ChunkGenerator
|
import org.bukkit.generator.ChunkGenerator
|
||||||
@@ -47,6 +46,7 @@ class ParcelsPlugin : JavaPlugin(), CoroutineScope, PluginScheduler {
|
|||||||
val jobDispatcher: JobDispatcher by lazy { BukkitJobDispatcher(this, options.tickJobtime) }
|
val jobDispatcher: JobDispatcher by lazy { BukkitJobDispatcher(this, options.tickJobtime) }
|
||||||
|
|
||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
|
plogger.info("Is server thread: ${isServerThread()}")
|
||||||
plogger.info("Debug enabled: ${plogger.isDebugEnabled}")
|
plogger.info("Debug enabled: ${plogger.isDebugEnabled}")
|
||||||
plogger.debug(System.getProperty("user.dir"))
|
plogger.debug(System.getProperty("user.dir"))
|
||||||
if (!init()) {
|
if (!init()) {
|
||||||
|
|||||||
@@ -6,27 +6,89 @@ import io.dico.parcels2.util.math.Vec3i
|
|||||||
import io.dico.parcels2.util.math.clampMax
|
import io.dico.parcels2.util.math.clampMax
|
||||||
|
|
||||||
private typealias Scope = SequenceScope<Vec3i>
|
private typealias Scope = SequenceScope<Vec3i>
|
||||||
|
/*
|
||||||
|
class ParcelTraverser(
|
||||||
|
val parcelProvider: ParcelProvider,
|
||||||
|
val delegate: RegionTraverser,
|
||||||
|
scope: CoroutineScope
|
||||||
|
) : RegionTraverser(), CoroutineScope by scope {
|
||||||
|
|
||||||
sealed class RegionTraverser {
|
class OccupiedException(parcelId: ParcelId) : Exception("Parcel $parcelId is occupied")
|
||||||
fun traverseRegion(region: Region, worldHeight: Int = 256): Iterable<Vec3i> =
|
|
||||||
Iterable { iterator<Vec3i> { build(validify(region, worldHeight)) } }
|
|
||||||
|
|
||||||
private fun validify(region: Region, worldHeight: Int): Region {
|
/**
|
||||||
if (region.origin.y < 0) {
|
* Traverse the blocks of parcel's land
|
||||||
val origin = region.origin withY 0
|
* The iterator must be exhausted, else the permit to traverse it will not be reclaimed.
|
||||||
val size = region.size.withY((region.size.y + region.origin.y).clampMax(worldHeight))
|
*
|
||||||
return Region(origin, size)
|
* @throws OccupiedException if a parcel is maintained with the given parcel id and an
|
||||||
|
* iterator exists for it that has not been exhausted
|
||||||
|
*/
|
||||||
|
fun traverseParcel(parcelId: ParcelId): Iterator<Vec3i> {
|
||||||
|
val world = parcelProvider.getWorldById(parcelId.worldId)
|
||||||
|
?: throw IllegalArgumentException()
|
||||||
|
val parcel = parcelProvider.getParcelById(parcelId)
|
||||||
|
|
||||||
|
val medium = if (parcel != null) {
|
||||||
|
if (parcel.hasBlockVisitors || parcel !is ParcelImpl) {
|
||||||
|
throw OccupiedException(parcelId)
|
||||||
|
}
|
||||||
|
parcel.hasBlockVisitors = true
|
||||||
|
TraverserMedium { parcel.hasBlockVisitors = false }
|
||||||
|
} else {
|
||||||
|
TraverserMedium.DoNothing
|
||||||
}
|
}
|
||||||
|
|
||||||
if (region.origin.y + region.size.y > worldHeight) {
|
val region = world.blockManager.getRegion(parcelId)
|
||||||
val size = region.size.withY(worldHeight - region.origin.y)
|
return traverseRegion(region, world.world.maxHeight, medium)
|
||||||
return Region(region.origin, size)
|
|
||||||
}
|
|
||||||
|
|
||||||
return region
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract suspend fun Scope.build(region: Region)
|
override suspend fun Scope.build(region: Region, medium: TraverserMedium) {
|
||||||
|
with(delegate) {
|
||||||
|
return build(region, medium)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("FunctionName")
|
||||||
|
inline fun TraverserMedium(crossinline whenComplete: () -> Unit) =
|
||||||
|
object : TraverserMedium {
|
||||||
|
override fun iterationCompleted() {
|
||||||
|
whenComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object that is able to communicate with an iterator returned by [RegionTraverser]
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
interface TraverserMedium {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the traverser during first [Iterator.hasNext] call that returns false
|
||||||
|
*/
|
||||||
|
fun iterationCompleted()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default [TraverserMedium], which does nothing.
|
||||||
|
*/
|
||||||
|
object DoNothing : TraverserMedium {
|
||||||
|
override fun iterationCompleted() {}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
sealed class RegionTraverser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an iterator traversing [region] using this traverser.
|
||||||
|
* Depending on the implementation, [region] might be traversed in a specific order and direction.
|
||||||
|
*/
|
||||||
|
fun traverseRegion(
|
||||||
|
region: Region,
|
||||||
|
worldHeight: Int = 256/*,
|
||||||
|
medium: TraverserMedium = TraverserMedium.DoNothing*/
|
||||||
|
): Iterator<Vec3i> = iterator { build(validify(region, worldHeight)/*, medium*/) }
|
||||||
|
|
||||||
|
abstract suspend fun Scope.build(region: Region/*, medium: TraverserMedium = TraverserMedium.DoNothing*/)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val upward = Directional(TraverseDirection(1, 1, 1), TraverseOrderFactory.createWith(Dimension.Y, Dimension.X))
|
val upward = Directional(TraverseDirection(1, 1, 1), TraverseOrderFactory.createWith(Dimension.Y, Dimension.X))
|
||||||
@@ -34,9 +96,35 @@ sealed class RegionTraverser {
|
|||||||
val toClear get() = downward
|
val toClear get() = downward
|
||||||
val toFill get() = upward
|
val toFill get() = upward
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The returned [RegionTraverser] will traverse the regions
|
||||||
|
* * below and including absolute level [y] first, in [upward] direction.
|
||||||
|
* * above absolute level [y] last, in [downward] direction.
|
||||||
|
*/
|
||||||
fun convergingTo(y: Int) = Slicing(y, upward, downward, true)
|
fun convergingTo(y: Int) = Slicing(y, upward, downward, true)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The returned [RegionTraverser] will traverse the regions
|
||||||
|
* * above absolute level [y] first, in [upward] direction.
|
||||||
|
* * below and including absolute level [y] second, in [downward] direction.
|
||||||
|
*/
|
||||||
fun separatingFrom(y: Int) = Slicing(y, downward, upward, false)
|
fun separatingFrom(y: Int) = Slicing(y, downward, upward, false)
|
||||||
|
|
||||||
|
private fun validify(region: Region, worldHeight: Int): Region {
|
||||||
|
if (region.origin.y < 0) {
|
||||||
|
val origin = region.origin withY 0
|
||||||
|
val size = region.size.withY((region.size.y + region.origin.y).clampMax(worldHeight))
|
||||||
|
return Region(origin, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (region.origin.y + region.size.y > worldHeight) {
|
||||||
|
val size = region.size.withY(worldHeight - region.origin.y)
|
||||||
|
return Region(region.origin, size)
|
||||||
|
}
|
||||||
|
|
||||||
|
return region
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Directional(
|
class Directional(
|
||||||
@@ -50,7 +138,7 @@ sealed class RegionTraverser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun Scope.build(region: Region) {
|
override suspend fun Scope.build(region: Region/*, medium: TraverserMedium*/) {
|
||||||
val order = order
|
val order = order
|
||||||
val (primary, secondary, tertiary) = order.toArray()
|
val (primary, secondary, tertiary) = order.toArray()
|
||||||
val (origin, size) = region
|
val (origin, size) = region
|
||||||
@@ -71,6 +159,7 @@ sealed class RegionTraverser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*medium.iterationCompleted()*/
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -91,7 +180,7 @@ sealed class RegionTraverser {
|
|||||||
return region to null
|
return region to null
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun Scope.build(region: Region) {
|
override suspend fun Scope.build(region: Region/*, medium: TraverserMedium*/) {
|
||||||
val (bottom, top) = slice(region, bottomSectionMaxY)
|
val (bottom, top) = slice(region, bottomSectionMaxY)
|
||||||
|
|
||||||
if (bottomFirst) {
|
if (bottomFirst) {
|
||||||
@@ -101,15 +190,22 @@ sealed class RegionTraverser {
|
|||||||
top?.let { with(topTraverser) { build(it) } }
|
top?.let { with(topTraverser) { build(it) } }
|
||||||
with(bottomTraverser) { build(bottom) }
|
with(bottomTraverser) { build(bottom) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*medium.iterationCompleted()*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns [Directional] instance that would be responsible for
|
||||||
|
* emitting the given position if it is contained in a region.
|
||||||
|
* [Directional] instance has a set order and direction
|
||||||
|
*/
|
||||||
fun childForPosition(position: Vec3i): Directional {
|
fun childForPosition(position: Vec3i): Directional {
|
||||||
var cur = this
|
var cur = this
|
||||||
while (true) {
|
while (true) {
|
||||||
when (cur) {
|
when (cur) {
|
||||||
is Directional ->
|
/*is ParcelTraverser -> cur = cur.delegate*/
|
||||||
return cur
|
is Directional -> return cur
|
||||||
is Slicing ->
|
is Slicing ->
|
||||||
cur =
|
cur =
|
||||||
if (position.y <= cur.bottomSectionMaxY) cur.bottomTraverser
|
if (position.y <= cur.bottomSectionMaxY) cur.bottomTraverser
|
||||||
@@ -118,10 +214,17 @@ sealed class RegionTraverser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if and only if this traverser would visit the given
|
||||||
|
* [block] position before the given [current] position.
|
||||||
|
* If at least one of [block] and [current] is not contained in a
|
||||||
|
* region being traversed the result is undefined.
|
||||||
|
*/
|
||||||
fun comesFirst(current: Vec3i, block: Vec3i): Boolean {
|
fun comesFirst(current: Vec3i, block: Vec3i): Boolean {
|
||||||
var cur = this
|
var cur = this
|
||||||
while (true) {
|
while (true) {
|
||||||
when (cur) {
|
when (cur) {
|
||||||
|
/*is ParcelTraverser -> cur = cur.delegate*/
|
||||||
is Directional -> return cur.direction.comesFirst(current, block)
|
is Directional -> return cur.direction.comesFirst(current, block)
|
||||||
is Slicing -> {
|
is Slicing -> {
|
||||||
val border = cur.bottomSectionMaxY
|
val border = cur.bottomSectionMaxY
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package io.dico.parcels2.blockvisitor
|
package io.dico.parcels2.blockvisitor
|
||||||
|
|
||||||
|
import io.dico.parcels2.JobFunction
|
||||||
|
import io.dico.parcels2.JobScope
|
||||||
import io.dico.parcels2.util.math.Region
|
import io.dico.parcels2.util.math.Region
|
||||||
import io.dico.parcels2.util.math.Vec3i
|
import io.dico.parcels2.util.math.Vec3i
|
||||||
import io.dico.parcels2.util.math.get
|
import io.dico.parcels2.util.math.get
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package io.dico.parcels2.command
|
package io.dico.parcels2.command
|
||||||
|
|
||||||
import io.dico.dicore.command.*
|
import io.dico.dicore.command.CommandException
|
||||||
import io.dico.parcels2.ParcelWorld
|
import io.dico.dicore.command.EMessageType
|
||||||
import io.dico.parcels2.ParcelsPlugin
|
import io.dico.dicore.command.ExecutionContext
|
||||||
import io.dico.parcels2.PlayerProfile
|
import io.dico.dicore.command.ICommandReceiver
|
||||||
import io.dico.parcels2.PlayerProfile.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.PrivilegeKey
|
import io.dico.parcels2.PlayerProfile.Real
|
||||||
import io.dico.parcels2.blockvisitor.Job
|
import io.dico.parcels2.PlayerProfile.Unresolved
|
||||||
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
|
||||||
@@ -42,15 +42,13 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei
|
|||||||
else -> throw CommandException()
|
else -> throw CommandException()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun areYouSureMessage(context: ExecutionContext) = "Are you sure? You cannot undo this action!\n" +
|
protected fun areYouSureMessage(context: ExecutionContext): String {
|
||||||
"Run \"/${context.route.joinToString(" ")} -sure\" if you want to go through with this."
|
val command = (context.route + context.original).joinToString(" ") + " -sure"
|
||||||
|
return "Are you sure? You cannot undo this action!\n" +
|
||||||
protected fun ParcelScope.clearWithProgressUpdates(context: ExecutionContext, action: String) {
|
"Run \"/$command\" if you want to go through with this."
|
||||||
Validate.isTrue(!parcel.hasBlockVisitors, "A process is already running in this parcel")
|
|
||||||
world.blockManager.clearParcel(parcel.id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun Job.reportProgressUpdates(context: ExecutionContext, action: String) {
|
protected fun Job.reportProgressUpdates(context: ExecutionContext, action: String): Job =
|
||||||
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)
|
||||||
@@ -59,7 +57,6 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei
|
|||||||
.format(progress * 100, elapsedTime / 1000.0)
|
.format(progress * 100, elapsedTime / 1000.0)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCoroutineContext() = plugin.coroutineContext
|
override fun getCoroutineContext() = plugin.coroutineContext
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,10 @@ import io.dico.dicore.command.ExecutionContext
|
|||||||
import io.dico.dicore.command.Validate
|
import io.dico.dicore.command.Validate
|
||||||
import io.dico.dicore.command.annotation.Cmd
|
import io.dico.dicore.command.annotation.Cmd
|
||||||
import io.dico.dicore.command.annotation.Flag
|
import io.dico.dicore.command.annotation.Flag
|
||||||
import io.dico.parcels2.ParcelsPlugin
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.PlayerProfile
|
|
||||||
import io.dico.parcels2.Privilege
|
|
||||||
import io.dico.parcels2.command.ParcelTarget.TargetKind
|
import io.dico.parcels2.command.ParcelTarget.TargetKind
|
||||||
import io.dico.parcels2.resolved
|
import io.dico.parcels2.defaultimpl.DefaultParcelContainer
|
||||||
|
import io.dico.parcels2.util.ext.PERM_ADMIN_MANAGE
|
||||||
|
|
||||||
class CommandsAdmin(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
class CommandsAdmin(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||||
|
|
||||||
@@ -23,6 +22,33 @@ class CommandsAdmin(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
return "${profile.notNullName}$fakeString is the new owner of (${parcel.id.idString})"
|
return "${profile.notNullName}$fakeString is the new owner of (${parcel.id.idString})"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Cmd("update_all_owner_signs")
|
||||||
|
fun cmdUpdateAllOwnerSigns(context: ExecutionContext): Any? {
|
||||||
|
Validate.isAuthorized(context.sender, PERM_ADMIN_MANAGE)
|
||||||
|
plugin.jobDispatcher.dispatch {
|
||||||
|
fun getParcelCount(world: ParcelWorld) = (world.options.axisLimit * 2 + 1).let { it * it }
|
||||||
|
val parcelCount = plugin.parcelProvider.worlds.values.sumBy { getParcelCount(it) }.toDouble()
|
||||||
|
var processed = 0
|
||||||
|
for (world in plugin.parcelProvider.worlds.values) {
|
||||||
|
markSuspensionPoint()
|
||||||
|
|
||||||
|
val container = world.container as? DefaultParcelContainer
|
||||||
|
if (container == null) {
|
||||||
|
processed += getParcelCount(world)
|
||||||
|
setProgress(processed / parcelCount)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for (parcel in container.getAllParcels()) {
|
||||||
|
parcel.updateOwnerSign(force = true)
|
||||||
|
processed++
|
||||||
|
setProgress(processed / parcelCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.reportProgressUpdates(context, "Updating")
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
@Cmd("dispose")
|
@Cmd("dispose")
|
||||||
@RequireParcelPrivilege(Privilege.ADMIN)
|
@RequireParcelPrivilege(Privilege.ADMIN)
|
||||||
fun ParcelScope.cmdDispose(): Any? {
|
fun ParcelScope.cmdDispose(): Any? {
|
||||||
@@ -37,15 +63,17 @@ class CommandsAdmin(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
if (!sure) return areYouSureMessage(context)
|
if (!sure) return areYouSureMessage(context)
|
||||||
|
|
||||||
parcel.dispose()
|
parcel.dispose()
|
||||||
world.blockManager.clearParcel(parcel.id).reportProgressUpdates(context, "Reset")
|
world.blockManager.clearParcel(parcel.id)?.reportProgressUpdates(context, "Reset")
|
||||||
return "Data of (${parcel.id.idString}) has been disposed"
|
return "Data of (${parcel.id.idString}) has been disposed"
|
||||||
}
|
}
|
||||||
|
|
||||||
@Cmd("swap")
|
@Cmd("swap")
|
||||||
@RequireParcelPrivilege(Privilege.ADMIN)
|
@RequireParcelPrivilege(Privilege.ADMIN)
|
||||||
fun ParcelScope.cmdSwap(context: ExecutionContext,
|
fun ParcelScope.cmdSwap(
|
||||||
@TargetKind(TargetKind.ID) target: ParcelTarget,
|
context: ExecutionContext,
|
||||||
@Flag sure: Boolean): Any? {
|
@TargetKind(TargetKind.ID) target: ParcelTarget,
|
||||||
|
@Flag sure: Boolean
|
||||||
|
): Any? {
|
||||||
Validate.isTrue(!parcel.hasBlockVisitors, "A process is already running in this parcel")
|
Validate.isTrue(!parcel.hasBlockVisitors, "A process is already running in this parcel")
|
||||||
if (!sure) return areYouSureMessage(context)
|
if (!sure) return areYouSureMessage(context)
|
||||||
|
|
||||||
@@ -53,13 +81,14 @@ class CommandsAdmin(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
?: throw CommandException("Invalid parcel target")
|
?: throw CommandException("Invalid parcel target")
|
||||||
|
|
||||||
// Validate.isTrue(parcel2.world == world, "Parcel must be in the same world")
|
// Validate.isTrue(parcel2.world == world, "Parcel must be in the same world")
|
||||||
Validate.isTrue(!parcel2.hasBlockVisitors, "A process is already running in this parcel")
|
Validate.isTrue(!parcel2.hasBlockVisitors, "A process is already running in that parcel")
|
||||||
|
|
||||||
val data = parcel.data
|
val data = parcel.data
|
||||||
parcel.copyData(parcel2.data)
|
parcel.copyData(parcel2.data)
|
||||||
parcel2.copyData(data)
|
parcel2.copyData(data)
|
||||||
|
|
||||||
world.blockManager.swapParcels(parcel.id, parcel2.id).reportProgressUpdates(context, "Swap")
|
val job = plugin.parcelProvider.swapParcels(parcel.id, parcel2.id)?.reportProgressUpdates(context, "Swap")
|
||||||
|
Validate.notNull(job, "A process is already running in some parcel (internal error)")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package io.dico.parcels2.command
|
package io.dico.parcels2.command
|
||||||
|
|
||||||
|
import io.dico.dicore.Formatting
|
||||||
import io.dico.dicore.command.*
|
import io.dico.dicore.command.*
|
||||||
import io.dico.dicore.command.IContextFilter.Priority.PERMISSION
|
import io.dico.dicore.command.IContextFilter.Priority.PERMISSION
|
||||||
import io.dico.dicore.command.annotation.Cmd
|
import io.dico.dicore.command.annotation.Cmd
|
||||||
@@ -54,9 +55,9 @@ class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
)
|
)
|
||||||
val random = Random()
|
val random = Random()
|
||||||
|
|
||||||
world.blockManager.doBlockOperation(parcel.id, traverser = RegionTraverser.upward) { block ->
|
world.blockManager.tryDoBlockOperation(plugin.parcelProvider, parcel.id, traverser = RegionTraverser.upward) { block ->
|
||||||
block.blockData = blockDatas[random.nextInt(7)]
|
block.blockData = blockDatas[random.nextInt(7)]
|
||||||
}.onProgressUpdate(1000, 1000) { progress, elapsedTime ->
|
}?.onProgressUpdate(1000, 1000) { progress, elapsedTime ->
|
||||||
context.sendMessage(
|
context.sendMessage(
|
||||||
EMessageType.INFORMATIVE, "Mess progress: %.02f%%, %.2fs elapsed"
|
EMessageType.INFORMATIVE, "Mess progress: %.02f%%, %.2fs elapsed"
|
||||||
.format(progress * 100, elapsedTime / 1000.0)
|
.format(progress * 100, elapsedTime / 1000.0)
|
||||||
@@ -82,7 +83,7 @@ class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
@Cmd("jobs")
|
@Cmd("jobs")
|
||||||
fun cmdJobs(): Any? {
|
fun cmdJobs(): Any? {
|
||||||
val workers = plugin.jobDispatcher.jobs
|
val workers = plugin.jobDispatcher.jobs
|
||||||
println(workers.map { it.job }.joinToString(separator = "\n"))
|
println(workers.map { it.coroutine }.joinToString(separator = "\n"))
|
||||||
return "Task count: ${workers.size}"
|
return "Task count: ${workers.size}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +96,7 @@ class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
@PreprocessArgs
|
@PreprocessArgs
|
||||||
fun cmdMessage(sender: CommandSender, message: String): Any? {
|
fun cmdMessage(sender: CommandSender, message: String): Any? {
|
||||||
// testing @PreprocessArgs which merges "hello there" into a single argument
|
// testing @PreprocessArgs which merges "hello there" into a single argument
|
||||||
sender.sendMessage(message)
|
sender.sendMessage(Formatting.translate(message))
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ class CommandsGeneral(plugin: ParcelsPlugin, parent: SpecialCommandAddress) : Ab
|
|||||||
fun ParcelScope.cmdClear(context: ExecutionContext, @Flag sure: Boolean): Any? {
|
fun ParcelScope.cmdClear(context: ExecutionContext, @Flag sure: Boolean): Any? {
|
||||||
Validate.isTrue(!parcel.hasBlockVisitors, "A process is already running in this parcel")
|
Validate.isTrue(!parcel.hasBlockVisitors, "A process is already running in this parcel")
|
||||||
if (!sure) return areYouSureMessage(context)
|
if (!sure) return areYouSureMessage(context)
|
||||||
world.blockManager.clearParcel(parcel.id).reportProgressUpdates(context, "Clear")
|
world.blockManager.clearParcel(parcel.id)?.reportProgressUpdates(context, "Clear")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ class CommandsGeneral(plugin: ParcelsPlugin, parent: SpecialCommandAddress) : Ab
|
|||||||
@RequireParcelPrivilege(Privilege.OWNER)
|
@RequireParcelPrivilege(Privilege.OWNER)
|
||||||
fun ParcelScope.cmdSetbiome(context: ExecutionContext, biome: Biome): Any? {
|
fun ParcelScope.cmdSetbiome(context: ExecutionContext, biome: Biome): Any? {
|
||||||
Validate.isTrue(!parcel.hasBlockVisitors, "A process is already running in this parcel")
|
Validate.isTrue(!parcel.hasBlockVisitors, "A process is already running in this parcel")
|
||||||
world.blockManager.setBiome(parcel.id, biome).reportProgressUpdates(context, "Biome change")
|
world.blockManager.setBiome(parcel.id, biome)?.reportProgressUpdates(context, "Biome change")
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,8 +92,8 @@ sealed class ParcelTarget(val world: ParcelWorld, val parsedKind: Int, val isDef
|
|||||||
|
|
||||||
override fun parse(parameter: Parameter<ParcelTarget, Int>, sender: CommandSender, buffer: ArgumentBuffer): ParcelTarget {
|
override fun parse(parameter: Parameter<ParcelTarget, Int>, sender: CommandSender, buffer: ArgumentBuffer): ParcelTarget {
|
||||||
var input = buffer.next()
|
var input = buffer.next()
|
||||||
val worldString = input.substringBefore("->", missingDelimiterValue = "")
|
val worldString = input.substringBefore("/", missingDelimiterValue = "")
|
||||||
input = input.substringAfter("->")
|
input = input.substringAfter("/")
|
||||||
|
|
||||||
val world = if (worldString.isEmpty()) {
|
val world = if (worldString.isEmpty()) {
|
||||||
val player = requirePlayer(sender, parameter, "the world")
|
val player = requirePlayer(sender, parameter, "the world")
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class DefaultParcelContainer(val world: ParcelWorld) : ParcelContainer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun allParcels(): Sequence<Parcel> = sequence {
|
fun getAllParcels(): Iterator<Parcel> = iterator {
|
||||||
for (array in parcels) {
|
for (array in parcels) {
|
||||||
yieldAll(array.iterator())
|
yieldAll(array.iterator())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,14 @@
|
|||||||
package io.dico.parcels2.defaultimpl
|
package io.dico.parcels2.defaultimpl
|
||||||
|
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.blockvisitor.*
|
import io.dico.parcels2.blockvisitor.RegionTraverser
|
||||||
import io.dico.parcels2.options.DefaultGeneratorOptions
|
import io.dico.parcels2.options.DefaultGeneratorOptions
|
||||||
import io.dico.parcels2.util.math.Region
|
import io.dico.parcels2.util.math.*
|
||||||
import io.dico.parcels2.util.math.Vec2i
|
|
||||||
import io.dico.parcels2.util.math.Vec3i
|
|
||||||
import io.dico.parcels2.util.math.even
|
|
||||||
import io.dico.parcels2.util.math.umod
|
|
||||||
import io.dico.parcels2.util.math.get
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.bukkit.*
|
import org.bukkit.*
|
||||||
import org.bukkit.block.Biome
|
import org.bukkit.block.Biome
|
||||||
import org.bukkit.block.BlockFace
|
import org.bukkit.block.BlockFace
|
||||||
import org.bukkit.block.Skull
|
import org.bukkit.block.Skull
|
||||||
import org.bukkit.block.data.BlockData
|
|
||||||
import org.bukkit.block.data.type.Slab
|
import org.bukkit.block.data.type.Slab
|
||||||
import org.bukkit.block.data.type.WallSign
|
import org.bukkit.block.data.type.WallSign
|
||||||
import java.util.Random
|
import java.util.Random
|
||||||
@@ -118,12 +110,13 @@ class DefaultParcelGenerator(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun makeParcelLocatorAndBlockManager(
|
override fun makeParcelLocatorAndBlockManager(
|
||||||
worldId: ParcelWorldId,
|
parcelProvider: ParcelProvider,
|
||||||
container: ParcelContainer,
|
container: ParcelContainer,
|
||||||
coroutineScope: CoroutineScope,
|
coroutineScope: CoroutineScope,
|
||||||
jobDispatcher: JobDispatcher
|
jobDispatcher: JobDispatcher
|
||||||
): Pair<ParcelLocator, ParcelBlockManager> {
|
): Pair<ParcelLocator, ParcelBlockManager> {
|
||||||
return ParcelLocatorImpl(worldId, container) to ParcelBlockManagerImpl(worldId, coroutineScope, jobDispatcher)
|
val impl = ParcelLocatorAndBlockManagerImpl(parcelProvider, container, coroutineScope, jobDispatcher)
|
||||||
|
return impl to impl
|
||||||
}
|
}
|
||||||
|
|
||||||
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? {
|
||||||
@@ -139,11 +132,25 @@ class DefaultParcelGenerator(
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class ParcelLocatorImpl(
|
@Suppress("DEPRECATION")
|
||||||
val worldId: ParcelWorldId,
|
private inner class ParcelLocatorAndBlockManagerImpl(
|
||||||
val container: ParcelContainer
|
val parcelProvider: ParcelProvider,
|
||||||
) : ParcelLocator {
|
val container: ParcelContainer,
|
||||||
override val world: World = this@DefaultParcelGenerator.world
|
coroutineScope: CoroutineScope,
|
||||||
|
override val jobDispatcher: JobDispatcher
|
||||||
|
) : ParcelBlockManagerBase(), ParcelLocator, CoroutineScope by coroutineScope {
|
||||||
|
|
||||||
|
override val world: World get() = this@DefaultParcelGenerator.world
|
||||||
|
val worldId = parcelProvider.getWorld(world)?.id ?: ParcelWorldId(world)
|
||||||
|
override val parcelTraverser: RegionTraverser = RegionTraverser.convergingTo(o.floorHeight)
|
||||||
|
|
||||||
|
private val cornerWallType = when {
|
||||||
|
o.wallType is Slab -> (o.wallType.clone() as Slab).apply { type = Slab.Type.DOUBLE }
|
||||||
|
o.wallType.material.name.endsWith("CARPET") -> {
|
||||||
|
Bukkit.createBlockData(Material.getMaterial(o.wallType.material.name.substringBefore("CARPET") + "WOOL"))
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
override fun getParcelAt(x: Int, z: Int): Parcel? {
|
override fun getParcelAt(x: Int, z: Int): Parcel? {
|
||||||
return convertBlockLocationToId(x, z, container::getParcelById)
|
return convertBlockLocationToId(x, z, container::getParcelById)
|
||||||
@@ -152,112 +159,113 @@ class DefaultParcelGenerator(
|
|||||||
override fun getParcelIdAt(x: Int, z: Int): ParcelId? {
|
override fun getParcelIdAt(x: Int, z: Int): ParcelId? {
|
||||||
return convertBlockLocationToId(x, z) { idx, idz -> ParcelId(worldId, idx, idz) }
|
return convertBlockLocationToId(x, z) { idx, idz -> ParcelId(worldId, idx, idz) }
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
private inner class ParcelBlockManagerImpl(
|
|
||||||
val worldId: ParcelWorldId,
|
|
||||||
coroutineScope: CoroutineScope,
|
|
||||||
override val jobDispatcher: JobDispatcher
|
|
||||||
) : ParcelBlockManagerBase(), CoroutineScope by coroutineScope {
|
|
||||||
override val world: World = this@DefaultParcelGenerator.world
|
|
||||||
override val parcelTraverser: RegionTraverser = RegionTraverser.convergingTo(o.floorHeight)
|
|
||||||
|
|
||||||
/*override*/ fun getBottomBlock(parcel: ParcelId): Vec2i = Vec2i(
|
private fun checkParcelId(parcel: ParcelId): ParcelId {
|
||||||
sectionSize * (parcel.x - 1) + pathOffset + o.offsetX,
|
if (!parcel.worldId.equals(worldId)) {
|
||||||
sectionSize * (parcel.z - 1) + pathOffset + o.offsetZ
|
throw IllegalArgumentException()
|
||||||
)
|
}
|
||||||
|
return parcel
|
||||||
|
}
|
||||||
|
|
||||||
override fun getHomeLocation(parcel: ParcelId): Location {
|
override fun getRegionOrigin(parcel: ParcelId): Vec2i {
|
||||||
val bottom = getBottomBlock(parcel)
|
checkParcelId(parcel)
|
||||||
val x = bottom.x + (o.parcelSize - 1) / 2.0
|
return Vec2i(
|
||||||
val z = bottom.z - 2
|
sectionSize * (parcel.x - 1) + pathOffset + o.offsetX,
|
||||||
return Location(world, x + 0.5, o.floorHeight + 1.0, z + 0.5, 0F, 0F)
|
sectionSize * (parcel.z - 1) + pathOffset + o.offsetZ
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getRegion(parcel: ParcelId): Region {
|
override fun getRegion(parcel: ParcelId): Region {
|
||||||
val bottom = getBottomBlock(parcel)
|
val origin = getRegionOrigin(parcel)
|
||||||
return Region(
|
return Region(
|
||||||
Vec3i(bottom.x, 0, bottom.z),
|
Vec3i(origin.x, 0, origin.z),
|
||||||
Vec3i(o.parcelSize, maxHeight, o.parcelSize)
|
Vec3i(o.parcelSize, maxHeight, o.parcelSize)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getRegionConsideringWorld(parcel: ParcelId): Region {
|
override fun getHomeLocation(parcel: ParcelId): Location {
|
||||||
if (parcel.worldId != worldId) {
|
val origin = getRegionOrigin(parcel)
|
||||||
(parcel.worldId as? ParcelWorld)?.let {
|
val x = origin.x + (o.parcelSize - 1) / 2.0
|
||||||
return it.blockManager.getRegion(parcel)
|
val z = origin.z - 2
|
||||||
}
|
return Location(world, x + 0.5, o.floorHeight + 1.0, z + 0.5, 0F, 0F)
|
||||||
throw IllegalArgumentException()
|
|
||||||
}
|
|
||||||
return getRegion(parcel)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setOwnerBlock(parcel: ParcelId, owner: PlayerProfile?) {
|
override fun getParcelForInfoBlockInteraction(block: Vec3i, type: Material, face: BlockFace): Parcel? {
|
||||||
val b = getBottomBlock(parcel)
|
if (block.y != o.floorHeight + 1) return null
|
||||||
|
|
||||||
|
val expectedParcelOrigin = when (type) {
|
||||||
|
Material.WALL_SIGN -> Vec2i(block.x + 1, block.z + 2)
|
||||||
|
o.wallType.material, cornerWallType?.material -> {
|
||||||
|
if (face != BlockFace.NORTH || world[block + Vec3i.convert(BlockFace.NORTH)].type == Material.WALL_SIGN) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec2i(block.x + 1, block.z + 1)
|
||||||
|
}
|
||||||
|
else -> return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return getParcelAt(expectedParcelOrigin.x, expectedParcelOrigin.z)
|
||||||
|
?.takeIf { expectedParcelOrigin == getRegionOrigin(it.id) }
|
||||||
|
?.also { parcel ->
|
||||||
|
if (type != Material.WALL_SIGN && parcel.owner != null) {
|
||||||
|
updateParcelInfo(parcel.id, parcel.owner)
|
||||||
|
parcel.isOwnerSignOutdated = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun isParcelInfoSectionLoaded(parcel: ParcelId): Boolean {
|
||||||
|
val wallBlockChunk = getRegionOrigin(parcel).add(-1, -1).toChunk()
|
||||||
|
return world.isChunkLoaded(wallBlockChunk.x, wallBlockChunk.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun updateParcelInfo(parcel: ParcelId, owner: PlayerProfile?) {
|
||||||
|
val b = getRegionOrigin(parcel)
|
||||||
|
|
||||||
val wallBlock = world.getBlockAt(b.x - 1, o.floorHeight + 1, b.z - 1)
|
val wallBlock = world.getBlockAt(b.x - 1, o.floorHeight + 1, b.z - 1)
|
||||||
val signBlock = world.getBlockAt(b.x - 2, o.floorHeight + 1, b.z - 1)
|
val signBlock = world.getBlockAt(b.x - 1, o.floorHeight + 1, b.z - 2)
|
||||||
val skullBlock = world.getBlockAt(b.x - 1, o.floorHeight + 2, b.z - 1)
|
val skullBlock = world.getBlockAt(b.x - 1, o.floorHeight + 2, b.z - 1)
|
||||||
|
|
||||||
if (owner == null) {
|
if (owner == null) {
|
||||||
wallBlock.blockData = o.wallType
|
wallBlock.blockData = o.wallType
|
||||||
signBlock.type = Material.AIR
|
signBlock.type = Material.AIR
|
||||||
skullBlock.type = Material.AIR
|
skullBlock.type = Material.AIR
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
cornerWallType?.let { wallBlock.blockData = it }
|
||||||
val wallBlockType: BlockData = if (o.wallType is Slab)
|
|
||||||
(o.wallType.clone() as Slab).apply { type = Slab.Type.DOUBLE }
|
|
||||||
else
|
|
||||||
o.wallType
|
|
||||||
|
|
||||||
wallBlock.blockData = wallBlockType
|
|
||||||
signBlock.blockData = (Bukkit.createBlockData(Material.WALL_SIGN) as WallSign).apply { facing = BlockFace.NORTH }
|
signBlock.blockData = (Bukkit.createBlockData(Material.WALL_SIGN) as WallSign).apply { facing = BlockFace.NORTH }
|
||||||
|
|
||||||
val sign = signBlock.state as org.bukkit.block.Sign
|
val sign = signBlock.state as org.bukkit.block.Sign
|
||||||
sign.setLine(0, "${parcel.x},${parcel.z}")
|
sign.setLine(0, "${parcel.x},${parcel.z}")
|
||||||
sign.setLine(2, owner.name)
|
sign.setLine(2, owner.name ?: "")
|
||||||
sign.update()
|
sign.update()
|
||||||
|
|
||||||
|
skullBlock.type = Material.AIR
|
||||||
skullBlock.type = Material.PLAYER_HEAD
|
skullBlock.type = Material.PLAYER_HEAD
|
||||||
val skull = skullBlock.state as Skull
|
val skull = skullBlock.state as Skull
|
||||||
if (owner is PlayerProfile.Real) {
|
if (owner is PlayerProfile.Real) {
|
||||||
skull.owningPlayer = Bukkit.getOfflinePlayer(owner.uuid)
|
skull.owningPlayer = Bukkit.getOfflinePlayer(owner.uuid)
|
||||||
} else {
|
|
||||||
skull.owner = owner.name
|
} else if (!skull.setOwner(owner.name)) {
|
||||||
|
skullBlock.type = Material.AIR
|
||||||
|
return
|
||||||
}
|
}
|
||||||
skull.rotation = BlockFace.WEST
|
|
||||||
|
skull.rotation = BlockFace.SOUTH
|
||||||
skull.update()
|
skull.update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getParcel(parcelId: ParcelId): Parcel? {
|
private fun trySubmitBlockVisitor(vararg parcels: ParcelId, function: JobFunction): Job? {
|
||||||
// todo dont rely on this cast
|
parcels.forEach { checkParcelId(it) }
|
||||||
val world = worldId as? ParcelWorld ?: return null
|
return parcelProvider.trySubmitBlockVisitor(Permit(), parcels, function)
|
||||||
return world.getParcelById(parcelId)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun submitBlockVisitor(vararg parcelIds: ParcelId, task: JobFunction): Job {
|
override fun setBiome(parcel: ParcelId, biome: Biome) = trySubmitBlockVisitor(checkParcelId(parcel)) {
|
||||||
val parcels = parcelIds.mapNotNull { getParcel(it) }
|
|
||||||
if (parcels.isEmpty()) return jobDispatcher.dispatch(task)
|
|
||||||
if (parcels.any { it.hasBlockVisitors }) throw IllegalArgumentException("This parcel already has a block visitor")
|
|
||||||
|
|
||||||
val worker = jobDispatcher.dispatch(task)
|
|
||||||
|
|
||||||
for (parcel in parcels) {
|
|
||||||
launch(start = UNDISPATCHED) {
|
|
||||||
parcel.withBlockVisitorPermit {
|
|
||||||
worker.awaitCompletion()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return worker
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setBiome(parcel: ParcelId, biome: Biome): Job = submitBlockVisitor(parcel) {
|
|
||||||
val world = world
|
val world = world
|
||||||
val b = getBottomBlock(parcel)
|
val b = getRegionOrigin(parcel)
|
||||||
val parcelSize = o.parcelSize
|
val parcelSize = o.parcelSize
|
||||||
for (x in b.x until b.x + parcelSize) {
|
for (x in b.x until b.x + parcelSize) {
|
||||||
for (z in b.z until b.z + parcelSize) {
|
for (z in b.z until b.z + parcelSize) {
|
||||||
@@ -267,7 +275,7 @@ class DefaultParcelGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clearParcel(parcel: ParcelId): Job = submitBlockVisitor(parcel) {
|
override fun clearParcel(parcel: ParcelId) = trySubmitBlockVisitor(checkParcelId(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()
|
||||||
@@ -291,22 +299,6 @@ class DefaultParcelGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun swapParcels(parcel1: ParcelId, parcel2: ParcelId): Job = submitBlockVisitor(parcel1, parcel2) {
|
|
||||||
var region1 = getRegionConsideringWorld(parcel1)
|
|
||||||
var region2 = getRegionConsideringWorld(parcel2)
|
|
||||||
|
|
||||||
val size = region1.size.clampMax(region2.size)
|
|
||||||
if (size != region1.size) {
|
|
||||||
region1 = region1.withSize(size)
|
|
||||||
region2 = region2.withSize(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
val schematicOf1 = delegateWork(0.25) { Schematic().apply { load(world, region1) } }
|
|
||||||
val schematicOf2 = delegateWork(0.25) { Schematic().apply { load(world, region2) } }
|
|
||||||
delegateWork(0.25) { with(schematicOf1) { paste(world, region2.origin) } }
|
|
||||||
delegateWork(0.25) { with(schematicOf2) { paste(world, region1.origin) } }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getParcelsWithOwnerBlockIn(chunk: Chunk): Collection<Vec2i> {
|
override fun getParcelsWithOwnerBlockIn(chunk: Chunk): Collection<Vec2i> {
|
||||||
/*
|
/*
|
||||||
* Get the offsets for the world out of the way
|
* Get the offsets for the world out of the way
|
||||||
|
|||||||
@@ -3,59 +3,84 @@ package io.dico.parcels2.defaultimpl
|
|||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.Privilege.*
|
import io.dico.parcels2.Privilege.*
|
||||||
import io.dico.parcels2.util.ext.alsoIfTrue
|
import io.dico.parcels2.util.ext.alsoIfTrue
|
||||||
|
import io.dico.parcels2.util.isServerThread
|
||||||
import io.dico.parcels2.util.math.Vec2i
|
import io.dico.parcels2.util.math.Vec2i
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.lang.IllegalStateException
|
||||||
|
|
||||||
class ParcelImpl(
|
class ParcelImpl (
|
||||||
override val world: ParcelWorld,
|
override val world: ParcelWorld,
|
||||||
override val x: Int,
|
override val x: Int,
|
||||||
override val z: Int
|
override val z: Int
|
||||||
) : Parcel, ParcelId {
|
) : Parcel, ParcelId {
|
||||||
override val id: ParcelId = this
|
override val id: ParcelId get() = this
|
||||||
override val pos get() = Vec2i(x, z)
|
override val pos get() = Vec2i(x, z)
|
||||||
override var data: ParcelDataHolder = ParcelDataHolder(); private set
|
override var data = ParcelDataHolder(); private set
|
||||||
override val hasBlockVisitors get() = blockVisitors.get() > 0
|
|
||||||
override val worldId: ParcelWorldId get() = world.id
|
override val worldId: ParcelWorldId get() = world.id
|
||||||
|
|
||||||
override fun copyDataIgnoringDatabase(data: ParcelData) {
|
override fun copyData(newData: ParcelDataHolder, callerIsDatabase: Boolean) {
|
||||||
this.data = ((data as? Parcel)?.data ?: data) as ParcelDataHolder
|
if (callerIsDatabase) {
|
||||||
}
|
data = newData
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val ownerChanged = owner != newData.owner
|
||||||
|
if (ownerChanged) {
|
||||||
|
updateOwnerSign(true, false, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val ownerSignWasOutdated = if (callerIsDatabase) newData.isOwnerSignOutdated else isOwnerSignOutdated
|
||||||
|
val ownerChanged = owner != newData.owner
|
||||||
|
|
||||||
|
data = newData
|
||||||
|
|
||||||
|
if (ownerChanged && isServerThread()) {
|
||||||
|
updateOwnerSign(true, false, updateDatabase = callerIsDatabase)
|
||||||
|
} else {
|
||||||
|
newData.isOwnerSignOutdated = ownerChanged || ownerSignWasOutdated
|
||||||
|
}
|
||||||
|
|
||||||
override fun copyData(data: ParcelData) {
|
|
||||||
copyDataIgnoringDatabase(data)
|
|
||||||
world.storage.setParcelData(this, data)
|
world.storage.setParcelData(this, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun dispose() {
|
|
||||||
copyDataIgnoringDatabase(ParcelDataHolder())
|
|
||||||
world.storage.setParcelData(this, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override var owner: PlayerProfile?
|
override var owner: PlayerProfile?
|
||||||
get() = data.owner
|
get() = data.owner
|
||||||
set(value) {
|
set(value) {
|
||||||
if (data.owner != value) {
|
if (data.owner != value) {
|
||||||
world.storage.setParcelOwner(this, value)
|
world.storage.setParcelOwner(this, value)
|
||||||
world.blockManager.setOwnerBlock(this, value)
|
|
||||||
data.owner = value
|
data.owner = value
|
||||||
|
updateOwnerSign(true, false, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override val lastClaimTime: DateTime?
|
override val lastClaimTime: DateTime?
|
||||||
get() = data.lastClaimTime
|
get() = data.lastClaimTime
|
||||||
|
|
||||||
override var ownerSignOutdated: Boolean
|
override var isOwnerSignOutdated: Boolean
|
||||||
get() = data.ownerSignOutdated
|
get() = data.isOwnerSignOutdated
|
||||||
set(value) {
|
set(value) {
|
||||||
if (data.ownerSignOutdated != value) {
|
if (data.isOwnerSignOutdated != value) {
|
||||||
world.storage.setParcelOwnerSignOutdated(this, value)
|
world.storage.setParcelOwnerSignOutdated(this, value)
|
||||||
data.ownerSignOutdated = value
|
data.isOwnerSignOutdated = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun updateOwnerSign(force: Boolean) {
|
||||||
|
updateOwnerSign(false, force, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateOwnerSign(ownerChanged: Boolean, force: Boolean, updateDatabase: Boolean) {
|
||||||
|
if (!ownerChanged && !isOwnerSignOutdated && !force) return
|
||||||
|
|
||||||
|
val update = force || world.blockManager.isParcelInfoSectionLoaded(this)
|
||||||
|
if (update) world.blockManager.updateParcelInfo(this, owner)
|
||||||
|
|
||||||
|
if (updateDatabase) isOwnerSignOutdated = !update
|
||||||
|
else data.isOwnerSignOutdated = !update
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override val privilegeMap: PrivilegeMap
|
override val privilegeMap: PrivilegeMap
|
||||||
get() = data.privilegeMap
|
get() = data.privilegeMap
|
||||||
@@ -106,7 +131,24 @@ class ParcelImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override val hasBlockVisitors: Boolean
|
||||||
|
get() = permit != null
|
||||||
|
|
||||||
|
private var permit: Permit? = null
|
||||||
|
|
||||||
|
fun acquireBlockVisitorPermit(with: Permit): Boolean {
|
||||||
|
if (permit === with) return true
|
||||||
|
if (permit != null) return false
|
||||||
|
permit = with
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun releaseBlockVisitorPermit(with: Permit) {
|
||||||
|
if (permit !== with) throw IllegalStateException()
|
||||||
|
permit = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
private var blockVisitors = AtomicInteger(0)
|
private var blockVisitors = AtomicInteger(0)
|
||||||
|
|
||||||
override suspend fun withBlockVisitorPermit(block: suspend () -> Unit) {
|
override suspend fun withBlockVisitorPermit(block: suspend () -> Unit) {
|
||||||
@@ -116,9 +158,9 @@ class ParcelImpl(
|
|||||||
} finally {
|
} finally {
|
||||||
blockVisitors.getAndDecrement()
|
blockVisitors.getAndDecrement()
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
override fun toString() = toStringExt()
|
override fun toString() = parcelIdToString()
|
||||||
|
|
||||||
override val infoString: String
|
override val infoString: String
|
||||||
get() = getInfoString()
|
get() = getInfoString()
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package io.dico.parcels2.defaultimpl
|
package io.dico.parcels2.defaultimpl
|
||||||
|
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
|
import io.dico.parcels2.blockvisitor.Schematic
|
||||||
import io.dico.parcels2.util.schedule
|
import io.dico.parcels2.util.schedule
|
||||||
import kotlinx.coroutines.Unconfined
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.WorldCreator
|
import org.bukkit.WorldCreator
|
||||||
@@ -44,10 +46,11 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
|||||||
private fun loadWorlds0() {
|
private fun loadWorlds0() {
|
||||||
if (Bukkit.getWorlds().isEmpty()) {
|
if (Bukkit.getWorlds().isEmpty()) {
|
||||||
plugin.schedule(::loadWorlds0)
|
plugin.schedule(::loadWorlds0)
|
||||||
plugin.logger.warning("Scheduling to load worlds in the next tick, \nbecause no bukkit worlds are loaded yet")
|
plugin.logger.warning("Scheduling to load worlds in the next tick because no bukkit worlds are loaded yet")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val newlyCreatedWorlds = mutableListOf<ParcelWorld>()
|
||||||
for ((worldName, worldOptions) in options.worlds.entries) {
|
for ((worldName, worldOptions) in options.worlds.entries) {
|
||||||
var parcelWorld = _worlds[worldName]
|
var parcelWorld = _worlds[worldName]
|
||||||
if (parcelWorld != null) continue
|
if (parcelWorld != null) continue
|
||||||
@@ -56,19 +59,20 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
|||||||
val worldExists = Bukkit.getWorld(worldName) != null
|
val worldExists = Bukkit.getWorld(worldName) != null
|
||||||
val bukkitWorld =
|
val bukkitWorld =
|
||||||
if (worldExists) Bukkit.getWorld(worldName)!!
|
if (worldExists) Bukkit.getWorld(worldName)!!
|
||||||
else WorldCreator(worldName).generator(generator).createWorld().also { logger.info("Creating world $worldName") }
|
else {
|
||||||
|
logger.info("Creating world $worldName")
|
||||||
|
WorldCreator(worldName).generator(generator).createWorld()
|
||||||
|
}
|
||||||
|
|
||||||
parcelWorld = ParcelWorldImpl(
|
parcelWorld = ParcelWorldImpl(plugin, bukkitWorld, generator, worldOptions.runtime,::DefaultParcelContainer)
|
||||||
bukkitWorld, generator, worldOptions.runtime, plugin.storage,
|
|
||||||
plugin.globalPrivileges, ::DefaultParcelContainer, plugin, plugin.jobDispatcher
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!worldExists) {
|
if (!worldExists) {
|
||||||
val time = DateTime.now()
|
val time = DateTime.now()
|
||||||
plugin.storage.setWorldCreationTime(parcelWorld.id, time)
|
plugin.storage.setWorldCreationTime(parcelWorld.id, time)
|
||||||
parcelWorld.creationTime = time
|
parcelWorld.creationTime = time
|
||||||
|
newlyCreatedWorlds.add(parcelWorld)
|
||||||
} else {
|
} else {
|
||||||
launch(context = Unconfined) {
|
GlobalScope.launch(context = Dispatchers.Unconfined) {
|
||||||
parcelWorld.creationTime = plugin.storage.getWorldCreationTime(parcelWorld.id).await() ?: DateTime.now()
|
parcelWorld.creationTime = plugin.storage.getWorldCreationTime(parcelWorld.id).await() ?: DateTime.now()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,11 +80,11 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
|||||||
_worlds[worldName] = parcelWorld
|
_worlds[worldName] = parcelWorld
|
||||||
}
|
}
|
||||||
|
|
||||||
loadStoredData()
|
loadStoredData(newlyCreatedWorlds.toSet())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadStoredData() {
|
private fun loadStoredData(newlyCreatedWorlds: Collection<ParcelWorld> = emptyList()) {
|
||||||
plugin.launch {
|
plugin.launch(Dispatchers.Default) {
|
||||||
val migration = plugin.options.migration
|
val migration = plugin.options.migration
|
||||||
if (migration.enabled) {
|
if (migration.enabled) {
|
||||||
migration.instance?.newInstance()?.apply {
|
migration.instance?.newInstance()?.apply {
|
||||||
@@ -96,11 +100,14 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.info("Loading all parcel data...")
|
logger.info("Loading all parcel data...")
|
||||||
val channel = plugin.storage.transmitAllParcelData()
|
|
||||||
while (true) {
|
val job1 = launch {
|
||||||
val (id, data) = channel.receiveOrNull() ?: break
|
val channel = plugin.storage.transmitAllParcelData()
|
||||||
val parcel = getParcelById(id) ?: continue
|
while (true) {
|
||||||
data?.let { parcel.copyDataIgnoringDatabase(it) }
|
val (id, data) = channel.receiveOrNull() ?: break
|
||||||
|
val parcel = getParcelById(id) ?: continue
|
||||||
|
data?.let { parcel.copyData(it, callerIsDatabase = true) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val channel2 = plugin.storage.transmitAllGlobalPrivileges()
|
val channel2 = plugin.storage.transmitAllGlobalPrivileges()
|
||||||
@@ -113,11 +120,61 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
|||||||
(plugin.globalPrivileges[profile] as PrivilegesHolder).copyPrivilegesFrom(data)
|
(plugin.globalPrivileges[profile] as PrivilegesHolder).copyPrivilegesFrom(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
job1.join()
|
||||||
|
|
||||||
logger.info("Loading data completed")
|
logger.info("Loading data completed")
|
||||||
_dataIsLoaded = true
|
_dataIsLoaded = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun acquireBlockVisitorPermit(parcelId: ParcelId, with: Permit): Boolean {
|
||||||
|
val parcel = getParcelById(parcelId) as? ParcelImpl ?: return true
|
||||||
|
return parcel.acquireBlockVisitorPermit(with)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun releaseBlockVisitorPermit(parcelId: ParcelId, with: Permit) {
|
||||||
|
val parcel = getParcelById(parcelId) as? ParcelImpl ?: return
|
||||||
|
parcel.releaseBlockVisitorPermit(with)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun trySubmitBlockVisitor(permit: Permit, vararg parcelIds: ParcelId, function: JobFunction): Job? {
|
||||||
|
val withPermit = parcelIds.filter { acquireBlockVisitorPermit(it, permit) }
|
||||||
|
if (withPermit.size != parcelIds.size) {
|
||||||
|
withPermit.forEach { releaseBlockVisitorPermit(it, permit) }
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val job = plugin.jobDispatcher.dispatch(function)
|
||||||
|
|
||||||
|
plugin.launch {
|
||||||
|
job.awaitCompletion()
|
||||||
|
withPermit.forEach { releaseBlockVisitorPermit(it, permit) }
|
||||||
|
}
|
||||||
|
|
||||||
|
return job
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun swapParcels(parcelId1: ParcelId, parcelId2: ParcelId): Job? {
|
||||||
|
val blockManager1 = getWorldById(parcelId1.worldId)?.blockManager ?: return null
|
||||||
|
val blockManager2 = getWorldById(parcelId2.worldId)?.blockManager ?: return null
|
||||||
|
|
||||||
|
return trySubmitBlockVisitor(Permit(), parcelId1, parcelId2) {
|
||||||
|
var region1 = blockManager1.getRegion(parcelId1)
|
||||||
|
var region2 = blockManager2.getRegion(parcelId2)
|
||||||
|
|
||||||
|
val size = region1.size.clampMax(region2.size)
|
||||||
|
if (size != region1.size) {
|
||||||
|
region1 = region1.withSize(size)
|
||||||
|
region2 = region2.withSize(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
val schematicOf1 = delegateWork(0.25) { Schematic().apply { load(blockManager1.world, region1) } }
|
||||||
|
val schematicOf2 = delegateWork(0.25) { Schematic().apply { load(blockManager2.world, region2) } }
|
||||||
|
delegateWork(0.25) { with(schematicOf1) { paste(blockManager2.world, region2.origin) } }
|
||||||
|
delegateWork(0.25) { with(schematicOf2) { paste(blockManager1.world, region1.origin) } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fun loadWorlds(options: Options) {
|
fun loadWorlds(options: Options) {
|
||||||
for ((worldName, worldOptions) in options.worlds.entries) {
|
for ((worldName, worldOptions) in options.worlds.entries) {
|
||||||
|
|||||||
@@ -3,30 +3,27 @@
|
|||||||
package io.dico.parcels2.defaultimpl
|
package io.dico.parcels2.defaultimpl
|
||||||
|
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
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
|
||||||
|
import org.bukkit.GameRule
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
|
||||||
class ParcelWorldImpl(override val world: World,
|
class ParcelWorldImpl(
|
||||||
override val generator: ParcelGenerator,
|
val plugin: ParcelsPlugin,
|
||||||
override var options: RuntimeWorldOptions,
|
override val world: World,
|
||||||
override val storage: Storage,
|
override val generator: ParcelGenerator,
|
||||||
override val globalPrivileges: GlobalPrivilegesManager,
|
override var options: RuntimeWorldOptions,
|
||||||
containerFactory: ParcelContainerFactory,
|
containerFactory: ParcelContainerFactory
|
||||||
coroutineScope: CoroutineScope,
|
) : ParcelWorld, ParcelWorldId, ParcelContainer, ParcelLocator {
|
||||||
jobDispatcher: JobDispatcher)
|
|
||||||
: ParcelWorld,
|
|
||||||
ParcelWorldId,
|
|
||||||
ParcelContainer, /* missing delegation */
|
|
||||||
ParcelLocator /* missing delegation */ {
|
|
||||||
|
|
||||||
override val id: ParcelWorldId get() = this
|
override val id: ParcelWorldId get() = this
|
||||||
override val uid: UUID? get() = world.uid
|
override val uid: UUID? get() = world.uid
|
||||||
|
|
||||||
|
override val storage get() = plugin.storage
|
||||||
|
override val globalPrivileges get() = plugin.globalPrivileges
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (generator.world != world) {
|
if (generator.world != world) {
|
||||||
throw IllegalArgumentException()
|
throw IllegalArgumentException()
|
||||||
@@ -39,52 +36,40 @@ class ParcelWorldImpl(override val world: World,
|
|||||||
override val blockManager: ParcelBlockManager
|
override val blockManager: ParcelBlockManager
|
||||||
|
|
||||||
init {
|
init {
|
||||||
val pair = generator.makeParcelLocatorAndBlockManager(id, container, coroutineScope, jobDispatcher)
|
val (locator, blockManager) = generator.makeParcelLocatorAndBlockManager(plugin.parcelProvider, container, plugin, plugin.jobDispatcher)
|
||||||
locator = pair.first
|
this.locator = locator
|
||||||
blockManager = pair.second
|
this.blockManager = blockManager
|
||||||
|
|
||||||
enforceOptions()
|
enforceOptions()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun enforceOptions() {
|
fun enforceOptions() {
|
||||||
if (options.dayTime) {
|
if (options.dayTime) {
|
||||||
world.setGameRuleValue("doDaylightCycle", "false")
|
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false)
|
||||||
world.setTime(6000)
|
world.setTime(6000)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.noWeather) {
|
if (options.noWeather) {
|
||||||
world.setStorm(false)
|
world.setStorm(false)
|
||||||
world.setThundering(false)
|
world.setThundering(false)
|
||||||
world.weatherDuration = Integer.MAX_VALUE
|
world.weatherDuration = Int.MAX_VALUE
|
||||||
}
|
}
|
||||||
|
|
||||||
world.setGameRuleValue("doTileDrops", "${options.doTileDrops}")
|
world.setGameRule(GameRule.DO_TILE_DROPS, options.doTileDrops)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updated by ParcelProviderImpl
|
// Accessed by ParcelProviderImpl
|
||||||
override var creationTime: DateTime? = null
|
override var creationTime: DateTime? = null
|
||||||
|
|
||||||
/*
|
|
||||||
Interface delegation needs to be implemented manually because JetBrains has yet to fix it.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ParcelLocator interface
|
override fun getParcelAt(x: Int, z: Int): Parcel? = locator.getParcelAt(x, z)
|
||||||
override fun getParcelAt(x: Int, z: Int): Parcel? {
|
|
||||||
return locator.getParcelAt(x, z)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getParcelIdAt(x: Int, z: Int): ParcelId? {
|
override fun getParcelIdAt(x: Int, z: Int): ParcelId? = locator.getParcelIdAt(x, z)
|
||||||
return locator.getParcelIdAt(x, z)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ParcelContainer interface
|
override fun getParcelById(x: Int, z: Int): Parcel? = container.getParcelById(x, z)
|
||||||
override fun getParcelById(x: Int, z: Int): Parcel? {
|
|
||||||
return container.getParcelById(x, z)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun nextEmptyParcel(): Parcel? {
|
override fun getParcelById(id: ParcelId): Parcel? = container.getParcelById(id)
|
||||||
return container.nextEmptyParcel()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString() = toStringExt()
|
override fun nextEmptyParcel(): Parcel? = container.nextEmptyParcel()
|
||||||
|
|
||||||
|
override fun toString() = parcelWorldIdToString()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,16 +2,13 @@ package io.dico.parcels2.listener
|
|||||||
|
|
||||||
import gnu.trove.TLongCollection
|
import gnu.trove.TLongCollection
|
||||||
import gnu.trove.set.hash.TLongHashSet
|
import gnu.trove.set.hash.TLongHashSet
|
||||||
|
import io.dico.dicore.Formatting
|
||||||
import io.dico.dicore.ListenerMarker
|
import io.dico.dicore.ListenerMarker
|
||||||
import io.dico.dicore.RegistratorListener
|
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.*
|
||||||
import io.dico.parcels2.util.math.Vec3d
|
|
||||||
import io.dico.parcels2.util.math.Vec3i
|
|
||||||
import io.dico.parcels2.util.math.clampMax
|
|
||||||
import io.dico.parcels2.util.math.clampMin
|
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.bukkit.Material.*
|
import org.bukkit.Material.*
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
@@ -128,6 +125,8 @@ class ParcelListeners(
|
|||||||
if (!canBuildOnArea(event.player, area)) {
|
if (!canBuildOnArea(event.player, area)) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
area?.updateOwnerSign()
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -253,10 +252,15 @@ class ParcelListeners(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onPlayerInteractEvent_RightClick(event, world, parcel)
|
onPlayerRightClick(event, world, parcel)
|
||||||
|
|
||||||
|
if (!event.isCancelled && parcel == null) {
|
||||||
|
world.blockManager.getParcelForInfoBlockInteraction(Vec3i(clickedBlock), type, event.blockFace)
|
||||||
|
?.apply { user.sendMessage(Formatting.GREEN + infoString) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Action.RIGHT_CLICK_AIR -> onPlayerInteractEvent_RightClick(event, world, parcel)
|
Action.RIGHT_CLICK_AIR -> onPlayerRightClick(event, world, parcel)
|
||||||
Action.PHYSICAL -> if (!canBuildOnArea(user, parcel) && !(parcel != null && parcel.interactableConfig("pressure_plates"))) {
|
Action.PHYSICAL -> if (!canBuildOnArea(user, parcel) && !(parcel != null && parcel.interactableConfig("pressure_plates"))) {
|
||||||
user.sendParcelMessage(nopermit = true, message = "You cannot use inputs in this parcel")
|
user.sendParcelMessage(nopermit = true, message = "You cannot use inputs in this parcel")
|
||||||
event.isCancelled = true; return@l
|
event.isCancelled = true; return@l
|
||||||
@@ -265,7 +269,7 @@ class ParcelListeners(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("NON_EXHAUSTIVE_WHEN")
|
@Suppress("NON_EXHAUSTIVE_WHEN")
|
||||||
private fun onPlayerInteractEvent_RightClick(event: PlayerInteractEvent, world: ParcelWorld, parcel: Parcel?) {
|
private fun onPlayerRightClick(event: PlayerInteractEvent, world: ParcelWorld, parcel: Parcel?) {
|
||||||
if (event.hasItem()) {
|
if (event.hasItem()) {
|
||||||
val item = event.item.type
|
val item = event.item.type
|
||||||
if (world.options.blockedItems.contains(item)) {
|
if (world.options.blockedItems.contains(item)) {
|
||||||
@@ -275,7 +279,9 @@ class ParcelListeners(
|
|||||||
|
|
||||||
if (!canBuildOnArea(event.player, parcel)) {
|
if (!canBuildOnArea(event.player, parcel)) {
|
||||||
when (item) {
|
when (item) {
|
||||||
LAVA_BUCKET, WATER_BUCKET, BUCKET, FLINT_AND_STEEL -> event.isCancelled = true
|
LAVA_BUCKET, WATER_BUCKET, BUCKET, FLINT_AND_STEEL -> {
|
||||||
|
event.isCancelled = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -614,9 +620,9 @@ class ParcelListeners(
|
|||||||
if (parcels.isEmpty()) return@l
|
if (parcels.isEmpty()) return@l
|
||||||
|
|
||||||
parcels.forEach { id ->
|
parcels.forEach { id ->
|
||||||
val parcel = world.getParcelById(id)?.takeIf { it.ownerSignOutdated } ?: return@forEach
|
val parcel = world.getParcelById(id)?.takeIf { it.isOwnerSignOutdated } ?: return@forEach
|
||||||
world.blockManager.setOwnerBlock(parcel.id, parcel.owner)
|
world.blockManager.updateParcelInfo(parcel.id, parcel.owner)
|
||||||
parcel.ownerSignOutdated = false
|
parcel.isOwnerSignOutdated = false
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,4 +18,5 @@ private class PlotmeMigrationFactory : PolymorphicOptionsFactory<Migration> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PlotmeMigrationOptions(val worldsFromTo: Map<String, String> = mapOf("plotworld" to "parcels"),
|
class PlotmeMigrationOptions(val worldsFromTo: Map<String, String> = mapOf("plotworld" to "parcels"),
|
||||||
val storage: StorageOptions = StorageOptions(options = DataConnectionOptions(database = "plotme")))
|
val storage: StorageOptions = StorageOptions(options = DataConnectionOptions(database = "plotme")),
|
||||||
|
val tableNamesUppercase: Boolean = false)
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package io.dico.parcels2.options
|
package io.dico.parcels2.options
|
||||||
|
|
||||||
import io.dico.parcels2.blockvisitor.TickJobtimeOptions
|
import io.dico.parcels2.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
|
||||||
|
|||||||
@@ -43,14 +43,14 @@ interface Backing {
|
|||||||
|
|
||||||
fun transmitAllParcelData(channel: SendChannel<DataPair>)
|
fun transmitAllParcelData(channel: SendChannel<DataPair>)
|
||||||
|
|
||||||
fun readParcelData(parcel: ParcelId): ParcelData?
|
fun readParcelData(parcel: ParcelId): ParcelDataHolder?
|
||||||
|
|
||||||
fun getOwnedParcels(user: PlayerProfile): List<ParcelId>
|
fun getOwnedParcels(user: PlayerProfile): List<ParcelId>
|
||||||
|
|
||||||
fun getNumParcels(user: PlayerProfile): Int = getOwnedParcels(user).size
|
fun getNumParcels(user: PlayerProfile): Int = getOwnedParcels(user).size
|
||||||
|
|
||||||
|
|
||||||
fun setParcelData(parcel: ParcelId, data: ParcelData?)
|
fun setParcelData(parcel: ParcelId, data: ParcelDataHolder?)
|
||||||
|
|
||||||
fun setParcelOwner(parcel: ParcelId, owner: PlayerProfile?)
|
fun setParcelOwner(parcel: ParcelId, owner: PlayerProfile?)
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import org.joda.time.DateTime
|
|||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
typealias DataPair = Pair<ParcelId, ParcelData?>
|
typealias DataPair = Pair<ParcelId, ParcelDataHolder?>
|
||||||
typealias PrivilegePair<TAttach> = Pair<TAttach, PrivilegesHolder>
|
typealias PrivilegePair<TAttach> = Pair<TAttach, PrivilegesHolder>
|
||||||
|
|
||||||
interface Storage {
|
interface Storage {
|
||||||
@@ -33,7 +33,7 @@ interface Storage {
|
|||||||
|
|
||||||
fun updatePlayerName(uuid: UUID, name: String): Job
|
fun updatePlayerName(uuid: UUID, name: String): Job
|
||||||
|
|
||||||
fun readParcelData(parcel: ParcelId): Deferred<ParcelData?>
|
fun readParcelData(parcel: ParcelId): Deferred<ParcelDataHolder?>
|
||||||
|
|
||||||
fun transmitParcelData(parcels: Sequence<ParcelId>): ReceiveChannel<DataPair>
|
fun transmitParcelData(parcels: Sequence<ParcelId>): ReceiveChannel<DataPair>
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ interface Storage {
|
|||||||
fun getNumParcels(user: PlayerProfile): Deferred<Int>
|
fun getNumParcels(user: PlayerProfile): Deferred<Int>
|
||||||
|
|
||||||
|
|
||||||
fun setParcelData(parcel: ParcelId, data: ParcelData?): Job
|
fun setParcelData(parcel: ParcelId, data: ParcelDataHolder?): Job
|
||||||
|
|
||||||
fun setParcelOwner(parcel: ParcelId, owner: PlayerProfile?): Job
|
fun setParcelOwner(parcel: ParcelId, owner: PlayerProfile?): Job
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ interface Storage {
|
|||||||
fun setGlobalPrivilege(owner: PlayerProfile, player: PlayerProfile, privilege: Privilege): Job
|
fun setGlobalPrivilege(owner: PlayerProfile, player: PlayerProfile, privilege: Privilege): Job
|
||||||
|
|
||||||
|
|
||||||
fun getChannelToUpdateParcelData(): SendChannel<Pair<ParcelId, ParcelData>>
|
fun getChannelToUpdateParcelData(): SendChannel<Pair<ParcelId, ParcelDataHolder>>
|
||||||
}
|
}
|
||||||
|
|
||||||
class BackedStorage internal constructor(val b: Backing) : Storage, CoroutineScope {
|
class BackedStorage internal constructor(val b: Backing) : Storage, CoroutineScope {
|
||||||
@@ -93,7 +93,7 @@ class BackedStorage internal constructor(val b: Backing) : Storage, CoroutineSco
|
|||||||
|
|
||||||
override fun getNumParcels(user: PlayerProfile) = b.launchFuture { b.getNumParcels(user) }
|
override fun getNumParcels(user: PlayerProfile) = b.launchFuture { b.getNumParcels(user) }
|
||||||
|
|
||||||
override fun setParcelData(parcel: ParcelId, data: ParcelData?) = b.launchJob { b.setParcelData(parcel, data) }
|
override fun setParcelData(parcel: ParcelId, data: ParcelDataHolder?) = b.launchJob { b.setParcelData(parcel, data) }
|
||||||
|
|
||||||
override fun setParcelOwner(parcel: ParcelId, owner: PlayerProfile?) = b.launchJob { b.setParcelOwner(parcel, owner) }
|
override fun setParcelOwner(parcel: ParcelId, owner: PlayerProfile?) = b.launchJob { b.setParcelOwner(parcel, owner) }
|
||||||
|
|
||||||
@@ -110,5 +110,5 @@ class BackedStorage internal constructor(val b: Backing) : Storage, CoroutineSco
|
|||||||
|
|
||||||
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) }
|
||||||
|
|
||||||
override fun getChannelToUpdateParcelData(): SendChannel<Pair<ParcelId, ParcelData>> = b.openChannelForWriting { b.setParcelData(it.first, it.second) }
|
override fun getChannelToUpdateParcelData(): SendChannel<Pair<ParcelId, ParcelDataHolder>> = b.openChannelForWriting { b.setParcelData(it.first, it.second) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import io.dico.parcels2.storage.*
|
|||||||
import io.dico.parcels2.util.math.clampMax
|
import io.dico.parcels2.util.math.clampMax
|
||||||
import io.dico.parcels2.util.ext.synchronized
|
import io.dico.parcels2.util.ext.synchronized
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.channels.ArrayChannel
|
import kotlinx.coroutines.channels.ArrayChannel
|
||||||
import kotlinx.coroutines.channels.LinkedListChannel
|
import kotlinx.coroutines.channels.LinkedListChannel
|
||||||
import kotlinx.coroutines.channels.ReceiveChannel
|
import kotlinx.coroutines.channels.ReceiveChannel
|
||||||
@@ -152,7 +153,7 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
|
|||||||
channel.close()
|
channel.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun readParcelData(parcel: ParcelId): ParcelData? {
|
override fun readParcelData(parcel: ParcelId): ParcelDataHolder? {
|
||||||
val row = ParcelsT.getRow(parcel) ?: return null
|
val row = ParcelsT.getRow(parcel) ?: return null
|
||||||
return rowToParcelData(row)
|
return rowToParcelData(row)
|
||||||
}
|
}
|
||||||
@@ -165,7 +166,7 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
|
|||||||
.toList()
|
.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setParcelData(parcel: ParcelId, data: ParcelData?) {
|
override fun setParcelData(parcel: ParcelId, data: ParcelDataHolder?) {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
transaction {
|
transaction {
|
||||||
ParcelsT.getId(parcel)?.let { id ->
|
ParcelsT.getId(parcel)?.let { id ->
|
||||||
@@ -262,7 +263,7 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
|
|||||||
private fun rowToParcelData(row: ResultRow) = ParcelDataHolder().apply {
|
private fun rowToParcelData(row: ResultRow) = ParcelDataHolder().apply {
|
||||||
owner = row[ParcelsT.owner_id]?.let { ProfilesT.getItem(it) }
|
owner = row[ParcelsT.owner_id]?.let { ProfilesT.getItem(it) }
|
||||||
lastClaimTime = row[ParcelsT.claim_time]
|
lastClaimTime = row[ParcelsT.claim_time]
|
||||||
ownerSignOutdated = row[ParcelsT.sign_oudated]
|
isOwnerSignOutdated = row[ParcelsT.sign_oudated]
|
||||||
|
|
||||||
val id = row[ParcelsT.id]
|
val id = row[ParcelsT.id]
|
||||||
ParcelOptionsT.select { ParcelOptionsT.parcel_id eq id }.firstOrNull()?.let { optrow ->
|
ParcelOptionsT.select { ParcelOptionsT.parcel_id eq id }.firstOrNull()?.let { optrow ->
|
||||||
|
|||||||
@@ -5,8 +5,7 @@ import org.jetbrains.exposed.sql.Function
|
|||||||
import org.jetbrains.exposed.sql.statements.InsertStatement
|
import org.jetbrains.exposed.sql.statements.InsertStatement
|
||||||
import org.jetbrains.exposed.sql.transactions.TransactionManager
|
import org.jetbrains.exposed.sql.transactions.TransactionManager
|
||||||
|
|
||||||
class UpsertStatement<Key : Any>(table: Table, conflictColumn: Column<*>? = null, conflictIndex: Index? = null)
|
class UpsertStatement<Key : Any>(table: Table, conflictColumn: Column<*>? = null, conflictIndex: Index? = null) : InsertStatement<Key>(table, false) {
|
||||||
: InsertStatement<Key>(table, false) {
|
|
||||||
val indexName: String
|
val indexName: String
|
||||||
val indexColumns: List<Column<*>>
|
val indexColumns: List<Column<*>>
|
||||||
|
|
||||||
@@ -66,9 +65,10 @@ class Abs<T : Int?>(val expr: Expression<T>) : Function<T>(IntegerColumnType())
|
|||||||
override fun toSQL(queryBuilder: QueryBuilder): String = "ABS(${expr.toSQL(queryBuilder)})"
|
override fun toSQL(queryBuilder: QueryBuilder): String = "ABS(${expr.toSQL(queryBuilder)})"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <T : Comparable<T>> SqlExpressionBuilder.greater(col1: ExpressionWithColumnType<T>, col2: ExpressionWithColumnType<T>): Expression<T> {
|
fun <T : Comparable<T>> greaterOf(col1: ExpressionWithColumnType<T>, col2: ExpressionWithColumnType<T>): Expression<T> =
|
||||||
return case(col1)
|
with(SqlExpressionBuilder) {
|
||||||
.When(col1.greater(col2), col1)
|
case(col1)
|
||||||
.Else(col2)
|
.When(col1.greater(col2), col1)
|
||||||
}
|
.Else(col2)
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,10 @@ import io.dico.parcels2.*
|
|||||||
import io.dico.parcels2.options.PlotmeMigrationOptions
|
import io.dico.parcels2.options.PlotmeMigrationOptions
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import io.dico.parcels2.storage.exposed.abs
|
import io.dico.parcels2.storage.exposed.abs
|
||||||
import io.dico.parcels2.storage.exposed.greater
|
import io.dico.parcels2.storage.exposed.greaterOf
|
||||||
import io.dico.parcels2.storage.migration.Migration
|
import io.dico.parcels2.storage.migration.Migration
|
||||||
|
import io.dico.parcels2.storage.migration.plotme.PlotmeTables.PlotmePlotPlayerMap
|
||||||
|
import io.dico.parcels2.storage.migration.plotme.PlotmeTables.PlotmeTable
|
||||||
import io.dico.parcels2.storage.toUUID
|
import io.dico.parcels2.storage.toUUID
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@@ -24,6 +26,7 @@ class PlotmeMigration(val options: PlotmeMigrationOptions) : Migration {
|
|||||||
private var database: Database? = null
|
private var database: Database? = null
|
||||||
private var isShutdown: Boolean = false
|
private var isShutdown: Boolean = false
|
||||||
private val mlogger = LoggerFactory.getLogger("PlotMe Migrator")
|
private val mlogger = LoggerFactory.getLogger("PlotMe Migrator")
|
||||||
|
private val tables = PlotmeTables(options.tableNamesUppercase)
|
||||||
val dispatcher = newFixedThreadPoolContext(1, "PlotMe Migration Thread")
|
val dispatcher = newFixedThreadPoolContext(1, "PlotMe Migration Thread")
|
||||||
|
|
||||||
private fun <T> transaction(statement: Transaction.() -> T) = org.jetbrains.exposed.sql.transactions.transaction(database!!, statement)
|
private fun <T> transaction(statement: Transaction.() -> T) = org.jetbrains.exposed.sql.transactions.transaction(database!!, statement)
|
||||||
@@ -51,9 +54,9 @@ class PlotmeMigration(val options: PlotmeMigrationOptions) : Migration {
|
|||||||
isShutdown = true
|
isShutdown = true
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun doWork(target: Storage) {
|
suspend fun doWork(target: Storage) = with (tables) {
|
||||||
val exit = transaction {
|
val exit = transaction {
|
||||||
(!PlotmePlotsT.exists()).also {
|
(!PlotmePlots.exists()).also {
|
||||||
if (it) mlogger.warn("Plotme tables don't appear to exist. Exiting.")
|
if (it) mlogger.warn("Plotme tables don't appear to exist. Exiting.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,29 +78,32 @@ class PlotmeMigration(val options: PlotmeMigrationOptions) : Migration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mlogger.info("Transmitting data from plotmeplots table")
|
mlogger.info("Transmitting data from plotmeplots table")
|
||||||
|
var count = 0
|
||||||
transaction {
|
transaction {
|
||||||
PlotmePlotsT.selectAll()
|
|
||||||
.orderBy(PlotmePlotsT.world_name)
|
PlotmePlots.selectAll()
|
||||||
.orderBy(with(SqlExpressionBuilder) { greater(PlotmePlotsT.px.abs(), PlotmePlotsT.pz.abs()) })
|
.orderBy(PlotmePlots.world_name)
|
||||||
|
.orderBy(greaterOf(PlotmePlots.px.abs(), PlotmePlots.pz.abs()))
|
||||||
.forEach { row ->
|
.forEach { row ->
|
||||||
val parcel = getParcelId(PlotmePlotsT, row) ?: return@forEach
|
val parcel = getParcelId(PlotmePlots, row) ?: return@forEach
|
||||||
val owner = PlayerProfile.safe(row[PlotmePlotsT.owner_uuid]?.toUUID(), row[PlotmePlotsT.owner_name])
|
val owner = PlayerProfile.safe(row[PlotmePlots.owner_uuid]?.toUUID(), row[PlotmePlots.owner_name])
|
||||||
target.setParcelOwner(parcel, owner)
|
target.setParcelOwner(parcel, owner)
|
||||||
target.setParcelOwnerSignOutdated(parcel, true)
|
target.setParcelOwnerSignOutdated(parcel, true)
|
||||||
|
++count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mlogger.info("Transmitting data from plotmeallowed table")
|
mlogger.info("Transmitting data from plotmeallowed table")
|
||||||
transaction {
|
transaction {
|
||||||
PlotmeAllowedT.transmitPlotmeAddedTable(Privilege.CAN_BUILD)
|
PlotmeAllowed.transmitPlotmeAddedTable(Privilege.CAN_BUILD)
|
||||||
}
|
}
|
||||||
|
|
||||||
mlogger.info("Transmitting data from plotmedenied table")
|
mlogger.info("Transmitting data from plotmedenied table")
|
||||||
transaction {
|
transaction {
|
||||||
PlotmeDeniedT.transmitPlotmeAddedTable(Privilege.BANNED)
|
PlotmeDenied.transmitPlotmeAddedTable(Privilege.BANNED)
|
||||||
}
|
}
|
||||||
|
|
||||||
mlogger.warn("Data has been **transmitted**.")
|
mlogger.warn("Data has been **transmitted**. $count plots were migrated to the parcels database.")
|
||||||
mlogger.warn("Loading parcel data might take a while as enqueued transactions from this migration are completed.")
|
mlogger.warn("Loading parcel data might take a while as enqueued transactions from this migration are completed.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,25 +2,30 @@ package io.dico.parcels2.storage.migration.plotme
|
|||||||
|
|
||||||
import org.jetbrains.exposed.sql.Table
|
import org.jetbrains.exposed.sql.Table
|
||||||
|
|
||||||
const val uppercase: Boolean = false
|
class PlotmeTables(val uppercase: Boolean) {
|
||||||
@Suppress("ConstantConditionIf")
|
fun String.toCorrectCase() = if (uppercase) this else toLowerCase()
|
||||||
fun String.toCorrectCase() = if (uppercase) this else toLowerCase()
|
|
||||||
|
|
||||||
sealed class PlotmeTable(name: String) : Table(name) {
|
val PlotmePlots = PlotmePlotsT()
|
||||||
val px = integer("idX").primaryKey()
|
val PlotmeAllowed = PlotmeAllowedT()
|
||||||
val pz = integer("idZ").primaryKey()
|
val PlotmeDenied = PlotmeDeniedT()
|
||||||
val world_name = varchar("world", 32).primaryKey()
|
|
||||||
|
inner abstract class PlotmeTable(name: String) : Table(name) {
|
||||||
|
val px = integer("idX").primaryKey()
|
||||||
|
val pz = integer("idZ").primaryKey()
|
||||||
|
val world_name = varchar("world", 32).primaryKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner abstract class PlotmePlotPlayerMap(name: String) : PlotmeTable(name) {
|
||||||
|
val player_name = varchar("player", 32)
|
||||||
|
val player_uuid = blob("playerid").nullable()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class PlotmePlotsT : PlotmeTable("plotmePlots".toCorrectCase()) {
|
||||||
|
val owner_name = varchar("owner", 32)
|
||||||
|
val owner_uuid = blob("ownerid").nullable()
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class PlotmeAllowedT : PlotmePlotPlayerMap("plotmeAllowed".toCorrectCase())
|
||||||
|
inner class PlotmeDeniedT : PlotmePlotPlayerMap("plotmeDenied".toCorrectCase())
|
||||||
}
|
}
|
||||||
|
|
||||||
object PlotmePlotsT : PlotmeTable("plotmePlots".toCorrectCase()) {
|
|
||||||
val owner_name = varchar("owner", 32)
|
|
||||||
val owner_uuid = blob("ownerid").nullable()
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class PlotmePlotPlayerMap(name: String) : PlotmeTable(name) {
|
|
||||||
val player_name = varchar("player", 32)
|
|
||||||
val player_uuid = blob("playerid").nullable()
|
|
||||||
}
|
|
||||||
|
|
||||||
object PlotmeAllowedT : PlotmePlotPlayerMap("plotmeAllowed".toCorrectCase())
|
|
||||||
object PlotmeDeniedT : PlotmePlotPlayerMap("plotmeDenied".toCorrectCase())
|
|
||||||
|
|||||||
@@ -10,3 +10,5 @@ fun getPlayerName(uuid: UUID): String? = getOfflinePlayer(uuid)?.name
|
|||||||
fun getOfflinePlayer(uuid: UUID): OfflinePlayer? = Bukkit.getOfflinePlayer(uuid).takeIf { it.isValid }
|
fun getOfflinePlayer(uuid: UUID): OfflinePlayer? = Bukkit.getOfflinePlayer(uuid).takeIf { it.isValid }
|
||||||
|
|
||||||
fun getOfflinePlayer(name: String): OfflinePlayer? = Bukkit.getOfflinePlayer(name).takeIf { it.isValid }
|
fun getOfflinePlayer(name: String): OfflinePlayer? = Bukkit.getOfflinePlayer(name).takeIf { it.isValid }
|
||||||
|
|
||||||
|
fun isServerThread(): Boolean = Thread.currentThread().name == "Server thread"
|
||||||
|
|||||||
@@ -3,4 +3,7 @@ package io.dico.parcels2.util.math
|
|||||||
data class Vec2i(
|
data class Vec2i(
|
||||||
val x: Int,
|
val x: Int,
|
||||||
val z: Int
|
val z: Int
|
||||||
)
|
) {
|
||||||
|
fun add(ox: Int, oz: Int) = Vec2i(x + ox, z + oz)
|
||||||
|
fun toChunk() = Vec2i(x shr 4, z shr 4)
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ data class Vec3i(
|
|||||||
val z: Int
|
val z: Int
|
||||||
) {
|
) {
|
||||||
constructor(loc: Location) : this(loc.blockX, loc.blockY, loc.blockZ)
|
constructor(loc: Location) : this(loc.blockX, loc.blockY, loc.blockZ)
|
||||||
|
constructor(block: Block) : this(block.x, block.y, block.z)
|
||||||
|
|
||||||
|
fun toVec2i() = Vec2i(x, z)
|
||||||
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)
|
||||||
|
|||||||
Reference in New Issue
Block a user