Refactor and improve a lot of the API. Move default implementations into a package. Reformatting.
This commit is contained in:
@@ -72,6 +72,7 @@ dependencies {
|
|||||||
compile("org.jetbrains.exposed:exposed:0.10.3") { isTransitive = false }
|
compile("org.jetbrains.exposed:exposed:0.10.3") { isTransitive = false }
|
||||||
compile("joda-time:joda-time:2.10")
|
compile("joda-time:joda-time:2.10")
|
||||||
compile("com.zaxxer:HikariCP:3.2.0")
|
compile("com.zaxxer:HikariCP:3.2.0")
|
||||||
|
compile("ch.qos.logback:logback-classic:1.2.3")
|
||||||
|
|
||||||
val jacksonVersion = "2.9.6"
|
val jacksonVersion = "2.9.6"
|
||||||
compile("com.fasterxml.jackson.core:jackson-core:$jacksonVersion")
|
compile("com.fasterxml.jackson.core:jackson-core:$jacksonVersion")
|
||||||
|
|||||||
@@ -2,10 +2,13 @@ package io.dico.parcels2
|
|||||||
|
|
||||||
import io.dico.parcels2.util.uuid
|
import io.dico.parcels2.util.uuid
|
||||||
import org.bukkit.OfflinePlayer
|
import org.bukkit.OfflinePlayer
|
||||||
import java.util.*
|
import java.util.UUID
|
||||||
|
|
||||||
|
typealias MutableAddedDataMap = MutableMap<UUID, AddedStatus>
|
||||||
|
typealias AddedDataMap = Map<UUID, AddedStatus>
|
||||||
|
|
||||||
interface AddedData {
|
interface AddedData {
|
||||||
val addedMap: Map<UUID, AddedStatus>
|
val addedMap: AddedDataMap
|
||||||
|
|
||||||
fun getAddedStatus(uuid: UUID): AddedStatus
|
fun getAddedStatus(uuid: UUID): AddedStatus
|
||||||
fun setAddedStatus(uuid: UUID, status: AddedStatus): Boolean
|
fun setAddedStatus(uuid: UUID, status: AddedStatus): Boolean
|
||||||
@@ -28,8 +31,7 @@ interface AddedData {
|
|||||||
fun unban(player: OfflinePlayer) = unban(player.uuid)
|
fun unban(player: OfflinePlayer) = unban(player.uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
open class AddedDataHolder(override var addedMap: MutableMap<UUID, AddedStatus>
|
open class AddedDataHolder(override var addedMap: MutableAddedDataMap = mutableMapOf()) : AddedData {
|
||||||
= mutableMapOf<UUID, AddedStatus>()) : AddedData {
|
|
||||||
override fun getAddedStatus(uuid: UUID): AddedStatus = addedMap.getOrDefault(uuid, AddedStatus.DEFAULT)
|
override fun getAddedStatus(uuid: UUID): AddedStatus = addedMap.getOrDefault(uuid, AddedStatus.DEFAULT)
|
||||||
override fun setAddedStatus(uuid: UUID, status: AddedStatus): Boolean = status.takeIf { it != AddedStatus.DEFAULT }
|
override fun setAddedStatus(uuid: UUID, status: AddedStatus): Boolean = status.takeIf { it != AddedStatus.DEFAULT }
|
||||||
?.let { addedMap.put(uuid, it) != it }
|
?.let { addedMap.put(uuid, it) != it }
|
||||||
@@ -44,4 +46,12 @@ enum class AddedStatus {
|
|||||||
val isDefault get() = this == DEFAULT
|
val isDefault get() = this == DEFAULT
|
||||||
val isAllowed get() = this == ALLOWED
|
val isAllowed get() = this == ALLOWED
|
||||||
val isBanned get() = this == BANNED
|
val isBanned get() = this == BANNED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface GlobalAddedData : AddedData {
|
||||||
|
val owner: ParcelOwner
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GlobalAddedDataManager {
|
||||||
|
operator fun get(owner: ParcelOwner): GlobalAddedData
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,27 +1,33 @@
|
|||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore
|
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||||
import io.dico.parcels2.blockvisitor.TickWorktimeOptions
|
import io.dico.parcels2.blockvisitor.TickWorktimeOptions
|
||||||
|
import io.dico.parcels2.defaultimpl.DefaultGeneratorOptions
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import io.dico.parcels2.storage.StorageFactory
|
import io.dico.parcels2.storage.StorageFactory
|
||||||
import io.dico.parcels2.storage.yamlObjectMapper
|
import io.dico.parcels2.storage.yamlObjectMapper
|
||||||
import org.bukkit.Bukkit.createBlockData
|
|
||||||
import org.bukkit.GameMode
|
import org.bukkit.GameMode
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.block.Biome
|
|
||||||
import org.bukkit.block.data.BlockData
|
|
||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
import java.io.Writer
|
import java.io.Writer
|
||||||
import java.util.*
|
import java.util.EnumSet
|
||||||
|
|
||||||
class Options {
|
class Options {
|
||||||
var worlds: Map<String, WorldOptions> = HashMap()
|
var worlds: Map<String, WorldOptionsHolder> = hashMapOf()
|
||||||
private set
|
private set
|
||||||
var storage: StorageOptions = StorageOptions("postgresql", DataConnectionOptions())
|
var storage: StorageOptions = StorageOptions("postgresql", DataConnectionOptions())
|
||||||
var tickWorktime: TickWorktimeOptions = TickWorktimeOptions(20, 1)
|
var tickWorktime: TickWorktimeOptions = TickWorktimeOptions(20, 1)
|
||||||
|
|
||||||
fun addWorld(name: String, options: WorldOptions) = (worlds as MutableMap).put(name, options)
|
fun addWorld(name: String,
|
||||||
|
generatorOptions: GeneratorOptions? = null,
|
||||||
|
worldOptions: WorldOptions? = null) {
|
||||||
|
val optionsHolder = WorldOptionsHolder(
|
||||||
|
generatorOptions ?: DefaultGeneratorOptions(),
|
||||||
|
worldOptions ?: WorldOptions()
|
||||||
|
)
|
||||||
|
|
||||||
|
(worlds as MutableMap).put(name, optionsHolder)
|
||||||
|
}
|
||||||
|
|
||||||
fun writeTo(writer: Writer) = yamlObjectMapper.writeValue(writer, this)
|
fun writeTo(writer: Writer) = yamlObjectMapper.writeValue(writer, this)
|
||||||
|
|
||||||
@@ -31,6 +37,9 @@ class Options {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class WorldOptionsHolder(var generator: GeneratorOptions = DefaultGeneratorOptions(),
|
||||||
|
var runtime: WorldOptions = WorldOptions())
|
||||||
|
|
||||||
data class WorldOptions(var gameMode: GameMode? = GameMode.CREATIVE,
|
data class WorldOptions(var gameMode: GameMode? = GameMode.CREATIVE,
|
||||||
var dayTime: Boolean = true,
|
var dayTime: Boolean = true,
|
||||||
var noWeather: Boolean = true,
|
var noWeather: Boolean = true,
|
||||||
@@ -42,8 +51,7 @@ data class WorldOptions(var gameMode: GameMode? = GameMode.CREATIVE,
|
|||||||
var blockPortalCreation: Boolean = true,
|
var blockPortalCreation: Boolean = true,
|
||||||
var blockMobSpawning: Boolean = true,
|
var blockMobSpawning: Boolean = true,
|
||||||
var blockedItems: Set<Material> = EnumSet.of(Material.FLINT_AND_STEEL, Material.SNOWBALL),
|
var blockedItems: Set<Material> = EnumSet.of(Material.FLINT_AND_STEEL, Material.SNOWBALL),
|
||||||
var axisLimit: Int = 10,
|
var axisLimit: Int = 10) {
|
||||||
var generator: GeneratorOptions = DefaultGeneratorOptions()) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,23 +59,7 @@ abstract class GeneratorOptions {
|
|||||||
|
|
||||||
abstract fun generatorFactory(): GeneratorFactory
|
abstract fun generatorFactory(): GeneratorFactory
|
||||||
|
|
||||||
fun getGenerator(worlds: Worlds, worldName: String) = generatorFactory().newParcelGenerator(worlds, worldName, this)
|
fun newGenerator(worldName: String) = generatorFactory().newParcelGenerator(worldName, this)
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
data class DefaultGeneratorOptions(var defaultBiome: Biome = Biome.JUNGLE,
|
|
||||||
var wallType: BlockData = createBlockData(Material.STONE_SLAB),
|
|
||||||
var floorType: BlockData = createBlockData(Material.QUARTZ_BLOCK),
|
|
||||||
var fillType: BlockData = createBlockData(Material.QUARTZ_BLOCK),
|
|
||||||
var pathMainType: BlockData = createBlockData(Material.SANDSTONE),
|
|
||||||
var pathAltType: BlockData = createBlockData(Material.REDSTONE_BLOCK),
|
|
||||||
var parcelSize: Int = 101,
|
|
||||||
var pathSize: Int = 9,
|
|
||||||
var floorHeight: Int = 64,
|
|
||||||
var offsetX: Int = 0,
|
|
||||||
var offsetZ: Int = 0) : GeneratorOptions() {
|
|
||||||
|
|
||||||
override fun generatorFactory(): GeneratorFactory = DefaultParcelGenerator.Factory
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,4 +96,9 @@ data class DataConnectionOptions(val address: String = "localhost",
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data class DataFileOptions(val location: String = "/flatfile-storage/")
|
data class DataFileOptions(val location: String = "/flatfile-storage/")
|
||||||
|
|
||||||
|
class MigrationOptions() {
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
import io.dico.dicore.Formatting
|
|
||||||
import io.dico.parcels2.util.Vec2i
|
import io.dico.parcels2.util.Vec2i
|
||||||
import io.dico.parcels2.util.getPlayerName
|
|
||||||
import io.dico.parcels2.util.hasBuildAnywhere
|
import io.dico.parcels2.util.hasBuildAnywhere
|
||||||
import org.bukkit.OfflinePlayer
|
import org.bukkit.OfflinePlayer
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import java.util.*
|
import java.util.UUID
|
||||||
import kotlin.reflect.KProperty
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parcel implementation of ParcelData will update the database when changes are made.
|
* Parcel implementation of ParcelData will update the database when changes are made.
|
||||||
@@ -18,73 +15,21 @@ import kotlin.reflect.KProperty
|
|||||||
* However, this implementation is intentionally not thread-safe.
|
* However, this implementation is intentionally not thread-safe.
|
||||||
* Therefore, database query callbacks should schedule their updates using the bukkit scheduler.
|
* Therefore, database query callbacks should schedule their updates using the bukkit scheduler.
|
||||||
*/
|
*/
|
||||||
class Parcel(val world: ParcelWorld, val pos: Vec2i) : ParcelData {
|
interface Parcel : ParcelData {
|
||||||
var data: ParcelData = ParcelDataHolder(); private set
|
val id: ParcelId
|
||||||
|
val world: ParcelWorld
|
||||||
|
val pos: Vec2i
|
||||||
|
val x: Int
|
||||||
|
val z: Int
|
||||||
|
val data: ParcelData
|
||||||
|
val infoString: String
|
||||||
|
val hasBlockVisitors: Boolean
|
||||||
|
|
||||||
val id get() = "${pos.x}:${pos.z}"
|
fun copyDataIgnoringDatabase(data: ParcelData)
|
||||||
val homeLocation get() = world.generator.getHomeLocation(this)
|
|
||||||
|
|
||||||
val infoString by ParcelInfoStringComputer
|
fun copyData(data: ParcelData)
|
||||||
|
|
||||||
fun copyDataIgnoringDatabase(data: ParcelData) {
|
fun dispose()
|
||||||
this.data = data
|
|
||||||
}
|
|
||||||
|
|
||||||
fun copyData(data: ParcelData) {
|
|
||||||
copyDataIgnoringDatabase(data)
|
|
||||||
world.storage.setParcelData(this, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun dispose() {
|
|
||||||
copyDataIgnoringDatabase(ParcelDataHolder())
|
|
||||||
world.storage.setParcelData(this, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val addedMap: Map<UUID, AddedStatus> get() = data.addedMap
|
|
||||||
override fun getAddedStatus(uuid: UUID) = data.getAddedStatus(uuid)
|
|
||||||
override fun isBanned(uuid: UUID) = data.isBanned(uuid)
|
|
||||||
override fun isAllowed(uuid: UUID) = data.isAllowed(uuid)
|
|
||||||
override fun canBuild(player: OfflinePlayer, checkAdmin: Boolean, checkGlobal: Boolean): Boolean {
|
|
||||||
return (data.canBuild(player, checkAdmin, false))
|
|
||||||
|| checkGlobal && world.globalAddedData[owner ?: return false].isAllowed(player)
|
|
||||||
}
|
|
||||||
|
|
||||||
val globalAddedMap: Map<UUID, AddedStatus>? get() = owner?.let { world.globalAddedData[it].addedMap }
|
|
||||||
|
|
||||||
override val since: DateTime? get() = data.since
|
|
||||||
|
|
||||||
override var owner: ParcelOwner?
|
|
||||||
get() = data.owner
|
|
||||||
set(value) {
|
|
||||||
if (data.owner != value) {
|
|
||||||
world.storage.setParcelOwner(this, value)
|
|
||||||
data.owner = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setAddedStatus(uuid: UUID, status: AddedStatus): Boolean {
|
|
||||||
return data.setAddedStatus(uuid, status).also {
|
|
||||||
if (it) world.storage.setParcelPlayerStatus(this, uuid, status)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override var allowInteractInputs: Boolean
|
|
||||||
get() = data.allowInteractInputs
|
|
||||||
set(value) {
|
|
||||||
if (data.allowInteractInputs == value) return
|
|
||||||
world.storage.setParcelAllowsInteractInputs(this, value)
|
|
||||||
data.allowInteractInputs = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override var allowInteractInventory: Boolean
|
|
||||||
get() = data.allowInteractInventory
|
|
||||||
set(value) {
|
|
||||||
if (data.allowInteractInventory == value) return
|
|
||||||
world.storage.setParcelAllowsInteractInventory(this, value)
|
|
||||||
data.allowInteractInventory = value
|
|
||||||
}
|
|
||||||
|
|
||||||
var hasBlockVisitors: Boolean = false; private set
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ParcelData : AddedData {
|
interface ParcelData : AddedData {
|
||||||
@@ -113,59 +58,3 @@ class ParcelDataHolder : AddedDataHolder(), ParcelData {
|
|||||||
override var allowInteractInventory = true
|
override var allowInteractInventory = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private object ParcelInfoStringComputer {
|
|
||||||
val infoStringColor1 = Formatting.GREEN
|
|
||||||
val infoStringColor2 = Formatting.AQUA
|
|
||||||
|
|
||||||
private inline fun StringBuilder.appendField(name: String, value: StringBuilder.() -> Unit) {
|
|
||||||
append(infoStringColor1)
|
|
||||||
append(name)
|
|
||||||
append(": ")
|
|
||||||
append(infoStringColor2)
|
|
||||||
value()
|
|
||||||
append(' ')
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun getValue(parcel: Parcel, property: KProperty<*>): String = buildString {
|
|
||||||
appendField("ID") {
|
|
||||||
append(parcel.pos.x)
|
|
||||||
append(':')
|
|
||||||
append(parcel.pos.z)
|
|
||||||
}
|
|
||||||
|
|
||||||
appendField("Owner") {
|
|
||||||
val owner = parcel.owner
|
|
||||||
if (owner == null) {
|
|
||||||
append(infoStringColor1)
|
|
||||||
append("none")
|
|
||||||
} else {
|
|
||||||
append(owner.notNullName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// plotme appends biome here
|
|
||||||
|
|
||||||
append('\n')
|
|
||||||
|
|
||||||
val allowedMap = parcel.addedMap.filterValues { it.isAllowed }
|
|
||||||
if (allowedMap.isNotEmpty()) appendField("Allowed") {
|
|
||||||
allowedMap.keys.map(::getPlayerName).joinTo(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
val bannedMap = parcel.addedMap.filterValues { it.isBanned }
|
|
||||||
if (bannedMap.isNotEmpty()) appendField("Banned") {
|
|
||||||
bannedMap.keys.map(::getPlayerName).joinTo(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!parcel.allowInteractInputs || !parcel.allowInteractInventory) {
|
|
||||||
appendField("Options") {
|
|
||||||
append("(")
|
|
||||||
appendField("inputs") { append(parcel.allowInteractInputs)}
|
|
||||||
append(", ")
|
|
||||||
appendField("inventory") { append(parcel.allowInteractInventory) }
|
|
||||||
append(")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
83
src/main/kotlin/io/dico/parcels2/ParcelGenerator.kt
Normal file
83
src/main/kotlin/io/dico/parcels2/ParcelGenerator.kt
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package io.dico.parcels2
|
||||||
|
|
||||||
|
import io.dico.parcels2.blockvisitor.RegionTraversal
|
||||||
|
import io.dico.parcels2.blockvisitor.Worker
|
||||||
|
import io.dico.parcels2.blockvisitor.WorktimeLimiter
|
||||||
|
import io.dico.parcels2.defaultimpl.DefaultParcelGenerator
|
||||||
|
import io.dico.parcels2.util.Vec2i
|
||||||
|
import org.bukkit.Chunk
|
||||||
|
import org.bukkit.Location
|
||||||
|
import org.bukkit.World
|
||||||
|
import org.bukkit.block.Biome
|
||||||
|
import org.bukkit.block.Block
|
||||||
|
import org.bukkit.entity.Entity
|
||||||
|
import org.bukkit.generator.BlockPopulator
|
||||||
|
import org.bukkit.generator.ChunkGenerator
|
||||||
|
import java.util.HashMap
|
||||||
|
import java.util.Random
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
object GeneratorFactories {
|
||||||
|
private val map: MutableMap<String, GeneratorFactory> = HashMap()
|
||||||
|
|
||||||
|
fun registerFactory(generator: GeneratorFactory): Boolean = map.putIfAbsent(generator.name, generator) == null
|
||||||
|
|
||||||
|
fun getFactory(name: String): GeneratorFactory? = map.get(name)
|
||||||
|
|
||||||
|
init {
|
||||||
|
registerFactory(DefaultParcelGenerator.Factory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GeneratorFactory {
|
||||||
|
val name: String
|
||||||
|
|
||||||
|
val optionsClass: KClass<out GeneratorOptions>
|
||||||
|
|
||||||
|
fun newParcelGenerator(worldName: String, options: GeneratorOptions): ParcelGenerator
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class ParcelGenerator : ChunkGenerator() {
|
||||||
|
abstract val world: World
|
||||||
|
|
||||||
|
abstract override fun generateChunkData(world: World?, random: Random?, chunkX: Int, chunkZ: Int, biome: BiomeGrid?): ChunkData
|
||||||
|
|
||||||
|
abstract fun populate(world: World?, random: Random?, chunk: Chunk?)
|
||||||
|
|
||||||
|
abstract override fun getFixedSpawnLocation(world: World?, random: Random?): Location
|
||||||
|
|
||||||
|
override fun getDefaultPopulators(world: World?): MutableList<BlockPopulator> {
|
||||||
|
return mutableListOf(object : BlockPopulator() {
|
||||||
|
override fun populate(world: World?, random: Random?, chunk: Chunk?) {
|
||||||
|
this@ParcelGenerator.populate(world, random, chunk)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun makeParcelBlockManager(worktimeLimiter: WorktimeLimiter): ParcelBlockManager
|
||||||
|
|
||||||
|
abstract fun makeParcelLocator(container: ParcelContainer): ParcelLocator
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ParcelBlockManager {
|
||||||
|
val world: World
|
||||||
|
val worktimeLimiter: WorktimeLimiter
|
||||||
|
|
||||||
|
fun getBottomBlock(parcel: ParcelId): Vec2i
|
||||||
|
|
||||||
|
fun getHomeLocation(parcel: ParcelId): Location
|
||||||
|
|
||||||
|
fun setOwnerBlock(parcel: ParcelId, owner: ParcelOwner?)
|
||||||
|
|
||||||
|
@Deprecated("")
|
||||||
|
fun getEntities(parcel: ParcelId): Collection<Entity> = TODO()
|
||||||
|
|
||||||
|
@Deprecated("")
|
||||||
|
fun getBlocks(parcel: ParcelId, yRange: IntRange = 0..255): Iterator<Block> = TODO()
|
||||||
|
|
||||||
|
fun setBiome(parcel: ParcelId, biome: Biome): Worker
|
||||||
|
|
||||||
|
fun clearParcel(parcel: ParcelId): Worker
|
||||||
|
|
||||||
|
fun doBlockOperation(parcel: ParcelId, direction: RegionTraversal = RegionTraversal.DOWNWARD, operation: (Block) -> Unit): Worker
|
||||||
|
}
|
||||||
49
src/main/kotlin/io/dico/parcels2/ParcelId.kt
Normal file
49
src/main/kotlin/io/dico/parcels2/ParcelId.kt
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
package io.dico.parcels2
|
||||||
|
|
||||||
|
import io.dico.parcels2.util.Vec2i
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.World
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by storage backing options to encompass the identity of a world
|
||||||
|
* Does NOT support equality operator.
|
||||||
|
*/
|
||||||
|
interface ParcelWorldId {
|
||||||
|
val name: String
|
||||||
|
val uid: UUID?
|
||||||
|
fun equals(id: ParcelWorldId): Boolean = name == name || (uid != null && uid == id.uid)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used by storage backing options to encompass the location of a parcel
|
||||||
|
* Does NOT support equality operator.
|
||||||
|
*/
|
||||||
|
interface ParcelId {
|
||||||
|
val worldId: ParcelWorldId
|
||||||
|
val x: Int
|
||||||
|
val z: Int
|
||||||
|
val pos: Vec2i get() = Vec2i(x, z)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ParcelWorldIdImpl(override val name: String,
|
||||||
|
override val uid: UUID?) : ParcelWorldId
|
||||||
|
|
||||||
|
private class ParcelIdImpl(override val worldId: ParcelWorldId,
|
||||||
|
override val x: Int,
|
||||||
|
override val z: Int) : ParcelId
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
@file:Suppress("unused")
|
@file:Suppress("unused", "UsePropertyAccessSyntax", "DEPRECATION")
|
||||||
|
|
||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
@@ -8,11 +8,10 @@ import io.dico.parcels2.util.uuid
|
|||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.OfflinePlayer
|
import org.bukkit.OfflinePlayer
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import java.util.*
|
import java.util.UUID
|
||||||
|
|
||||||
@Suppress("UsePropertyAccessSyntax")
|
class ParcelOwner(val uuid: UUID?,
|
||||||
class ParcelOwner private constructor(val uuid: UUID?,
|
val name: String?) {
|
||||||
val name: String?) {
|
|
||||||
val notNullName: String by lazy { name ?: getPlayerNameOrDefault(uuid!!) }
|
val notNullName: String by lazy { name ?: getPlayerNameOrDefault(uuid!!) }
|
||||||
|
|
||||||
constructor(name: String) : this(null, name)
|
constructor(name: String) : this(null, name)
|
||||||
@@ -26,11 +25,11 @@ class ParcelOwner private constructor(val uuid: UUID?,
|
|||||||
inline val hasUUID: Boolean get() = uuid != null
|
inline val hasUUID: Boolean get() = uuid != null
|
||||||
|
|
||||||
val onlinePlayer: Player? get() = uuid?.let { Bukkit.getPlayer(uuid) }
|
val onlinePlayer: Player? get() = uuid?.let { Bukkit.getPlayer(uuid) }
|
||||||
@Suppress("DEPRECATION")
|
|
||||||
val onlinePlayerAllowingNameMatch: Player? get() = onlinePlayer ?: name?.let { Bukkit.getPlayerExact(name) }
|
val onlinePlayerAllowingNameMatch: Player? get() = onlinePlayer ?: name?.let { Bukkit.getPlayerExact(name) }
|
||||||
val offlinePlayer: OfflinePlayer? get() = uuid?.let { Bukkit.getOfflinePlayer(it).takeIf { it.isValid } }
|
val offlinePlayer: OfflinePlayer? get() = uuid?.let { Bukkit.getOfflinePlayer(it).takeIf { it.isValid } }
|
||||||
@Suppress("DEPRECATION")
|
val offlinePlayerAllowingNameMatch: OfflinePlayer?
|
||||||
val offlinePlayerAllowingNameMatch: OfflinePlayer? get() = offlinePlayer ?: Bukkit.getOfflinePlayer(name).takeIf { it.isValid }
|
get() = offlinePlayer ?: Bukkit.getOfflinePlayer(name).takeIf { it.isValid }
|
||||||
|
|
||||||
fun matches(player: OfflinePlayer, allowNameMatch: Boolean = false): Boolean {
|
fun matches(player: OfflinePlayer, allowNameMatch: Boolean = false): Boolean {
|
||||||
return uuid?.let { it == player.uniqueId } ?: false
|
return uuid?.let { it == player.uniqueId } ?: false
|
||||||
|
|||||||
@@ -1,223 +1,86 @@
|
|||||||
package io.dico.parcels2
|
package io.dico.parcels2
|
||||||
|
|
||||||
import io.dico.parcels2.storage.SerializableParcel
|
|
||||||
import io.dico.parcels2.storage.SerializableWorld
|
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
import io.dico.parcels2.storage.getParcelBySerializedValue
|
|
||||||
import io.dico.parcels2.util.Vec2i
|
import io.dico.parcels2.util.Vec2i
|
||||||
import io.dico.parcels2.util.floor
|
import io.dico.parcels2.util.floor
|
||||||
import kotlinx.coroutines.experimental.launch
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
import org.bukkit.WorldCreator
|
|
||||||
import org.bukkit.block.Block
|
import org.bukkit.block.Block
|
||||||
import org.bukkit.entity.Entity
|
import org.bukkit.entity.Entity
|
||||||
import org.bukkit.entity.Player
|
import java.util.UUID
|
||||||
import java.util.*
|
|
||||||
import kotlin.coroutines.experimental.buildIterator
|
|
||||||
import kotlin.coroutines.experimental.buildSequence
|
|
||||||
|
|
||||||
class Worlds(val plugin: ParcelsPlugin) {
|
interface ParcelProvider {
|
||||||
val worlds: Map<String, ParcelWorld> get() = _worlds
|
val worlds: Map<String, ParcelWorld>
|
||||||
private val _worlds: MutableMap<String, ParcelWorld> = HashMap()
|
|
||||||
|
|
||||||
fun getWorld(name: String): ParcelWorld? = _worlds[name]
|
fun getWorldById(id: ParcelWorldId): ParcelWorld?
|
||||||
|
|
||||||
|
fun getParcelById(id: ParcelId): Parcel?
|
||||||
|
|
||||||
|
fun getWorld(name: String): ParcelWorld?
|
||||||
|
|
||||||
fun getWorld(world: World): ParcelWorld? = getWorld(world.name)
|
fun getWorld(world: World): ParcelWorld? = getWorld(world.name)
|
||||||
|
|
||||||
fun getParcelAt(block: Block): Parcel? = getParcelAt(block.world, block.x, block.z)
|
fun getWorld(block: Block): ParcelWorld? = getWorld(block.world)
|
||||||
|
|
||||||
fun getParcelAt(player: Player): Parcel? = getParcelAt(player.location)
|
fun getWorld(loc: Location): ParcelWorld? = getWorld(loc.world)
|
||||||
|
|
||||||
fun getParcelAt(location: Location): Parcel? = getParcelAt(location.world, location.x.floor(), location.z.floor())
|
fun getWorld(entity: Entity): ParcelWorld? = getWorld(entity.location)
|
||||||
|
|
||||||
|
fun getParcelAt(worldName: String, x: Int, z: Int): Parcel? = getWorld(worldName)?.locator?.getParcelAt(x, z)
|
||||||
|
|
||||||
fun getParcelAt(world: World, x: Int, z: Int): Parcel? = getParcelAt(world.name, x, z)
|
fun getParcelAt(world: World, x: Int, z: Int): Parcel? = getParcelAt(world.name, x, z)
|
||||||
|
|
||||||
fun getParcelAt(world: String, x: Int, z: Int): Parcel? {
|
fun getParcelAt(world: World, vec: Vec2i): Parcel? = getParcelAt(world, vec.x, vec.z)
|
||||||
with(getWorld(world) ?: return null) {
|
|
||||||
return generator.parcelAt(x, z)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun SerializableParcel.invoke(): Parcel? {
|
fun getParcelAt(loc: Location): Parcel? = getParcelAt(loc.world, loc.x.floor(), loc.z.floor())
|
||||||
return world()?.parcelByID(pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun SerializableWorld.invoke(): ParcelWorld? {
|
fun getParcelAt(entity: Entity): Parcel? = getParcelAt(entity.location)
|
||||||
return world?.let { getWorld(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadWorlds(options: Options) {
|
fun getParcelAt(block: Block): Parcel? = getParcelAt(block.world, block.x, block.z)
|
||||||
for ((worldName, worldOptions) in options.worlds.entries) {
|
|
||||||
val world: ParcelWorld
|
|
||||||
try {
|
|
||||||
|
|
||||||
world = ParcelWorld(
|
fun getWorldGenerator(worldName: String): ParcelGenerator?
|
||||||
worldName,
|
|
||||||
worldOptions,
|
|
||||||
worldOptions.generator.getGenerator(this, worldName),
|
|
||||||
plugin.storage,
|
|
||||||
plugin.globalAddedData)
|
|
||||||
|
|
||||||
} catch (ex: Exception) {
|
fun loadWorlds()
|
||||||
ex.printStackTrace()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
_worlds[worldName] = world
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin.functionHelper.schedule(10) {
|
|
||||||
println("Parcels generating worlds now")
|
|
||||||
for ((name, world) in _worlds) {
|
|
||||||
if (Bukkit.getWorld(name) == null) {
|
|
||||||
val bworld = WorldCreator(name).generator(world.generator).createWorld()
|
|
||||||
val spawn = world.generator.getFixedSpawnLocation(bworld, null)
|
|
||||||
bworld.setSpawnLocation(spawn.x.floor(), spawn.y.floor(), spawn.z.floor())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val channel = plugin.storage.readAllParcelData()
|
|
||||||
val job = plugin.functionHelper.launchLazilyOnMainThread {
|
|
||||||
do {
|
|
||||||
val pair = channel.receiveOrNull() ?: break
|
|
||||||
val parcel = getParcelBySerializedValue(pair.first) ?: continue
|
|
||||||
pair.second?.let { parcel.copyDataIgnoringDatabase(it) }
|
|
||||||
} while (true)
|
|
||||||
}
|
|
||||||
job.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ParcelProvider {
|
interface ParcelLocator {
|
||||||
|
val world: World
|
||||||
|
|
||||||
fun parcelAt(x: Int, z: Int): Parcel?
|
fun getParcelIdAt(x: Int, z: Int): ParcelId?
|
||||||
|
|
||||||
fun parcelAt(vec: Vec2i): Parcel? = parcelAt(vec.x, vec.z)
|
fun getParcelAt(x: Int, z: Int): Parcel?
|
||||||
|
|
||||||
fun parcelAt(loc: Location): Parcel? = parcelAt(loc.x.floor(), loc.z.floor())
|
fun getParcelAt(vec: Vec2i): Parcel? = getParcelAt(vec.x, vec.z)
|
||||||
|
|
||||||
fun parcelAt(entity: Entity): Parcel? = parcelAt(entity.location)
|
fun getParcelAt(loc: Location): Parcel? = getParcelAt(loc.x.floor(), loc.z.floor()).takeIf { loc.world == world }
|
||||||
|
|
||||||
fun parcelAt(block: Block): Parcel? = parcelAt(block.x, block.z)
|
fun getParcelAt(entity: Entity): Parcel? = getParcelAt(entity.location).takeIf { entity.world == world }
|
||||||
}
|
|
||||||
|
|
||||||
class ParcelWorld constructor(val name: String,
|
fun getParcelAt(block: Block): Parcel? = getParcelAt(block.x, block.z).takeIf { block.world == world }
|
||||||
val options: WorldOptions,
|
|
||||||
val generator: ParcelGenerator,
|
|
||||||
val storage: Storage,
|
|
||||||
val globalAddedData: GlobalAddedDataManager) : ParcelProvider by generator, ParcelContainer {
|
|
||||||
val world: World by lazy {
|
|
||||||
Bukkit.getWorld(name) ?: throw NullPointerException("World $name does not appear to be loaded")
|
|
||||||
}
|
|
||||||
val container: ParcelContainer = DefaultParcelContainer(this, storage)
|
|
||||||
|
|
||||||
override fun parcelByID(x: Int, z: Int): Parcel? {
|
|
||||||
return container.parcelByID(x, z)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun nextEmptyParcel(): Parcel? {
|
|
||||||
return container.nextEmptyParcel()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun parcelByID(id: Vec2i): Parcel? = parcelByID(id.x, id.z)
|
|
||||||
|
|
||||||
fun enforceOptionsIfApplicable() {
|
|
||||||
val world = world
|
|
||||||
val options = options
|
|
||||||
if (options.dayTime) {
|
|
||||||
world.setGameRuleValue("doDaylightCycle", "false")
|
|
||||||
world.setTime(6000)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.noWeather) {
|
|
||||||
world.setStorm(false)
|
|
||||||
world.setThundering(false)
|
|
||||||
world.weatherDuration = Integer.MAX_VALUE
|
|
||||||
}
|
|
||||||
|
|
||||||
world.setGameRuleValue("doTileDrops", "${options.doTileDrops}")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ParcelContainer {
|
|
||||||
|
|
||||||
fun parcelByID(x: Int, z: Int): Parcel?
|
|
||||||
|
|
||||||
fun nextEmptyParcel(): Parcel?
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typealias ParcelContainerFactory = (ParcelWorld) -> ParcelContainer
|
typealias ParcelContainerFactory = (ParcelWorld) -> ParcelContainer
|
||||||
|
|
||||||
class DefaultParcelContainer(private val world: ParcelWorld,
|
interface ParcelContainer {
|
||||||
private val storage: Storage) : ParcelContainer {
|
|
||||||
private var parcels: Array<Array<Parcel>>
|
|
||||||
|
|
||||||
init {
|
fun getParcelById(x: Int, z: Int): Parcel?
|
||||||
parcels = initArray(world.options.axisLimit, world)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun resizeIfSizeChanged() {
|
fun getParcelById(id: Vec2i): Parcel? = getParcelById(id.x, id.z)
|
||||||
if (parcels.size / 2 != world.options.axisLimit) {
|
|
||||||
resize(world.options.axisLimit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun resize(axisLimit: Int) {
|
fun nextEmptyParcel(): Parcel?
|
||||||
parcels = initArray(axisLimit, world, this)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun initArray(axisLimit: Int, world: ParcelWorld, cur: DefaultParcelContainer? = null): Array<Array<Parcel>> {
|
}
|
||||||
val arraySize = 2 * axisLimit + 1
|
|
||||||
return Array(arraySize) {
|
|
||||||
val x = it - axisLimit
|
|
||||||
Array(arraySize) {
|
|
||||||
val z = it - axisLimit
|
|
||||||
cur?.parcelByID(x, z) ?: Parcel(world, Vec2i(x, z))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun parcelByID(x: Int, z: Int): Parcel? {
|
interface ParcelWorld : ParcelLocator, ParcelContainer, ParcelBlockManager {
|
||||||
return parcels.getOrNull(x + world.options.axisLimit)?.getOrNull(z + world.options.axisLimit)
|
val id: ParcelWorldId
|
||||||
}
|
val name: String
|
||||||
|
val uid: UUID?
|
||||||
override fun nextEmptyParcel(): Parcel? {
|
val options: WorldOptions
|
||||||
return walkInCircle().find { it.owner == null }
|
val generator: ParcelGenerator
|
||||||
}
|
val storage: Storage
|
||||||
|
val container: ParcelContainer
|
||||||
private fun walkInCircle(): Iterable<Parcel> = Iterable {
|
val locator: ParcelLocator
|
||||||
buildIterator {
|
val blockManager: ParcelBlockManager
|
||||||
val center = world.options.axisLimit
|
val globalAddedData: GlobalAddedDataManager
|
||||||
for (radius in 0..center) {
|
}
|
||||||
var x = center - radius;
|
|
||||||
var z = center - radius
|
|
||||||
repeat(radius * 2) { yield(parcels[x++][z]) }
|
|
||||||
repeat(radius * 2) { yield(parcels[x][z++]) }
|
|
||||||
repeat(radius * 2) { yield(parcels[x--][z]) }
|
|
||||||
repeat(radius * 2) { yield(parcels[x][z--]) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun allParcels(): Sequence<Parcel> = buildSequence {
|
|
||||||
for (array in parcels) {
|
|
||||||
yieldAll(array.iterator())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadAllData() {
|
|
||||||
val channel = storage.readParcelData(allParcels())
|
|
||||||
launch(storage.asyncDispatcher) {
|
|
||||||
for ((parcel, data) in channel) {
|
|
||||||
data?.let { parcel.copyDataIgnoringDatabase(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import io.dico.dicore.command.ICommandDispatcher
|
|||||||
import io.dico.parcels2.blockvisitor.TickWorktimeLimiter
|
import io.dico.parcels2.blockvisitor.TickWorktimeLimiter
|
||||||
import io.dico.parcels2.blockvisitor.WorktimeLimiter
|
import io.dico.parcels2.blockvisitor.WorktimeLimiter
|
||||||
import io.dico.parcels2.command.getParcelCommands
|
import io.dico.parcels2.command.getParcelCommands
|
||||||
|
import io.dico.parcels2.defaultimpl.GlobalAddedDataManagerImpl
|
||||||
|
import io.dico.parcels2.defaultimpl.ParcelProviderImpl
|
||||||
import io.dico.parcels2.listener.ParcelEntityTracker
|
import io.dico.parcels2.listener.ParcelEntityTracker
|
||||||
import io.dico.parcels2.listener.ParcelListeners
|
import io.dico.parcels2.listener.ParcelListeners
|
||||||
import io.dico.parcels2.storage.Storage
|
import io.dico.parcels2.storage.Storage
|
||||||
@@ -13,6 +15,7 @@ import io.dico.parcels2.storage.yamlObjectMapper
|
|||||||
import io.dico.parcels2.util.FunctionHelper
|
import io.dico.parcels2.util.FunctionHelper
|
||||||
import io.dico.parcels2.util.tryCreate
|
import io.dico.parcels2.util.tryCreate
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.generator.ChunkGenerator
|
||||||
import org.bukkit.plugin.java.JavaPlugin
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
@@ -24,7 +27,7 @@ private inline val plogger get() = logger
|
|||||||
class ParcelsPlugin : JavaPlugin() {
|
class ParcelsPlugin : JavaPlugin() {
|
||||||
lateinit var optionsFile: File; private set
|
lateinit var optionsFile: File; private set
|
||||||
lateinit var options: Options; private set
|
lateinit var options: Options; private set
|
||||||
lateinit var worlds: Worlds; private set
|
lateinit var parcelProvider: ParcelProvider; private set
|
||||||
lateinit var storage: Storage; private set
|
lateinit var storage: Storage; private set
|
||||||
lateinit var globalAddedData: GlobalAddedDataManager; private set
|
lateinit var globalAddedData: GlobalAddedDataManager; private set
|
||||||
|
|
||||||
@@ -50,7 +53,7 @@ class ParcelsPlugin : JavaPlugin() {
|
|||||||
private fun init(): Boolean {
|
private fun init(): Boolean {
|
||||||
optionsFile = File(dataFolder, "options.yml")
|
optionsFile = File(dataFolder, "options.yml")
|
||||||
options = Options()
|
options = Options()
|
||||||
worlds = Worlds(this)
|
parcelProvider = ParcelProviderImpl(this)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!loadOptions()) return false
|
if (!loadOptions()) return false
|
||||||
@@ -64,8 +67,7 @@ class ParcelsPlugin : JavaPlugin() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
globalAddedData = GlobalAddedDataManagerImpl(this)
|
globalAddedData = GlobalAddedDataManagerImpl(this)
|
||||||
worlds.loadWorlds(options)
|
entityTracker = ParcelEntityTracker(parcelProvider)
|
||||||
entityTracker = ParcelEntityTracker(worlds)
|
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
plogger.error("Error loading options", ex)
|
plogger.error("Error loading options", ex)
|
||||||
return false
|
return false
|
||||||
@@ -74,6 +76,7 @@ class ParcelsPlugin : JavaPlugin() {
|
|||||||
registerListeners()
|
registerListeners()
|
||||||
registerCommands()
|
registerCommands()
|
||||||
|
|
||||||
|
parcelProvider.loadWorlds()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +84,7 @@ class ParcelsPlugin : JavaPlugin() {
|
|||||||
when {
|
when {
|
||||||
optionsFile.exists() -> yamlObjectMapper.readerForUpdating(options).readValue<Options>(optionsFile)
|
optionsFile.exists() -> yamlObjectMapper.readerForUpdating(options).readValue<Options>(optionsFile)
|
||||||
optionsFile.tryCreate() -> {
|
optionsFile.tryCreate() -> {
|
||||||
options.addWorld("parcels", WorldOptions())
|
options.addWorld("parcels")
|
||||||
try {
|
try {
|
||||||
yamlObjectMapper.writeValue(optionsFile, options)
|
yamlObjectMapper.writeValue(optionsFile, options)
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
@@ -99,6 +102,10 @@ class ParcelsPlugin : JavaPlugin() {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getDefaultWorldGenerator(worldName: String, generatorId: String?): ChunkGenerator? {
|
||||||
|
return parcelProvider.getWorldGenerator(worldName)
|
||||||
|
}
|
||||||
|
|
||||||
private fun registerCommands() {
|
private fun registerCommands() {
|
||||||
cmdDispatcher = getParcelCommands(this).apply {
|
cmdDispatcher = getParcelCommands(this).apply {
|
||||||
registerToCommandMap("parcels:", EOverridePolicy.FALLBACK_ONLY)
|
registerToCommandMap("parcels:", EOverridePolicy.FALLBACK_ONLY)
|
||||||
@@ -107,7 +114,7 @@ class ParcelsPlugin : JavaPlugin() {
|
|||||||
|
|
||||||
private fun registerListeners() {
|
private fun registerListeners() {
|
||||||
if (listeners == null) {
|
if (listeners == null) {
|
||||||
listeners = ParcelListeners(worlds, entityTracker)
|
listeners = ParcelListeners(parcelProvider, entityTracker)
|
||||||
registrator.registerListeners(listeners!!)
|
registrator.registerListeners(listeners!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,319 +0,0 @@
|
|||||||
package io.dico.parcels2
|
|
||||||
|
|
||||||
import io.dico.parcels2.blockvisitor.Worker
|
|
||||||
import io.dico.parcels2.blockvisitor.RegionTraversal
|
|
||||||
import io.dico.parcels2.util.*
|
|
||||||
import org.bukkit.*
|
|
||||||
import org.bukkit.Bukkit.createBlockData
|
|
||||||
import org.bukkit.block.Biome
|
|
||||||
import org.bukkit.block.Block
|
|
||||||
import org.bukkit.block.BlockFace
|
|
||||||
import org.bukkit.block.Skull
|
|
||||||
import org.bukkit.block.data.BlockData
|
|
||||||
import org.bukkit.block.data.type.Sign
|
|
||||||
import org.bukkit.block.data.type.Slab
|
|
||||||
import org.bukkit.entity.Entity
|
|
||||||
import org.bukkit.generator.BlockPopulator
|
|
||||||
import org.bukkit.generator.ChunkGenerator
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.coroutines.experimental.buildIterator
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
abstract class ParcelGenerator : ChunkGenerator(), ParcelProvider {
|
|
||||||
abstract val world: ParcelWorld
|
|
||||||
|
|
||||||
abstract val factory: GeneratorFactory
|
|
||||||
|
|
||||||
abstract fun parcelIDAt(x: Int, z: Int): Vec2i?
|
|
||||||
|
|
||||||
abstract override fun generateChunkData(world: World?, random: Random?, chunkX: Int, chunkZ: Int, biome: BiomeGrid?): ChunkData
|
|
||||||
|
|
||||||
abstract fun populate(world: World?, random: Random?, chunk: Chunk?)
|
|
||||||
|
|
||||||
abstract override fun getFixedSpawnLocation(world: World?, random: Random?): Location
|
|
||||||
|
|
||||||
override fun getDefaultPopulators(world: World?): MutableList<BlockPopulator> {
|
|
||||||
return Collections.singletonList(object : BlockPopulator() {
|
|
||||||
override fun populate(world: World?, random: Random?, chunk: Chunk?) {
|
|
||||||
this@ParcelGenerator.populate(world, random, chunk)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun updateOwner(parcel: Parcel)
|
|
||||||
|
|
||||||
abstract fun getBottomCoord(parcel: Parcel): Vec2i
|
|
||||||
|
|
||||||
abstract fun getHomeLocation(parcel: Parcel): Location
|
|
||||||
|
|
||||||
abstract fun setBiome(parcel: Parcel, biome: Biome)
|
|
||||||
|
|
||||||
abstract fun getEntities(parcel: Parcel): Collection<Entity>
|
|
||||||
|
|
||||||
abstract fun getBlocks(parcel: Parcel, yRange: IntRange = 0..255): Iterator<Block>
|
|
||||||
|
|
||||||
abstract fun clearParcel(parcel: Parcel): Worker
|
|
||||||
|
|
||||||
abstract fun doBlockOperation(parcel: Parcel, direction: RegionTraversal = RegionTraversal.DOWNWARD, operation: (Block) -> Unit): Worker
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GeneratorFactory {
|
|
||||||
companion object GeneratorFactories {
|
|
||||||
private val map: MutableMap<String, GeneratorFactory> = HashMap()
|
|
||||||
|
|
||||||
fun registerFactory(generator: GeneratorFactory): Boolean = map.putIfAbsent(generator.name, generator) == null
|
|
||||||
|
|
||||||
fun getFactory(name: String): GeneratorFactory? = map.get(name)
|
|
||||||
|
|
||||||
init {
|
|
||||||
registerFactory(DefaultParcelGenerator.Factory)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
val name: String
|
|
||||||
|
|
||||||
val optionsClass: KClass<out GeneratorOptions>
|
|
||||||
|
|
||||||
fun newParcelGenerator(worlds: Worlds, worldName: String, options: GeneratorOptions): ParcelGenerator
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class DefaultParcelGenerator(val worlds: Worlds, val name: String, private val o: DefaultGeneratorOptions) : ParcelGenerator() {
|
|
||||||
override val world: ParcelWorld by lazy { worlds.getWorld(name)!! }
|
|
||||||
override val factory = Factory
|
|
||||||
val worktimeLimiter = worlds.plugin.worktimeLimiter
|
|
||||||
val maxHeight by lazy { world.world.maxHeight }
|
|
||||||
val airType = worlds.plugin.server.createBlockData(Material.AIR)
|
|
||||||
|
|
||||||
companion object Factory : GeneratorFactory {
|
|
||||||
override val name get() = "default"
|
|
||||||
override val optionsClass get() = DefaultGeneratorOptions::class
|
|
||||||
override fun newParcelGenerator(worlds: Worlds, worldName: String, options: GeneratorOptions): ParcelGenerator {
|
|
||||||
return DefaultParcelGenerator(worlds, worldName, options as DefaultGeneratorOptions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val sectionSize = o.parcelSize + o.pathSize
|
|
||||||
val pathOffset = (if (o.pathSize % 2 == 0) o.pathSize + 2 else o.pathSize + 1) / 2
|
|
||||||
val makePathMain = o.pathSize > 2
|
|
||||||
val makePathAlt = o.pathSize > 4
|
|
||||||
|
|
||||||
private inline fun <T> generate(chunkX: Int,
|
|
||||||
chunkZ: Int,
|
|
||||||
floor: T, wall:
|
|
||||||
T, pathMain: T,
|
|
||||||
pathAlt: T,
|
|
||||||
fill: T,
|
|
||||||
setter: (Int, Int, Int, T) -> Unit) {
|
|
||||||
|
|
||||||
val floorHeight = o.floorHeight
|
|
||||||
val parcelSize = o.parcelSize
|
|
||||||
val sectionSize = sectionSize
|
|
||||||
val pathOffset = pathOffset
|
|
||||||
val makePathMain = makePathMain
|
|
||||||
val makePathAlt = makePathAlt
|
|
||||||
|
|
||||||
// parcel bottom x and z
|
|
||||||
// umod is unsigned %: the result is always >= 0
|
|
||||||
val pbx = ((chunkX shl 4) - o.offsetX) umod sectionSize
|
|
||||||
val pbz = ((chunkZ shl 4) - o.offsetZ) umod sectionSize
|
|
||||||
|
|
||||||
var curHeight: Int
|
|
||||||
var x: Int
|
|
||||||
var z: Int
|
|
||||||
for (cx in 0..15) {
|
|
||||||
for (cz in 0..15) {
|
|
||||||
x = (pbx + cx) % sectionSize - pathOffset
|
|
||||||
z = (pbz + cz) % sectionSize - pathOffset
|
|
||||||
curHeight = floorHeight
|
|
||||||
|
|
||||||
val type = when {
|
|
||||||
(x in 0 until parcelSize && z in 0 until parcelSize) -> floor
|
|
||||||
(x in -1..parcelSize && z in -1..parcelSize) -> {
|
|
||||||
curHeight++
|
|
||||||
wall
|
|
||||||
}
|
|
||||||
(makePathAlt && x in -2 until parcelSize + 2 && z in -2 until parcelSize + 2) -> pathAlt
|
|
||||||
(makePathMain) -> pathMain
|
|
||||||
else -> {
|
|
||||||
curHeight++
|
|
||||||
wall
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (y in 0 until curHeight) {
|
|
||||||
setter(cx, y, cz, fill)
|
|
||||||
}
|
|
||||||
setter(cx, curHeight, cz, type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun generateChunkData(world: World?, random: Random?, chunkX: Int, chunkZ: Int, biome: BiomeGrid?): ChunkData {
|
|
||||||
val out = Bukkit.createChunkData(world)
|
|
||||||
generate(chunkX, chunkZ, o.floorType, o.wallType, o.pathMainType, o.pathAltType, o.fillType) { x, y, z, type ->
|
|
||||||
out.setBlock(x, y, z, type)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
override fun populate(world: World?, random: Random?, chunk: Chunk?) {
|
|
||||||
/*
|
|
||||||
generate(chunk!!.x, chunk.z, o.floorType.data, o.wallType.data, o.pathMainType.data, o.pathAltType.data, o.fillType.data) { x, y, z, type ->
|
|
||||||
if (type == 0.toByte()) chunk.getBlock(x, y, z).setData(type, false)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getFixedSpawnLocation(world: World?, random: Random?): Location {
|
|
||||||
val fix = if (o.parcelSize.even) 0.5 else 0.0
|
|
||||||
return Location(world, o.offsetX + fix, o.floorHeight + 1.0, o.offsetZ + fix)
|
|
||||||
}
|
|
||||||
|
|
||||||
private inline fun <T> convertBlockLocationToID(x: Int, z: Int, mapper: (Int, Int) -> T): T? {
|
|
||||||
val sectionSize = sectionSize
|
|
||||||
val parcelSize = o.parcelSize
|
|
||||||
val absX = x - o.offsetX - pathOffset
|
|
||||||
val absZ = z - o.offsetZ - pathOffset
|
|
||||||
val modX = absX umod sectionSize
|
|
||||||
val modZ = absZ umod sectionSize
|
|
||||||
if (modX in 0 until parcelSize && modZ in 0 until parcelSize) {
|
|
||||||
return mapper((absX - modX) / sectionSize, (absZ - modZ) / sectionSize)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun parcelIDAt(x: Int, z: Int): Vec2i? {
|
|
||||||
return convertBlockLocationToID(x, z) { idx, idz -> Vec2i(idx, idz) }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun parcelAt(x: Int, z: Int): Parcel? {
|
|
||||||
return convertBlockLocationToID(x, z) { idx, idz ->
|
|
||||||
world.parcelByID(idx, idz)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getBottomCoord(parcel: Parcel): Vec2i = Vec2i(sectionSize * parcel.pos.x + pathOffset + o.offsetX,
|
|
||||||
sectionSize * parcel.pos.z + pathOffset + o.offsetZ)
|
|
||||||
|
|
||||||
override fun getHomeLocation(parcel: Parcel): Location {
|
|
||||||
val bottom = getBottomCoord(parcel)
|
|
||||||
return Location(world.world, bottom.x.toDouble(), o.floorHeight + 1.0, bottom.z + (o.parcelSize - 1) / 2.0, -90F, 0F)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateOwner(parcel: Parcel) {
|
|
||||||
val world = this.world.world
|
|
||||||
val b = getBottomCoord(parcel)
|
|
||||||
|
|
||||||
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 skullBlock = world.getBlockAt(b.x - 1, o.floorHeight + 2, b.z - 1)
|
|
||||||
|
|
||||||
val owner = parcel.owner
|
|
||||||
if (owner == null) {
|
|
||||||
wallBlock.blockData = o.wallType
|
|
||||||
signBlock.type = Material.AIR
|
|
||||||
skullBlock.type = Material.AIR
|
|
||||||
} else {
|
|
||||||
|
|
||||||
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 = (createBlockData(Material.WALL_SIGN) as Sign).apply { rotation = BlockFace.NORTH }
|
|
||||||
|
|
||||||
val sign = signBlock.state as org.bukkit.block.Sign
|
|
||||||
sign.setLine(0, parcel.id)
|
|
||||||
sign.setLine(2, owner.name)
|
|
||||||
sign.update()
|
|
||||||
|
|
||||||
skullBlock.type = Material.PLAYER_HEAD
|
|
||||||
val skull = skullBlock.state as Skull
|
|
||||||
if (owner.uuid != null) {
|
|
||||||
skull.owningPlayer = owner.offlinePlayer
|
|
||||||
} else {
|
|
||||||
skull.owner = owner.name
|
|
||||||
}
|
|
||||||
skull.rotation = BlockFace.WEST
|
|
||||||
skull.update()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setBiome(parcel: Parcel, biome: Biome) {
|
|
||||||
val world = this.world.world
|
|
||||||
val b = getBottomCoord(parcel)
|
|
||||||
val parcelSize = o.parcelSize
|
|
||||||
for (x in b.x until b.x + parcelSize) {
|
|
||||||
for (z in b.z until b.z + parcelSize) {
|
|
||||||
world.setBiome(x, z, biome)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getEntities(parcel: Parcel): Collection<Entity> {
|
|
||||||
val world = this.world.world
|
|
||||||
val b = getBottomCoord(parcel)
|
|
||||||
val parcelSize = o.parcelSize
|
|
||||||
val center = Location(world, (b.x + parcelSize) / 2.0, 128.0, (b.z + parcelSize) / 2.0)
|
|
||||||
return world.getNearbyEntities(center, parcelSize / 2.0 + 0.2, 128.0, parcelSize / 2.0 + 0.2)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getBlocks(parcel: Parcel, yRange: IntRange): Iterator<Block> = buildIterator {
|
|
||||||
val range = yRange.clamp(0, 255)
|
|
||||||
val world = this@DefaultParcelGenerator.world.world
|
|
||||||
val b = getBottomCoord(parcel)
|
|
||||||
val parcelSize = o.parcelSize
|
|
||||||
for (x in b.x until b.x + parcelSize) {
|
|
||||||
for (z in b.z until b.z + parcelSize) {
|
|
||||||
for (y in range) {
|
|
||||||
yield(world.getBlockAt(x, y, z))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun clearParcel(parcel: Parcel) = worktimeLimiter.submit {
|
|
||||||
val bottom = getBottomCoord(parcel)
|
|
||||||
val region = Region(Vec3i(bottom.x, 0, bottom.z), Vec3i(o.parcelSize, maxHeight + 1, o.parcelSize))
|
|
||||||
val blocks = RegionTraversal.DOWNWARD.regionTraverser(region)
|
|
||||||
val blockCount = region.blockCount.toDouble()
|
|
||||||
|
|
||||||
val world = world.world
|
|
||||||
val floorHeight = o.floorHeight
|
|
||||||
val airType = airType; val floorType = o.floorType; val fillType = o.fillType
|
|
||||||
|
|
||||||
for ((index, vec) in blocks.withIndex()) {
|
|
||||||
markSuspensionPoint()
|
|
||||||
val y = vec.y
|
|
||||||
val blockType = when {
|
|
||||||
y > floorHeight -> airType
|
|
||||||
y == floorHeight -> floorType
|
|
||||||
else -> fillType
|
|
||||||
}
|
|
||||||
world[vec].blockData = blockType
|
|
||||||
setProgress((index + 1) / blockCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun doBlockOperation(parcel: Parcel, direction: RegionTraversal, operation: (Block) -> Unit) = worktimeLimiter.submit {
|
|
||||||
val bottom = getBottomCoord(parcel)
|
|
||||||
val region = Region(Vec3i(bottom.x, 0, bottom.z), Vec3i(o.parcelSize, maxHeight + 1, o.parcelSize))
|
|
||||||
val blocks = direction.regionTraverser(region)
|
|
||||||
val blockCount = region.blockCount.toDouble()
|
|
||||||
val world = world.world
|
|
||||||
|
|
||||||
for ((index, vec) in blocks.withIndex()) {
|
|
||||||
markSuspensionPoint()
|
|
||||||
operation(world[vec])
|
|
||||||
setProgress((index + 1) / blockCount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -2,7 +2,7 @@ package io.dico.parcels2.blockvisitor
|
|||||||
|
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.Material.*
|
import org.bukkit.Material.*
|
||||||
import java.util.*
|
import java.util.EnumSet
|
||||||
|
|
||||||
val attachables: Set<Material> = EnumSet.of(
|
val attachables: Set<Material> = EnumSet.of(
|
||||||
ACACIA_DOOR,
|
ACACIA_DOOR,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import kotlinx.coroutines.experimental.CancellationException
|
|||||||
import kotlinx.coroutines.experimental.Job
|
import kotlinx.coroutines.experimental.Job
|
||||||
import org.bukkit.scheduler.BukkitTask
|
import org.bukkit.scheduler.BukkitTask
|
||||||
import java.lang.System.currentTimeMillis
|
import java.lang.System.currentTimeMillis
|
||||||
import java.util.*
|
import java.util.LinkedList
|
||||||
import java.util.logging.Level
|
import java.util.logging.Level
|
||||||
import kotlin.coroutines.experimental.Continuation
|
import kotlin.coroutines.experimental.Continuation
|
||||||
import kotlin.coroutines.experimental.intrinsics.COROUTINE_SUSPENDED
|
import kotlin.coroutines.experimental.intrinsics.COROUTINE_SUSPENDED
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei
|
|||||||
|
|
||||||
override fun getPlugin(): Plugin = plugin
|
override fun getPlugin(): Plugin = plugin
|
||||||
override fun getReceiver(context: ExecutionContext, target: Method, cmdName: String): ICommandReceiver {
|
override fun getReceiver(context: ExecutionContext, target: Method, cmdName: String): ICommandReceiver {
|
||||||
return getParcelCommandReceiver(plugin.worlds, context, target, cmdName)
|
return getParcelCommandReceiver(plugin.parcelProvider, context, target, cmdName)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected inline val worlds get() = plugin.worlds
|
protected inline val worlds get() = plugin.parcelProvider
|
||||||
|
|
||||||
protected fun error(message: String): Nothing {
|
protected fun error(message: String): Nothing {
|
||||||
throw CommandException(message)
|
throw CommandException(message)
|
||||||
@@ -32,7 +32,7 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei
|
|||||||
protected suspend fun checkParcelLimit(player: Player, world: ParcelWorld) {
|
protected suspend fun checkParcelLimit(player: Player, world: ParcelWorld) {
|
||||||
if (player.hasAdminManage) return
|
if (player.hasAdminManage) return
|
||||||
val numOwnedParcels = plugin.storage.getOwnedParcels(ParcelOwner(player)).await()
|
val numOwnedParcels = plugin.storage.getOwnedParcels(ParcelOwner(player)).await()
|
||||||
.filter { it.world.world == world.world }.size
|
.filter { it.worldId.equals(world.id) }.size
|
||||||
|
|
||||||
val limit = player.parcelLimit
|
val limit = player.parcelLimit
|
||||||
if (numOwnedParcels >= limit) {
|
if (numOwnedParcels >= limit) {
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package io.dico.parcels2.command
|
||||||
|
|
||||||
|
import io.dico.dicore.command.Validate
|
||||||
|
import io.dico.dicore.command.annotation.Cmd
|
||||||
|
import io.dico.dicore.command.annotation.Desc
|
||||||
|
import io.dico.parcels2.GlobalAddedData
|
||||||
|
import io.dico.parcels2.GlobalAddedDataManager
|
||||||
|
import io.dico.parcels2.ParcelOwner
|
||||||
|
import io.dico.parcels2.ParcelsPlugin
|
||||||
|
import org.bukkit.OfflinePlayer
|
||||||
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
|
class CommandsAddedStatusGlobal(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||||
|
private inline val data get() = plugin.globalAddedData
|
||||||
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
|
private inline operator fun GlobalAddedDataManager.get(player: OfflinePlayer): GlobalAddedData = data[ParcelOwner(player)]
|
||||||
|
|
||||||
|
@Cmd("allow", aliases = ["add", "permit"])
|
||||||
|
@Desc("Globally allows a player to build on all",
|
||||||
|
"the parcels that you own.",
|
||||||
|
shortVersion = "globally allows a player to build on your parcels")
|
||||||
|
@ParcelRequire(owner = true)
|
||||||
|
fun cmdAllow(sender: Player, player: OfflinePlayer): Any? {
|
||||||
|
Validate.isTrue(player != sender, "The target cannot be yourself")
|
||||||
|
Validate.isTrue(data[sender].allow(player), "${player.name} is already allowed globally")
|
||||||
|
return "${player.name} is now allowed to build on all your parcels"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Cmd("disallow", aliases = ["remove", "forbid"])
|
||||||
|
@Desc("Globally disallows a player to build on",
|
||||||
|
"the parcels that you own.",
|
||||||
|
"If the player is allowed to build on specific",
|
||||||
|
"parcels, they can still build there.",
|
||||||
|
shortVersion = "globally disallows a player to build on your parcels")
|
||||||
|
@ParcelRequire(owner = true)
|
||||||
|
fun cmdDisallow(sender: Player, player: OfflinePlayer): Any? {
|
||||||
|
Validate.isTrue(player != sender, "The target cannot be yourself")
|
||||||
|
Validate.isTrue(data[sender].disallow(player), "${player.name} is not currently allowed globally")
|
||||||
|
return "${player.name} is not allowed to build on all your parcels anymore"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Cmd("ban", aliases = ["deny"])
|
||||||
|
@Desc("Globally bans a player from all the parcels",
|
||||||
|
"that you own, making them unable to enter.",
|
||||||
|
shortVersion = "globally bans a player from your parcels")
|
||||||
|
@ParcelRequire(owner = true)
|
||||||
|
fun cmdBan(sender: Player, player: OfflinePlayer): Any? {
|
||||||
|
Validate.isTrue(player != sender, "The target cannot be yourself")
|
||||||
|
Validate.isTrue(data[sender].ban(player), "${player.name} is already banned from all your parcels")
|
||||||
|
return "${player.name} is now banned from all your parcels"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Cmd("unban", aliases = ["undeny"])
|
||||||
|
@Desc("Globally unbans a player from all the parcels",
|
||||||
|
"that you own, they can enter again.",
|
||||||
|
"If the player is banned from specific parcels,",
|
||||||
|
"they will still be banned there.",
|
||||||
|
shortVersion = "globally unbans a player from your parcels")
|
||||||
|
@ParcelRequire(owner = true)
|
||||||
|
fun cmdUnban(sender: Player, player: OfflinePlayer): Any? {
|
||||||
|
Validate.isTrue(data[sender].unban(player), "${player.name} is not currently banned from all your parcels")
|
||||||
|
return "${player.name} is not banned from all your parcels anymore"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ import io.dico.parcels2.util.hasAdminManage
|
|||||||
import org.bukkit.OfflinePlayer
|
import org.bukkit.OfflinePlayer
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
class CommandsAddedStatus(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
class CommandsAddedStatusLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||||
|
|
||||||
@Cmd("allow", aliases = ["add", "permit"])
|
@Cmd("allow", aliases = ["add", "permit"])
|
||||||
@Desc("Allows a player to build on this parcel",
|
@Desc("Allows a player to build on this parcel",
|
||||||
@@ -9,7 +9,7 @@ import io.dico.parcels2.blockvisitor.RegionTraversal
|
|||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.Material
|
import org.bukkit.Material
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import java.util.*
|
import java.util.Random
|
||||||
|
|
||||||
class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||||
|
|
||||||
@@ -39,7 +39,8 @@ class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
server.createBlockData(Material.QUARTZ_BLOCK)
|
server.createBlockData(Material.QUARTZ_BLOCK)
|
||||||
)
|
)
|
||||||
val random = Random()
|
val random = Random()
|
||||||
world.generator.doBlockOperation(parcel, direction = RegionTraversal.UPWARD) { block ->
|
|
||||||
|
world.doBlockOperation(parcel.id, direction = RegionTraversal.UPWARD) { block ->
|
||||||
block.blockData = blockDatas[random.nextInt(4)]
|
block.blockData = blockDatas[random.nextInt(4)]
|
||||||
}.onProgressUpdate(1000, 1000) { progress, elapsedTime ->
|
}.onProgressUpdate(1000, 1000) { progress, elapsedTime ->
|
||||||
context.sendMessage(EMessageType.INFORMATIVE, "Mess progress: %.02f%%, %.2fs elapsed"
|
context.sendMessage(EMessageType.INFORMATIVE, "Mess progress: %.02f%%, %.2fs elapsed"
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import io.dico.dicore.command.annotation.Flag
|
|||||||
import io.dico.dicore.command.annotation.RequireParameters
|
import io.dico.dicore.command.annotation.RequireParameters
|
||||||
import io.dico.parcels2.ParcelOwner
|
import io.dico.parcels2.ParcelOwner
|
||||||
import io.dico.parcels2.ParcelsPlugin
|
import io.dico.parcels2.ParcelsPlugin
|
||||||
import io.dico.parcels2.storage.getParcelBySerializedValue
|
|
||||||
import io.dico.parcels2.util.hasAdminManage
|
import io.dico.parcels2.util.hasAdminManage
|
||||||
import io.dico.parcels2.util.hasParcelHomeOthers
|
import io.dico.parcels2.util.hasParcelHomeOthers
|
||||||
import io.dico.parcels2.util.uuid
|
import io.dico.parcels2.util.uuid
|
||||||
@@ -27,7 +26,7 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
val parcel = world.nextEmptyParcel()
|
val parcel = world.nextEmptyParcel()
|
||||||
?: error("This world is full, please ask an admin to upsize it")
|
?: error("This world is full, please ask an admin to upsize it")
|
||||||
parcel.owner = ParcelOwner(uuid = player.uuid)
|
parcel.owner = ParcelOwner(uuid = player.uuid)
|
||||||
player.teleport(parcel.homeLocation)
|
player.teleport(parcel.world.getHomeLocation(parcel.id))
|
||||||
return "Enjoy your new parcel!"
|
return "Enjoy your new parcel!"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,13 +52,13 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
val ownedParcelsResult = plugin.storage.getOwnedParcels(ownerTarget.owner).await()
|
val ownedParcelsResult = plugin.storage.getOwnedParcels(ownerTarget.owner).await()
|
||||||
|
|
||||||
val ownedParcels = ownedParcelsResult
|
val ownedParcels = ownedParcelsResult
|
||||||
.map { worlds.getParcelBySerializedValue(it) }
|
.map { worlds.getParcelById(it) }
|
||||||
.filter { it != null && ownerTarget.world == it.world }
|
.filter { it != null && ownerTarget.world == it.world }
|
||||||
|
|
||||||
val targetMatch = ownedParcels.getOrNull(target.index)
|
val targetMatch = ownedParcels.getOrNull(target.index)
|
||||||
?: error("The specified parcel could not be matched")
|
?: error("The specified parcel could not be matched")
|
||||||
|
|
||||||
player.teleport(targetMatch.homeLocation)
|
player.teleport(targetMatch.world.getHomeLocation(targetMatch.id))
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +90,7 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
|||||||
if (!sure) return "Are you sure? You cannot undo this action!\n" +
|
if (!sure) return "Are you sure? You cannot undo this action!\n" +
|
||||||
"Type ${context.rawInput} -sure if you want to go through with this."
|
"Type ${context.rawInput} -sure if you want to go through with this."
|
||||||
|
|
||||||
world.generator.clearParcel(parcel)
|
world.clearParcel(parcel.id)
|
||||||
.onProgressUpdate(1000, 1000) { progress, elapsedTime ->
|
.onProgressUpdate(1000, 1000) { progress, elapsedTime ->
|
||||||
context.sendMessage(EMessageType.INFORMATIVE, "Clear progress: %.02f%%, %.2fs elapsed"
|
context.sendMessage(EMessageType.INFORMATIVE, "Clear progress: %.02f%%, %.2fs elapsed"
|
||||||
.format(progress * 100, elapsedTime / 1000.0))
|
.format(progress * 100, elapsedTime / 1000.0))
|
||||||
|
|||||||
@@ -3,29 +3,32 @@ package io.dico.parcels2.command
|
|||||||
import io.dico.dicore.command.CommandBuilder
|
import io.dico.dicore.command.CommandBuilder
|
||||||
import io.dico.dicore.command.ICommandAddress
|
import io.dico.dicore.command.ICommandAddress
|
||||||
import io.dico.dicore.command.ICommandDispatcher
|
import io.dico.dicore.command.ICommandDispatcher
|
||||||
import io.dico.dicore.command.predef.PredefinedCommand
|
|
||||||
import io.dico.dicore.command.registration.reflect.ReflectiveRegistration
|
import io.dico.dicore.command.registration.reflect.ReflectiveRegistration
|
||||||
import io.dico.parcels2.ParcelsPlugin
|
import io.dico.parcels2.ParcelsPlugin
|
||||||
import io.dico.parcels2.logger
|
import java.util.LinkedList
|
||||||
import java.util.*
|
import java.util.Queue
|
||||||
|
|
||||||
@Suppress("UsePropertyAccessSyntax")
|
@Suppress("UsePropertyAccessSyntax")
|
||||||
fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher {
|
fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
return CommandBuilder()
|
return CommandBuilder()
|
||||||
.setChatController(ParcelsChatController())
|
.setChatController(ParcelsChatController())
|
||||||
.addParameterType(false, ParcelParameterType(plugin.worlds))
|
.addParameterType(false, ParcelParameterType(plugin.parcelProvider))
|
||||||
.addParameterType(true, ParcelTarget.PType(plugin.worlds))
|
.addParameterType(true, ParcelTarget.PType(plugin.parcelProvider))
|
||||||
|
|
||||||
.group("parcel", "plot", "plots", "p")
|
.group("parcel", "plot", "plots", "p")
|
||||||
.registerCommands(CommandsGeneral(plugin))
|
.registerCommands(CommandsGeneral(plugin))
|
||||||
.registerCommands(CommandsAddedStatus(plugin))
|
.registerCommands(CommandsAddedStatusLocal(plugin))
|
||||||
|
|
||||||
.group("option")
|
.group("option", "opt", "o")
|
||||||
//.apply { CommandsParcelOptions.setGroupDescription(this) }
|
//.apply { CommandsParcelOptions.setGroupDescription(this) }
|
||||||
.registerCommands(CommandsParcelOptions(plugin))
|
.registerCommands(CommandsParcelOptions(plugin))
|
||||||
.parent()
|
.parent()
|
||||||
|
|
||||||
|
.group("global", "g")
|
||||||
|
.registerCommands(CommandsAddedStatusGlobal(plugin))
|
||||||
|
.parent()
|
||||||
|
|
||||||
.group("admin", "a")
|
.group("admin", "a")
|
||||||
.registerCommands(CommandsAdmin(plugin))
|
.registerCommands(CommandsAdmin(plugin))
|
||||||
.parent()
|
.parent()
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import io.dico.dicore.command.ExecutionContext
|
|||||||
import io.dico.dicore.command.ICommandReceiver
|
import io.dico.dicore.command.ICommandReceiver
|
||||||
import io.dico.dicore.command.Validate
|
import io.dico.dicore.command.Validate
|
||||||
import io.dico.parcels2.Parcel
|
import io.dico.parcels2.Parcel
|
||||||
|
import io.dico.parcels2.ParcelProvider
|
||||||
import io.dico.parcels2.ParcelWorld
|
import io.dico.parcels2.ParcelWorld
|
||||||
import io.dico.parcels2.Worlds
|
|
||||||
import io.dico.parcels2.util.hasAdminManage
|
import io.dico.parcels2.util.hasAdminManage
|
||||||
import io.dico.parcels2.util.uuid
|
import io.dico.parcels2.util.uuid
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
@@ -30,7 +30,7 @@ open class ParcelScope(val parcel: Parcel) : WorldScope(parcel.world) {
|
|||||||
"You must own this parcel to $action")
|
"You must own this parcel to $action")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getParcelCommandReceiver(worlds: Worlds, context: ExecutionContext, method: Method, cmdName: String): ICommandReceiver {
|
fun getParcelCommandReceiver(parcelProvider: ParcelProvider, context: ExecutionContext, method: Method, cmdName: String): ICommandReceiver {
|
||||||
val player = context.sender as Player
|
val player = context.sender as Player
|
||||||
val function = method.kotlinFunction!!
|
val function = method.kotlinFunction!!
|
||||||
val receiverType = function.extensionReceiverParameter!!.type
|
val receiverType = function.extensionReceiverParameter!!.type
|
||||||
@@ -39,20 +39,20 @@ fun getParcelCommandReceiver(worlds: Worlds, context: ExecutionContext, method:
|
|||||||
val owner = require?.owner == true
|
val owner = require?.owner == true
|
||||||
|
|
||||||
return when (receiverType.jvmErasure) {
|
return when (receiverType.jvmErasure) {
|
||||||
ParcelScope::class -> ParcelScope(worlds.getParcelRequired(player, admin, owner))
|
ParcelScope::class -> ParcelScope(parcelProvider.getParcelRequired(player, admin, owner))
|
||||||
WorldScope::class -> WorldScope(worlds.getWorldRequired(player, admin))
|
WorldScope::class -> WorldScope(parcelProvider.getWorldRequired(player, admin))
|
||||||
else -> throw InternalError("Invalid command receiver type")
|
else -> throw InternalError("Invalid command receiver type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Worlds.getWorldRequired(player: Player, admin: Boolean = false): ParcelWorld {
|
fun ParcelProvider.getWorldRequired(player: Player, admin: Boolean = false): ParcelWorld {
|
||||||
if (admin) Validate.isTrue(player.hasAdminManage, "You must have admin rights to use that command")
|
if (admin) Validate.isTrue(player.hasAdminManage, "You must have admin rights to use that command")
|
||||||
return getWorld(player.world)
|
return getWorld(player.world)
|
||||||
?: throw CommandException("You must be in a parcel world to use that command")
|
?: throw CommandException("You must be in a parcel world to use that command")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Worlds.getParcelRequired(player: Player, admin: Boolean = false, own: Boolean = false): Parcel {
|
fun ParcelProvider.getParcelRequired(player: Player, admin: Boolean = false, own: Boolean = false): Parcel {
|
||||||
val parcel = getWorldRequired(player, admin = admin).parcelAt(player)
|
val parcel = getWorldRequired(player, admin = admin).getParcelAt(player)
|
||||||
?: throw CommandException("You must be in a parcel to use that command")
|
?: throw CommandException("You must be in a parcel to use that command")
|
||||||
if (own) Validate.isTrue(parcel.isOwner(player.uuid) || player.hasAdminManage,
|
if (own) Validate.isTrue(parcel.isOwner(player.uuid) || player.hasAdminManage,
|
||||||
"You must own this parcel to use that command")
|
"You must own this parcel to use that command")
|
||||||
|
|||||||
@@ -3,15 +3,10 @@ package io.dico.parcels2.command
|
|||||||
import io.dico.dicore.command.CommandException
|
import io.dico.dicore.command.CommandException
|
||||||
import io.dico.dicore.command.parameter.ArgumentBuffer
|
import io.dico.dicore.command.parameter.ArgumentBuffer
|
||||||
import io.dico.dicore.command.parameter.Parameter
|
import io.dico.dicore.command.parameter.Parameter
|
||||||
import io.dico.dicore.command.parameter.type.ParameterConfig
|
|
||||||
import io.dico.dicore.command.parameter.type.ParameterType
|
import io.dico.dicore.command.parameter.type.ParameterType
|
||||||
import io.dico.parcels2.Parcel
|
import io.dico.parcels2.Parcel
|
||||||
|
import io.dico.parcels2.ParcelProvider
|
||||||
import io.dico.parcels2.ParcelWorld
|
import io.dico.parcels2.ParcelWorld
|
||||||
import io.dico.parcels2.ParcelsPlugin
|
|
||||||
import io.dico.parcels2.Worlds
|
|
||||||
import io.dico.parcels2.util.isValid
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.OfflinePlayer
|
|
||||||
import org.bukkit.command.CommandSender
|
import org.bukkit.command.CommandSender
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
|
|
||||||
@@ -19,7 +14,7 @@ fun invalidInput(parameter: Parameter<*, *>, message: String): Nothing {
|
|||||||
throw CommandException("invalid input for ${parameter.name}: $message")
|
throw CommandException("invalid input for ${parameter.name}: $message")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Worlds.getTargetWorld(input: String?, sender: CommandSender, parameter: Parameter<*, *>): ParcelWorld {
|
fun ParcelProvider.getTargetWorld(input: String?, sender: CommandSender, parameter: Parameter<*, *>): ParcelWorld {
|
||||||
val worldName = input
|
val worldName = input
|
||||||
?.takeUnless { it.isEmpty() }
|
?.takeUnless { it.isEmpty() }
|
||||||
?: (sender as? Player)?.world?.name
|
?: (sender as? Player)?.world?.name
|
||||||
@@ -29,14 +24,14 @@ fun Worlds.getTargetWorld(input: String?, sender: CommandSender, parameter: Para
|
|||||||
?: invalidInput(parameter, "$worldName is not a parcel world")
|
?: invalidInput(parameter, "$worldName is not a parcel world")
|
||||||
}
|
}
|
||||||
|
|
||||||
class ParcelParameterType(val worlds: Worlds) : ParameterType<Parcel, Void>(Parcel::class.java) {
|
class ParcelParameterType(val parcelProvider: ParcelProvider) : ParameterType<Parcel, Void>(Parcel::class.java) {
|
||||||
val regex = Regex.fromLiteral("((.+)->)?([0-9]+):([0-9]+)")
|
val regex = Regex.fromLiteral("((.+)->)?([0-9]+):([0-9]+)")
|
||||||
|
|
||||||
override fun parse(parameter: Parameter<Parcel, Void>, sender: CommandSender, buffer: ArgumentBuffer): Parcel {
|
override fun parse(parameter: Parameter<Parcel, Void>, sender: CommandSender, buffer: ArgumentBuffer): Parcel {
|
||||||
val matchResult = regex.matchEntire(buffer.next())
|
val matchResult = regex.matchEntire(buffer.next())
|
||||||
?: invalidInput(parameter, "must match (w->)?a:b (/${regex.pattern}/)")
|
?: invalidInput(parameter, "must match (w->)?a:b (/${regex.pattern}/)")
|
||||||
|
|
||||||
val world = worlds.getTargetWorld(matchResult.groupValues[2], sender, parameter)
|
val world = parcelProvider.getTargetWorld(matchResult.groupValues[2], sender, parameter)
|
||||||
|
|
||||||
val x = matchResult.groupValues[3].toIntOrNull()
|
val x = matchResult.groupValues[3].toIntOrNull()
|
||||||
?: invalidInput(parameter, "couldn't parse int")
|
?: invalidInput(parameter, "couldn't parse int")
|
||||||
@@ -44,7 +39,7 @@ class ParcelParameterType(val worlds: Worlds) : ParameterType<Parcel, Void>(Parc
|
|||||||
val z = matchResult.groupValues[4].toIntOrNull()
|
val z = matchResult.groupValues[4].toIntOrNull()
|
||||||
?: invalidInput(parameter, "couldn't parse int")
|
?: invalidInput(parameter, "couldn't parse int")
|
||||||
|
|
||||||
return world.parcelByID(x, z)
|
return world.getParcelById(x, z)
|
||||||
?: invalidInput(parameter, "parcel id is out of range")
|
?: invalidInput(parameter, "parcel id is out of range")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import io.dico.dicore.command.parameter.Parameter
|
|||||||
import io.dico.dicore.command.parameter.type.ParameterConfig
|
import io.dico.dicore.command.parameter.type.ParameterConfig
|
||||||
import io.dico.dicore.command.parameter.type.ParameterType
|
import io.dico.dicore.command.parameter.type.ParameterType
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.storage.getParcelBySerializedValue
|
|
||||||
import io.dico.parcels2.util.Vec2i
|
import io.dico.parcels2.util.Vec2i
|
||||||
import io.dico.parcels2.util.floor
|
import io.dico.parcels2.util.floor
|
||||||
import io.dico.parcels2.util.isValid
|
import io.dico.parcels2.util.isValid
|
||||||
@@ -20,7 +19,7 @@ sealed class ParcelTarget(val world: ParcelWorld, val isDefault: Boolean) {
|
|||||||
|
|
||||||
class ByID(world: ParcelWorld, val id: Vec2i?, isDefault: Boolean) : ParcelTarget(world, isDefault) {
|
class ByID(world: ParcelWorld, val id: Vec2i?, isDefault: Boolean) : ParcelTarget(world, isDefault) {
|
||||||
override suspend fun ParcelsPlugin.getParcelSuspend(): Parcel? = getParcel()
|
override suspend fun ParcelsPlugin.getParcelSuspend(): Parcel? = getParcel()
|
||||||
fun getParcel() = id?.let { world.parcelByID(it) }
|
fun getParcel() = id?.let { world.getParcelById(it) }
|
||||||
val isPath: Boolean get() = id == null
|
val isPath: Boolean get() = id == null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +31,7 @@ sealed class ParcelTarget(val world: ParcelWorld, val isDefault: Boolean) {
|
|||||||
override suspend fun ParcelsPlugin.getParcelSuspend(): Parcel? {
|
override suspend fun ParcelsPlugin.getParcelSuspend(): Parcel? {
|
||||||
val ownedParcelsSerialized = storage.getOwnedParcels(owner).await()
|
val ownedParcelsSerialized = storage.getOwnedParcels(owner).await()
|
||||||
val ownedParcels = ownedParcelsSerialized
|
val ownedParcels = ownedParcelsSerialized
|
||||||
.map { worlds.getParcelBySerializedValue(it) }
|
.map { parcelProvider.getParcelById(it) }
|
||||||
.filter { it != null && world == it.world && owner == it.owner }
|
.filter { it != null && world == it.world && owner == it.owner }
|
||||||
return ownedParcels.getOrNull(index)
|
return ownedParcels.getOrNull(index)
|
||||||
}
|
}
|
||||||
@@ -59,7 +58,7 @@ sealed class ParcelTarget(val world: ParcelWorld, val isDefault: Boolean) {
|
|||||||
// instead of parcel that the player is in
|
// instead of parcel that the player is in
|
||||||
}
|
}
|
||||||
|
|
||||||
class PType(val worlds: Worlds) : ParameterType<ParcelTarget, Int>(ParcelTarget::class.java, ParcelTarget.Config) {
|
class PType(val parcelProvider: ParcelProvider) : ParameterType<ParcelTarget, Int>(ParcelTarget::class.java, ParcelTarget.Config) {
|
||||||
|
|
||||||
override fun parse(parameter: Parameter<ParcelTarget, Int>, sender: CommandSender, buffer: ArgumentBuffer): ParcelTarget {
|
override fun parse(parameter: Parameter<ParcelTarget, Int>, sender: CommandSender, buffer: ArgumentBuffer): ParcelTarget {
|
||||||
var input = buffer.next()
|
var input = buffer.next()
|
||||||
@@ -68,19 +67,19 @@ sealed class ParcelTarget(val world: ParcelWorld, val isDefault: Boolean) {
|
|||||||
|
|
||||||
val world = if (worldString.isEmpty()) {
|
val world = if (worldString.isEmpty()) {
|
||||||
val player = requirePlayer(sender, parameter, "the world")
|
val player = requirePlayer(sender, parameter, "the world")
|
||||||
worlds.getWorld(player.world)
|
parcelProvider.getWorld(player.world)
|
||||||
?: invalidInput(parameter, "You cannot omit the world if you're not in a parcel world")
|
?: invalidInput(parameter, "You cannot omit the world if you're not in a parcel world")
|
||||||
} else {
|
} else {
|
||||||
worlds.getWorld(worldString) ?: invalidInput(parameter, "$worldString is not a parcel world")
|
parcelProvider.getWorld(worldString) ?: invalidInput(parameter, "$worldString is not a parcel world")
|
||||||
}
|
}
|
||||||
|
|
||||||
val kind = parameter.paramInfo ?: DEFAULT_KIND
|
val kind = parameter.paramInfo ?: DEFAULT_KIND
|
||||||
if (input.contains(',')) {
|
if (input.contains(',')) {
|
||||||
if (kind and ID == 0) invalidInput(parameter, "You must specify a parcel by ID, that is, the x and z component separated by a comma")
|
if (kind and ID == 0) invalidInput(parameter, "You must specify a parcel by OWNER, that is, an owner and index")
|
||||||
return ByID(world, getId(parameter, input), false)
|
return ByID(world, getId(parameter, input), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kind and OWNER == 0) invalidInput(parameter, "You must specify a parcel by OWNER, that is, an owner and index")
|
if (kind and OWNER == 0) invalidInput(parameter, "You must specify a parcel by ID, that is, the x and z component separated by a comma")
|
||||||
val (owner, index) = getHomeIndex(parameter, sender, input)
|
val (owner, index) = getHomeIndex(parameter, sender, input)
|
||||||
return ByOwner(world, owner, index, false)
|
return ByOwner(world, owner, index, false)
|
||||||
}
|
}
|
||||||
@@ -106,7 +105,7 @@ sealed class ParcelTarget(val world: ParcelWorld, val isDefault: Boolean) {
|
|||||||
indexString = input
|
indexString = input
|
||||||
} else {
|
} else {
|
||||||
ownerString = input.substring(0, splitIdx)
|
ownerString = input.substring(0, splitIdx)
|
||||||
indexString = input.substring(0, splitIdx + 1)
|
indexString = input.substring(splitIdx + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
val owner = if (ownerString.isEmpty())
|
val owner = if (ownerString.isEmpty())
|
||||||
@@ -151,9 +150,9 @@ sealed class ParcelTarget(val world: ParcelWorld, val isDefault: Boolean) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val player = requirePlayer(sender, parameter, "the parcel")
|
val player = requirePlayer(sender, parameter, "the parcel")
|
||||||
val world = worlds.getWorld(player.world) ?: invalidInput(parameter, "You must be in a parcel world to omit the parcel")
|
val world = parcelProvider.getWorld(player.world) ?: invalidInput(parameter, "You must be in a parcel world to omit the parcel")
|
||||||
if (useLocation) {
|
if (useLocation) {
|
||||||
val id = player.location.let { world.generator.parcelIDAt(it.x.floor(), it.z.floor()) }
|
val id = player.location.let { world.getParcelIdAt(it.x.floor(), it.z.floor())?.pos }
|
||||||
return ByID(world, id, true)
|
return ByID(world, id, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package io.dico.parcels2.defaultimpl
|
||||||
|
|
||||||
|
import io.dico.parcels2.Parcel
|
||||||
|
import io.dico.parcels2.ParcelContainer
|
||||||
|
import io.dico.parcels2.ParcelWorld
|
||||||
|
import kotlin.coroutines.experimental.buildIterator
|
||||||
|
import kotlin.coroutines.experimental.buildSequence
|
||||||
|
|
||||||
|
class DefaultParcelContainer(val world: ParcelWorld) : ParcelContainer {
|
||||||
|
private var parcels: Array<Array<Parcel>>
|
||||||
|
|
||||||
|
init {
|
||||||
|
parcels = initArray(world.options.axisLimit, world)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resizeIfSizeChanged() {
|
||||||
|
if (parcels.size != world.options.axisLimit * 2 + 1) {
|
||||||
|
resize(world.options.axisLimit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resize(axisLimit: Int) {
|
||||||
|
parcels = initArray(axisLimit, world, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun initArray(axisLimit: Int, world: ParcelWorld, cur: DefaultParcelContainer? = null): Array<Array<Parcel>> {
|
||||||
|
val arraySize = 2 * axisLimit + 1
|
||||||
|
return Array(arraySize) {
|
||||||
|
val x = it - axisLimit
|
||||||
|
Array(arraySize) {
|
||||||
|
val z = it - axisLimit
|
||||||
|
cur?.getParcelById(x, z) ?: ParcelImpl(world, x, z)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getParcelById(x: Int, z: Int): Parcel? {
|
||||||
|
return parcels.getOrNull(x + world.options.axisLimit)?.getOrNull(z + world.options.axisLimit)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun nextEmptyParcel(): Parcel? {
|
||||||
|
return walkInCircle().find { it.owner == null }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun walkInCircle(): Iterable<Parcel> = Iterable {
|
||||||
|
buildIterator {
|
||||||
|
val center = world.options.axisLimit
|
||||||
|
for (radius in 0..center) {
|
||||||
|
var x = center - radius;
|
||||||
|
var z = center - radius
|
||||||
|
repeat(radius * 2) { yield(parcels[x++][z]) }
|
||||||
|
repeat(radius * 2) { yield(parcels[x][z++]) }
|
||||||
|
repeat(radius * 2) { yield(parcels[x--][z]) }
|
||||||
|
repeat(radius * 2) { yield(parcels[x][z--]) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun allParcels(): Sequence<Parcel> = buildSequence {
|
||||||
|
for (array in parcels) {
|
||||||
|
yieldAll(array.iterator())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
package io.dico.parcels2.defaultimpl
|
||||||
|
|
||||||
|
import io.dico.parcels2.*
|
||||||
|
import io.dico.parcels2.blockvisitor.RegionTraversal
|
||||||
|
import io.dico.parcels2.blockvisitor.Worker
|
||||||
|
import io.dico.parcels2.blockvisitor.WorktimeLimiter
|
||||||
|
import io.dico.parcels2.util.*
|
||||||
|
import org.bukkit.*
|
||||||
|
import org.bukkit.block.Biome
|
||||||
|
import org.bukkit.block.Block
|
||||||
|
import org.bukkit.block.BlockFace
|
||||||
|
import org.bukkit.block.Skull
|
||||||
|
import org.bukkit.block.data.BlockData
|
||||||
|
import org.bukkit.block.data.type.Sign
|
||||||
|
import org.bukkit.block.data.type.Slab
|
||||||
|
import java.util.Random
|
||||||
|
|
||||||
|
private val airType = Bukkit.createBlockData(Material.AIR)
|
||||||
|
|
||||||
|
data class DefaultGeneratorOptions(var defaultBiome: Biome = Biome.JUNGLE,
|
||||||
|
var wallType: BlockData = Bukkit.createBlockData(Material.STONE_SLAB),
|
||||||
|
var floorType: BlockData = Bukkit.createBlockData(Material.QUARTZ_BLOCK),
|
||||||
|
var fillType: BlockData = Bukkit.createBlockData(Material.QUARTZ_BLOCK),
|
||||||
|
var pathMainType: BlockData = Bukkit.createBlockData(Material.SANDSTONE),
|
||||||
|
var pathAltType: BlockData = Bukkit.createBlockData(Material.REDSTONE_BLOCK),
|
||||||
|
var parcelSize: Int = 101,
|
||||||
|
var pathSize: Int = 9,
|
||||||
|
var floorHeight: Int = 64,
|
||||||
|
var offsetX: Int = 0,
|
||||||
|
var offsetZ: Int = 0) : GeneratorOptions() {
|
||||||
|
|
||||||
|
override fun generatorFactory(): GeneratorFactory = DefaultParcelGenerator.Factory
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultParcelGenerator(val name: String, private val o: DefaultGeneratorOptions) : ParcelGenerator() {
|
||||||
|
private var _world: World? = null
|
||||||
|
override val world: World
|
||||||
|
get() {
|
||||||
|
if (_world == null) _world = Bukkit.getWorld(name)!!.also {
|
||||||
|
maxHeight = it.maxHeight
|
||||||
|
return it
|
||||||
|
}
|
||||||
|
return _world!!
|
||||||
|
}
|
||||||
|
|
||||||
|
private var maxHeight = 0
|
||||||
|
|
||||||
|
companion object Factory : GeneratorFactory {
|
||||||
|
override val name get() = "default"
|
||||||
|
override val optionsClass get() = DefaultGeneratorOptions::class
|
||||||
|
override fun newParcelGenerator(worldName: String, options: GeneratorOptions): ParcelGenerator {
|
||||||
|
return DefaultParcelGenerator(worldName, options as DefaultGeneratorOptions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val sectionSize = o.parcelSize + o.pathSize
|
||||||
|
val pathOffset = (if (o.pathSize % 2 == 0) o.pathSize + 2 else o.pathSize + 1) / 2
|
||||||
|
val makePathMain = o.pathSize > 2
|
||||||
|
val makePathAlt = o.pathSize > 4
|
||||||
|
|
||||||
|
private inline fun <T> generate(chunkX: Int,
|
||||||
|
chunkZ: Int,
|
||||||
|
floor: T, wall:
|
||||||
|
T, pathMain: T,
|
||||||
|
pathAlt: T,
|
||||||
|
fill: T,
|
||||||
|
setter: (Int, Int, Int, T) -> Unit) {
|
||||||
|
|
||||||
|
val floorHeight = o.floorHeight
|
||||||
|
val parcelSize = o.parcelSize
|
||||||
|
val sectionSize = sectionSize
|
||||||
|
val pathOffset = pathOffset
|
||||||
|
val makePathMain = makePathMain
|
||||||
|
val makePathAlt = makePathAlt
|
||||||
|
|
||||||
|
// parcel bottom x and z
|
||||||
|
// umod is unsigned %: the result is always >= 0
|
||||||
|
val pbx = ((chunkX shl 4) - o.offsetX) umod sectionSize
|
||||||
|
val pbz = ((chunkZ shl 4) - o.offsetZ) umod sectionSize
|
||||||
|
|
||||||
|
var curHeight: Int
|
||||||
|
var x: Int
|
||||||
|
var z: Int
|
||||||
|
for (cx in 0..15) {
|
||||||
|
for (cz in 0..15) {
|
||||||
|
x = (pbx + cx) % sectionSize - pathOffset
|
||||||
|
z = (pbz + cz) % sectionSize - pathOffset
|
||||||
|
curHeight = floorHeight
|
||||||
|
|
||||||
|
val type = when {
|
||||||
|
(x in 0 until parcelSize && z in 0 until parcelSize) -> floor
|
||||||
|
(x in -1..parcelSize && z in -1..parcelSize) -> {
|
||||||
|
curHeight++
|
||||||
|
wall
|
||||||
|
}
|
||||||
|
(makePathAlt && x in -2 until parcelSize + 2 && z in -2 until parcelSize + 2) -> pathAlt
|
||||||
|
(makePathMain) -> pathMain
|
||||||
|
else -> {
|
||||||
|
curHeight++
|
||||||
|
wall
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (y in 0 until curHeight) {
|
||||||
|
setter(cx, y, cz, fill)
|
||||||
|
}
|
||||||
|
setter(cx, curHeight, cz, type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateChunkData(world: World?, random: Random?, chunkX: Int, chunkZ: Int, biome: BiomeGrid?): ChunkData {
|
||||||
|
val out = Bukkit.createChunkData(world)
|
||||||
|
generate(chunkX, chunkZ, o.floorType, o.wallType, o.pathMainType, o.pathAltType, o.fillType) { x, y, z, type ->
|
||||||
|
out.setBlock(x, y, z, type)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun populate(world: World?, random: Random?, chunk: Chunk?) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFixedSpawnLocation(world: World?, random: Random?): Location {
|
||||||
|
val fix = if (o.parcelSize.even) 0.5 else 0.0
|
||||||
|
return Location(world, o.offsetX + fix, o.floorHeight + 1.0, o.offsetZ + fix)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun makeParcelBlockManager(worktimeLimiter: WorktimeLimiter): ParcelBlockManager {
|
||||||
|
return ParcelBlockManagerImpl(worktimeLimiter)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun makeParcelLocator(container: ParcelContainer): ParcelLocator {
|
||||||
|
return ParcelLocatorImpl(container)
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <T> convertBlockLocationToId(x: Int, z: Int, mapper: (Int, Int) -> T): T? {
|
||||||
|
val sectionSize = sectionSize
|
||||||
|
val parcelSize = o.parcelSize
|
||||||
|
val absX = x - o.offsetX - pathOffset
|
||||||
|
val absZ = z - o.offsetZ - pathOffset
|
||||||
|
val modX = absX umod sectionSize
|
||||||
|
val modZ = absZ umod sectionSize
|
||||||
|
if (modX in 0 until parcelSize && modZ in 0 until parcelSize) {
|
||||||
|
return mapper((absX - modX) / sectionSize, (absZ - modZ) / sectionSize)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
private inner class ParcelLocatorImpl(val container: ParcelContainer) : ParcelLocator {
|
||||||
|
override val world: World = this@DefaultParcelGenerator.world
|
||||||
|
override fun getParcelAt(x: Int, z: Int): Parcel? {
|
||||||
|
return convertBlockLocationToId(x, z, container::getParcelById)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getParcelIdAt(x: Int, z: Int): ParcelId? {
|
||||||
|
return convertBlockLocationToId(x, z) { idx, idz -> ParcelId(world.name, world.uid, idx, idz) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
private inner class ParcelBlockManagerImpl(override val worktimeLimiter: WorktimeLimiter) : ParcelBlockManager {
|
||||||
|
override val world: World = this@DefaultParcelGenerator.world
|
||||||
|
|
||||||
|
override fun getBottomBlock(parcel: ParcelId): Vec2i = Vec2i(
|
||||||
|
sectionSize * parcel.pos.x + pathOffset + o.offsetX,
|
||||||
|
sectionSize * parcel.pos.z + pathOffset + o.offsetZ
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun getHomeLocation(parcel: ParcelId): Location {
|
||||||
|
val bottom = getBottomBlock(parcel)
|
||||||
|
return Location(world, bottom.x.toDouble(), o.floorHeight + 1.0, bottom.z + (o.parcelSize - 1) / 2.0, -90F, 0F)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setOwnerBlock(parcel: ParcelId, owner: ParcelOwner?) {
|
||||||
|
val b = getBottomBlock(parcel)
|
||||||
|
|
||||||
|
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 skullBlock = world.getBlockAt(b.x - 1, o.floorHeight + 2, b.z - 1)
|
||||||
|
|
||||||
|
if (owner == null) {
|
||||||
|
wallBlock.blockData = o.wallType
|
||||||
|
signBlock.type = Material.AIR
|
||||||
|
skullBlock.type = Material.AIR
|
||||||
|
} else {
|
||||||
|
|
||||||
|
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 Sign).apply { rotation = BlockFace.NORTH }
|
||||||
|
|
||||||
|
val sign = signBlock.state as org.bukkit.block.Sign
|
||||||
|
sign.setLine(0, "${parcel.x},${parcel.z}")
|
||||||
|
sign.setLine(2, owner.name)
|
||||||
|
sign.update()
|
||||||
|
|
||||||
|
skullBlock.type = Material.PLAYER_HEAD
|
||||||
|
val skull = skullBlock.state as Skull
|
||||||
|
if (owner.uuid != null) {
|
||||||
|
skull.owningPlayer = owner.offlinePlayer
|
||||||
|
} else {
|
||||||
|
skull.owner = owner.name
|
||||||
|
}
|
||||||
|
skull.rotation = BlockFace.WEST
|
||||||
|
skull.update()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setBiome(parcel: ParcelId, biome: Biome): Worker = worktimeLimiter.submit {
|
||||||
|
val world = world
|
||||||
|
val b = getBottomBlock(parcel)
|
||||||
|
val parcelSize = o.parcelSize
|
||||||
|
for (x in b.x until b.x + parcelSize) {
|
||||||
|
for (z in b.z until b.z + parcelSize) {
|
||||||
|
markSuspensionPoint()
|
||||||
|
world.setBiome(x, z, biome)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun clearParcel(parcel: ParcelId): Worker = worktimeLimiter.submit {
|
||||||
|
val bottom = getBottomBlock(parcel)
|
||||||
|
val region = Region(Vec3i(bottom.x, 0, bottom.z), Vec3i(o.parcelSize, maxHeight + 1, o.parcelSize))
|
||||||
|
val blocks = RegionTraversal.DOWNWARD.regionTraverser(region)
|
||||||
|
val blockCount = region.blockCount.toDouble()
|
||||||
|
|
||||||
|
val world = world
|
||||||
|
val floorHeight = o.floorHeight
|
||||||
|
val airType = airType
|
||||||
|
val floorType = o.floorType
|
||||||
|
val fillType = o.fillType
|
||||||
|
|
||||||
|
for ((index, vec) in blocks.withIndex()) {
|
||||||
|
markSuspensionPoint()
|
||||||
|
val y = vec.y
|
||||||
|
val blockType = when {
|
||||||
|
y > floorHeight -> airType
|
||||||
|
y == floorHeight -> floorType
|
||||||
|
else -> fillType
|
||||||
|
}
|
||||||
|
world[vec].blockData = blockType
|
||||||
|
setProgress((index + 1) / blockCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doBlockOperation(parcel: ParcelId, direction: RegionTraversal, operation: (Block) -> Unit): Worker = worktimeLimiter.submit {
|
||||||
|
val bottom = getBottomBlock(parcel)
|
||||||
|
val region = Region(Vec3i(bottom.x, 0, bottom.z), Vec3i(o.parcelSize, maxHeight + 1, o.parcelSize))
|
||||||
|
val blocks = direction.regionTraverser(region)
|
||||||
|
val blockCount = region.blockCount.toDouble()
|
||||||
|
val world = world
|
||||||
|
|
||||||
|
for ((index, vec) in blocks.withIndex()) {
|
||||||
|
markSuspensionPoint()
|
||||||
|
operation(world[vec])
|
||||||
|
setProgress((index + 1) / blockCount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,16 +1,10 @@
|
|||||||
@file:Suppress("UNCHECKED_CAST")
|
@file:Suppress("UNCHECKED_CAST")
|
||||||
|
|
||||||
package io.dico.parcels2
|
package io.dico.parcels2.defaultimpl
|
||||||
|
|
||||||
import java.util.*
|
import io.dico.parcels2.*
|
||||||
|
import java.util.Collections
|
||||||
interface GlobalAddedData : AddedData {
|
import java.util.UUID
|
||||||
val owner: ParcelOwner
|
|
||||||
}
|
|
||||||
|
|
||||||
interface GlobalAddedDataManager {
|
|
||||||
operator fun get(owner: ParcelOwner): GlobalAddedData
|
|
||||||
}
|
|
||||||
|
|
||||||
class GlobalAddedDataManagerImpl(val plugin: ParcelsPlugin) : GlobalAddedDataManager {
|
class GlobalAddedDataManagerImpl(val plugin: ParcelsPlugin) : GlobalAddedDataManager {
|
||||||
private val map = mutableMapOf<ParcelOwner, GlobalAddedData>()
|
private val map = mutableMapOf<ParcelOwner, GlobalAddedData>()
|
||||||
@@ -20,7 +14,7 @@ class GlobalAddedDataManagerImpl(val plugin: ParcelsPlugin) : GlobalAddedDataMan
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class GlobalAddedDataImpl(override val owner: ParcelOwner,
|
private inner class GlobalAddedDataImpl(override val owner: ParcelOwner,
|
||||||
data: MutableMap<UUID, AddedStatus> = emptyData)
|
data: MutableAddedDataMap = emptyData)
|
||||||
: AddedDataHolder(data), GlobalAddedData {
|
: AddedDataHolder(data), GlobalAddedData {
|
||||||
|
|
||||||
private inline var data get() = addedMap; set(value) = run { addedMap = value }
|
private inline var data get() = addedMap; set(value) = run { addedMap = value }
|
||||||
@@ -39,10 +33,7 @@ class GlobalAddedDataManagerImpl(val plugin: ParcelsPlugin) : GlobalAddedDataMan
|
|||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
val emptyData = Collections.emptyMap<UUID, AddedStatus>() as MutableMap<UUID, AddedStatus>
|
val emptyData = Collections.emptyMap<Any, Any>() as MutableAddedDataMap
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
138
src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt
Normal file
138
src/main/kotlin/io/dico/parcels2/defaultimpl/ParcelImpl.kt
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
package io.dico.parcels2.defaultimpl
|
||||||
|
|
||||||
|
import io.dico.dicore.Formatting
|
||||||
|
import io.dico.parcels2.*
|
||||||
|
import io.dico.parcels2.util.Vec2i
|
||||||
|
import io.dico.parcels2.util.getPlayerName
|
||||||
|
import org.bukkit.OfflinePlayer
|
||||||
|
import org.joda.time.DateTime
|
||||||
|
import java.util.UUID
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
class ParcelImpl(override val world: ParcelWorld,
|
||||||
|
override val x: Int,
|
||||||
|
override val z: Int) : Parcel, ParcelId {
|
||||||
|
override val id: ParcelId = this
|
||||||
|
override val pos get() = Vec2i(x, z)
|
||||||
|
override var data: ParcelDataHolder = ParcelDataHolder(); private set
|
||||||
|
override val infoString by ParcelInfoStringComputer
|
||||||
|
override var hasBlockVisitors: Boolean = false; private set
|
||||||
|
override val worldId: ParcelWorldId get() = world.id
|
||||||
|
|
||||||
|
override fun copyDataIgnoringDatabase(data: ParcelData) {
|
||||||
|
this.data = ((data as? Parcel)?.data ?: data) as ParcelDataHolder
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun copyData(data: ParcelData) {
|
||||||
|
copyDataIgnoringDatabase(data)
|
||||||
|
world.storage.setParcelData(this, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun dispose() {
|
||||||
|
copyDataIgnoringDatabase(ParcelDataHolder())
|
||||||
|
world.storage.setParcelData(this, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override val addedMap: Map<UUID, AddedStatus> get() = data.addedMap
|
||||||
|
override fun getAddedStatus(uuid: UUID) = data.getAddedStatus(uuid)
|
||||||
|
override fun isBanned(uuid: UUID) = data.isBanned(uuid)
|
||||||
|
override fun isAllowed(uuid: UUID) = data.isAllowed(uuid)
|
||||||
|
override fun canBuild(player: OfflinePlayer, checkAdmin: Boolean, checkGlobal: Boolean): Boolean {
|
||||||
|
return (data.canBuild(player, checkAdmin, false))
|
||||||
|
|| checkGlobal && world.globalAddedData[owner ?: return false].isAllowed(player)
|
||||||
|
}
|
||||||
|
|
||||||
|
val globalAddedMap: Map<UUID, AddedStatus>? get() = owner?.let { world.globalAddedData[it].addedMap }
|
||||||
|
|
||||||
|
override val since: DateTime? get() = data.since
|
||||||
|
|
||||||
|
override var owner: ParcelOwner?
|
||||||
|
get() = data.owner
|
||||||
|
set(value) {
|
||||||
|
if (data.owner != value) {
|
||||||
|
world.storage.setParcelOwner(this, value)
|
||||||
|
data.owner = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setAddedStatus(uuid: UUID, status: AddedStatus): Boolean {
|
||||||
|
return data.setAddedStatus(uuid, status).also {
|
||||||
|
if (it) world.storage.setParcelPlayerStatus(this, uuid, status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override var allowInteractInputs: Boolean
|
||||||
|
get() = data.allowInteractInputs
|
||||||
|
set(value) {
|
||||||
|
if (data.allowInteractInputs == value) return
|
||||||
|
world.storage.setParcelAllowsInteractInputs(this, value)
|
||||||
|
data.allowInteractInputs = value
|
||||||
|
}
|
||||||
|
|
||||||
|
override var allowInteractInventory: Boolean
|
||||||
|
get() = data.allowInteractInventory
|
||||||
|
set(value) {
|
||||||
|
if (data.allowInteractInventory == value) return
|
||||||
|
world.storage.setParcelAllowsInteractInventory(this, value)
|
||||||
|
data.allowInteractInventory = value
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private object ParcelInfoStringComputer {
|
||||||
|
val infoStringColor1 = Formatting.GREEN
|
||||||
|
val infoStringColor2 = Formatting.AQUA
|
||||||
|
|
||||||
|
private inline fun StringBuilder.appendField(name: String, value: StringBuilder.() -> Unit) {
|
||||||
|
append(infoStringColor1)
|
||||||
|
append(name)
|
||||||
|
append(": ")
|
||||||
|
append(infoStringColor2)
|
||||||
|
value()
|
||||||
|
append(' ')
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun getValue(parcel: Parcel, property: KProperty<*>): String = buildString {
|
||||||
|
appendField("ID") {
|
||||||
|
append(parcel.x)
|
||||||
|
append(',')
|
||||||
|
append(parcel.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
appendField("Owner") {
|
||||||
|
val owner = parcel.owner
|
||||||
|
if (owner == null) {
|
||||||
|
append(infoStringColor1)
|
||||||
|
append("none")
|
||||||
|
} else {
|
||||||
|
append(owner.notNullName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// plotme appends biome here
|
||||||
|
|
||||||
|
append('\n')
|
||||||
|
|
||||||
|
val allowedMap = parcel.addedMap.filterValues { it.isAllowed }
|
||||||
|
if (allowedMap.isNotEmpty()) appendField("Allowed") {
|
||||||
|
allowedMap.keys.map(::getPlayerName).joinTo(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
val bannedMap = parcel.addedMap.filterValues { it.isBanned }
|
||||||
|
if (bannedMap.isNotEmpty()) appendField("Banned") {
|
||||||
|
bannedMap.keys.map(::getPlayerName).joinTo(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parcel.allowInteractInputs || !parcel.allowInteractInventory) {
|
||||||
|
appendField("Options") {
|
||||||
|
append("(")
|
||||||
|
appendField("inputs") { append(parcel.allowInteractInputs) }
|
||||||
|
append(", ")
|
||||||
|
appendField("inventory") { append(parcel.allowInteractInventory) }
|
||||||
|
append(")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package io.dico.parcels2.defaultimpl
|
||||||
|
|
||||||
|
import io.dico.parcels2.*
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.bukkit.WorldCreator
|
||||||
|
|
||||||
|
class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
|
||||||
|
inline val options get() = plugin.options
|
||||||
|
override val worlds: Map<String, ParcelWorld> get() = _worlds
|
||||||
|
private val _worlds: MutableMap<String, ParcelWorld> = hashMapOf()
|
||||||
|
private val _generators: MutableMap<String, ParcelGenerator> = hashMapOf()
|
||||||
|
private var _worldsLoaded = false
|
||||||
|
private var _dataIsLoaded = false
|
||||||
|
|
||||||
|
// disabled while !_dataIsLoaded. getParcelById() will work though for data loading.
|
||||||
|
override fun getWorld(name: String): ParcelWorld? = _worlds[name]?.takeIf { _dataIsLoaded }
|
||||||
|
|
||||||
|
override fun getWorldById(id: ParcelWorldId): ParcelWorld? {
|
||||||
|
if (id is ParcelWorld) return id
|
||||||
|
return _worlds[id.name] ?: id.bukkitWorld?.let { getWorld(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getParcelById(id: ParcelId): Parcel? {
|
||||||
|
if (id is Parcel) return id
|
||||||
|
return getWorldById(id.worldId)?.container?.getParcelById(id.x, id.z)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getWorldGenerator(worldName: String): ParcelGenerator? {
|
||||||
|
return _worlds[worldName]?.generator
|
||||||
|
?: _generators[worldName]
|
||||||
|
?: options.worlds[worldName]?.generator?.newGenerator(worldName)?.also { _generators[worldName] = it }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loadWorlds() {
|
||||||
|
if (_worldsLoaded) throw IllegalStateException()
|
||||||
|
_worldsLoaded = true
|
||||||
|
loadWorlds0()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadWorlds0() {
|
||||||
|
if (Bukkit.getWorlds().isEmpty()) {
|
||||||
|
plugin.functionHelper.schedule(::loadWorlds0)
|
||||||
|
plugin.logger.warning("Scheduling to load worlds in the next tick, \nbecause no bukkit worlds are loaded yet")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((worldName, worldOptions) in options.worlds.entries) {
|
||||||
|
var parcelWorld = _worlds[worldName]
|
||||||
|
if (parcelWorld != null) continue
|
||||||
|
|
||||||
|
val generator: ParcelGenerator = getWorldGenerator(worldName)!!
|
||||||
|
val bukkitWorld = Bukkit.getWorld(worldName) ?: WorldCreator(worldName).generator(generator).createWorld()
|
||||||
|
parcelWorld = ParcelWorldImpl(bukkitWorld, generator, worldOptions.runtime, plugin.storage,
|
||||||
|
plugin.globalAddedData, ::DefaultParcelContainer, plugin.worktimeLimiter)
|
||||||
|
_worlds[worldName] = parcelWorld
|
||||||
|
}
|
||||||
|
|
||||||
|
loadStoredData()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadStoredData() {
|
||||||
|
plugin.functionHelper.launchLazilyOnMainThread {
|
||||||
|
val channel = plugin.storage.readAllParcelData()
|
||||||
|
do {
|
||||||
|
val pair = channel.receiveOrNull() ?: break
|
||||||
|
val parcel = getParcelById(pair.first) ?: continue
|
||||||
|
pair.second?.let { parcel.copyDataIgnoringDatabase(it) }
|
||||||
|
} while (true)
|
||||||
|
|
||||||
|
_dataIsLoaded = true
|
||||||
|
}.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
fun loadWorlds(options: Options) {
|
||||||
|
for ((worldName, worldOptions) in options.worlds.entries) {
|
||||||
|
val world: ParcelWorld
|
||||||
|
try {
|
||||||
|
|
||||||
|
world = ParcelWorldImpl(
|
||||||
|
worldName,
|
||||||
|
worldOptions,
|
||||||
|
worldOptions.generator.newGenerator(this, worldName),
|
||||||
|
plugin.storage,
|
||||||
|
plugin.globalAddedData,
|
||||||
|
::DefaultParcelContainer)
|
||||||
|
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
ex.printStackTrace()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_worlds[worldName] = world
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.functionHelper.schedule(10) {
|
||||||
|
println("Parcels generating parcelProvider now")
|
||||||
|
for ((name, world) in _worlds) {
|
||||||
|
if (Bukkit.getWorld(name) == null) {
|
||||||
|
val bworld = WorldCreator(name).generator(world.generator).createWorld()
|
||||||
|
val spawn = world.generator.getFixedSpawnLocation(bworld, null)
|
||||||
|
bworld.setSpawnLocation(spawn.x.floor(), spawn.y.floor(), spawn.z.floor())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val channel = plugin.storage.readAllParcelData()
|
||||||
|
val job = plugin.functionHelper.launchLazilyOnMainThread {
|
||||||
|
do {
|
||||||
|
val pair = channel.receiveOrNull() ?: break
|
||||||
|
val parcel = getParcelById(pair.first) ?: continue
|
||||||
|
pair.second?.let { parcel.copyDataIgnoringDatabase(it) }
|
||||||
|
} while (true)
|
||||||
|
}
|
||||||
|
job.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
@file:Suppress("CanBePrimaryConstructorProperty", "UsePropertyAccessSyntax")
|
||||||
|
|
||||||
|
package io.dico.parcels2.defaultimpl
|
||||||
|
|
||||||
|
import io.dico.parcels2.*
|
||||||
|
import io.dico.parcels2.blockvisitor.WorktimeLimiter
|
||||||
|
import io.dico.parcels2.storage.Storage
|
||||||
|
import org.bukkit.World
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
class ParcelWorldImpl private
|
||||||
|
constructor(override val world: World,
|
||||||
|
override val generator: ParcelGenerator,
|
||||||
|
override var options: WorldOptions,
|
||||||
|
override val storage: Storage,
|
||||||
|
override val globalAddedData: GlobalAddedDataManager,
|
||||||
|
containerFactory: ParcelContainerFactory,
|
||||||
|
blockManager: ParcelBlockManager)
|
||||||
|
: ParcelWorld,
|
||||||
|
ParcelWorldId,
|
||||||
|
ParcelContainer, // missing delegation
|
||||||
|
ParcelLocator, // missing delegation
|
||||||
|
ParcelBlockManager by blockManager {
|
||||||
|
override val id: ParcelWorldId get() = this
|
||||||
|
override val uid: UUID? get() = world.uid
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (generator.world != world) {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override val name: String = world.name!!
|
||||||
|
override val container: ParcelContainer = containerFactory(this)
|
||||||
|
override val locator: ParcelLocator = generator.makeParcelLocator(container)
|
||||||
|
override val blockManager: ParcelBlockManager = blockManager
|
||||||
|
|
||||||
|
init {
|
||||||
|
enforceOptions()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun enforceOptions() {
|
||||||
|
if (options.dayTime) {
|
||||||
|
world.setGameRuleValue("doDaylightCycle", "false")
|
||||||
|
world.setTime(6000)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.noWeather) {
|
||||||
|
world.setStorm(false)
|
||||||
|
world.setThundering(false)
|
||||||
|
world.weatherDuration = Integer.MAX_VALUE
|
||||||
|
}
|
||||||
|
|
||||||
|
world.setGameRuleValue("doTileDrops", "${options.doTileDrops}")
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Interface delegation needs to be implemented manually because JetBrains has yet to fix it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
// Use this to be able to delegate blockManager and assign it to a property too, at least.
|
||||||
|
operator fun invoke(world: World,
|
||||||
|
generator: ParcelGenerator,
|
||||||
|
options: WorldOptions,
|
||||||
|
storage: Storage,
|
||||||
|
globalAddedData: GlobalAddedDataManager,
|
||||||
|
containerFactory: ParcelContainerFactory,
|
||||||
|
worktimeLimiter: WorktimeLimiter): ParcelWorldImpl {
|
||||||
|
val blockManager = generator.makeParcelBlockManager(worktimeLimiter)
|
||||||
|
return ParcelWorldImpl(world, generator, options, storage, globalAddedData, containerFactory, blockManager)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParcelLocator interface
|
||||||
|
override fun getParcelAt(x: Int, z: Int): Parcel? {
|
||||||
|
return locator.getParcelAt(x, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getParcelIdAt(x: Int, z: Int): ParcelId? {
|
||||||
|
return locator.getParcelIdAt(x, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParcelContainer interface
|
||||||
|
override fun getParcelById(x: Int, z: Int): Parcel? {
|
||||||
|
return container.getParcelById(x, z)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun nextEmptyParcel(): Parcel? {
|
||||||
|
return container.nextEmptyParcel()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -8,14 +8,7 @@ interface HasPlugin {
|
|||||||
val plugin: ParcelsPlugin
|
val plugin: ParcelsPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T: Event> HasPlugin.listener(crossinline block: suspend (T) -> Unit) = RegistratorListener<T> { event ->
|
inline fun <reified T : Event> HasPlugin.listener(crossinline block: suspend (T) -> Unit) = RegistratorListener<T> { event ->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
package io.dico.parcels2.listener
|
package io.dico.parcels2.listener
|
||||||
|
|
||||||
import io.dico.parcels2.Parcel
|
import io.dico.parcels2.Parcel
|
||||||
import io.dico.parcels2.Worlds
|
import io.dico.parcels2.ParcelProvider
|
||||||
import io.dico.parcels2.util.editLoop
|
import io.dico.parcels2.util.editLoop
|
||||||
import io.dico.parcels2.util.isPresentAnd
|
import io.dico.parcels2.util.isPresentAnd
|
||||||
import org.bukkit.entity.Entity
|
import org.bukkit.entity.Entity
|
||||||
|
|
||||||
class ParcelEntityTracker(val worlds: Worlds) {
|
class ParcelEntityTracker(val parcelProvider: ParcelProvider) {
|
||||||
val map = mutableMapOf<Entity, Parcel?>()
|
val map = mutableMapOf<Entity, Parcel?>()
|
||||||
|
|
||||||
fun untrack(entity: Entity) {
|
fun untrack(entity: Entity) {
|
||||||
@@ -32,7 +32,7 @@ class ParcelEntityTracker(val worlds: Worlds) {
|
|||||||
if (parcel.isPresentAnd { hasBlockVisitors }) {
|
if (parcel.isPresentAnd { hasBlockVisitors }) {
|
||||||
remove()
|
remove()
|
||||||
}
|
}
|
||||||
val newParcel = worlds.getParcelAt(entity.location)
|
val newParcel = parcelProvider.getParcelAt(entity.location)
|
||||||
if (newParcel !== parcel && !newParcel.isPresentAnd { hasBlockVisitors }) {
|
if (newParcel !== parcel && !newParcel.isPresentAnd { hasBlockVisitors }) {
|
||||||
remove()
|
remove()
|
||||||
entity.remove()
|
entity.remove()
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import gnu.trove.TLongCollection
|
|||||||
import io.dico.dicore.ListenerMarker
|
import io.dico.dicore.ListenerMarker
|
||||||
import io.dico.dicore.RegistratorListener
|
import io.dico.dicore.RegistratorListener
|
||||||
import io.dico.parcels2.Parcel
|
import io.dico.parcels2.Parcel
|
||||||
|
import io.dico.parcels2.ParcelProvider
|
||||||
import io.dico.parcels2.ParcelWorld
|
import io.dico.parcels2.ParcelWorld
|
||||||
import io.dico.parcels2.Worlds
|
|
||||||
import io.dico.parcels2.util.*
|
import io.dico.parcels2.util.*
|
||||||
import org.bukkit.Material.*
|
import org.bukkit.Material.*
|
||||||
import org.bukkit.World
|
import org.bukkit.World
|
||||||
@@ -26,11 +26,10 @@ import org.bukkit.event.player.*
|
|||||||
import org.bukkit.event.vehicle.VehicleMoveEvent
|
import org.bukkit.event.vehicle.VehicleMoveEvent
|
||||||
import org.bukkit.event.weather.WeatherChangeEvent
|
import org.bukkit.event.weather.WeatherChangeEvent
|
||||||
import org.bukkit.event.world.StructureGrowEvent
|
import org.bukkit.event.world.StructureGrowEvent
|
||||||
import org.bukkit.event.world.WorldLoadEvent
|
|
||||||
import org.bukkit.inventory.InventoryHolder
|
import org.bukkit.inventory.InventoryHolder
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
@Suppress("NOTHING_TO_INLINE")
|
||||||
class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker) {
|
class ParcelListeners(val parcelProvider: ParcelProvider, val entityTracker: ParcelEntityTracker) {
|
||||||
private inline fun Parcel?.canBuildN(user: Player) = isPresentAnd { canBuild(user) } || user.hasBuildAnywhere
|
private inline fun Parcel?.canBuildN(user: Player) = isPresentAnd { canBuild(user) } || user.hasBuildAnywhere
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,8 +39,8 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
* returns null if not in a registered parcel world
|
* returns null if not in a registered parcel world
|
||||||
*/
|
*/
|
||||||
private fun getWoAndPPa(block: Block): Pair<ParcelWorld, Parcel?>? {
|
private fun getWoAndPPa(block: Block): Pair<ParcelWorld, Parcel?>? {
|
||||||
val world = worlds.getWorld(block.world) ?: return null
|
val world = parcelProvider.getWorld(block.world) ?: return null
|
||||||
return world to world.parcelAt(block)
|
return world to world.getParcelAt(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -51,10 +50,10 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
val onPlayerMoveEvent = RegistratorListener<PlayerMoveEvent> l@{ event ->
|
val onPlayerMoveEvent = RegistratorListener<PlayerMoveEvent> l@{ event ->
|
||||||
val user = event.player
|
val user = event.player
|
||||||
if (user.hasBanBypass) return@l
|
if (user.hasBanBypass) return@l
|
||||||
val parcel = worlds.getParcelAt(event.to) ?: return@l
|
val parcel = parcelProvider.getParcelAt(event.to) ?: return@l
|
||||||
if (parcel.isBanned(user.uuid)) {
|
if (parcel.isBanned(user.uuid)) {
|
||||||
worlds.getParcelAt(event.from)?.also {
|
parcelProvider.getParcelAt(event.from)?.also {
|
||||||
user.teleport(it.homeLocation)
|
user.teleport(it.world.getHomeLocation(it.id))
|
||||||
user.sendParcelMessage(nopermit = true, message = "You are banned from this parcel")
|
user.sendParcelMessage(nopermit = true, message = "You are banned from this parcel")
|
||||||
} ?: run { event.to = event.from }
|
} ?: run { event.to = event.from }
|
||||||
}
|
}
|
||||||
@@ -113,7 +112,7 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
private inline fun TLongCollection.troveForEach(block: (Long) -> Unit) = iterator().let { while (it.hasNext()) block(it.next()) }
|
private inline fun TLongCollection.troveForEach(block: (Long) -> Unit) = iterator().let { while (it.hasNext()) block(it.next()) }
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
private fun checkPistonMovement(event: BlockPistonEvent, blocks: List<Block>) {
|
private fun checkPistonMovement(event: BlockPistonEvent, blocks: List<Block>) {
|
||||||
val world = worlds.getWorld(event.block.world) ?: return
|
val world = parcelProvider.getWorld(event.block.world) ?: return
|
||||||
val direction = event.direction
|
val direction = event.direction
|
||||||
val columns = gnu.trove.set.hash.TLongHashSet(blocks.size * 2)
|
val columns = gnu.trove.set.hash.TLongHashSet(blocks.size * 2)
|
||||||
|
|
||||||
@@ -123,7 +122,7 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
}
|
}
|
||||||
|
|
||||||
columns.troveForEach {
|
columns.troveForEach {
|
||||||
val ppa = world.parcelAt(it.columnX, it.columnZ)
|
val ppa = world.getParcelAt(it.columnX, it.columnZ)
|
||||||
if (ppa.isNullOr { hasBlockVisitors }) {
|
if (ppa.isNullOr { hasBlockVisitors }) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
return
|
return
|
||||||
@@ -150,8 +149,8 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
@field:ListenerMarker(priority = NORMAL)
|
@field:ListenerMarker(priority = NORMAL)
|
||||||
val onEntityExplodeEvent = RegistratorListener<EntityExplodeEvent> l@{ event ->
|
val onEntityExplodeEvent = RegistratorListener<EntityExplodeEvent> l@{ event ->
|
||||||
entityTracker.untrack(event.entity)
|
entityTracker.untrack(event.entity)
|
||||||
val world = worlds.getWorld(event.entity.world) ?: return@l
|
val world = parcelProvider.getWorld(event.entity.world) ?: return@l
|
||||||
if (world.options.disableExplosions || world.parcelAt(event.entity).isPresentAnd { hasBlockVisitors }) {
|
if (world.options.disableExplosions || world.getParcelAt(event.entity).isPresentAnd { hasBlockVisitors }) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -175,9 +174,9 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
@field:ListenerMarker(priority = NORMAL)
|
@field:ListenerMarker(priority = NORMAL)
|
||||||
val onPlayerInteractEvent = RegistratorListener<PlayerInteractEvent> l@{ event ->
|
val onPlayerInteractEvent = RegistratorListener<PlayerInteractEvent> l@{ event ->
|
||||||
val user = event.player
|
val user = event.player
|
||||||
val world = worlds.getWorld(user.world) ?: return@l
|
val world = parcelProvider.getWorld(user.world) ?: return@l
|
||||||
val clickedBlock = event.clickedBlock
|
val clickedBlock = event.clickedBlock
|
||||||
val parcel = clickedBlock?.let { world.parcelAt(it) }
|
val parcel = clickedBlock?.let { world.getParcelAt(it) }
|
||||||
|
|
||||||
if (!user.hasBuildAnywhere && parcel.isPresentAnd { isBanned(user.uuid) }) {
|
if (!user.hasBuildAnywhere && parcel.isPresentAnd { isBanned(user.uuid) }) {
|
||||||
user.sendParcelMessage(nopermit = true, message = "You cannot interact with parcels you're banned from")
|
user.sendParcelMessage(nopermit = true, message = "You cannot interact with parcels you're banned from")
|
||||||
@@ -300,7 +299,7 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
*/
|
*/
|
||||||
@field:ListenerMarker(priority = NORMAL)
|
@field:ListenerMarker(priority = NORMAL)
|
||||||
val onEntityCreatePortalEvent = RegistratorListener<EntityCreatePortalEvent> l@{ event ->
|
val onEntityCreatePortalEvent = RegistratorListener<EntityCreatePortalEvent> l@{ event ->
|
||||||
val world = worlds.getWorld(event.entity.world) ?: return@l
|
val world = parcelProvider.getWorld(event.entity.world) ?: return@l
|
||||||
if (world.options.blockPortalCreation) event.isCancelled = true
|
if (world.options.blockPortalCreation) event.isCancelled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,7 +340,7 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
*/
|
*/
|
||||||
@field:ListenerMarker(priority = NORMAL)
|
@field:ListenerMarker(priority = NORMAL)
|
||||||
val onWeatherChangeEvent = RegistratorListener<WeatherChangeEvent> l@{ event ->
|
val onWeatherChangeEvent = RegistratorListener<WeatherChangeEvent> l@{ event ->
|
||||||
val world = worlds.getWorld(event.world) ?: return@l
|
val world = parcelProvider.getWorld(event.world) ?: return@l
|
||||||
if (world.options.noWeather && event.toWeatherState()) {
|
if (world.options.noWeather && event.toWeatherState()) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
@@ -353,29 +352,6 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
world.weatherDuration = Int.MAX_VALUE
|
world.weatherDuration = Int.MAX_VALUE
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Sets time to day and doDayLightCycle gamerule if requested by the config for that world
|
|
||||||
* Sets the weather to sunny if requested by the config for that world.
|
|
||||||
*/
|
|
||||||
@field:ListenerMarker(priority = NORMAL)
|
|
||||||
val onWorldLoadEvent = RegistratorListener<WorldLoadEvent> l@{ event ->
|
|
||||||
enforceWorldSettingsIfApplicable(event.world)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun enforceWorldSettingsIfApplicable(w: World) {
|
|
||||||
val world = worlds.getWorld(w) ?: return
|
|
||||||
if (world.options.dayTime) {
|
|
||||||
w.setGameRuleValue("doDaylightCycle", "false")
|
|
||||||
w.time = 6000
|
|
||||||
}
|
|
||||||
|
|
||||||
if (world.options.noWeather) {
|
|
||||||
resetWeather(w)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.setGameRuleValue("doTileDrops", world.options.doTileDrops.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: BlockFormEvent, BlockSpreadEvent, BlockFadeEvent
|
// TODO: BlockFormEvent, BlockSpreadEvent, BlockFadeEvent
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -396,10 +372,10 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
|
|
||||||
val cancel: Boolean = when (block.type) {
|
val cancel: Boolean = when (block.type) {
|
||||||
|
|
||||||
// prevent ice generation from Frost Walkers enchantment
|
// prevent ice generation from Frost Walkers enchantment
|
||||||
ICE -> player != null && !ppa.canBuild(player)
|
ICE -> player != null && !ppa.canBuild(player)
|
||||||
|
|
||||||
// prevent snow generation from weather
|
// prevent snow generation from weather
|
||||||
SNOW -> !hasEntity && wo.options.preventWeatherBlockChanges
|
SNOW -> !hasEntity && wo.options.preventWeatherBlockChanges
|
||||||
|
|
||||||
else -> false
|
else -> false
|
||||||
@@ -415,10 +391,10 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
*/
|
*/
|
||||||
@field:ListenerMarker(priority = NORMAL)
|
@field:ListenerMarker(priority = NORMAL)
|
||||||
val onEntitySpawnEvent = RegistratorListener<EntitySpawnEvent> l@{ event ->
|
val onEntitySpawnEvent = RegistratorListener<EntitySpawnEvent> l@{ event ->
|
||||||
val world = worlds.getWorld(event.entity.world) ?: return@l
|
val world = parcelProvider.getWorld(event.entity.world) ?: return@l
|
||||||
if (event.entity is Creature && world.options.blockMobSpawning) {
|
if (event.entity is Creature && world.options.blockMobSpawning) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
} else if (world.parcelAt(event.entity).isPresentAnd { hasBlockVisitors }) {
|
} else if (world.getParcelAt(event.entity).isPresentAnd { hasBlockVisitors }) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -448,7 +424,7 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
*/
|
*/
|
||||||
@field:ListenerMarker(priority = NORMAL)
|
@field:ListenerMarker(priority = NORMAL)
|
||||||
val onEntityDamageByEntityEvent = RegistratorListener<EntityDamageByEntityEvent> l@{ event ->
|
val onEntityDamageByEntityEvent = RegistratorListener<EntityDamageByEntityEvent> l@{ event ->
|
||||||
val world = worlds.getWorld(event.entity.world) ?: return@l
|
val world = parcelProvider.getWorld(event.entity.world) ?: return@l
|
||||||
if (world.options.disableExplosions && event.damager is ExplosiveMinecart || event.damager is Creeper) {
|
if (world.options.disableExplosions && event.damager is ExplosiveMinecart || event.damager is Creeper) {
|
||||||
event.isCancelled = true; return@l
|
event.isCancelled = true; return@l
|
||||||
}
|
}
|
||||||
@@ -457,19 +433,19 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
?: (event.damager as? Projectile)?.let { it.shooter as? Player }
|
?: (event.damager as? Projectile)?.let { it.shooter as? Player }
|
||||||
?: return@l
|
?: return@l
|
||||||
|
|
||||||
if (!world.parcelAt(event.entity).canBuildN(user)) {
|
if (!world.getParcelAt(event.entity).canBuildN(user)) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@field:ListenerMarker(priority = NORMAL)
|
@field:ListenerMarker(priority = NORMAL)
|
||||||
val onHangingBreakEvent = RegistratorListener<HangingBreakEvent> l@{ event ->
|
val onHangingBreakEvent = RegistratorListener<HangingBreakEvent> l@{ event ->
|
||||||
val world = worlds.getWorld(event.entity.world) ?: return@l
|
val world = parcelProvider.getWorld(event.entity.world) ?: return@l
|
||||||
if (event.cause == HangingBreakEvent.RemoveCause.EXPLOSION && world.options.disableExplosions) {
|
if (event.cause == HangingBreakEvent.RemoveCause.EXPLOSION && world.options.disableExplosions) {
|
||||||
event.isCancelled = true; return@l
|
event.isCancelled = true; return@l
|
||||||
}
|
}
|
||||||
|
|
||||||
if (world.parcelAt(event.entity).isPresentAnd { hasBlockVisitors }) {
|
if (world.getParcelAt(event.entity).isPresentAnd { hasBlockVisitors }) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -480,9 +456,9 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
*/
|
*/
|
||||||
@field:ListenerMarker(priority = NORMAL)
|
@field:ListenerMarker(priority = NORMAL)
|
||||||
val onHangingBreakByEntityEvent = RegistratorListener<HangingBreakByEntityEvent> l@{ event ->
|
val onHangingBreakByEntityEvent = RegistratorListener<HangingBreakByEntityEvent> l@{ event ->
|
||||||
val world = worlds.getWorld(event.entity.world) ?: return@l
|
val world = parcelProvider.getWorld(event.entity.world) ?: return@l
|
||||||
val user = event.remover as? Player ?: return@l
|
val user = event.remover as? Player ?: return@l
|
||||||
if (!world.parcelAt(event.entity).canBuildN(user)) {
|
if (!world.getParcelAt(event.entity).canBuildN(user)) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -492,9 +468,9 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
*/
|
*/
|
||||||
@field:ListenerMarker(priority = NORMAL)
|
@field:ListenerMarker(priority = NORMAL)
|
||||||
val onHangingPlaceEvent = RegistratorListener<HangingPlaceEvent> l@{ event ->
|
val onHangingPlaceEvent = RegistratorListener<HangingPlaceEvent> l@{ event ->
|
||||||
val world = worlds.getWorld(event.entity.world) ?: return@l
|
val world = parcelProvider.getWorld(event.entity.world) ?: return@l
|
||||||
val block = event.block.getRelative(event.blockFace)
|
val block = event.block.getRelative(event.blockFace)
|
||||||
if (!world.parcelAt(block).canBuildN(event.player)) {
|
if (!world.getParcelAt(block).canBuildN(event.player)) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -513,7 +489,7 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
event.isCancelled = true; return@l
|
event.isCancelled = true; return@l
|
||||||
}
|
}
|
||||||
|
|
||||||
event.blocks.removeIf { wo.parcelAt(it.block) !== ppa }
|
event.blocks.removeIf { wo.getParcelAt(it.block) !== ppa }
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -523,10 +499,10 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
val onBlockDispenseEvent = RegistratorListener<BlockDispenseEvent> l@{ event ->
|
val onBlockDispenseEvent = RegistratorListener<BlockDispenseEvent> l@{ event ->
|
||||||
val block = event.block
|
val block = event.block
|
||||||
if (!block.type.let { it == DISPENSER || it == DROPPER }) return@l
|
if (!block.type.let { it == DISPENSER || it == DROPPER }) return@l
|
||||||
val world = worlds.getWorld(block.world) ?: return@l
|
val world = parcelProvider.getWorld(block.world) ?: return@l
|
||||||
val data = block.blockData as Directional
|
val data = block.blockData as Directional
|
||||||
val targetBlock = block.getRelative(data.facing)
|
val targetBlock = block.getRelative(data.facing)
|
||||||
if (world.parcelAt(targetBlock) == null) {
|
if (world.getParcelAt(targetBlock) == null) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -547,7 +523,7 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
@field:ListenerMarker(priority = NORMAL)
|
@field:ListenerMarker(priority = NORMAL)
|
||||||
val onEntityTeleportEvent = RegistratorListener<EntityTeleportEvent> l@{ event ->
|
val onEntityTeleportEvent = RegistratorListener<EntityTeleportEvent> l@{ event ->
|
||||||
val (wo, ppa) = getWoAndPPa(event.from.block) ?: return@l
|
val (wo, ppa) = getWoAndPPa(event.from.block) ?: return@l
|
||||||
if (ppa !== wo.parcelAt(event.to)) {
|
if (ppa !== wo.getParcelAt(event.to)) {
|
||||||
event.isCancelled = true
|
event.isCancelled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -572,7 +548,7 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
@field:ListenerMarker(priority = NORMAL)
|
@field:ListenerMarker(priority = NORMAL)
|
||||||
val onEntityDeathEvent = RegistratorListener<EntityDeathEvent> l@{ event ->
|
val onEntityDeathEvent = RegistratorListener<EntityDeathEvent> l@{ event ->
|
||||||
entityTracker.untrack(event.entity)
|
entityTracker.untrack(event.entity)
|
||||||
val world = worlds.getWorld(event.entity.world) ?: return@l
|
val world = parcelProvider.getWorld(event.entity.world) ?: return@l
|
||||||
if (!world.options.dropEntityItems) {
|
if (!world.options.dropEntityItems) {
|
||||||
event.drops.clear()
|
event.drops.clear()
|
||||||
event.droppedExp = 0
|
event.droppedExp = 0
|
||||||
@@ -584,7 +560,7 @@ class ParcelListeners(val worlds: Worlds, val entityTracker: ParcelEntityTracker
|
|||||||
*/
|
*/
|
||||||
@field:ListenerMarker(priority = NORMAL)
|
@field:ListenerMarker(priority = NORMAL)
|
||||||
val onPlayerChangedWorldEvent = RegistratorListener<PlayerChangedWorldEvent> l@{ event ->
|
val onPlayerChangedWorldEvent = RegistratorListener<PlayerChangedWorldEvent> l@{ event ->
|
||||||
val world = worlds.getWorld(event.player.world) ?: return@l
|
val world = parcelProvider.getWorld(event.player.world) ?: return@l
|
||||||
if (world.options.gameMode != null && !event.player.hasGamemodeBypass) {
|
if (world.options.gameMode != null && !event.player.hasGamemodeBypass) {
|
||||||
event.player.gameMode = world.options.gameMode
|
event.player.gameMode = world.options.gameMode
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
package io.dico.parcels2.storage
|
package io.dico.parcels2.storage
|
||||||
|
|
||||||
import io.dico.parcels2.AddedStatus
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.Parcel
|
import kotlinx.coroutines.experimental.channels.SendChannel
|
||||||
import io.dico.parcels2.ParcelData
|
import java.util.UUID
|
||||||
import io.dico.parcels2.ParcelOwner
|
|
||||||
import kotlinx.coroutines.experimental.channels.ProducerScope
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
interface Backing {
|
interface Backing {
|
||||||
|
|
||||||
@@ -22,31 +19,31 @@ interface Backing {
|
|||||||
* This producer function is capable of constantly reading parcels from a potentially infinite sequence,
|
* This producer function is capable of constantly reading parcels from a potentially infinite sequence,
|
||||||
* and provide parcel data for it as read from the database.
|
* and provide parcel data for it as read from the database.
|
||||||
*/
|
*/
|
||||||
suspend fun ProducerScope<Pair<Parcel, ParcelData?>>.produceParcelData(parcels: Sequence<Parcel>)
|
suspend fun produceParcelData(channel: SendChannel<DataPair>, parcels: Sequence<ParcelId>)
|
||||||
|
|
||||||
suspend fun ProducerScope<Pair<SerializableParcel, ParcelData?>>.produceAllParcelData()
|
suspend fun produceAllParcelData(channel: SendChannel<DataPair>)
|
||||||
|
|
||||||
suspend fun readParcelData(parcelFor: Parcel): ParcelData?
|
suspend fun readParcelData(parcel: ParcelId): ParcelData?
|
||||||
|
|
||||||
suspend fun getOwnedParcels(user: ParcelOwner): List<SerializableParcel>
|
suspend fun getOwnedParcels(user: ParcelOwner): List<ParcelId>
|
||||||
|
|
||||||
suspend fun getNumParcels(user: ParcelOwner): Int = getOwnedParcels(user).size
|
suspend fun getNumParcels(user: ParcelOwner): Int = getOwnedParcels(user).size
|
||||||
|
|
||||||
|
|
||||||
suspend fun setParcelData(parcelFor: Parcel, data: ParcelData?)
|
suspend fun setParcelData(parcel: ParcelId, data: ParcelData?)
|
||||||
|
|
||||||
suspend fun setParcelOwner(parcelFor: Parcel, owner: ParcelOwner?)
|
suspend fun setParcelOwner(parcel: ParcelId, owner: ParcelOwner?)
|
||||||
|
|
||||||
suspend fun setLocalPlayerStatus(parcelFor: Parcel, player: UUID, status: AddedStatus)
|
suspend fun setLocalPlayerStatus(parcel: ParcelId, player: UUID, status: AddedStatus)
|
||||||
|
|
||||||
suspend fun setParcelAllowsInteractInventory(parcel: Parcel, value: Boolean)
|
suspend fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean)
|
||||||
|
|
||||||
suspend fun setParcelAllowsInteractInputs(parcel: Parcel, value: Boolean)
|
suspend fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean)
|
||||||
|
|
||||||
|
|
||||||
suspend fun ProducerScope<Pair<ParcelOwner, MutableMap<UUID, AddedStatus>>>.produceAllGlobalAddedData()
|
suspend fun produceAllGlobalAddedData(channel: SendChannel<AddedDataPair<ParcelOwner>>)
|
||||||
|
|
||||||
suspend fun readGlobalAddedData(owner: ParcelOwner): MutableMap<UUID, AddedStatus>
|
suspend fun readGlobalAddedData(owner: ParcelOwner): MutableAddedDataMap
|
||||||
|
|
||||||
suspend fun setGlobalPlayerStatus(owner: ParcelOwner, player: UUID, status: AddedStatus)
|
suspend fun setGlobalPlayerStatus(owner: ParcelOwner, player: UUID, status: AddedStatus)
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import com.fasterxml.jackson.databind.ser.BeanSerializerModifier
|
|||||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer
|
import com.fasterxml.jackson.databind.ser.std.StdSerializer
|
||||||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
|
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
|
||||||
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
import com.fasterxml.jackson.module.kotlin.KotlinModule
|
||||||
import io.dico.parcels2.GeneratorFactory
|
import io.dico.parcels2.GeneratorFactories
|
||||||
import io.dico.parcels2.GeneratorOptions
|
import io.dico.parcels2.GeneratorOptions
|
||||||
import io.dico.parcels2.StorageOptions
|
import io.dico.parcels2.StorageOptions
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
@@ -100,7 +100,7 @@ class GeneratorOptionsDeserializer : JsonDeserializer<GeneratorOptions>() {
|
|||||||
val node = parser!!.readValueAsTree<JsonNode>()
|
val node = parser!!.readValueAsTree<JsonNode>()
|
||||||
val name = node.get("name").asText()
|
val name = node.get("name").asText()
|
||||||
val optionsNode = node.get("options")
|
val optionsNode = node.get("options")
|
||||||
val factory = GeneratorFactory.getFactory(name) ?: throw IllegalStateException("Unknown generator: $name")
|
val factory = GeneratorFactories.getFactory(name) ?: throw IllegalStateException("Unknown generator: $name")
|
||||||
|
|
||||||
return parser.codec.treeToValue(optionsNode, factory.optionsClass.java)
|
return parser.codec.treeToValue(optionsNode, factory.optionsClass.java)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
package io.dico.parcels2.storage
|
|
||||||
|
|
||||||
import io.dico.parcels2.Parcel
|
|
||||||
import io.dico.parcels2.ParcelWorld
|
|
||||||
import io.dico.parcels2.Worlds
|
|
||||||
import io.dico.parcels2.util.Vec2i
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.World
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
data class SerializableWorld(val name: String? = null,
|
|
||||||
val uid: UUID? = null) {
|
|
||||||
|
|
||||||
init {
|
|
||||||
uid ?: name ?: throw IllegalArgumentException("uuid and/or name must be present")
|
|
||||||
}
|
|
||||||
|
|
||||||
val world: World? by lazy { uid?.let { Bukkit.getWorld(it) } ?: name?.let { Bukkit.getWorld(it) } }
|
|
||||||
//val parcelWorld: ParcelWorld? by lazy { TODO() }
|
|
||||||
|
|
||||||
constructor(world: World) : this(world.name, world.uid)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used by storage backing options to encompass the location of a parcel
|
|
||||||
*/
|
|
||||||
data class SerializableParcel(val world: SerializableWorld,
|
|
||||||
val pos: Vec2i) {
|
|
||||||
|
|
||||||
//val parcel: Parcel? by lazy { TODO() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Worlds.getWorldBySerializedValue(input: SerializableWorld): ParcelWorld? {
|
|
||||||
return input.world?.let { getWorld(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Worlds.getParcelBySerializedValue(input: SerializableParcel): Parcel? {
|
|
||||||
return getWorldBySerializedValue(input.world)
|
|
||||||
?.parcelByID(input.pos)
|
|
||||||
}
|
|
||||||
@@ -1,16 +1,19 @@
|
|||||||
|
@file:Suppress("NOTHING_TO_INLINE")
|
||||||
|
|
||||||
package io.dico.parcels2.storage
|
package io.dico.parcels2.storage
|
||||||
|
|
||||||
import io.dico.parcels2.AddedStatus
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.Parcel
|
|
||||||
import io.dico.parcels2.ParcelData
|
|
||||||
import io.dico.parcels2.ParcelOwner
|
|
||||||
import kotlinx.coroutines.experimental.*
|
import kotlinx.coroutines.experimental.*
|
||||||
|
import kotlinx.coroutines.experimental.channels.ProducerScope
|
||||||
import kotlinx.coroutines.experimental.channels.ReceiveChannel
|
import kotlinx.coroutines.experimental.channels.ReceiveChannel
|
||||||
import kotlinx.coroutines.experimental.channels.produce
|
import kotlinx.coroutines.experimental.channels.produce
|
||||||
import java.util.*
|
import java.util.UUID
|
||||||
import java.util.concurrent.Executor
|
import java.util.concurrent.Executor
|
||||||
import java.util.concurrent.Executors
|
import java.util.concurrent.Executors
|
||||||
|
|
||||||
|
typealias DataPair = Pair<ParcelId, ParcelData?>
|
||||||
|
typealias AddedDataPair<TAttach> = Pair<TAttach, MutableAddedDataMap>
|
||||||
|
|
||||||
interface Storage {
|
interface Storage {
|
||||||
val name: String
|
val name: String
|
||||||
val syncDispatcher: CoroutineDispatcher
|
val syncDispatcher: CoroutineDispatcher
|
||||||
@@ -22,31 +25,31 @@ interface Storage {
|
|||||||
fun shutdown(): Job
|
fun shutdown(): Job
|
||||||
|
|
||||||
|
|
||||||
fun readParcelData(parcelFor: Parcel): Deferred<ParcelData?>
|
fun readParcelData(parcel: ParcelId): Deferred<ParcelData?>
|
||||||
|
|
||||||
fun readParcelData(parcelsFor: Sequence<Parcel>): ReceiveChannel<Pair<Parcel, ParcelData?>>
|
fun readParcelData(parcels: Sequence<ParcelId>): ReceiveChannel<DataPair>
|
||||||
|
|
||||||
fun readAllParcelData(): ReceiveChannel<Pair<SerializableParcel, ParcelData?>>
|
fun readAllParcelData(): ReceiveChannel<DataPair>
|
||||||
|
|
||||||
fun getOwnedParcels(user: ParcelOwner): Deferred<List<SerializableParcel>>
|
fun getOwnedParcels(user: ParcelOwner): Deferred<List<ParcelId>>
|
||||||
|
|
||||||
fun getNumParcels(user: ParcelOwner): Deferred<Int>
|
fun getNumParcels(user: ParcelOwner): Deferred<Int>
|
||||||
|
|
||||||
|
|
||||||
fun setParcelData(parcelFor: Parcel, data: ParcelData?): Job
|
fun setParcelData(parcel: ParcelId, data: ParcelData?): Job
|
||||||
|
|
||||||
fun setParcelOwner(parcelFor: Parcel, owner: ParcelOwner?): Job
|
fun setParcelOwner(parcel: ParcelId, owner: ParcelOwner?): Job
|
||||||
|
|
||||||
fun setParcelPlayerStatus(parcelFor: Parcel, player: UUID, status: AddedStatus): Job
|
fun setParcelPlayerStatus(parcel: ParcelId, player: UUID, status: AddedStatus): Job
|
||||||
|
|
||||||
fun setParcelAllowsInteractInventory(parcel: Parcel, value: Boolean): Job
|
fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean): Job
|
||||||
|
|
||||||
fun setParcelAllowsInteractInputs(parcel: Parcel, value: Boolean): Job
|
fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean): Job
|
||||||
|
|
||||||
|
|
||||||
fun readAllGlobalAddedData(): ReceiveChannel<Pair<ParcelOwner, MutableMap<UUID, AddedStatus>>>
|
fun readAllGlobalAddedData(): ReceiveChannel<AddedDataPair<ParcelOwner>>
|
||||||
|
|
||||||
fun readGlobalAddedData(owner: ParcelOwner): Deferred<MutableMap<UUID, AddedStatus>?>
|
fun readGlobalAddedData(owner: ParcelOwner): Deferred<MutableAddedDataMap?>
|
||||||
|
|
||||||
fun setGlobalAddedStatus(owner: ParcelOwner, player: UUID, status: AddedStatus): Job
|
fun setGlobalAddedStatus(owner: ParcelOwner, player: UUID, status: AddedStatus): Job
|
||||||
}
|
}
|
||||||
@@ -59,48 +62,47 @@ class StorageWithCoroutineBacking internal constructor(val backing: Backing) : S
|
|||||||
override val isConnected get() = backing.isConnected
|
override val isConnected get() = backing.isConnected
|
||||||
val channelCapacity = 16
|
val channelCapacity = 16
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
private inline fun <T> defer(noinline block: suspend CoroutineScope.() -> T): Deferred<T> {
|
private inline fun <T> defer(noinline block: suspend CoroutineScope.() -> T): Deferred<T> {
|
||||||
return async(context = asyncDispatcher, start = CoroutineStart.ATOMIC, block = block)
|
return async(context = asyncDispatcher, start = CoroutineStart.ATOMIC, block = block)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("NOTHING_TO_INLINE")
|
|
||||||
private inline fun job(noinline block: suspend CoroutineScope.() -> Unit): Job {
|
private inline fun job(noinline block: suspend CoroutineScope.() -> Unit): Job {
|
||||||
return launch(context = asyncDispatcher, start = CoroutineStart.ATOMIC, block = block)
|
return launch(context = asyncDispatcher, start = CoroutineStart.ATOMIC, block = block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inline fun <T> openChannel(noinline block: suspend ProducerScope<T>.() -> Unit): ReceiveChannel<T> {
|
||||||
|
return produce(asyncDispatcher, capacity = channelCapacity, block = block)
|
||||||
|
}
|
||||||
|
|
||||||
override fun init() = job { backing.init() }
|
override fun init() = job { backing.init() }
|
||||||
|
|
||||||
override fun shutdown() = job { backing.shutdown() }
|
override fun shutdown() = job { backing.shutdown() }
|
||||||
|
|
||||||
|
|
||||||
override fun readParcelData(parcelFor: Parcel) = defer { backing.readParcelData(parcelFor) }
|
override fun readParcelData(parcel: ParcelId) = defer { backing.readParcelData(parcel) }
|
||||||
|
|
||||||
override fun readParcelData(parcelsFor: Sequence<Parcel>) =
|
override fun readParcelData(parcels: Sequence<ParcelId>) = openChannel<DataPair> { backing.produceParcelData(channel, parcels) }
|
||||||
produce(asyncDispatcher, capacity = channelCapacity) { with(backing) { produceParcelData(parcelsFor) } }
|
|
||||||
|
|
||||||
override fun readAllParcelData(): ReceiveChannel<Pair<SerializableParcel, ParcelData?>> =
|
override fun readAllParcelData() = openChannel<DataPair> { backing.produceAllParcelData(channel) }
|
||||||
produce(asyncDispatcher, capacity = channelCapacity) { with(backing) { produceAllParcelData() } }
|
|
||||||
|
|
||||||
override fun getOwnedParcels(user: ParcelOwner) = defer { backing.getOwnedParcels(user) }
|
override fun getOwnedParcels(user: ParcelOwner) = defer { backing.getOwnedParcels(user) }
|
||||||
|
|
||||||
override fun getNumParcels(user: ParcelOwner) = defer { backing.getNumParcels(user) }
|
override fun getNumParcels(user: ParcelOwner) = defer { backing.getNumParcels(user) }
|
||||||
|
|
||||||
override fun setParcelData(parcelFor: Parcel, data: ParcelData?) = job { backing.setParcelData(parcelFor, data) }
|
override fun setParcelData(parcel: ParcelId, data: ParcelData?) = job { backing.setParcelData(parcel, data) }
|
||||||
|
|
||||||
override fun setParcelOwner(parcelFor: Parcel, owner: ParcelOwner?) = job { backing.setParcelOwner(parcelFor, owner) }
|
override fun setParcelOwner(parcel: ParcelId, owner: ParcelOwner?) = job { backing.setParcelOwner(parcel, owner) }
|
||||||
|
|
||||||
override fun setParcelPlayerStatus(parcelFor: Parcel, player: UUID, status: AddedStatus) = job { backing.setLocalPlayerStatus(parcelFor, player, status) }
|
override fun setParcelPlayerStatus(parcel: ParcelId, player: UUID, status: AddedStatus) = job { backing.setLocalPlayerStatus(parcel, player, status) }
|
||||||
|
|
||||||
override fun setParcelAllowsInteractInventory(parcel: Parcel, value: Boolean) = job { backing.setParcelAllowsInteractInventory(parcel, value) }
|
override fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean) = job { backing.setParcelAllowsInteractInventory(parcel, value) }
|
||||||
|
|
||||||
override fun setParcelAllowsInteractInputs(parcel: Parcel, value: Boolean) = job { backing.setParcelAllowsInteractInputs(parcel, value) }
|
override fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean) = job { backing.setParcelAllowsInteractInputs(parcel, value) }
|
||||||
|
|
||||||
|
|
||||||
override fun readAllGlobalAddedData(): ReceiveChannel<Pair<ParcelOwner, MutableMap<UUID, AddedStatus>>> =
|
override fun readAllGlobalAddedData(): ReceiveChannel<AddedDataPair<ParcelOwner>> = openChannel { backing.produceAllGlobalAddedData(channel) }
|
||||||
produce(asyncDispatcher, capacity = channelCapacity) { with(backing) { produceAllGlobalAddedData() } }
|
|
||||||
|
|
||||||
override fun readGlobalAddedData(owner: ParcelOwner): Deferred<MutableMap<UUID, AddedStatus>?> = defer { backing.readGlobalAddedData(owner) }
|
override fun readGlobalAddedData(owner: ParcelOwner): Deferred<MutableAddedDataMap?> = defer { backing.readGlobalAddedData(owner) }
|
||||||
|
|
||||||
override fun setGlobalAddedStatus(owner: ParcelOwner, player: UUID, status: AddedStatus) = job { backing.setGlobalPlayerStatus(owner, player, status) }
|
override fun setGlobalAddedStatus(owner: ParcelOwner, player: UUID, status: AddedStatus) = job { backing.setGlobalPlayerStatus(owner, player, status) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,4 +40,4 @@ class ConnectionStorageFactory : StorageFactory {
|
|||||||
return StorageWithCoroutineBacking(ExposedBacking(dataSourceFactory))
|
return StorageWithCoroutineBacking(ExposedBacking(dataSourceFactory))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,18 +5,18 @@ package io.dico.parcels2.storage.exposed
|
|||||||
import com.zaxxer.hikari.HikariDataSource
|
import com.zaxxer.hikari.HikariDataSource
|
||||||
import io.dico.parcels2.*
|
import io.dico.parcels2.*
|
||||||
import io.dico.parcels2.storage.Backing
|
import io.dico.parcels2.storage.Backing
|
||||||
import io.dico.parcels2.storage.SerializableParcel
|
import io.dico.parcels2.storage.DataPair
|
||||||
import io.dico.parcels2.util.toUUID
|
import io.dico.parcels2.util.toUUID
|
||||||
import kotlinx.coroutines.experimental.CoroutineStart
|
import kotlinx.coroutines.experimental.CoroutineStart
|
||||||
import kotlinx.coroutines.experimental.Unconfined
|
import kotlinx.coroutines.experimental.Unconfined
|
||||||
import kotlinx.coroutines.experimental.channels.ProducerScope
|
import kotlinx.coroutines.experimental.channels.SendChannel
|
||||||
import kotlinx.coroutines.experimental.launch
|
import kotlinx.coroutines.experimental.launch
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.SchemaUtils.create
|
import org.jetbrains.exposed.sql.SchemaUtils.create
|
||||||
import org.jetbrains.exposed.sql.transactions.transaction
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
import org.jetbrains.exposed.sql.vendors.DatabaseDialect
|
import org.jetbrains.exposed.sql.vendors.DatabaseDialect
|
||||||
import org.joda.time.DateTime
|
import org.joda.time.DateTime
|
||||||
import java.util.*
|
import java.util.UUID
|
||||||
import javax.sql.DataSource
|
import javax.sql.DataSource
|
||||||
|
|
||||||
class ExposedDatabaseException(message: String? = null) : Exception(message)
|
class ExposedDatabaseException(message: String? = null) : Exception(message)
|
||||||
@@ -63,7 +63,7 @@ class ExposedBacking(private val dataSourceFactory: suspend () -> DataSource) :
|
|||||||
isShutdown = true
|
isShutdown = true
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun ProducerScope<Pair<Parcel, ParcelData?>>.produceParcelData(parcels: Sequence<Parcel>) {
|
override suspend fun produceParcelData(channel: SendChannel<DataPair>, parcels: Sequence<ParcelId>) {
|
||||||
for (parcel in parcels) {
|
for (parcel in parcels) {
|
||||||
val data = readParcelData(parcel)
|
val data = readParcelData(parcel)
|
||||||
channel.send(parcel to data)
|
channel.send(parcel to data)
|
||||||
@@ -71,32 +71,32 @@ class ExposedBacking(private val dataSourceFactory: suspend () -> DataSource) :
|
|||||||
channel.close()
|
channel.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun ProducerScope<Pair<SerializableParcel, ParcelData?>>.produceAllParcelData() = transactionLaunch {
|
override suspend fun produceAllParcelData(channel: SendChannel<Pair<ParcelId, ParcelData?>>) = transactionLaunch {
|
||||||
ParcelsT.selectAll().forEach { row ->
|
ParcelsT.selectAll().forEach { row ->
|
||||||
val parcel = ParcelsT.getSerializable(row) ?: return@forEach
|
val parcel = ParcelsT.getId(row) ?: return@forEach
|
||||||
val data = rowToParcelData(row)
|
val data = rowToParcelData(row)
|
||||||
channel.send(parcel to data)
|
channel.send(parcel to data)
|
||||||
}
|
}
|
||||||
channel.close()
|
channel.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun readParcelData(parcelFor: Parcel): ParcelData? = transaction {
|
override suspend fun readParcelData(parcel: ParcelId): ParcelData? = transaction {
|
||||||
val row = ParcelsT.getRow(parcelFor) ?: return@transaction null
|
val row = ParcelsT.getRow(parcel) ?: return@transaction null
|
||||||
rowToParcelData(row)
|
rowToParcelData(row)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getOwnedParcels(user: ParcelOwner): List<SerializableParcel> = transaction {
|
override suspend fun getOwnedParcels(user: ParcelOwner): List<ParcelId> = transaction {
|
||||||
val user_id = OwnersT.getId(user) ?: return@transaction emptyList()
|
val user_id = OwnersT.getId(user) ?: return@transaction emptyList()
|
||||||
ParcelsT.select { ParcelsT.owner_id eq user_id }
|
ParcelsT.select { ParcelsT.owner_id eq user_id }
|
||||||
.orderBy(ParcelsT.claim_time, isAsc = true)
|
.orderBy(ParcelsT.claim_time, isAsc = true)
|
||||||
.mapNotNull(ParcelsT::getSerializable)
|
.mapNotNull(ParcelsT::getId)
|
||||||
.toList()
|
.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setParcelData(parcelFor: Parcel, data: ParcelData?) {
|
override suspend fun setParcelData(parcel: ParcelId, data: ParcelData?) {
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
transaction {
|
transaction {
|
||||||
ParcelsT.getId(parcelFor)?.let { id ->
|
ParcelsT.getId(parcel)?.let { id ->
|
||||||
ParcelsT.deleteIgnoreWhere { ParcelsT.id eq id }
|
ParcelsT.deleteIgnoreWhere { ParcelsT.id eq id }
|
||||||
|
|
||||||
// Below should cascade automatically
|
// Below should cascade automatically
|
||||||
@@ -111,25 +111,25 @@ class ExposedBacking(private val dataSourceFactory: suspend () -> DataSource) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
transaction {
|
transaction {
|
||||||
val id = ParcelsT.getOrInitId(parcelFor)
|
val id = ParcelsT.getOrInitId(parcel)
|
||||||
AddedLocalT.deleteIgnoreWhere { AddedLocalT.attach_id eq id }
|
AddedLocalT.deleteIgnoreWhere { AddedLocalT.attach_id eq id }
|
||||||
}
|
}
|
||||||
|
|
||||||
setParcelOwner(parcelFor, data.owner)
|
setParcelOwner(parcel, data.owner)
|
||||||
|
|
||||||
for ((uuid, status) in data.addedMap) {
|
for ((uuid, status) in data.addedMap) {
|
||||||
setLocalPlayerStatus(parcelFor, uuid, status)
|
setLocalPlayerStatus(parcel, uuid, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
setParcelAllowsInteractInputs(parcelFor, data.allowInteractInputs)
|
setParcelAllowsInteractInputs(parcel, data.allowInteractInputs)
|
||||||
setParcelAllowsInteractInventory(parcelFor, data.allowInteractInventory)
|
setParcelAllowsInteractInventory(parcel, data.allowInteractInventory)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setParcelOwner(parcelFor: Parcel, owner: ParcelOwner?) = transaction {
|
override suspend fun setParcelOwner(parcel: ParcelId, owner: ParcelOwner?) = transaction {
|
||||||
val id = if (owner == null)
|
val id = if (owner == null)
|
||||||
ParcelsT.getId(parcelFor) ?: return@transaction
|
ParcelsT.getId(parcel) ?: return@transaction
|
||||||
else
|
else
|
||||||
ParcelsT.getOrInitId(parcelFor)
|
ParcelsT.getOrInitId(parcel)
|
||||||
|
|
||||||
val owner_id = owner?.let { OwnersT.getOrInitId(it) }
|
val owner_id = owner?.let { OwnersT.getOrInitId(it) }
|
||||||
val time = owner?.let { DateTime.now() }
|
val time = owner?.let { DateTime.now() }
|
||||||
@@ -140,11 +140,11 @@ class ExposedBacking(private val dataSourceFactory: suspend () -> DataSource) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setLocalPlayerStatus(parcelFor: Parcel, player: UUID, status: AddedStatus) = transaction {
|
override suspend fun setLocalPlayerStatus(parcel: ParcelId, player: UUID, status: AddedStatus) = transaction {
|
||||||
AddedLocalT.setPlayerStatus(parcelFor, player, status)
|
AddedLocalT.setPlayerStatus(parcel, player, status)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setParcelAllowsInteractInventory(parcel: Parcel, value: Boolean): Unit = transaction {
|
override suspend fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean): Unit = transaction {
|
||||||
val id = ParcelsT.getOrInitId(parcel)
|
val id = ParcelsT.getOrInitId(parcel)
|
||||||
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
|
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
|
||||||
it[ParcelOptionsT.parcel_id] = id
|
it[ParcelOptionsT.parcel_id] = id
|
||||||
@@ -152,7 +152,7 @@ class ExposedBacking(private val dataSourceFactory: suspend () -> DataSource) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun setParcelAllowsInteractInputs(parcel: Parcel, value: Boolean): Unit = transaction {
|
override suspend fun setParcelAllowsInteractInputs(parcel: ParcelId, value: Boolean): Unit = transaction {
|
||||||
val id = ParcelsT.getOrInitId(parcel)
|
val id = ParcelsT.getOrInitId(parcel)
|
||||||
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
|
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
|
||||||
it[ParcelOptionsT.parcel_id] = id
|
it[ParcelOptionsT.parcel_id] = id
|
||||||
@@ -160,7 +160,7 @@ class ExposedBacking(private val dataSourceFactory: suspend () -> DataSource) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun ProducerScope<Pair<ParcelOwner, MutableMap<UUID, AddedStatus>>>.produceAllGlobalAddedData() = transactionLaunch {
|
override suspend fun produceAllGlobalAddedData(channel: SendChannel<Pair<ParcelOwner, MutableMap<UUID, AddedStatus>>>) = transactionLaunch {
|
||||||
AddedGlobalT.sendAllAddedData(channel)
|
AddedGlobalT.sendAllAddedData(channel)
|
||||||
channel.close()
|
channel.close()
|
||||||
}
|
}
|
||||||
@@ -174,7 +174,7 @@ class ExposedBacking(private val dataSourceFactory: suspend () -> DataSource) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun rowToParcelData(row: ResultRow) = ParcelDataHolder().apply {
|
private fun rowToParcelData(row: ResultRow) = ParcelDataHolder().apply {
|
||||||
owner = row[ParcelsT.owner_id]?.let { OwnersT.getSerializable(it) }
|
owner = row[ParcelsT.owner_id]?.let { OwnersT.getId(it) }
|
||||||
since = row[ParcelsT.claim_time]
|
since = row[ParcelsT.claim_time]
|
||||||
|
|
||||||
val parcelId = row[ParcelsT.id]
|
val parcelId = row[ParcelsT.id]
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class UpsertStatement<Key : Any>(table: Table, conflictColumn: Column<*>? = null
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
append (" ON DUPLICATE KEY UPDATE ")
|
append(" ON DUPLICATE KEY UPDATE ")
|
||||||
values.keys.filter { it !in indexColumns }.joinTo(this) { "${transaction.identity(it)}=VALUES(${transaction.identity(it)})" }
|
values.keys.filter { it !in indexColumns }.joinTo(this) { "${transaction.identity(it)}=VALUES(${transaction.identity(it)})" }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,16 @@
|
|||||||
|
|
||||||
package io.dico.parcels2.storage.exposed
|
package io.dico.parcels2.storage.exposed
|
||||||
|
|
||||||
import io.dico.parcels2.Parcel
|
import io.dico.parcels2.ParcelId
|
||||||
import io.dico.parcels2.ParcelOwner
|
import io.dico.parcels2.ParcelOwner
|
||||||
import io.dico.parcels2.ParcelWorld
|
import io.dico.parcels2.ParcelWorldId
|
||||||
import io.dico.parcels2.storage.SerializableParcel
|
|
||||||
import io.dico.parcels2.storage.SerializableWorld
|
|
||||||
import io.dico.parcels2.util.Vec2i
|
|
||||||
import io.dico.parcels2.util.toByteArray
|
import io.dico.parcels2.util.toByteArray
|
||||||
import io.dico.parcels2.util.toUUID
|
import io.dico.parcels2.util.toUUID
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import org.jetbrains.exposed.sql.statements.InsertStatement
|
import org.jetbrains.exposed.sql.statements.InsertStatement
|
||||||
import java.util.*
|
import java.util.UUID
|
||||||
|
|
||||||
sealed class IdTransactionsTable<TableT : IdTransactionsTable<TableT, QueryObj, SerializableObj>,
|
sealed class IdTransactionsTable<TableT : IdTransactionsTable<TableT, QueryObj>, QueryObj>(tableName: String, columnName: String)
|
||||||
QueryObj, SerializableObj>(tableName: String, columnName: String)
|
|
||||||
: Table(tableName) {
|
: Table(tableName) {
|
||||||
val id = integer(columnName).autoIncrement().primaryKey()
|
val id = integer(columnName).autoIncrement().primaryKey()
|
||||||
|
|
||||||
@@ -35,31 +31,32 @@ sealed class IdTransactionsTable<TableT : IdTransactionsTable<TableT, QueryObj,
|
|||||||
|
|
||||||
abstract fun getId(obj: QueryObj): Int?
|
abstract fun getId(obj: QueryObj): Int?
|
||||||
abstract fun getOrInitId(obj: QueryObj): Int
|
abstract fun getOrInitId(obj: QueryObj): Int
|
||||||
fun getSerializable(id: Int): SerializableObj? = select { this@IdTransactionsTable.id eq id }.firstOrNull()?.let { getSerializable(it) }
|
fun getId(id: Int): QueryObj? = select { this@IdTransactionsTable.id eq id }.firstOrNull()?.let { getId(it) }
|
||||||
abstract fun getSerializable(row: ResultRow): SerializableObj?
|
abstract fun getId(row: ResultRow): QueryObj?
|
||||||
}
|
}
|
||||||
|
|
||||||
object WorldsT : IdTransactionsTable<WorldsT, ParcelWorld, SerializableWorld>("parcel_worlds", "world_id") {
|
object WorldsT : IdTransactionsTable<WorldsT, ParcelWorldId>("parcel_worlds", "world_id") {
|
||||||
val name = varchar("name", 50)
|
val name = varchar("name", 50)
|
||||||
val uid = binary("uid", 16)
|
val uid = binary("uid", 16).nullable()
|
||||||
|
val index_name = uniqueIndexR("index_name", name)
|
||||||
val index_uid = uniqueIndexR("index_uid", uid)
|
val index_uid = uniqueIndexR("index_uid", uid)
|
||||||
|
|
||||||
internal inline fun getId(binaryUid: ByteArray): Int? = getId { uid eq binaryUid }
|
internal inline fun getId(worldName: String, binaryUid: ByteArray?): Int? = getId { (name eq worldName).let { if (binaryUid == null) it else it or (uid eq binaryUid) } }
|
||||||
internal inline fun getId(uid: UUID): Int? = getId(uid.toByteArray())
|
internal inline fun getId(worldName: String, uid: UUID?): Int? = getId(worldName, uid?.toByteArray())
|
||||||
internal inline fun getOrInitId(worldUid: UUID, worldName: String): Int = worldUid.toByteArray().let { binaryUid ->
|
internal inline fun getOrInitId(worldName: String, worldUid: UUID?): Int = worldUid?.toByteArray().let { binaryUid ->
|
||||||
getId(binaryUid)
|
getId(worldName, binaryUid)
|
||||||
?: insertAndGetId("world named $worldName") { it[uid] = binaryUid; it[name] = worldName }
|
?: insertAndGetId("world named $worldName") { it[name] = worldName; binaryUid?.let { buid -> it[uid] = buid } }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getId(world: ParcelWorld): Int? = getId(world.world.uid)
|
override fun getId(world: ParcelWorldId): Int? = getId(world.name, world.uid)
|
||||||
override fun getOrInitId(world: ParcelWorld): Int = world.world.let { getOrInitId(it.uid, it.name) }
|
override fun getOrInitId(world: ParcelWorldId): Int = getOrInitId(world.name, world.uid)
|
||||||
|
|
||||||
override fun getSerializable(row: ResultRow): SerializableWorld {
|
override fun getId(row: ResultRow): ParcelWorldId {
|
||||||
return SerializableWorld(row[name], row[uid].toUUID())
|
return ParcelWorldId(row[name], row[uid]?.toUUID())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ParcelsT : IdTransactionsTable<ParcelsT, Parcel, SerializableParcel>("parcels", "parcel_id") {
|
object ParcelsT : IdTransactionsTable<ParcelsT, ParcelId>("parcels", "parcel_id") {
|
||||||
val world_id = integer("world_id").references(WorldsT.id)
|
val world_id = integer("world_id").references(WorldsT.id)
|
||||||
val px = integer("px")
|
val px = integer("px")
|
||||||
val pz = integer("pz")
|
val pz = integer("pz")
|
||||||
@@ -68,27 +65,27 @@ object ParcelsT : IdTransactionsTable<ParcelsT, Parcel, SerializableParcel>("par
|
|||||||
val index_location = uniqueIndexR("index_location", world_id, px, pz)
|
val index_location = uniqueIndexR("index_location", world_id, px, pz)
|
||||||
|
|
||||||
private inline fun getId(worldId: Int, parcelX: Int, parcelZ: Int): Int? = getId { world_id.eq(worldId) and px.eq(parcelX) and pz.eq(parcelZ) }
|
private inline fun getId(worldId: Int, parcelX: Int, parcelZ: Int): Int? = getId { world_id.eq(worldId) and px.eq(parcelX) and pz.eq(parcelZ) }
|
||||||
private inline fun getId(worldUid: UUID, parcelX: Int, parcelZ: Int): Int? = WorldsT.getId(worldUid)?.let { getId(it, parcelX, parcelZ) }
|
private inline fun getId(worldName: String, worldUid: UUID?, parcelX: Int, parcelZ: Int): Int? = WorldsT.getId(worldName, worldUid)?.let { getId(it, parcelX, parcelZ) }
|
||||||
private inline fun getOrInitId(worldUid: UUID, worldName: String, parcelX: Int, parcelZ: Int): Int {
|
private inline fun getOrInitId(worldName: String, worldUid: UUID?, parcelX: Int, parcelZ: Int): Int {
|
||||||
val worldId = WorldsT.getOrInitId(worldUid, worldName)
|
val worldId = WorldsT.getOrInitId(worldName, worldUid)
|
||||||
return getId(worldId, parcelX, parcelZ)
|
return getId(worldId, parcelX, parcelZ)
|
||||||
?: insertAndGetId("parcel at $worldName($parcelX, $parcelZ)") { it[world_id] = worldId; it[px] = parcelX; it[pz] = parcelZ }
|
?: insertAndGetId("parcel at $worldName($parcelX, $parcelZ)") { it[world_id] = worldId; it[px] = parcelX; it[pz] = parcelZ }
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getId(parcel: Parcel): Int? = getId(parcel.world.world.uid, parcel.pos.x, parcel.pos.z)
|
override fun getId(parcel: ParcelId): Int? = getId(parcel.worldId.name, parcel.worldId.uid, parcel.x, parcel.z)
|
||||||
override fun getOrInitId(parcel: Parcel): Int = parcel.world.world.let { getOrInitId(it.uid, it.name, parcel.pos.x, parcel.pos.z) }
|
override fun getOrInitId(parcel: ParcelId): Int = getOrInitId(parcel.worldId.name, parcel.worldId.uid, parcel.x, parcel.z)
|
||||||
|
|
||||||
private inline fun getRow(id: Int): ResultRow? = select { ParcelsT.id eq id }.firstOrNull()
|
private inline fun getRow(id: Int): ResultRow? = select { ParcelsT.id eq id }.firstOrNull()
|
||||||
fun getRow(parcel: Parcel): ResultRow? = getId(parcel)?.let { getRow(it) }
|
fun getRow(parcel: ParcelId): ResultRow? = getId(parcel)?.let { getRow(it) }
|
||||||
|
|
||||||
override fun getSerializable(row: ResultRow): SerializableParcel? {
|
override fun getId(row: ResultRow): ParcelId? {
|
||||||
val worldId = row[world_id]
|
val worldId = row[world_id]
|
||||||
val world = WorldsT.getSerializable(worldId) ?: return null
|
val world = WorldsT.getId(worldId) ?: return null
|
||||||
return SerializableParcel(world, Vec2i(row[px], row[pz]))
|
return ParcelId(world, row[px], row[pz])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object OwnersT : IdTransactionsTable<OwnersT, ParcelOwner, ParcelOwner>("parcel_owners", "owner_id") {
|
object OwnersT : IdTransactionsTable<OwnersT, ParcelOwner>("parcel_owners", "owner_id") {
|
||||||
val uuid = binary("uuid", 16).nullable()
|
val uuid = binary("uuid", 16).nullable()
|
||||||
val name = varchar("name", 32)
|
val name = varchar("name", 32)
|
||||||
val index_pair = uniqueIndexR("index_pair", uuid, name)
|
val index_pair = uniqueIndexR("index_pair", uuid, name)
|
||||||
@@ -115,7 +112,7 @@ object OwnersT : IdTransactionsTable<OwnersT, ParcelOwner, ParcelOwner>("parcel_
|
|||||||
if (owner.hasUUID) getOrInitId(owner.uuid!!, owner.notNullName)
|
if (owner.hasUUID) getOrInitId(owner.uuid!!, owner.notNullName)
|
||||||
else getOrInitId(owner.name!!)
|
else getOrInitId(owner.name!!)
|
||||||
|
|
||||||
override fun getSerializable(row: ResultRow): ParcelOwner {
|
override fun getId(row: ResultRow): ParcelOwner {
|
||||||
return row[uuid]?.toUUID()?.let { ParcelOwner(it) } ?: ParcelOwner(row[name])
|
return row[uuid]?.toUUID()?.let { ParcelOwner(it) } ?: ParcelOwner(row[name])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,16 @@
|
|||||||
package io.dico.parcels2.storage.exposed
|
package io.dico.parcels2.storage.exposed
|
||||||
|
|
||||||
import io.dico.parcels2.AddedStatus
|
import io.dico.parcels2.AddedStatus
|
||||||
import io.dico.parcels2.Parcel
|
import io.dico.parcels2.ParcelId
|
||||||
import io.dico.parcels2.ParcelOwner
|
import io.dico.parcels2.ParcelOwner
|
||||||
import io.dico.parcels2.storage.SerializableParcel
|
|
||||||
import io.dico.parcels2.util.toByteArray
|
import io.dico.parcels2.util.toByteArray
|
||||||
import io.dico.parcels2.util.toUUID
|
import io.dico.parcels2.util.toUUID
|
||||||
import kotlinx.coroutines.experimental.channels.SendChannel
|
import kotlinx.coroutines.experimental.channels.SendChannel
|
||||||
import org.jetbrains.exposed.sql.*
|
import org.jetbrains.exposed.sql.*
|
||||||
import java.util.*
|
import java.util.UUID
|
||||||
|
|
||||||
object AddedLocalT : AddedTable<Parcel, SerializableParcel>("parcels_added_local", ParcelsT)
|
object AddedLocalT : AddedTable<ParcelId>("parcels_added_local", ParcelsT)
|
||||||
object AddedGlobalT : AddedTable<ParcelOwner, ParcelOwner>("parcels_added_global", OwnersT)
|
object AddedGlobalT : AddedTable<ParcelOwner>("parcels_added_global", OwnersT)
|
||||||
|
|
||||||
object ParcelOptionsT : Table("parcel_options") {
|
object ParcelOptionsT : Table("parcel_options") {
|
||||||
val parcel_id = integer("parcel_id").primaryKey().references(ParcelsT.id, ReferenceOption.CASCADE)
|
val parcel_id = integer("parcel_id").primaryKey().references(ParcelsT.id, ReferenceOption.CASCADE)
|
||||||
@@ -23,7 +22,7 @@ object ParcelOptionsT : Table("parcel_options") {
|
|||||||
|
|
||||||
typealias AddedStatusSendChannel<AttachT> = SendChannel<Pair<AttachT, MutableMap<UUID, AddedStatus>>>
|
typealias AddedStatusSendChannel<AttachT> = SendChannel<Pair<AttachT, MutableMap<UUID, AddedStatus>>>
|
||||||
|
|
||||||
sealed class AddedTable<AttachT, SerializableT>(name: String, val idTable: IdTransactionsTable<*, AttachT, SerializableT>) : Table(name) {
|
sealed class AddedTable<AttachT>(name: String, val idTable: IdTransactionsTable<*, AttachT>) : Table(name) {
|
||||||
val attach_id = integer("attach_id").references(idTable.id, ReferenceOption.CASCADE)
|
val attach_id = integer("attach_id").references(idTable.id, ReferenceOption.CASCADE)
|
||||||
val player_uuid = binary("player_uuid", 16)
|
val player_uuid = binary("player_uuid", 16)
|
||||||
val allowed_flag = bool("allowed_flag")
|
val allowed_flag = bool("allowed_flag")
|
||||||
@@ -52,7 +51,7 @@ sealed class AddedTable<AttachT, SerializableT>(name: String, val idTable: IdTra
|
|||||||
.associateByTo(hashMapOf(), { it[player_uuid].toUUID() }, { it[allowed_flag].asAddedStatus() })
|
.associateByTo(hashMapOf(), { it[player_uuid].toUUID() }, { it[allowed_flag].asAddedStatus() })
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun sendAllAddedData(channel: AddedStatusSendChannel<SerializableT>) {
|
suspend fun sendAllAddedData(channel: AddedStatusSendChannel<AttachT>) {
|
||||||
/*
|
/*
|
||||||
val iterator = selectAll().orderBy(attach_id).iterator()
|
val iterator = selectAll().orderBy(attach_id).iterator()
|
||||||
|
|
||||||
@@ -63,7 +62,7 @@ sealed class AddedTable<AttachT, SerializableT>(name: String, val idTable: IdTra
|
|||||||
var map: MutableMap<UUID, AddedStatus>? = null
|
var map: MutableMap<UUID, AddedStatus>? = null
|
||||||
|
|
||||||
fun initAttachAndMap() {
|
fun initAttachAndMap() {
|
||||||
attach = idTable.getSerializable(id)
|
attach = idTable.getId(id)
|
||||||
map = attach?.let { mutableMapOf() }
|
map = attach?.let { mutableMapOf() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package io.dico.parcels2.storage.migration
|
||||||
|
|
||||||
|
import io.dico.parcels2.storage.Storage
|
||||||
|
|
||||||
|
interface Migration {
|
||||||
|
fun migrateTo(storage: Storage)
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package io.dico.parcels2.storage.migration
|
||||||
|
|
||||||
|
interface MigrationFactory {
|
||||||
|
fun getMigration()
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package io.dico.parcels2.storage.migration.plotme
|
||||||
|
|
||||||
|
import com.zaxxer.hikari.HikariDataSource
|
||||||
|
import io.dico.parcels2.*
|
||||||
|
import io.dico.parcels2.storage.Storage
|
||||||
|
import io.dico.parcels2.storage.migration.Migration
|
||||||
|
import io.dico.parcels2.util.Vec2i
|
||||||
|
import io.dico.parcels2.util.isValid
|
||||||
|
import io.dico.parcels2.util.toUUID
|
||||||
|
import io.dico.parcels2.util.uuid
|
||||||
|
import kotlinx.coroutines.experimental.asCoroutineDispatcher
|
||||||
|
import kotlinx.coroutines.experimental.launch
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import org.jetbrains.exposed.sql.*
|
||||||
|
import org.slf4j.LoggerFactory
|
||||||
|
import java.io.ByteArrayOutputStream
|
||||||
|
import java.sql.Blob
|
||||||
|
import java.util.UUID
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import javax.sql.DataSource
|
||||||
|
|
||||||
|
class PlotmeMigration(val parcelProvider: ParcelProvider,
|
||||||
|
val worldMapper: Map<String, String>,
|
||||||
|
val dataSourceFactory: () -> DataSource) : Migration {
|
||||||
|
private var dataSource: DataSource? = null
|
||||||
|
private var database: Database? = null
|
||||||
|
private var isShutdown: Boolean = false
|
||||||
|
private val dispatcher = Executors.newSingleThreadExecutor { Thread(it, "PlotMe Migration Thread") }.asCoroutineDispatcher()
|
||||||
|
private val mlogger = LoggerFactory.getLogger("PlotMe Migrator")
|
||||||
|
|
||||||
|
private fun <T> transaction(statement: Transaction.() -> T) = org.jetbrains.exposed.sql.transactions.transaction(database!!, statement)
|
||||||
|
|
||||||
|
override fun migrateTo(storage: Storage) {
|
||||||
|
launch(context = dispatcher) {
|
||||||
|
init()
|
||||||
|
doWork(storage)
|
||||||
|
shutdown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun init() {
|
||||||
|
if (isShutdown) throw IllegalStateException()
|
||||||
|
dataSource = dataSourceFactory()
|
||||||
|
database = Database.connect(dataSource!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun shutdown() {
|
||||||
|
if (isShutdown) throw IllegalStateException()
|
||||||
|
dataSource?.let {
|
||||||
|
(it as? HikariDataSource)?.close()
|
||||||
|
}
|
||||||
|
database = null
|
||||||
|
isShutdown = true
|
||||||
|
}
|
||||||
|
|
||||||
|
val parcelsCache = hashMapOf<String, MutableMap<Vec2i, ParcelData>>()
|
||||||
|
|
||||||
|
private fun getMap(worldName: String): MutableMap<Vec2i, ParcelData>? {
|
||||||
|
val mapped = worldMapper[worldName] ?: return null
|
||||||
|
return parcelsCache.computeIfAbsent(mapped) { mutableMapOf() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getData(worldName: String, position: Vec2i): ParcelData? {
|
||||||
|
return getMap(worldName)?.computeIfAbsent(position) { ParcelDataHolder() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun doWork(target: Storage): Unit = transaction {
|
||||||
|
if (!PlotmePlotsT.exists()) {
|
||||||
|
mlogger.warn("Plotme tables don't appear to exist. Exiting.")
|
||||||
|
return@transaction
|
||||||
|
}
|
||||||
|
parcelsCache.clear()
|
||||||
|
|
||||||
|
iterPlotmeTable(PlotmePlotsT) { data, row ->
|
||||||
|
// in practice, owner_uuid is not null for any plot currently. It will convert well.
|
||||||
|
data.owner = ParcelOwner(row[owner_uuid]?.toUUID(), row[owner_name])
|
||||||
|
}
|
||||||
|
|
||||||
|
iterPlotmeTable(PlotmeAllowedT) { data, row ->
|
||||||
|
val uuid = row[player_uuid]?.toUUID()
|
||||||
|
?: Bukkit.getOfflinePlayer(row[player_name]).takeIf { it.isValid }?.uuid
|
||||||
|
?: return@iterPlotmeTable
|
||||||
|
|
||||||
|
data.setAddedStatus(uuid, AddedStatus.ALLOWED)
|
||||||
|
}
|
||||||
|
|
||||||
|
iterPlotmeTable(PlotmeDeniedT) { data, row ->
|
||||||
|
val uuid = row[PlotmeAllowedT.player_uuid]?.toUUID()
|
||||||
|
?: Bukkit.getOfflinePlayer(row[PlotmeAllowedT.player_name]).takeIf { it.isValid }?.uuid
|
||||||
|
?: return@iterPlotmeTable
|
||||||
|
|
||||||
|
data.setAddedStatus(uuid, AddedStatus.BANNED)
|
||||||
|
}
|
||||||
|
|
||||||
|
for ((worldName, map) in parcelsCache) {
|
||||||
|
val world = ParcelWorldId(worldName)
|
||||||
|
for ((pos, data) in map) {
|
||||||
|
val parcel = ParcelId(world, pos)
|
||||||
|
target.setParcelData(parcel, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Blob.toUUID(): UUID {
|
||||||
|
val out = ByteArrayOutputStream(16)
|
||||||
|
binaryStream.copyTo(out, bufferSize = 16)
|
||||||
|
return out.toByteArray().toUUID()
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <T : PlotmeTable> iterPlotmeTable(table: T, block: T.(ParcelData, ResultRow) -> Unit) {
|
||||||
|
table.selectAll().forEach { row ->
|
||||||
|
val data = getData(row[table.world_name], Vec2i(row[table.px], row[table.pz])) ?: return@forEach
|
||||||
|
table.block(data, row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package io.dico.parcels2.storage.migration.plotme
|
||||||
|
|
||||||
|
import org.jetbrains.exposed.sql.Table
|
||||||
|
|
||||||
|
const val uppercase: Boolean = false
|
||||||
|
@Suppress("ConstantConditionIf")
|
||||||
|
fun String.toCorrectCase() = if (uppercase) this else toLowerCase()
|
||||||
|
|
||||||
|
sealed class PlotmeTable(name: String) : Table(name) {
|
||||||
|
val px = PlotmePlotsT.integer("idX").primaryKey()
|
||||||
|
val pz = PlotmePlotsT.integer("idZ").primaryKey()
|
||||||
|
val world_name = PlotmePlotsT.varchar("world", 32).primaryKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = PlotmePlotsT.varchar("player", 32)
|
||||||
|
val player_uuid = PlotmePlotsT.blob("playerid").nullable()
|
||||||
|
}
|
||||||
|
|
||||||
|
object PlotmeAllowedT : PlotmePlotPlayerMap("plotmeAllowed".toCorrectCase())
|
||||||
|
object PlotmeDeniedT : PlotmePlotPlayerMap("plotmeDenied".toCorrectCase())
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
package io.dico.parcels2.util
|
|
||||||
|
|
||||||
import org.bukkit.plugin.Plugin
|
|
||||||
import org.bukkit.scheduler.BukkitTask
|
|
||||||
|
|
||||||
inline fun Plugin.doAwait(checkNow: Boolean = true, configure: AwaitTask.() -> Unit) {
|
|
||||||
with(AwaitTask()) {
|
|
||||||
configure()
|
|
||||||
start(checkNow = checkNow)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private typealias Action<T> = () -> T
|
|
||||||
|
|
||||||
class AwaitTask : Runnable {
|
|
||||||
//@formatter:off
|
|
||||||
var cond: Action<Boolean>? = null ; set(value) { checkNotRunning(); field = value }
|
|
||||||
var onSuccess: Action<Unit>? = null ; set(value) { checkNotRunning(); field = value }
|
|
||||||
var onFailure: Action<Unit>? = null ; set(value) { checkNotRunning(); field = value }
|
|
||||||
var delay: Int = -1 ; set(value) { checkNotRunning(); field = value }
|
|
||||||
var interval: Int = 20 ; set(value) { checkNotRunning(); field = value }
|
|
||||||
var maxChecks: Int = 0 ; set(value) { checkNotRunning(); field = value }
|
|
||||||
|
|
||||||
var task: BukkitTask? = null ; private set
|
|
||||||
var elapsedChecks = 0 ; private set
|
|
||||||
var cancelled = false ; private set
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
fun Plugin.start(checkNow: Boolean = true) {
|
|
||||||
if (cancelled) throw IllegalStateException()
|
|
||||||
|
|
||||||
requireNotNull(cond)
|
|
||||||
requireNotNull(onSuccess)
|
|
||||||
|
|
||||||
if (checkNow && check()) {
|
|
||||||
cancel()
|
|
||||||
onSuccess!!.invoke()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
task = server.scheduler.runTaskTimer(this, this@AwaitTask, delay.toLong(), interval.toLong())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun run() {
|
|
||||||
if (task?.isCancelled != false) return
|
|
||||||
|
|
||||||
if (check()) {
|
|
||||||
cancel()
|
|
||||||
onSuccess!!.invoke()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxChecks in 1 until elapsedChecks) {
|
|
||||||
cancel()
|
|
||||||
onFailure?.invoke()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun check(): Boolean {
|
|
||||||
elapsedChecks++
|
|
||||||
return cond!!.invoke()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun cancel() {
|
|
||||||
task?.cancel()
|
|
||||||
cancelled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkNotRunning() {
|
|
||||||
if (cancelled || task != null) throw IllegalStateException()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -10,62 +10,67 @@ wood:
|
|||||||
OAK_$, BIRCH_$, SPRUCE_$, JUNGLE_$, ACACIA_$, DARK_OAK_$,
|
OAK_$, BIRCH_$, SPRUCE_$, JUNGLE_$, ACACIA_$, DARK_OAK_$,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
val Material.isBed get() = when(this) {
|
val Material.isBed
|
||||||
WHITE_BED,
|
get() = when (this) {
|
||||||
ORANGE_BED,
|
WHITE_BED,
|
||||||
MAGENTA_BED,
|
ORANGE_BED,
|
||||||
LIGHT_BLUE_BED,
|
MAGENTA_BED,
|
||||||
YELLOW_BED,
|
LIGHT_BLUE_BED,
|
||||||
LIME_BED,
|
YELLOW_BED,
|
||||||
PINK_BED,
|
LIME_BED,
|
||||||
GRAY_BED,
|
PINK_BED,
|
||||||
LIGHT_GRAY_BED,
|
GRAY_BED,
|
||||||
CYAN_BED,
|
LIGHT_GRAY_BED,
|
||||||
PURPLE_BED,
|
CYAN_BED,
|
||||||
BLUE_BED,
|
PURPLE_BED,
|
||||||
BROWN_BED,
|
BLUE_BED,
|
||||||
GREEN_BED,
|
BROWN_BED,
|
||||||
RED_BED,
|
GREEN_BED,
|
||||||
BLACK_BED -> true
|
RED_BED,
|
||||||
else -> false
|
BLACK_BED -> true
|
||||||
}
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
val Material.isWoodDoor get() = when(this) {
|
val Material.isWoodDoor
|
||||||
OAK_DOOR,
|
get() = when (this) {
|
||||||
BIRCH_DOOR,
|
OAK_DOOR,
|
||||||
SPRUCE_DOOR,
|
BIRCH_DOOR,
|
||||||
JUNGLE_DOOR,
|
SPRUCE_DOOR,
|
||||||
ACACIA_DOOR,
|
JUNGLE_DOOR,
|
||||||
DARK_OAK_DOOR -> true
|
ACACIA_DOOR,
|
||||||
else -> false
|
DARK_OAK_DOOR -> true
|
||||||
}
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
val Material.isWoodTrapdoor get() = when(this) {
|
val Material.isWoodTrapdoor
|
||||||
OAK_TRAPDOOR,
|
get() = when (this) {
|
||||||
BIRCH_TRAPDOOR,
|
OAK_TRAPDOOR,
|
||||||
SPRUCE_TRAPDOOR,
|
BIRCH_TRAPDOOR,
|
||||||
JUNGLE_TRAPDOOR,
|
SPRUCE_TRAPDOOR,
|
||||||
ACACIA_TRAPDOOR,
|
JUNGLE_TRAPDOOR,
|
||||||
DARK_OAK_TRAPDOOR -> true
|
ACACIA_TRAPDOOR,
|
||||||
else -> false
|
DARK_OAK_TRAPDOOR -> true
|
||||||
}
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
val Material.isWoodFenceGate get() = when(this) {
|
val Material.isWoodFenceGate
|
||||||
OAK_FENCE_GATE,
|
get() = when (this) {
|
||||||
BIRCH_FENCE_GATE,
|
OAK_FENCE_GATE,
|
||||||
SPRUCE_FENCE_GATE,
|
BIRCH_FENCE_GATE,
|
||||||
JUNGLE_FENCE_GATE,
|
SPRUCE_FENCE_GATE,
|
||||||
ACACIA_FENCE_GATE,
|
JUNGLE_FENCE_GATE,
|
||||||
DARK_OAK_FENCE_GATE -> true
|
ACACIA_FENCE_GATE,
|
||||||
else -> false
|
DARK_OAK_FENCE_GATE -> true
|
||||||
}
|
else -> false
|
||||||
|
}
|
||||||
|
|
||||||
val Material.isWoodButton get() = when(this) {
|
val Material.isWoodButton
|
||||||
OAK_BUTTON,
|
get() = when (this) {
|
||||||
BIRCH_BUTTON,
|
OAK_BUTTON,
|
||||||
SPRUCE_BUTTON,
|
BIRCH_BUTTON,
|
||||||
JUNGLE_BUTTON,
|
SPRUCE_BUTTON,
|
||||||
ACACIA_BUTTON,
|
JUNGLE_BUTTON,
|
||||||
DARK_OAK_BUTTON -> true
|
ACACIA_BUTTON,
|
||||||
else -> false
|
DARK_OAK_BUTTON -> true
|
||||||
}
|
else -> false
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import org.bukkit.plugin.java.JavaPlugin
|
|||||||
|
|
||||||
inline val OfflinePlayer.uuid get() = uniqueId
|
inline val OfflinePlayer.uuid get() = uniqueId
|
||||||
@Suppress("UsePropertyAccessSyntax")
|
@Suppress("UsePropertyAccessSyntax")
|
||||||
inline val OfflinePlayer.isValid get() = isOnline() || hasPlayedBefore()
|
inline val OfflinePlayer.isValid
|
||||||
|
get() = isOnline() || hasPlayedBefore()
|
||||||
|
|
||||||
inline val Player.hasBanBypass get() = hasPermission("parcels.admin.bypass.ban")
|
inline val Player.hasBanBypass get() = hasPermission("parcels.admin.bypass.ban")
|
||||||
inline val Player.hasGamemodeBypass get() = hasPermission("parcels.admin.bypass.gamemode")
|
inline val Player.hasGamemodeBypass get() = hasPermission("parcels.admin.bypass.gamemode")
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
package io.dico.parcels2.util
|
package io.dico.parcels2.util
|
||||||
|
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.jetbrains.annotations.Contract
|
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.util.*
|
import java.util.UUID
|
||||||
|
|
||||||
@Suppress("UsePropertyAccessSyntax")
|
@Suppress("UsePropertyAccessSyntax")
|
||||||
fun getPlayerNameOrDefault(uuid: UUID?, ifUnknown: String? = null): String {
|
fun getPlayerNameOrDefault(uuid: UUID?, ifUnknown: String? = null): String {
|
||||||
|
|||||||
Reference in New Issue
Block a user