Archived
0
This commit is contained in:
Dico
2018-08-02 03:42:48 +01:00
parent 3917855a72
commit 6513ad9237
15 changed files with 117 additions and 99 deletions

View File

@@ -39,7 +39,7 @@ class GlobalAddedDataManagerImpl(val plugin: ParcelsPlugin) : GlobalAddedDataMan
}
private companion object {
val emptyData = mapOf<UUID, AddedStatus>() as MutableMap<UUID, AddedStatus>
val emptyData = Collections.emptyMap<UUID, AddedStatus>() as MutableMap<UUID, AddedStatus>
}
}

View File

@@ -31,8 +31,13 @@ class Parcel(val world: ParcelWorld, val pos: Vec2i) : ParcelData {
}
fun copyData(data: ParcelData) {
world.storage.setParcelData(this, data)
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

View File

@@ -3,8 +3,8 @@ 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.getParcelBySerializedValue
import io.dico.parcels2.util.Vec2i
import io.dico.parcels2.util.doAwait
import io.dico.parcels2.util.floor
import kotlinx.coroutines.experimental.launch
import org.bukkit.Bukkit
@@ -17,8 +17,6 @@ import org.bukkit.entity.Player
import java.util.*
import kotlin.coroutines.experimental.buildIterator
import kotlin.coroutines.experimental.buildSequence
import kotlin.reflect.jvm.javaMethod
import kotlin.reflect.jvm.kotlinFunction
class Worlds(val plugin: ParcelsPlugin) {
val worlds: Map<String, ParcelWorld> get() = _worlds
@@ -42,11 +40,6 @@ class Worlds(val plugin: ParcelsPlugin) {
}
}
init {
val function = ::loadWorlds
function.javaMethod!!.kotlinFunction
}
operator fun SerializableParcel.invoke(): Parcel? {
return world()?.parcelByID(pos)
}
@@ -72,31 +65,28 @@ class Worlds(val plugin: ParcelsPlugin) {
continue
}
_worlds.put(worldName, world)
_worlds[worldName] = world
}
if (Bukkit.getWorld(worldName) == null) {
plugin.doAwait {
cond = {
try {
// server.getDefaultGameMode() throws an error before any worlds are initialized.
// createWorld() below calls that method.
// Plugin needs to load on STARTUP for generators to be registered correctly.
// Means we need to await the initial worlds getting loaded.
plugin.server.defaultGameMode; true
} catch (ex: Throwable) {
false
}
}
onSuccess = {
val bworld = WorldCreator(worldName).generator(world.generator).createWorld()
val spawn = world.generator.getFixedSpawnLocation(bworld, null)
bworld.setSpawnLocation(spawn.x.floor(), spawn.y.floor(), spawn.z.floor())
}
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()
}
}
@@ -205,7 +195,8 @@ class DefaultParcelContainer(private val world: ParcelWorld,
buildIterator {
val center = world.options.axisLimit
for (radius in 0..center) {
var x = center - radius; var z = center - radius
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]) }

View File

@@ -12,14 +12,13 @@ import io.dico.parcels2.storage.Storage
import io.dico.parcels2.storage.yamlObjectMapper
import io.dico.parcels2.util.FunctionHelper
import io.dico.parcels2.util.tryCreate
import kotlinx.coroutines.experimental.asCoroutineDispatcher
import org.bukkit.Bukkit
import org.bukkit.plugin.java.JavaPlugin
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.io.File
import java.util.concurrent.Executor
val logger = LoggerFactory.getLogger("ParcelsPlugin")
val logger: Logger = LoggerFactory.getLogger("ParcelsPlugin")
private inline val plogger get() = logger
class ParcelsPlugin : JavaPlugin() {
@@ -64,14 +63,14 @@ class ParcelsPlugin : JavaPlugin() {
return false
}
globalAddedData = GlobalAddedDataManagerImpl(this)
worlds.loadWorlds(options)
entityTracker = ParcelEntityTracker(worlds)
} catch (ex: Exception) {
plogger.error("Error loading options", ex)
return false
}
globalAddedData = GlobalAddedDataManagerImpl(this)
entityTracker = ParcelEntityTracker(worlds)
registerListeners()
registerCommands()
@@ -79,21 +78,23 @@ class ParcelsPlugin : JavaPlugin() {
}
fun loadOptions(): Boolean {
if (optionsFile.exists()) {
yamlObjectMapper.readerForUpdating(options).readValue<Options>(optionsFile)
} else if (optionsFile.tryCreate()) {
options.addWorld("parcels", WorldOptions())
try {
yamlObjectMapper.writeValue(optionsFile, options)
} catch (ex: Throwable) {
optionsFile.delete()
throw ex
when {
optionsFile.exists() -> yamlObjectMapper.readerForUpdating(options).readValue<Options>(optionsFile)
optionsFile.tryCreate() -> {
options.addWorld("parcels", WorldOptions())
try {
yamlObjectMapper.writeValue(optionsFile, options)
} catch (ex: Throwable) {
optionsFile.delete()
throw ex
}
plogger.warn("Created options file with a world template. Please review it before next start.")
return false
}
else -> {
plogger.error("Failed to save options file ${optionsFile.canonicalPath}")
return false
}
plogger.warn("Created options file with a world template. Please review it before next start.")
return false
} else {
plogger.error("Failed to save options file ${optionsFile.canonicalPath}")
return false
}
return true
}
@@ -105,7 +106,7 @@ class ParcelsPlugin : JavaPlugin() {
}
private fun registerListeners() {
if (listeners != null) {
if (listeners == null) {
listeners = ParcelListeners(worlds, entityTracker)
registrator.registerListeners(listeners!!)
}

View File

@@ -20,7 +20,7 @@ enum class RegionTraversal(private val builder: suspend SequenceBuilder<Vec3i>.(
}),
UPDARD({ region ->
UPWARD({ region ->
val origin = region.origin
val size = region.size

View File

@@ -4,10 +4,10 @@ import io.dico.dicore.command.CommandException
import io.dico.dicore.command.ExecutionContext
import io.dico.dicore.command.ICommandReceiver
import io.dico.parcels2.ParcelOwner
import io.dico.parcels2.ParcelWorld
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.util.hasAdminManage
import io.dico.parcels2.util.parcelLimit
import io.dico.parcels2.util.uuid
import org.bukkit.entity.Player
import org.bukkit.plugin.Plugin
import java.lang.reflect.Method
@@ -29,9 +29,10 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei
if (!plugin.storage.isConnected) error("Parcels cannot $action right now because of a database error")
}
protected suspend fun checkParcelLimit(player: Player) {
protected suspend fun checkParcelLimit(player: Player, world: ParcelWorld) {
if (player.hasAdminManage) return
val numOwnedParcels = plugin.storage.getNumParcels(ParcelOwner(uuid = player.uuid)).await()
val numOwnedParcels = plugin.storage.getOwnedParcels(ParcelOwner(player)).await()
.filter { it.world.world == world.world }.size
val limit = player.parcelLimit
if (numOwnedParcels >= limit) {

View File

@@ -15,7 +15,7 @@ class CommandsAddedStatus(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin
shortVersion = "allows a player to build on this parcel")
@ParcelRequire(owner = true)
fun ParcelScope.cmdAllow(sender: Player, player: OfflinePlayer): Any? {
Validate.isTrue(parcel.owner != null && !sender.hasAdminManage, "This parcel is unowned")
Validate.isTrue(parcel.owner != null || sender.hasAdminManage, "This parcel is unowned")
Validate.isTrue(!parcel.owner!!.matches(player), "The target already owns the parcel")
Validate.isTrue(parcel.allow(player), "${player.name} is already allowed to build on this parcel")
return "${player.name} is now allowed to build on this parcel"
@@ -37,7 +37,7 @@ class CommandsAddedStatus(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin
shortVersion = "bans a player from this parcel")
@ParcelRequire(owner = true)
fun ParcelScope.cmdBan(sender: Player, player: OfflinePlayer): Any? {
Validate.isTrue(parcel.owner != null && !sender.hasAdminManage, "This parcel is unowned")
Validate.isTrue(parcel.owner != null || sender.hasAdminManage, "This parcel is unowned")
Validate.isTrue(!parcel.owner!!.matches(player), "The owner cannot be banned from the parcel")
Validate.isTrue(parcel.ban(player), "${player.name} is already banned from this parcel")
return "${player.name} is now banned from this parcel"

View File

@@ -1,12 +1,17 @@
package io.dico.parcels2.command
import io.dico.dicore.command.CommandException
import io.dico.dicore.command.EMessageType
import io.dico.dicore.command.ExecutionContext
import io.dico.dicore.command.annotation.Cmd
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.blockvisitor.RegionTraversal
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.entity.Player
import java.util.*
class CommandsDebug(val plugin: ParcelsPlugin) {
class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
@Cmd("reloadoptions")
fun reloadOptions() {
@@ -23,4 +28,23 @@ class CommandsDebug(val plugin: ParcelsPlugin) {
return "Teleported you to $worldName spawn"
}
@Cmd("make_mess")
@ParcelRequire(owner = true)
fun ParcelScope.cmdMakeMess(context: ExecutionContext) {
val server = plugin.server
val blockDatas = arrayOf(
server.createBlockData(Material.STICKY_PISTON),
server.createBlockData(Material.GLASS),
server.createBlockData(Material.STONE_SLAB),
server.createBlockData(Material.QUARTZ_BLOCK)
)
val random = Random()
world.generator.doBlockOperation(parcel, direction = RegionTraversal.UPWARD) { block ->
block.blockData = blockDatas[random.nextInt(4)]
}.onProgressUpdate(1000, 1000) { progress, elapsedTime ->
context.sendMessage(EMessageType.INFORMATIVE, "Mess progress: %.02f%%, %.2fs elapsed"
.format(progress * 100, elapsedTime / 1000.0))
}
}
}

View File

@@ -8,16 +8,12 @@ import io.dico.dicore.command.annotation.Flag
import io.dico.dicore.command.annotation.RequireParameters
import io.dico.parcels2.ParcelOwner
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.blockvisitor.RegionTraversal
import io.dico.parcels2.storage.getParcelBySerializedValue
import io.dico.parcels2.util.hasAdminManage
import io.dico.parcels2.util.hasParcelHomeOthers
import io.dico.parcels2.util.uuid
import org.bukkit.Material
import org.bukkit.entity.Player
import java.util.*
//@Suppress("unused")
class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
@Cmd("auto")
@@ -26,7 +22,7 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
shortVersion = "sets you up with a fresh, unclaimed parcel")
suspend fun WorldScope.cmdAuto(player: Player): Any? {
checkConnected("be claimed")
checkParcelLimit(player)
checkParcelLimit(player, world)
val parcel = world.nextEmptyParcel()
?: error("This world is full, please ask an admin to upsize it")
@@ -58,7 +54,7 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
val ownedParcels = ownedParcelsResult
.map { worlds.getParcelBySerializedValue(it) }
.filter { it != null && ownerTarget.world == it.world && ownerTarget.owner == it.owner }
.filter { it != null && ownerTarget.world == it.world }
val targetMatch = ownedParcels.getOrNull(target.index)
?: error("The specified parcel could not be matched")
@@ -76,11 +72,19 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
error(if (it.matches(player)) "You already own this parcel" else "This parcel is not available")
}
checkParcelLimit(player)
checkParcelLimit(player, world)
parcel.owner = ParcelOwner(player)
return "Enjoy your new parcel!"
}
@Cmd("unclaim")
@Desc("Unclaims this parcel")
@ParcelRequire(owner = true)
fun ParcelScope.cmdUnclaim(player: Player): Any? {
parcel.dispose()
return "Your parcel has been disposed"
}
@Cmd("clear")
@ParcelRequire(owner = true)
fun ParcelScope.cmdClear(context: ExecutionContext, @Flag sure: Boolean): Any? {
@@ -101,23 +105,4 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
TODO()
}
@Cmd("make_mess")
@ParcelRequire(owner = true)
fun ParcelScope.cmdMakeMess(context: ExecutionContext) {
val server = plugin.server
val blockDatas = arrayOf(
server.createBlockData(Material.STICKY_PISTON),
server.createBlockData(Material.GLASS),
server.createBlockData(Material.STONE_SLAB),
server.createBlockData(Material.QUARTZ_BLOCK)
)
val random = Random()
world.generator.doBlockOperation(parcel, direction = RegionTraversal.UPDARD) { block ->
block.blockData = blockDatas[random.nextInt(4)]
}.onProgressUpdate(1000, 1000) { progress, elapsedTime ->
context.sendMessage(EMessageType.INFORMATIVE, "Mess progress: %.02f%%, %.2fs elapsed"
.format(progress * 100, elapsedTime / 1000.0))
}
}
}

View File

@@ -15,7 +15,7 @@ fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher {
return CommandBuilder()
.setChatController(ParcelsChatController())
.addParameterType(false, ParcelParameterType(plugin.worlds))
.addParameterType(true, ParcelHomeParameterType(plugin.worlds))
.addParameterType(true, ParcelTarget.PType(plugin.worlds))
.group("parcel", "plot", "plots", "p")
.registerCommands(CommandsGeneral(plugin))

View File

@@ -17,6 +17,8 @@ data class SerializableWorld(val name: String? = null,
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)
}
/**
@@ -33,5 +35,6 @@ fun Worlds.getWorldBySerializedValue(input: SerializableWorld): ParcelWorld? {
}
fun Worlds.getParcelBySerializedValue(input: SerializableParcel): Parcel? {
return getWorldBySerializedValue(input.world)?.parcelByID(input.pos)
return getWorldBySerializedValue(input.world)
?.parcelByID(input.pos)
}

View File

@@ -4,9 +4,13 @@ package io.dico.parcels2.storage.exposed
import com.zaxxer.hikari.HikariDataSource
import io.dico.parcels2.*
import io.dico.parcels2.storage.*
import io.dico.parcels2.storage.Backing
import io.dico.parcels2.storage.SerializableParcel
import io.dico.parcels2.util.toUUID
import kotlinx.coroutines.experimental.CoroutineStart
import kotlinx.coroutines.experimental.Unconfined
import kotlinx.coroutines.experimental.channels.ProducerScope
import kotlinx.coroutines.experimental.launch
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.SchemaUtils.create
import org.jetbrains.exposed.sql.transactions.transaction
@@ -35,6 +39,12 @@ class ExposedBacking(private val dataSourceFactory: suspend () -> DataSource) :
private fun <T> transaction(statement: Transaction.() -> T) = transaction(database!!, statement)
private suspend fun transactionLaunch(statement: suspend Transaction.() -> Unit): Unit = transaction(database!!) {
launch(context = Unconfined, start = CoroutineStart.UNDISPATCHED) {
statement(this@transaction)
}
}
override suspend fun init() {
if (isShutdown) throw IllegalStateException()
dataSource = dataSourceFactory()
@@ -61,7 +71,7 @@ class ExposedBacking(private val dataSourceFactory: suspend () -> DataSource) :
channel.close()
}
override suspend fun ProducerScope<Pair<SerializableParcel, ParcelData?>>.produceAllParcelData() {
override suspend fun ProducerScope<Pair<SerializableParcel, ParcelData?>>.produceAllParcelData() = transactionLaunch {
ParcelsT.selectAll().forEach { row ->
val parcel = ParcelsT.getSerializable(row) ?: return@forEach
val data = rowToParcelData(row)
@@ -150,13 +160,13 @@ class ExposedBacking(private val dataSourceFactory: suspend () -> DataSource) :
}
}
override suspend fun ProducerScope<Pair<ParcelOwner, MutableMap<UUID, AddedStatus>>>.produceAllGlobalAddedData() {
override suspend fun ProducerScope<Pair<ParcelOwner, MutableMap<UUID, AddedStatus>>>.produceAllGlobalAddedData() = transactionLaunch {
AddedGlobalT.sendAllAddedData(channel)
channel.close()
}
override suspend fun readGlobalAddedData(owner: ParcelOwner): MutableMap<UUID, AddedStatus> {
return AddedGlobalT.readAddedData(OwnersT.getId(owner) ?: return hashMapOf())
override suspend fun readGlobalAddedData(owner: ParcelOwner): MutableMap<UUID, AddedStatus> = transaction {
return@transaction AddedGlobalT.readAddedData(OwnersT.getId(owner) ?: return@transaction hashMapOf())
}
override suspend fun setGlobalPlayerStatus(owner: ParcelOwner, player: UUID, status: AddedStatus) = transaction {

View File

@@ -1,4 +1,4 @@
package io.dico.parcels2.storage
package io.dico.parcels2.storage.exposed
import org.jetbrains.exposed.sql.Column
import org.jetbrains.exposed.sql.Index

View File

@@ -7,7 +7,6 @@ import io.dico.parcels2.ParcelOwner
import io.dico.parcels2.ParcelWorld
import io.dico.parcels2.storage.SerializableParcel
import io.dico.parcels2.storage.SerializableWorld
import io.dico.parcels2.storage.uniqueIndexR
import io.dico.parcels2.util.Vec2i
import io.dico.parcels2.util.toByteArray
import io.dico.parcels2.util.toUUID
@@ -42,7 +41,7 @@ sealed class IdTransactionsTable<TableT : IdTransactionsTable<TableT, QueryObj,
object WorldsT : IdTransactionsTable<WorldsT, ParcelWorld, SerializableWorld>("parcel_worlds", "world_id") {
val name = varchar("name", 50)
val uid = binary("uid", 2)
val uid = binary("uid", 16)
val index_uid = uniqueIndexR("index_uid", uid)
internal inline fun getId(binaryUid: ByteArray): Int? = getId { uid eq binaryUid }
@@ -90,7 +89,7 @@ object ParcelsT : IdTransactionsTable<ParcelsT, Parcel, SerializableParcel>("par
}
object OwnersT : IdTransactionsTable<OwnersT, ParcelOwner, ParcelOwner>("parcel_owners", "owner_id") {
val uuid = binary("uuid", 2).nullable()
val uuid = binary("uuid", 16).nullable()
val name = varchar("name", 32)
val index_pair = uniqueIndexR("index_pair", uuid, name)

View File

@@ -6,8 +6,6 @@ import io.dico.parcels2.AddedStatus
import io.dico.parcels2.Parcel
import io.dico.parcels2.ParcelOwner
import io.dico.parcels2.storage.SerializableParcel
import io.dico.parcels2.storage.uniqueIndexR
import io.dico.parcels2.storage.upsert
import io.dico.parcels2.util.toByteArray
import io.dico.parcels2.util.toUUID
import kotlinx.coroutines.experimental.channels.SendChannel
@@ -55,6 +53,7 @@ sealed class AddedTable<AttachT, SerializableT>(name: String, val idTable: IdTra
}
suspend fun sendAllAddedData(channel: AddedStatusSendChannel<SerializableT>) {
/*
val iterator = selectAll().orderBy(attach_id).iterator()
if (iterator.hasNext()) {
@@ -96,7 +95,7 @@ sealed class AddedTable<AttachT, SerializableT>(name: String, val idTable: IdTra
}
sendIfPresent()
}
}*/
}
private inline fun Boolean?.asAddedStatus() = if (this == null) AddedStatus.DEFAULT else if (this) AddedStatus.ALLOWED else AddedStatus.BANNED