Archived
0

Replace AddedData API with Privileges API, adding CAN_MANAGE and required changes

This commit is contained in:
Dico
2018-09-24 02:45:41 +01:00
parent e0bf8249bd
commit 1a440767b3
33 changed files with 552 additions and 413 deletions

View File

@@ -87,10 +87,11 @@ dependencies {
tasks {
removeIf { it is ShadowJar }
val compileKotlin by getting(KotlinCompile::class) {
tasks.withType<KotlinCompile> {
kotlinOptions {
javaParameters = true
suppressWarnings = true
jvmTarget = "1.8"
//freeCompilerArgs = listOf("-XXLanguage:+InlineClasses", "-Xuse-experimental=kotlin.Experimental")
}
}

View File

@@ -1,62 +0,0 @@
package io.dico.parcels2
import io.dico.parcels2.AddedStatus.*
import org.bukkit.OfflinePlayer
enum class AddedStatus {
DEFAULT, ALLOWED, BANNED;
}
typealias StatusKey = PlayerProfile.Real
typealias MutableAddedDataMap = MutableMap<StatusKey, AddedStatus>
typealias AddedDataMap = Map<StatusKey, AddedStatus>
@Suppress("FunctionName")
fun MutableAddedDataMap(): MutableAddedDataMap = hashMapOf()
interface AddedData {
val addedMap: AddedDataMap
var statusOfStar: AddedStatus
fun getStatus(key: StatusKey): AddedStatus
fun setStatus(key: StatusKey, status: AddedStatus): Boolean
fun casStatus(key: StatusKey, expect: AddedStatus, status: AddedStatus): Boolean =
getStatus(key) == expect && setStatus(key, status)
fun isAllowed(key: StatusKey) = getStatus(key) == ALLOWED
fun allow(key: StatusKey) = setStatus(key, ALLOWED)
fun disallow(key: StatusKey) = casStatus(key, ALLOWED, DEFAULT)
fun isBanned(key: StatusKey) = getStatus(key) == BANNED
fun ban(key: StatusKey) = setStatus(key, BANNED)
fun unban(key: StatusKey) = casStatus(key, BANNED, DEFAULT)
fun isAllowed(player: OfflinePlayer) = isAllowed(player.statusKey)
fun allow(player: OfflinePlayer) = allow(player.statusKey)
fun disallow(player: OfflinePlayer) = disallow(player.statusKey)
fun isBanned(player: OfflinePlayer) = isBanned(player.statusKey)
fun ban(player: OfflinePlayer) = ban(player.statusKey)
fun unban(player: OfflinePlayer) = unban(player.statusKey)
}
inline val OfflinePlayer.statusKey: StatusKey
get() = PlayerProfile.nameless(this)
open class AddedDataHolder(override var addedMap: MutableAddedDataMap = MutableAddedDataMap()) : AddedData {
override var statusOfStar: AddedStatus = DEFAULT
override fun getStatus(key: StatusKey): AddedStatus = addedMap.getOrDefault(key, statusOfStar)
override fun setStatus(key: StatusKey, status: AddedStatus): Boolean {
return if (status == DEFAULT) addedMap.remove(key) != null
else addedMap.put(key, status) != status
}
}
interface GlobalAddedData : AddedData {
val owner: PlayerProfile
}
interface GlobalAddedDataManager {
operator fun get(owner: PlayerProfile): GlobalAddedData
}

View File

@@ -2,7 +2,6 @@ package io.dico.parcels2
import io.dico.parcels2.util.ext.getMaterialsWithWoodTypePrefix
import org.bukkit.Material
import java.lang.IllegalArgumentException
import java.util.EnumMap
class Interactables
@@ -113,13 +112,14 @@ val pathInteractableConfig: InteractableConfiguration = run {
interface InteractableConfiguration {
val interactableClasses: List<Interactables> get() = Interactables.classesById.filter { isInteractable(it) }
fun isInteractable(material: Material): Boolean
fun isInteractable(clazz: Interactables): Boolean
fun setInteractable(clazz: Interactables, interactable: Boolean): Boolean
fun clear(): Boolean
fun copyFrom(other: InteractableConfiguration) {
Interactables.classesById.forEach { setInteractable(it, other.isInteractable(it)) }
}
fun copyFrom(other: InteractableConfiguration) =
Interactables.classesById.fold(false) { cur, elem -> setInteractable(elem, other.isInteractable(elem) || cur) }
operator fun invoke(material: Material) = isInteractable(material)
operator fun invoke(className: String) = isInteractable(Interactables[className])

View File

@@ -1,7 +1,7 @@
package io.dico.parcels2
import io.dico.parcels2.util.Vec2i
import io.dico.parcels2.util.ext.hasBuildAnywhere
import io.dico.parcels2.util.ext.hasPermBuildAnywhere
import org.bukkit.Location
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
@@ -37,7 +37,7 @@ interface Parcel : ParcelData {
val homeLocation: Location get() = world.blockManager.getHomeLocation(id)
}
interface ParcelData : AddedData {
interface ParcelData : Privileges {
var owner: PlayerProfile?
val lastClaimTime: DateTime?
var ownerSignOutdated: Boolean
@@ -54,14 +54,15 @@ interface ParcelData : AddedData {
}
}
class ParcelDataHolder(addedMap: MutableAddedDataMap = mutableMapOf())
: ParcelData, AddedDataHolder(addedMap) {
class ParcelDataHolder(addedMap: MutablePrivilegeMap = mutableMapOf())
: ParcelData, PrivilegesHolder(addedMap) {
override var owner: PlayerProfile? = null
override var lastClaimTime: DateTime? = null
override var ownerSignOutdated = false
override fun canBuild(player: OfflinePlayer, checkAdmin: Boolean, checkGlobal: Boolean) = isAllowed(player.statusKey)
override fun canBuild(player: OfflinePlayer, checkAdmin: Boolean, checkGlobal: Boolean) =
hasPrivilegeToBuild(player)
|| owner.let { it != null && it.matches(player, allowNameMatch = false) }
|| (checkAdmin && player is Player && player.hasBuildAnywhere)
|| (checkAdmin && player is Player && player.hasPermBuildAnywhere)
override var interactableConfig: InteractableConfiguration = BitmaskInteractableConfiguration()
}

View File

@@ -85,7 +85,7 @@ interface ParcelWorld : ParcelLocator, ParcelContainer {
val container: ParcelContainer
val locator: ParcelLocator
val blockManager: ParcelBlockManager
val globalAddedData: GlobalAddedDataManager
val globalPrivileges: GlobalPrivilegesManager
val creationTime: DateTime?

View File

@@ -6,7 +6,7 @@ import io.dico.dicore.command.ICommandDispatcher
import io.dico.parcels2.blockvisitor.TickWorktimeLimiter
import io.dico.parcels2.blockvisitor.WorktimeLimiter
import io.dico.parcels2.command.getParcelCommands
import io.dico.parcels2.defaultimpl.GlobalAddedDataManagerImpl
import io.dico.parcels2.defaultimpl.GlobalPrivilegesManagerImpl
import io.dico.parcels2.defaultimpl.ParcelProviderImpl
import io.dico.parcels2.listener.ParcelEntityTracker
import io.dico.parcels2.listener.ParcelListeners
@@ -35,7 +35,7 @@ class ParcelsPlugin : JavaPlugin(), CoroutineScope, PluginScheduler {
lateinit var options: Options; private set
lateinit var parcelProvider: ParcelProvider; private set
lateinit var storage: Storage; private set
lateinit var globalAddedData: GlobalAddedDataManager; private set
lateinit var globalPrivileges: GlobalPrivilegesManager; private set
val registrator = Registrator(this)
lateinit var entityTracker: ParcelEntityTracker; private set
@@ -83,7 +83,7 @@ class ParcelsPlugin : JavaPlugin(), CoroutineScope, PluginScheduler {
return false
}
globalAddedData = GlobalAddedDataManagerImpl(this)
globalPrivileges = GlobalPrivilegesManagerImpl(this)
entityTracker = ParcelEntityTracker(parcelProvider)
} catch (ex: Exception) {
plogger.error("Error loading options", ex)

View File

@@ -0,0 +1,134 @@
package io.dico.parcels2
import io.dico.parcels2.Privilege.*
import org.bukkit.OfflinePlayer
enum class Privilege(
val number: Int,
val transient: Boolean = false
) {
BANNED(1),
DEFAULT(2),
CAN_BUILD(3),
CAN_MANAGE(4),
OWNER(-1, transient = true),
ADMIN(-1, transient = true);
fun requireNonTransient(): Privilege {
if (transient) {
throw IllegalArgumentException("Transient privilege $this is invalid")
}
return this
}
/*
fun canEnter() = this >= BANNED
fun canBuild() = this >= CAN_BUILD
fun canManage() = this >= CAN_MANAGE
*/
companion object {
fun getByNumber(number: Int) = safeGetByNumber(number)
?: throw IllegalArgumentException(
if (number == -1) "Transient privileges are not stored"
else "Privilege with number $number doesn't exist"
)
fun safeGetByNumber(id: Int) =
when (id) {
1 -> BANNED
2 -> DEFAULT
3 -> CAN_BUILD
4 -> CAN_MANAGE
else -> null
}
}
}
typealias PrivilegeKey = PlayerProfile.Real
typealias MutablePrivilegeMap = MutableMap<PrivilegeKey, Privilege>
typealias PrivilegeMap = Map<PrivilegeKey, Privilege>
@Suppress("FunctionName")
fun MutablePrivilegeMap(): MutablePrivilegeMap = hashMapOf()
/**
* Privileges object never returns a transient privilege.
*/
interface Privileges {
val map: PrivilegeMap
var privilegeOfStar: Privilege
fun privilege(key: PrivilegeKey): Privilege
fun privilege(player: OfflinePlayer) = privilege(player.privilegeKey)
fun setPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean
fun setPrivilege(player: OfflinePlayer, privilege: Privilege) = setPrivilege(player.privilegeKey, privilege)
fun changePrivilege(key: PrivilegeKey, expect: Privilege, update: Privilege): Boolean =
(when { // if CAN_BUILD is expected, CAN_MANAGE is valid.
expect > DEFAULT -> privilege(key) >= expect
expect == DEFAULT -> privilege(key) == expect
else -> privilege(key) <= expect
})
&& setPrivilege(key, update)
fun hasPrivilegeToManage(key: PrivilegeKey) = privilege(key) >= CAN_MANAGE
fun allowManage(key: PrivilegeKey) = setPrivilege(key, CAN_MANAGE)
fun disallowManage(key: PrivilegeKey) = changePrivilege(key, CAN_MANAGE, CAN_BUILD)
fun hasPrivilegeToBuild(key: PrivilegeKey) = privilege(key) >= CAN_BUILD
fun allowBuild(key: PrivilegeKey) = setPrivilege(key, CAN_BUILD)
fun disallowBuild(key: PrivilegeKey) = changePrivilege(key, CAN_BUILD, DEFAULT)
fun isBanned(key: PrivilegeKey) = privilege(key) == BANNED
fun ban(key: PrivilegeKey) = setPrivilege(key, BANNED)
fun unban(key: PrivilegeKey) = changePrivilege(key, BANNED, DEFAULT)
/* OfflinePlayer overloads */
fun hasPrivilegeToManage(player: OfflinePlayer) = hasPrivilegeToManage(player.privilegeKey)
fun allowManage(player: OfflinePlayer) = allowManage(player.privilegeKey)
fun disallowManage(player: OfflinePlayer) = disallowManage(player.privilegeKey)
fun hasPrivilegeToBuild(player: OfflinePlayer) = hasPrivilegeToBuild(player.privilegeKey)
fun allowBuild(player: OfflinePlayer) = allowBuild(player.privilegeKey)
fun disallowBuild(player: OfflinePlayer) = disallowBuild(player.privilegeKey)
fun isBanned(player: OfflinePlayer) = isBanned(player.privilegeKey)
fun ban(player: OfflinePlayer) = ban(player.privilegeKey)
fun unban(player: OfflinePlayer) = unban(player.privilegeKey)
}
inline val OfflinePlayer.privilegeKey: PrivilegeKey
get() = PlayerProfile.nameless(this)
open class PrivilegesHolder(override var map: MutablePrivilegeMap = MutablePrivilegeMap()) : Privileges {
override var privilegeOfStar: Privilege = DEFAULT
set(value) = run { field = value.requireNonTransient() }
override fun privilege(key: PrivilegeKey): Privilege = map.getOrDefault(key, privilegeOfStar)
override fun setPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
privilege.requireNonTransient()
if (key.isStar) {
if (privilegeOfStar == privilege) return false
privilegeOfStar = privilege
return true
}
return if (privilege == DEFAULT) map.remove(key) != null
else map.put(key, privilege) != privilege
}
}
interface GlobalPrivileges : Privileges {
val owner: PlayerProfile
}
interface GlobalPrivilegesManager {
operator fun get(owner: PlayerProfile): GlobalPrivileges
}

View File

@@ -4,7 +4,7 @@ import io.dico.dicore.command.*
import io.dico.parcels2.ParcelWorld
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.PlayerProfile
import io.dico.parcels2.util.ext.hasAdminManage
import io.dico.parcels2.util.ext.hasPermAdminManage
import io.dico.parcels2.util.ext.parcelLimit
import org.bukkit.entity.Player
import org.bukkit.plugin.Plugin
@@ -26,7 +26,7 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei
}
protected suspend fun checkParcelLimit(player: Player, world: ParcelWorld) {
if (player.hasAdminManage) return
if (player.hasPermAdminManage) return
val numOwnedParcels = plugin.storage.getOwnedParcels(PlayerProfile(player)).await()
.filter { it.worldId.equals(world.id) }.size

View File

@@ -1,56 +0,0 @@
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.ParcelsPlugin
import io.dico.parcels2.util.ext.hasAdminManage
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
class CommandsAddedStatusLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
@Cmd("allow", aliases = ["add", "permit"])
@Desc("Allows a player to build on this parcel",
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!!.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"
}
@Cmd("disallow", aliases = ["remove", "forbid"])
@Desc("Disallows a player to build on this parcel,",
"they won't be allowed to anymore",
shortVersion = "disallows a player to build on this parcel")
@ParcelRequire(owner = true)
fun ParcelScope.cmdDisallow(sender: Player, player: OfflinePlayer): Any? {
Validate.isTrue(parcel.disallow(player), "${player.name} is not currently allowed to build on this parcel")
return "${player.name} is not allowed to build on this parcel anymore"
}
@Cmd("ban", aliases = ["deny"])
@Desc("Bans a player from this parcel,",
"making them unable to enter",
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!!.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"
}
@Cmd("unban", aliases = ["undeny"])
@Desc("Unbans a player from this parcel,",
"they will be able to enter it again",
shortVersion = "unbans a player from this parcel")
@ParcelRequire(owner = true)
fun ParcelScope.cmdUnban(sender: Player, player: OfflinePlayer): Any? {
Validate.isTrue(parcel.unban(player), "${player.name} is not currently banned from this parcel")
return "${player.name} is not banned from this parcel anymore"
}
}

View File

@@ -5,11 +5,12 @@ import io.dico.dicore.command.annotation.Cmd
import io.dico.dicore.command.annotation.Flag
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.PlayerProfile
import io.dico.parcels2.Privilege
class CommandsAdmin(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
@Cmd("setowner")
@ParcelRequire(admin = true)
@RequireParcelPrivilege(Privilege.ADMIN)
fun ParcelScope.cmdSetowner(target: PlayerProfile): Any? {
parcel.owner = target
@@ -18,14 +19,14 @@ class CommandsAdmin(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
}
@Cmd("dispose")
@ParcelRequire(admin = true)
@RequireParcelPrivilege(Privilege.ADMIN)
fun ParcelScope.cmdDispose(): Any? {
parcel.dispose()
return "Data of (${parcel.id.idString}) has been disposed"
}
@Cmd("reset")
@ParcelRequire(admin = true)
@RequireParcelPrivilege(Privilege.ADMIN)
fun ParcelScope.cmdReset(context: ExecutionContext, @Flag sure: Boolean): Any? {
if (!sure) return areYouSureMessage(context)
parcel.dispose()
@@ -34,9 +35,10 @@ class CommandsAdmin(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
}
@Cmd("swap")
@RequireParcelPrivilege(Privilege.ADMIN)
fun ParcelScope.cmdSwap(context: ExecutionContext, @Flag sure: Boolean): Any? {
if (!sure) return areYouSureMessage(context)
TODO()
TODO("implement swap")
}

View File

@@ -5,6 +5,7 @@ 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.Privilege
import io.dico.parcels2.blockvisitor.RegionTraverser
import io.dico.parcels2.doBlockOperation
import org.bukkit.Bukkit
@@ -30,7 +31,7 @@ class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
}
@Cmd("make_mess")
@ParcelRequire(owner = true)
@RequireParcelPrivilege(Privilege.OWNER)
fun ParcelScope.cmdMakeMess(context: ExecutionContext) {
val server = plugin.server
val blockDatas = arrayOf(
@@ -47,8 +48,10 @@ class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
world.blockManager.doBlockOperation(parcel.id, traverser = RegionTraverser.upward) { block ->
block.blockData = blockDatas[random.nextInt(7)]
}.onProgressUpdate(1000, 1000) { progress, elapsedTime ->
context.sendMessage(EMessageType.INFORMATIVE, "Mess progress: %.02f%%, %.2fs elapsed"
.format(progress * 100, elapsedTime / 1000.0))
context.sendMessage(
EMessageType.INFORMATIVE, "Mess progress: %.02f%%, %.2fs elapsed"
.format(progress * 100, elapsedTime / 1000.0)
)
}
}

View File

@@ -9,8 +9,8 @@ import io.dico.dicore.command.annotation.RequireParameters
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.PlayerProfile
import io.dico.parcels2.command.ParcelTarget.Kind
import io.dico.parcels2.util.ext.hasAdminManage
import io.dico.parcels2.util.ext.hasParcelHomeOthers
import io.dico.parcels2.util.ext.hasPermAdminManage
import io.dico.parcels2.util.ext.uuid
import org.bukkit.block.Biome
import org.bukkit.entity.Player
@@ -99,7 +99,7 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
)
suspend fun ParcelScope.cmdClaim(player: Player): Any? {
checkConnected("be claimed")
parcel.owner.takeIf { !player.hasAdminManage }?.let {
parcel.owner.takeIf { !player.hasPermAdminManage }?.let {
error(if (it.matches(player)) "You already own this parcel" else "This parcel is not available")
}
@@ -110,14 +110,14 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
@Cmd("unclaim")
@Desc("Unclaims this parcel")
@ParcelRequire(owner = true)
@RequireParcelPrivilege(Privilege.OWNER)
fun ParcelScope.cmdUnclaim(player: Player): Any? {
parcel.dispose()
return "Your parcel has been disposed"
}
@Cmd("clear")
@ParcelRequire(owner = true)
@RequireParcelPrivilege(Privilege.OWNER)
fun ParcelScope.cmdClear(context: ExecutionContext, @Flag sure: Boolean): Any? {
if (!sure) return areYouSureMessage(context)
@@ -126,7 +126,7 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
}
@Cmd("setbiome")
@ParcelRequire(owner = true)
@RequireParcelPrivilege(Privilege.OWNER)
fun ParcelScope.cmdSetbiome(context: ExecutionContext, biome: Biome): Any? {
Validate.isTrue(!parcel.hasBlockVisitors, "A process is already running in this parcel")
world.blockManager.setBiome(parcel.id, biome)

View File

@@ -1,61 +0,0 @@
package io.dico.parcels2.command
import io.dico.dicore.command.CommandBuilder
import io.dico.dicore.command.Validate
import io.dico.dicore.command.annotation.Cmd
import io.dico.dicore.command.annotation.Desc
import io.dico.dicore.command.annotation.RequireParameters
import io.dico.parcels2.Parcel
import io.dico.parcels2.ParcelsPlugin
import org.bukkit.entity.Player
import kotlin.reflect.KMutableProperty
class CommandsParcelOptions(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
/* TODO options
@Cmd("inputs")
@Desc("Sets whether players who are not allowed to",
"build here can use levers, buttons,",
"pressure plates, tripwire or redstone ore",
shortVersion = "allows using inputs")
@RequireParameters(0)
fun ParcelScope.cmdInputs(player: Player, enabled: Boolean?): Any? {
return runOptionCommand(player, Parcel::allowInteractInputs, enabled, "using levers, buttons, etc.")
}
@Cmd("inventory")
@Desc("Sets whether players who are not allowed to",
"build here can interact with inventories",
shortVersion = "allows editing inventories")
@RequireParameters(0)
fun ParcelScope.cmdInventory(player: Player, enabled: Boolean?): Any? {
return runOptionCommand(player, Parcel::allowInteractInventory, enabled, "interaction with inventories")
}*/
private inline val Boolean.enabledWord get() = if (this) "enabled" else "disabled"
private fun ParcelScope.runOptionCommand(player: Player,
property: KMutableProperty<Boolean>,
enabled: Boolean?,
desc: String): Any? {
checkConnected("have their options changed")
val current = property.getter.call(parcel)
if (enabled == null) {
val word = if (current) "" else "not "
return "This parcel does ${word}allow $desc"
}
checkCanManage(player, "change its options")
Validate.isTrue(current != enabled, "That option was already ${enabled.enabledWord}")
property.setter.call(parcel, enabled)
return "That option is now ${enabled.enabledWord}"
}
companion object {
private const val descShort = "changes interaction options for this parcel"
private val desc = arrayOf("Sets whether players who are not allowed to", "build here can interact with certain things.")
fun setGroupDescription(builder: CommandBuilder) {
builder.setGroupDescription(descShort, *desc)
}
}
}

View File

@@ -3,47 +3,72 @@ 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.PlayerProfile
import io.dico.parcels2.GlobalPrivileges
import io.dico.parcels2.GlobalPrivilegesManager
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.PlayerProfile
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
class CommandsAddedStatusGlobal(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
private inline val data get() = plugin.globalAddedData
class CommandsPrivilegesGlobal(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
private inline val data get() = plugin.globalPrivileges
@Suppress("NOTHING_TO_INLINE")
private inline operator fun GlobalAddedDataManager.get(player: OfflinePlayer): GlobalAddedData = data[PlayerProfile(player)]
private inline operator fun GlobalPrivilegesManager.get(player: OfflinePlayer): GlobalPrivileges = this[PlayerProfile(player)]
@Cmd("entrust")
@Desc(
"Allows a player to manage this parcel",
shortVersion = "allows a player to manage this parcel"
)
fun cmdEntrust(sender: Player, player: OfflinePlayer): Any? {
Validate.isTrue(player != sender, "The target cannot be yourself")
Validate.isTrue(data[sender].allowManage(player), "${player.name} is already allowed to manage globally")
return "${player.name} is now allowed to manage globally"
}
@Cmd("distrust")
@Desc(
"Disallows a player to manage globally,",
"they will still be able to build",
shortVersion = "disallows a player to manage globally"
)
fun cmdDistrust(sender: Player, player: OfflinePlayer): Any? {
Validate.isTrue(data[sender].disallowManage(player), "${player.name} is not currently allowed to manage globally")
return "${player.name} is not allowed to manage globally anymore"
}
@Cmd("allow", aliases = ["add", "permit"])
@Desc("Globally allows a player to build on all",
@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)
shortVersion = "globally allows a player to build on your parcels"
)
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")
Validate.isTrue(data[sender].allowBuild(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",
@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)
shortVersion = "globally disallows a player to build on your parcels"
)
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")
Validate.isTrue(data[sender].disallowBuild(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",
@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)
shortVersion = "globally bans a player from your parcels"
)
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")
@@ -51,12 +76,13 @@ class CommandsAddedStatusGlobal(plugin: ParcelsPlugin) : AbstractParcelCommands(
}
@Cmd("unban", aliases = ["undeny"])
@Desc("Globally unbans a player from all the parcels",
@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)
shortVersion = "globally unbans a player from your parcels"
)
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"

View File

@@ -0,0 +1,90 @@
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.ParcelsPlugin
import io.dico.parcels2.Privilege
import io.dico.parcels2.util.ext.hasPermAdminManage
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
@Cmd("entrust")
@Desc(
"Allows a player to manage this parcel",
shortVersion = "allows a player to manage this parcel"
)
@RequireParcelPrivilege(Privilege.OWNER)
fun ParcelScope.cmdEntrust(sender: Player, player: OfflinePlayer): Any? {
Validate.isTrue(parcel.owner != null || sender.hasPermAdminManage, "This parcel is unowned")
Validate.isTrue(!parcel.owner!!.matches(player), "The target already owns the parcel")
Validate.isTrue(parcel.allowManage(player), "${player.name} is already allowed to manage this parcel")
return "${player.name} is now allowed to manage this parcel"
}
@Cmd("distrust")
@Desc(
"Disallows a player to manage this parcel,",
"they will still be able to build",
shortVersion = "disallows a player to manage this parcel"
)
@RequireParcelPrivilege(Privilege.OWNER)
fun ParcelScope.cmdDistrust(sender: Player, player: OfflinePlayer): Any? {
Validate.isTrue(parcel.disallowManage(player), "${player.name} is not currently allowed to manage this parcel")
return "${player.name} is not allowed to manage this parcel anymore"
}
@Cmd("allow", aliases = ["add", "permit"])
@Desc(
"Allows a player to build on this parcel",
shortVersion = "allows a player to build on this parcel"
)
@RequireParcelPrivilege(Privilege.CAN_MANAGE)
fun ParcelScope.cmdAllow(sender: Player, player: OfflinePlayer): Any? {
Validate.isTrue(parcel.owner != null || sender.hasPermAdminManage, "This parcel is unowned")
Validate.isTrue(!parcel.owner!!.matches(player), "The target already owns the parcel")
Validate.isTrue(parcel.allowBuild(player), "${player.name} is already allowed to build on this parcel")
return "${player.name} is now allowed to build on this parcel"
}
@Cmd("disallow", aliases = ["remove", "forbid"])
@Desc(
"Disallows a player to build on this parcel,",
"they won't be allowed to anymore",
shortVersion = "disallows a player to build on this parcel"
)
@RequireParcelPrivilege(Privilege.CAN_MANAGE)
fun ParcelScope.cmdDisallow(sender: Player, player: OfflinePlayer): Any? {
Validate.isTrue(parcel.disallowBuild(player), "${player.name} is not currently allowed to build on this parcel")
return "${player.name} is not allowed to build on this parcel anymore"
}
@Cmd("ban", aliases = ["deny"])
@Desc(
"Bans a player from this parcel,",
"making them unable to enter",
shortVersion = "bans a player from this parcel"
)
@RequireParcelPrivilege(Privilege.CAN_MANAGE)
fun ParcelScope.cmdBan(sender: Player, player: OfflinePlayer): Any? {
Validate.isTrue(parcel.owner != null || sender.hasPermAdminManage, "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"
}
@Cmd("unban", aliases = ["undeny"])
@Desc(
"Unbans a player from this parcel,",
"they will be able to enter it again",
shortVersion = "unbans a player from this parcel"
)
@RequireParcelPrivilege(Privilege.CAN_MANAGE)
fun ParcelScope.cmdUnban(sender: Player, player: OfflinePlayer): Any? {
Validate.isTrue(parcel.unban(player), "${player.name} is not currently banned from this parcel")
return "${player.name} is not banned from this parcel anymore"
}
}

View File

@@ -4,6 +4,7 @@ import io.dico.dicore.command.CommandBuilder
import io.dico.dicore.command.ICommandAddress
import io.dico.dicore.command.ICommandDispatcher
import io.dico.dicore.command.registration.reflect.ReflectiveRegistration
import io.dico.parcels2.Interactables
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.logger
import java.util.LinkedList
@@ -20,15 +21,25 @@ fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher =
group("parcel", "plot", "plots", "p") {
addRequiredPermission("parcels.command")
registerCommands(CommandsGeneral(plugin))
registerCommands(CommandsAddedStatusLocal(plugin))
registerCommands(CommandsPrivilegesLocal(plugin))
group("option", "opt", "o") {
CommandsParcelOptions.setGroupDescription(this)
registerCommands(CommandsParcelOptions(plugin))
setGroupDescription(
"changes interaction options for this parcel",
"Sets whether players who are not allowed to",
"build here can interact with certain things."
)
group("interact", "i") {
val command = ParcelOptionsInteractCommand(plugin.parcelProvider)
Interactables.classesById.forEach {
addSubCommand(it.name, command)
}
}
}
group("global", "g") {
registerCommands(CommandsAddedStatusGlobal(plugin))
registerCommands(CommandsPrivilegesGlobal(plugin))
}
group("admin", "a") {

View File

@@ -7,7 +7,9 @@ import io.dico.dicore.command.Validate
import io.dico.parcels2.Parcel
import io.dico.parcels2.ParcelProvider
import io.dico.parcels2.ParcelWorld
import io.dico.parcels2.util.ext.hasAdminManage
import io.dico.parcels2.Privilege
import io.dico.parcels2.Privilege.*
import io.dico.parcels2.util.ext.hasPermAdminManage
import io.dico.parcels2.util.ext.uuid
import org.bukkit.entity.Player
import java.lang.reflect.Method
@@ -18,44 +20,55 @@ import kotlin.reflect.jvm.kotlinFunction
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class ParcelRequire(val admin: Boolean = false, val owner: Boolean = false)
annotation class RequireParcelPrivilege(val privilege: Privilege)
/*
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class SuspensionTimeout(val millis: Int)
*/
open class WorldScope(val world: ParcelWorld) : ICommandReceiver
open class ParcelScope(val parcel: Parcel) : WorldScope(parcel.world) {
fun checkCanManage(player: Player, action: String) = Validate.isTrue(player.hasAdminManage || parcel.isOwner(player.uuid),
"You must own this parcel to $action")
fun checkCanManage(player: Player, action: String) = Validate.isTrue(
player.hasPermAdminManage || parcel.hasPrivilegeToManage(player),
"You must own this parcel to $action"
)
}
fun getParcelCommandReceiver(parcelProvider: ParcelProvider, context: ExecutionContext, method: Method, cmdName: String): ICommandReceiver {
val player = context.sender as Player
val function = method.kotlinFunction!!
val receiverType = function.extensionReceiverParameter!!.type
val require = function.findAnnotation<ParcelRequire>()
val admin = require?.admin == true
val owner = require?.owner == true
val require = function.findAnnotation<RequireParcelPrivilege>()
return when (receiverType.jvmErasure) {
ParcelScope::class -> ParcelScope(parcelProvider.getParcelRequired(player, admin, owner))
WorldScope::class -> WorldScope(parcelProvider.getWorldRequired(player, admin))
ParcelScope::class -> ParcelScope(parcelProvider.getParcelRequired(player, require?.privilege))
WorldScope::class -> WorldScope(parcelProvider.getWorldRequired(player, require?.privilege == ADMIN))
else -> throw InternalError("Invalid command receiver type")
}
}
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.hasPermAdminManage, "You must have admin rights to use that command")
return getWorld(player.world)
?: throw CommandException("You must be in a parcel world to use that command")
}
fun ParcelProvider.getParcelRequired(player: Player, admin: Boolean = false, own: Boolean = false): Parcel {
val parcel = getWorldRequired(player, admin = admin).getParcelAt(player)
fun ParcelProvider.getParcelRequired(player: Player, privilege: Privilege? = null): Parcel {
val parcel = getWorldRequired(player, admin = privilege == ADMIN).getParcelAt(player)
?: throw CommandException("You must be in a parcel to use that command")
if (own) Validate.isTrue(parcel.isOwner(player.uuid) || player.hasAdminManage,
"You must own this parcel to use that command")
if (!player.hasPermAdminManage) {
@Suppress("NON_EXHAUSTIVE_WHEN")
when (privilege) {
OWNER ->
Validate.isTrue(parcel.isOwner(player.uuid), "You must own this parcel to use that command")
CAN_MANAGE ->
Validate.isTrue(parcel.hasPrivilegeToManage(player), "You must have management privileges on this parcel to use that command")
}
}
return parcel
}

View File

@@ -0,0 +1,36 @@
package io.dico.parcels2.command
import io.dico.dicore.command.Command
import io.dico.dicore.command.CommandException
import io.dico.dicore.command.ExecutionContext
import io.dico.dicore.command.IContextFilter
import io.dico.dicore.command.parameter.type.ParameterTypes
import io.dico.parcels2.Interactables
import io.dico.parcels2.ParcelProvider
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
class ParcelOptionsInteractCommand(val parcelProvider: ParcelProvider) : Command() {
init {
addContextFilter(IContextFilter.PLAYER_ONLY)
addParameter("allowed", "allowed", ParameterTypes.BOOLEAN)
}
override fun execute(sender: CommandSender, context: ExecutionContext): String? {
val parcel = parcelProvider.getParcelRequired(sender as Player, owner = true)
val interactableClassName = context.address.mainKey
val allowed: Boolean = context.get("allowed")
val change = parcel.interactableConfig.setInteractable(Interactables[interactableClassName], allowed)
return when {
allowed && change -> "Other players can now interact with $interactableClassName"
allowed && !change -> err("Other players could already interact with $interactableClassName")
change -> "Other players can not interact with $interactableClassName anymore"
else -> err("Other players were not allowed to interact with $interactableClassName")
}
}
}
private fun err(message: String): Nothing = throw CommandException(message)

View File

@@ -8,7 +8,7 @@ import io.dico.parcels2.*
import io.dico.parcels2.storage.Storage
import io.dico.parcels2.util.Vec2i
import io.dico.parcels2.util.ext.floor
import kotlinx.coroutines.CoroutineStart.*
import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.async
import org.bukkit.command.CommandSender
@@ -26,12 +26,14 @@ sealed class ParcelTarget(val world: ParcelWorld, val parsedKind: Int, val isDef
val isPath: Boolean get() = id == null
}
class ByOwner(world: ParcelWorld,
owner: PlayerProfile,
val index: Int,
parsedKind: Int,
isDefault: Boolean,
val onResolveFailure: (() -> Unit)? = null) : ParcelTarget(world, parsedKind, isDefault) {
class ByOwner(
world: ParcelWorld,
owner: PlayerProfile,
val index: Int,
parsedKind: Int,
isDefault: Boolean,
val onResolveFailure: (() -> Unit)? = null
) : ParcelTarget(world, parsedKind, isDefault) {
init {
if (index < 0) throw IllegalArgumentException("Invalid parcel home index: $index")
}

View File

@@ -1,38 +0,0 @@
@file:Suppress("UNCHECKED_CAST")
package io.dico.parcels2.defaultimpl
import io.dico.parcels2.*
import io.dico.parcels2.util.ext.alsoIfTrue
import java.util.Collections
class GlobalAddedDataManagerImpl(val plugin: ParcelsPlugin) : GlobalAddedDataManager {
private val map = mutableMapOf<PlayerProfile, GlobalAddedData>()
override fun get(owner: PlayerProfile): GlobalAddedData {
return map[owner] ?: GlobalAddedDataImpl(owner).also { map[owner] = it }
}
private inner class GlobalAddedDataImpl(override val owner: PlayerProfile,
data: MutableAddedDataMap = emptyData)
: AddedDataHolder(data), GlobalAddedData {
private inline var data get() = addedMap; set(value) = run { addedMap = value }
private inline val isEmpty get() = data === emptyData
override fun setStatus(key: StatusKey, status: AddedStatus): Boolean {
if (isEmpty) {
if (status == AddedStatus.DEFAULT) return false
data = mutableMapOf()
}
return super.setStatus(key, status).alsoIfTrue {
plugin.storage.setGlobalAddedStatus(owner, key, status)
}
}
}
private companion object {
val emptyData = Collections.emptyMap<Any, Any>() as MutableAddedDataMap
}
}

View File

@@ -0,0 +1,38 @@
@file:Suppress("UNCHECKED_CAST")
package io.dico.parcels2.defaultimpl
import io.dico.parcels2.*
import io.dico.parcels2.util.ext.alsoIfTrue
import java.util.Collections
class GlobalPrivilegesManagerImpl(val plugin: ParcelsPlugin) : GlobalPrivilegesManager {
private val map = mutableMapOf<PlayerProfile, GlobalPrivileges>()
override fun get(owner: PlayerProfile): GlobalPrivileges {
return map[owner] ?: GlobalPrivilegesImpl(owner).also { map[owner] = it }
}
private inner class GlobalPrivilegesImpl(override val owner: PlayerProfile,
data: MutablePrivilegeMap = emptyData)
: PrivilegesHolder(data), GlobalPrivileges {
private inline var data get() = map; set(value) = run { map = value }
private inline val isEmpty get() = data === emptyData
override fun setPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
if (isEmpty) {
if (privilege == Privilege.DEFAULT) return false
data = mutableMapOf()
}
return super.set(key, privilege).alsoIfTrue {
plugin.storage.setGlobalPrivilege(owner, key, privilege)
}
}
}
private companion object {
val emptyData = Collections.emptyMap<Any, Any>() as MutablePrivilegeMap
}
}

View File

@@ -35,20 +35,20 @@ class ParcelImpl(
world.storage.setParcelData(this, null)
}
override val addedMap: AddedDataMap get() = data.addedMap
override fun getStatus(key: StatusKey) = data.getStatus(key)
override fun isBanned(key: StatusKey) = data.isBanned(key)
override fun isAllowed(key: StatusKey) = data.isAllowed(key)
override val map: PrivilegeMap get() = data.map
override fun privilege(key: PrivilegeKey) = data.privilege(key)
override fun isBanned(key: PrivilegeKey) = data.isBanned(key)
override fun hasPrivilegeToBuild(key: PrivilegeKey) = data.hasPrivilegeToBuild(key)
override fun canBuild(player: OfflinePlayer, checkAdmin: Boolean, checkGlobal: Boolean): Boolean {
return (data.canBuild(player, checkAdmin, false))
|| checkGlobal && world.globalAddedData[owner ?: return false].isAllowed(player)
|| checkGlobal && world.globalPrivileges[owner ?: return false].hasPrivilegeToBuild(player)
}
override var statusOfStar: AddedStatus
get() = data.statusOfStar
set(value) = run { setStatus(PlayerProfile.Star, value) }
override var privilegeOfStar: Privilege
get() = data.privilegeOfStar
set(value) = run { setPrivilege(PlayerProfile.Star, value) }
val globalAddedMap: AddedDataMap? get() = owner?.let { world.globalAddedData[it].addedMap }
val globalAddedMap: PrivilegeMap? get() = owner?.let { world.globalPrivileges[it].map }
override val lastClaimTime: DateTime? get() = data.lastClaimTime
@@ -71,12 +71,16 @@ class ParcelImpl(
}
}
override fun setStatus(key: StatusKey, status: AddedStatus): Boolean {
return data.setStatus(key, status).alsoIfTrue {
world.storage.setParcelPlayerStatus(this, key, status)
override fun setPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
return data.setPrivilege(key, privilege).alsoIfTrue {
world.storage.setLocalPrivilege(this, key, privilege)
}
}
private fun updateInteractableConfigStorage() {
world.storage.setParcelOptionsInteractConfig(this, data.interactableConfig)
}
private var _interactableConfig: InteractableConfiguration? = null
override var interactableConfig: InteractableConfiguration
get() {
@@ -86,21 +90,18 @@ class ParcelImpl(
override fun isInteractable(clazz: Interactables): Boolean = data.interactableConfig.isInteractable(clazz)
override fun setInteractable(clazz: Interactables, interactable: Boolean): Boolean =
data.interactableConfig.setInteractable(clazz, interactable).alsoIfTrue {
// TODO update storage
}
data.interactableConfig.setInteractable(clazz, interactable).alsoIfTrue { updateInteractableConfigStorage() }
override fun clear(): Boolean =
data.interactableConfig.clear().alsoIfTrue {
// TODO update storage
}
data.interactableConfig.clear().alsoIfTrue { updateInteractableConfigStorage() }
}
}
return _interactableConfig!!
}
set(value) {
data.interactableConfig.copyFrom(value)
// TODO update storage
if (data.interactableConfig.copyFrom(value)) {
updateInteractableConfigStorage()
}
}
private var blockVisitors = AtomicInteger(0)
@@ -139,10 +140,10 @@ private object ParcelInfoStringComputer {
append(' ')
}
private fun StringBuilder.appendAddedList(local: AddedDataMap, global: AddedDataMap, status: AddedStatus, fieldName: String) {
private fun StringBuilder.appendAddedList(local: PrivilegeMap, global: PrivilegeMap, status: Privilege, fieldName: String) {
val globalSet = global.filterValues { it == status }.keys
val localList = local.filterValues { it == status }.keys.filter { it !in globalSet }
val stringList = globalSet.map(StatusKey::notNullName).map { "(G)$it" } + localList.map(StatusKey::notNullName)
val stringList = globalSet.map(PrivilegeKey::notNullName).map { "(G)$it" } + localList.map(PrivilegeKey::notNullName)
if (stringList.isEmpty()) return
appendField({
@@ -182,11 +183,11 @@ private object ParcelInfoStringComputer {
append('\n')
val global = owner?.let { parcel.world.globalAddedData[owner].addedMap } ?: emptyMap()
val local = parcel.addedMap
appendAddedList(local, global, AddedStatus.ALLOWED, "Allowed")
val global = owner?.let { parcel.world.globalPrivileges[owner].map } ?: emptyMap()
val local = parcel.map
appendAddedList(local, global, Privilege.CAN_BUILD, "Allowed")
append('\n')
appendAddedList(local, global, AddedStatus.BANNED, "Banned")
appendAddedList(local, global, Privilege.BANNED, "Banned")
/* TODO options
if (!parcel.allowInteractInputs || !parcel.allowInteractInventory) {

View File

@@ -2,8 +2,6 @@ package io.dico.parcels2.defaultimpl
import io.dico.parcels2.*
import io.dico.parcels2.util.schedule
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.CoroutineStart.*
import kotlinx.coroutines.Unconfined
import kotlinx.coroutines.launch
import org.bukkit.Bukkit
@@ -61,7 +59,7 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
else WorldCreator(worldName).generator(generator).createWorld().also { logger.info("Creating world $worldName") }
parcelWorld = ParcelWorldImpl(bukkitWorld, generator, worldOptions.runtime, plugin.storage,
plugin.globalAddedData, ::DefaultParcelContainer, plugin, plugin.worktimeLimiter)
plugin.globalPrivileges, ::DefaultParcelContainer, plugin, plugin.worktimeLimiter)
if (!worldExists) {
val time = DateTime.now()
@@ -119,7 +117,7 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
worldOptions,
worldOptions.generator.newGenerator(this, worldName),
plugin.storage,
plugin.globalAddedData,
plugin.globalPrivileges,
::DefaultParcelContainer)
} catch (ex: Exception) {

View File

@@ -15,7 +15,7 @@ class ParcelWorldImpl(override val world: World,
override val generator: ParcelGenerator,
override var options: RuntimeWorldOptions,
override val storage: Storage,
override val globalAddedData: GlobalAddedDataManager,
val globalPrivileges: GlobalPrivilegesManager,
containerFactory: ParcelContainerFactory,
coroutineScope: CoroutineScope,
worktimeLimiter: WorktimeLimiter)

View File

@@ -36,7 +36,7 @@ class ParcelListeners(
val entityTracker: ParcelEntityTracker,
val storage: Storage
) {
private inline fun Parcel?.canBuildN(user: Player) = isPresentAnd { canBuild(user) } || user.hasBuildAnywhere
private inline fun Parcel?.canBuildN(user: Player) = isPresentAnd { canBuild(user) } || user.hasPermBuildAnywhere
/**
* Get the world and parcel that the block resides in
@@ -55,9 +55,9 @@ class ParcelListeners(
@field:ListenerMarker(priority = NORMAL)
val onPlayerMoveEvent = RegistratorListener<PlayerMoveEvent> l@{ event ->
val user = event.player
if (user.hasBanBypass) return@l
if (user.hasPermBanBypass) return@l
val parcel = parcelProvider.getParcelAt(event.to) ?: return@l
if (parcel.isBanned(user.statusKey)) {
if (parcel.isBanned(user.privilegeKey)) {
parcelProvider.getParcelAt(event.from)?.also {
user.teleport(it.homeLocation)
user.sendParcelMessage(nopermit = true, message = "You are banned from this parcel")
@@ -72,7 +72,7 @@ class ParcelListeners(
@field:ListenerMarker(priority = NORMAL)
val onBlockBreakEvent = RegistratorListener<BlockBreakEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.block) ?: return@l
if (!event.player.hasBuildAnywhere && ppa.isNullOr { !canBuild(event.player) }) {
if (!event.player.hasPermBuildAnywhere && ppa.isNullOr { !canBuild(event.player) }) {
event.isCancelled = true; return@l
}
@@ -91,7 +91,7 @@ class ParcelListeners(
@field:ListenerMarker(priority = NORMAL)
val onBlockPlaceEvent = RegistratorListener<BlockPlaceEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.block) ?: return@l
if (!event.player.hasBuildAnywhere && ppa.isNullOr { !canBuild(event.player) }) {
if (!event.player.hasPermBuildAnywhere && ppa.isNullOr { !canBuild(event.player) }) {
event.isCancelled = true
}
}
@@ -185,7 +185,7 @@ class ParcelListeners(
val clickedBlock = event.clickedBlock
val parcel = clickedBlock?.let { world.getParcelAt(it) }
if (!user.hasBuildAnywhere && parcel.isPresentAnd { isBanned(user.statusKey) }) {
if (!user.hasPermBuildAnywhere && parcel.isPresentAnd { isBanned(user.privilegeKey) }) {
user.sendParcelMessage(nopermit = true, message = "You cannot interact with parcels you're banned from")
event.isCancelled = true; return@l
}
@@ -218,7 +218,7 @@ class ParcelListeners(
}
Action.RIGHT_CLICK_AIR -> onPlayerInteractEvent_RightClick(event, world, parcel)
Action.PHYSICAL -> if (!user.hasBuildAnywhere && !parcel.isPresentAnd { canBuild(user) || interactableConfig("pressure_plates") }) {
Action.PHYSICAL -> if (!user.hasPermBuildAnywhere && !parcel.isPresentAnd { canBuild(user) || interactableConfig("pressure_plates") }) {
user.sendParcelMessage(nopermit = true, message = "You cannot use inputs in this parcel")
event.isCancelled = true; return@l
}
@@ -484,7 +484,7 @@ class ParcelListeners(
event.isCancelled = true; return@l
}
if (!event.player.hasBuildAnywhere && !ppa.canBuild(event.player)) {
if (!event.player.hasPermBuildAnywhere && !ppa.canBuild(event.player)) {
event.isCancelled = true; return@l
}
@@ -560,7 +560,7 @@ class ParcelListeners(
@field:ListenerMarker(priority = NORMAL)
val onPlayerChangedWorldEvent = RegistratorListener<PlayerChangedWorldEvent> l@{ event ->
val world = parcelProvider.getWorld(event.player.world) ?: return@l
if (world.options.gameMode != null && !event.player.hasGamemodeBypass) {
if (world.options.gameMode != null && !event.player.hasPermGamemodeBypass) {
event.player.gameMode = world.options.gameMode
}
}

View File

@@ -4,7 +4,6 @@ import com.sk89q.worldedit.EditSession.Stage.BEFORE_REORDER
import com.sk89q.worldedit.Vector
import com.sk89q.worldedit.Vector2D
import com.sk89q.worldedit.WorldEdit
import com.sk89q.worldedit.WorldEditException
import com.sk89q.worldedit.bukkit.WorldEditPlugin
import com.sk89q.worldedit.event.extent.EditSessionEvent
import com.sk89q.worldedit.extent.AbstractDelegateExtent
@@ -12,11 +11,10 @@ import com.sk89q.worldedit.extent.Extent
import com.sk89q.worldedit.util.eventbus.EventHandler.Priority.VERY_EARLY
import com.sk89q.worldedit.util.eventbus.Subscribe
import com.sk89q.worldedit.world.biome.BaseBiome
import com.sk89q.worldedit.world.block.BaseBlock
import com.sk89q.worldedit.world.block.BlockStateHolder
import io.dico.parcels2.ParcelWorld
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.util.ext.hasBuildAnywhere
import io.dico.parcels2.util.ext.hasPermBuildAnywhere
import io.dico.parcels2.util.ext.sendParcelMessage
import org.bukkit.entity.Player
import org.bukkit.plugin.Plugin
@@ -33,7 +31,7 @@ class WorldEditListener(val parcels: ParcelsPlugin, val worldEdit: WorldEdit) {
if (actor == null || !actor.isPlayer) return
val player = parcels.server.getPlayer(actor.uniqueId)
if (player.hasBuildAnywhere) return
if (player.hasPermBuildAnywhere) return
event.extent = ParcelsExtent(event.extent, world, player)
}

View File

@@ -1,13 +1,13 @@
package io.dico.parcels2.storage
import io.dico.parcels2.*
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.ReceiveChannel
import kotlinx.coroutines.channels.SendChannel
import org.joda.time.DateTime
import java.util.UUID
import kotlin.coroutines.CoroutineContext
interface Backing {
@@ -15,7 +15,7 @@ interface Backing {
val isConnected: Boolean
val dispatcher: CoroutineDispatcher
val coroutineContext: CoroutineContext
fun launchJob(job: Backing.() -> Unit): Job
@@ -56,9 +56,9 @@ interface Backing {
fun setParcelOwnerSignOutdated(parcel: ParcelId, outdated: Boolean)
fun setLocalPlayerStatus(parcel: ParcelId, player: PlayerProfile, status: AddedStatus)
fun setLocalPrivilege(parcel: ParcelId, player: PlayerProfile, status: Privilege)
fun setParcelOptionsInteractBitmask(parcel: ParcelId, bitmask: IntArray?)
fun setParcelOptionsInteractConfig(parcel: ParcelId, config: InteractableConfiguration)
/*
fun setParcelAllowsInteractInventory(parcel: ParcelId, value: Boolean)
@@ -67,7 +67,7 @@ interface Backing {
fun transmitAllGlobalAddedData(channel: SendChannel<AddedDataPair<PlayerProfile>>)
fun readGlobalAddedData(owner: PlayerProfile): MutableAddedDataMap
fun readGlobalPrivileges(owner: PlayerProfile): MutablePrivilegeMap
fun setGlobalPlayerStatus(owner: PlayerProfile, player: PlayerProfile, status: AddedStatus)
fun setGlobalPrivilege(owner: PlayerProfile, player: PlayerProfile, status: Privilege)
}

View File

@@ -3,6 +3,7 @@
package io.dico.parcels2.storage
import io.dico.parcels2.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.ReceiveChannel
@@ -10,9 +11,10 @@ import kotlinx.coroutines.channels.SendChannel
import kotlinx.coroutines.launch
import org.joda.time.DateTime
import java.util.UUID
import kotlin.coroutines.CoroutineContext
typealias DataPair = Pair<ParcelId, ParcelData?>
typealias AddedDataPair<TAttach> = Pair<TAttach, MutableAddedDataMap>
typealias AddedDataPair<TAttach> = Pair<TAttach, MutablePrivilegeMap>
interface Storage {
val name: String
@@ -48,28 +50,29 @@ interface Storage {
fun setParcelOwnerSignOutdated(parcel: ParcelId, outdated: Boolean): Job
fun setParcelPlayerStatus(parcel: ParcelId, player: PlayerProfile, status: AddedStatus): Job
fun setLocalPrivilege(parcel: ParcelId, player: PlayerProfile, privilege: Privilege): Job
fun setParcelOptionsInteractBitmask(parcel: ParcelId, bitmask: IntArray): Job
fun setParcelOptionsInteractConfig(parcel: ParcelId, config: InteractableConfiguration): Job
fun transmitAllGlobalAddedData(): ReceiveChannel<AddedDataPair<PlayerProfile>>
fun readGlobalAddedData(owner: PlayerProfile): Deferred<MutableAddedDataMap?>
fun readGlobalPrivileges(owner: PlayerProfile): Deferred<MutablePrivilegeMap?>
fun setGlobalAddedStatus(owner: PlayerProfile, player: PlayerProfile, status: AddedStatus): Job
fun setGlobalPrivilege(owner: PlayerProfile, player: PlayerProfile, status: Privilege): Job
fun getChannelToUpdateParcelData(): SendChannel<Pair<ParcelId, ParcelData>>
}
class BackedStorage internal constructor(val b: Backing) : Storage {
class BackedStorage internal constructor(val b: Backing) : Storage, CoroutineScope {
override val name get() = b.name
override val isConnected get() = b.isConnected
override val coroutineContext: CoroutineContext get() = b.coroutineContext
override fun init() = launch(b.dispatcher) { b.init() }
override fun init() = launch { b.init() }
override fun shutdown() = launch(b.dispatcher) { b.shutdown() }
override fun shutdown() = launch { b.shutdown() }
override fun getWorldCreationTime(worldId: ParcelWorldId): Deferred<DateTime?> = b.launchFuture { b.getWorldCreationTime(worldId) }
@@ -96,16 +99,16 @@ class BackedStorage internal constructor(val b: Backing) : Storage {
override fun setParcelOwnerSignOutdated(parcel: ParcelId, outdated: Boolean): Job = b.launchJob { b.setParcelOwnerSignOutdated(parcel, outdated) }
override fun setParcelPlayerStatus(parcel: ParcelId, player: PlayerProfile, status: AddedStatus) = b.launchJob { b.setLocalPlayerStatus(parcel, player, status) }
override fun setLocalPrivilege(parcel: ParcelId, player: PlayerProfile, privilege: Privilege) = b.launchJob { b.setLocalPrivilege(parcel, player, privilege) }
override fun setParcelOptionsInteractBitmask(parcel: ParcelId, bitmask: IntArray) = b.launchJob { b.setParcelOptionsInteractBitmask(parcel, bitmask) }
override fun setParcelOptionsInteractConfig(parcel: ParcelId, config: InteractableConfiguration) = b.launchJob { b.setParcelOptionsInteractConfig(parcel, config) }
override fun transmitAllGlobalAddedData(): ReceiveChannel<AddedDataPair<PlayerProfile>> = b.openChannel { b.transmitAllGlobalAddedData(it) }
override fun readGlobalAddedData(owner: PlayerProfile): Deferred<MutableAddedDataMap?> = b.launchFuture { b.readGlobalAddedData(owner) }
override fun readGlobalPrivileges(owner: PlayerProfile): Deferred<MutablePrivilegeMap?> = b.launchFuture { b.readGlobalPrivileges(owner) }
override fun setGlobalAddedStatus(owner: PlayerProfile, player: PlayerProfile, status: AddedStatus) = b.launchJob { b.setGlobalPlayerStatus(owner, player, status) }
override fun setGlobalPrivilege(owner: PlayerProfile, player: PlayerProfile, status: Privilege) = b.launchJob { b.setGlobalPrivilege(owner, player, status) }
override fun getChannelToUpdateParcelData(): SendChannel<Pair<ParcelId, ParcelData>> = b.openChannelForWriting { b.setParcelData(it.first, it.second) }
}

View File

@@ -23,17 +23,16 @@ import javax.sql.DataSource
class ExposedDatabaseException(message: String? = null) : Exception(message)
class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSize: Int) : Backing {
class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSize: Int) : Backing, CoroutineScope {
override val name get() = "Exposed"
override val dispatcher: ThreadPoolDispatcher = newFixedThreadPoolContext(poolSize, "Parcels StorageThread")
override val coroutineContext = Job() + newFixedThreadPoolContext(poolSize, "Parcels StorageThread")
private var dataSource: DataSource? = null
private var database: Database? = null
private var isShutdown: Boolean = false
override val isConnected get() = database != null
override fun launchJob(job: Backing.() -> Unit): Job = launch(dispatcher) { transaction { job() } }
override fun <T> launchFuture(future: Backing.() -> T): Deferred<T> = async(dispatcher) { transaction { future() } }
override fun launchJob(job: Backing.() -> Unit): Job = launch { transaction { job() } }
override fun <T> launchFuture(future: Backing.() -> T): Deferred<T> = async { transaction { future() } }
override fun <T> openChannel(future: Backing.(SendChannel<T>) -> Unit): ReceiveChannel<T> {
val channel = LinkedListChannel<T>()
@@ -44,8 +43,8 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
override fun <T> openChannelForWriting(action: Backing.(T) -> Unit): SendChannel<T> {
val channel = ArrayChannel<T>(poolSize * 2)
repeat(poolSize) {
launch(dispatcher) {
repeat(poolSize.clampMax(3)) {
launch {
try {
while (true) {
action(channel.receive())
@@ -75,7 +74,7 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
dataSource = dataSourceFactory()
database = Database.connect(dataSource!!)
transaction(database!!) {
create(WorldsT, ProfilesT, ParcelsT, ParcelOptionsT, AddedLocalT, AddedGlobalT)
create(WorldsT, ProfilesT, ParcelsT, ParcelOptionsT, PrivilegesLocalT, PrivilegesGlobalT)
}
}
}
@@ -83,11 +82,12 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
override fun shutdown() {
synchronized {
if (isShutdown) throw IllegalStateException()
isShutdown = true
coroutineContext[Job]!!.cancel(CancellationException("ExposedBacking shutdown"))
dataSource?.let {
(it as? HikariDataSource)?.close()
}
database = null
isShutdown = true
}
}
@@ -173,7 +173,7 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
// Below should cascade automatically
/*
AddedLocalT.deleteIgnoreWhere { AddedLocalT.parcel_id eq id }
PrivilegesLocalT.deleteIgnoreWhere { PrivilegesLocalT.parcel_id eq id }
ParcelOptionsT.deleteIgnoreWhere(limit = 1) { ParcelOptionsT.parcel_id eq id }
*/
}
@@ -184,18 +184,16 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
transaction {
val id = ParcelsT.getOrInitId(parcel)
AddedLocalT.deleteIgnoreWhere { AddedLocalT.attach_id eq id }
PrivilegesLocalT.deleteIgnoreWhere { PrivilegesLocalT.attach_id eq id }
}
setParcelOwner(parcel, data.owner)
for ((profile, status) in data.addedMap) {
AddedLocalT.setPlayerStatus(parcel, profile, status)
for ((profile, privilege) in data.map) {
PrivilegesLocalT.setPrivilege(parcel, profile, privilege)
}
val bitmaskArray = (data.interactableConfig as? BitmaskInteractableConfiguration ?: return).bitmaskArray
val isAllZero = bitmaskArray.fold(false) { cur, elem -> cur || elem != 0 }
setParcelOptionsInteractBitmask(parcel, if (isAllZero) null else bitmaskArray)
setParcelOptionsInteractConfig(parcel, data.interactableConfig)
}
override fun setParcelOwner(parcel: ParcelId, owner: PlayerProfile?) {
@@ -221,19 +219,22 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
}
}
override fun setLocalPlayerStatus(parcel: ParcelId, player: PlayerProfile, status: AddedStatus) {
AddedLocalT.setPlayerStatus(parcel, player.toRealProfile(), status)
override fun setLocalPrivilege(parcel: ParcelId, player: PlayerProfile, privilege: Privilege) {
PrivilegesLocalT.setPrivilege(parcel, player.toRealProfile(), privilege)
}
override fun setParcelOptionsInteractBitmask(parcel: ParcelId, bitmask: IntArray?) {
if (bitmask == null) {
override fun setParcelOptionsInteractConfig(parcel: ParcelId, config: InteractableConfiguration) {
val bitmaskArray = (config as? BitmaskInteractableConfiguration ?: return).bitmaskArray
val isAllZero = !bitmaskArray.fold(false) { cur, elem -> cur || elem != 0 }
if (isAllZero) {
val id = ParcelsT.getId(parcel) ?: return
ParcelOptionsT.deleteWhere { ParcelOptionsT.parcel_id eq id }
return
}
if (bitmask.size != 1) throw IllegalArgumentException()
val array = bitmask.toByteArray()
if (bitmaskArray.size != 1) throw IllegalArgumentException()
val array = bitmaskArray.toByteArray()
val id = ParcelsT.getOrInitId(parcel)
ParcelOptionsT.upsert(ParcelOptionsT.parcel_id) {
it[parcel_id] = id
@@ -242,16 +243,16 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
}
override fun transmitAllGlobalAddedData(channel: SendChannel<AddedDataPair<PlayerProfile>>) {
AddedGlobalT.sendAllAddedData(channel)
PrivilegesGlobalT.sendAllAddedData(channel)
channel.close()
}
override fun readGlobalAddedData(owner: PlayerProfile): MutableAddedDataMap {
return AddedGlobalT.readAddedData(ProfilesT.getId(owner.toOwnerProfile()) ?: return hashMapOf())
override fun readGlobalPrivileges(owner: PlayerProfile): MutablePrivilegeMap {
return PrivilegesGlobalT.readPrivileges(ProfilesT.getId(owner.toOwnerProfile()) ?: return hashMapOf())
}
override fun setGlobalPlayerStatus(owner: PlayerProfile, player: PlayerProfile, status: AddedStatus) {
AddedGlobalT.setPlayerStatus(owner, player.toRealProfile(), status)
override fun setGlobalPrivilege(owner: PlayerProfile, player: PlayerProfile, privilege: Privilege) {
PrivilegesGlobalT.setPrivilege(owner, player.toRealProfile(), privilege)
}
private fun rowToParcelData(row: ResultRow) = ParcelDataHolder().apply {
@@ -266,7 +267,7 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
System.arraycopy(source, 0, target, 0, source.size.clampMax(target.size))
}
addedMap = AddedLocalT.readAddedData(id)
map = PrivilegesLocalT.readPrivileges(id)
}
}

View File

@@ -26,7 +26,7 @@ abstract class IdTransactionsTable<TableT : IdTransactionsTable<TableT, QueryObj
internal inline fun getOrInitId(getId: () -> Int?, noinline body: TableT.(UpdateBuilder<*>) -> Unit, objName: () -> String): Int {
return getId() ?: table.insertIgnore(body)[id] ?: getId()
?: throw ExposedDatabaseException("This should not happen - failed to insert ${objName()} and get its id")
?: throw ExposedDatabaseException("This should not happen - failed to insert ${objName()} and get its number")
}
abstract fun getId(obj: QueryObj): Int?

View File

@@ -3,30 +3,30 @@
package io.dico.parcels2.storage.exposed
import io.dico.parcels2.*
import io.dico.parcels2.AddedStatus.ALLOWED
import io.dico.parcels2.AddedStatus.DEFAULT
import io.dico.parcels2.Privilege.DEFAULT
import kotlinx.coroutines.channels.SendChannel
import org.jetbrains.exposed.sql.*
import java.util.UUID
object AddedLocalT : AddedTable<ParcelId>("parcels_added_local", ParcelsT)
object AddedGlobalT : AddedTable<PlayerProfile>("parcels_added_global", ProfilesT)
object PrivilegesLocalT : PrivilegesTable<ParcelId>("parcels_added_local", ParcelsT)
object PrivilegesGlobalT : PrivilegesTable<PlayerProfile>("parcels_added_global", ProfilesT)
object ParcelOptionsT : Table("parcel_options") {
val parcel_id = integer("parcel_id").primaryKey().references(ParcelsT.id, ReferenceOption.CASCADE)
val interact_bitmask = binary("interact_bitmask", 4).default(ByteArray(4) { 0 }) // all zero by default
val interact_bitmask = binary("interact_bitmask", 4)
}
typealias AddedStatusSendChannel<AttachT> = SendChannel<Pair<AttachT, MutableAddedDataMap>>
typealias PrivilegesSendChannel<AttachT> = SendChannel<Pair<AttachT, MutablePrivilegeMap>>
sealed class AddedTable<AttachT>(name: String, val idTable: IdTransactionsTable<*, AttachT>) : Table(name) {
sealed class PrivilegesTable<AttachT>(name: String, val idTable: IdTransactionsTable<*, AttachT>) : Table(name) {
val attach_id = integer("attach_id").references(idTable.id, ReferenceOption.CASCADE)
val profile_id = integer("profile_id").references(ProfilesT.id, ReferenceOption.CASCADE)
val allowed_flag = bool("allowed_flag")
val privilege = integer("privilege")
val index_pair = uniqueIndexR("index_pair", attach_id, profile_id)
fun setPlayerStatus(attachedOn: AttachT, player: PlayerProfile.Real, status: AddedStatus) {
if (status == DEFAULT) {
fun setPrivilege(attachedOn: AttachT, player: PlayerProfile.Real, privilege: Privilege) {
privilege.requireNonTransient()
if (privilege == DEFAULT) {
val player_id = ProfilesT.getId(player) ?: return
idTable.getId(attachedOn)?.let { holder ->
deleteWhere { (attach_id eq holder) and (profile_id eq player_id) }
@@ -39,28 +39,28 @@ sealed class AddedTable<AttachT>(name: String, val idTable: IdTransactionsTable<
upsert(conflictIndex = index_pair) {
it[attach_id] = holder
it[profile_id] = player_id
it[allowed_flag] = status == ALLOWED
it[this.privilege] = privilege.number
}
}
fun readAddedData(id: Int): MutableAddedDataMap {
val list = slice(profile_id, allowed_flag).select { attach_id eq id }
val result = MutableAddedDataMap()
fun readPrivileges(id: Int): MutablePrivilegeMap {
val list = slice(profile_id, privilege).select { attach_id eq id }
val result = MutablePrivilegeMap()
for (row in list) {
val profile = ProfilesT.getRealItem(row[profile_id]) ?: continue
result[profile] = row[allowed_flag].asAddedStatus()
result[profile] = Privilege.safeGetByNumber(row[privilege]) ?: continue
}
return result
}
fun sendAllAddedData(channel: AddedStatusSendChannel<AttachT>) {
fun sendAllAddedData(channel: PrivilegesSendChannel<AttachT>) {
val iterator = selectAll().orderBy(attach_id).iterator()
if (iterator.hasNext()) {
val firstRow = iterator.next()
var id: Int = firstRow[attach_id]
var attach: AttachT? = null
var map: MutableAddedDataMap? = null
var map: MutablePrivilegeMap? = null
fun initAttachAndMap() {
attach = idTable.getItem(id)
@@ -90,14 +90,12 @@ sealed class AddedTable<AttachT>(name: String, val idTable: IdTransactionsTable<
}
val profile = ProfilesT.getRealItem(row[profile_id]) ?: continue
val status = row[allowed_flag].asAddedStatus()
map!![profile] = status
val privilege = Privilege.safeGetByNumber(row[privilege]) ?: continue
map!![profile] = privilege
}
sendIfPresent()
}
}
private inline fun Boolean?.asAddedStatus() = if (this == null) AddedStatus.DEFAULT else if (this) ALLOWED else AddedStatus.BANNED
}

View File

@@ -66,11 +66,11 @@ class PlotmeMigration(val options: PlotmeMigrationOptions) : Migration {
return ParcelId(world, row[table.px], row[table.pz])
}
fun PlotmePlotPlayerMap.transmitPlotmeAddedTable(kind: AddedStatus) {
fun PlotmePlotPlayerMap.transmitPlotmeAddedTable(kind: Privilege) {
selectAll().forEach { row ->
val parcel = getParcelId(this, row) ?: return@forEach
val profile = StatusKey.safe(row[player_uuid]?.toUUID(), row[player_name]) ?: return@forEach
target.setParcelPlayerStatus(parcel, profile, kind)
target.setLocalPrivilege(parcel, profile, kind)
}
}
@@ -89,12 +89,12 @@ class PlotmeMigration(val options: PlotmeMigrationOptions) : Migration {
mlogger.info("Transmitting data from plotmeallowed table")
transaction {
PlotmeAllowedT.transmitPlotmeAddedTable(AddedStatus.ALLOWED)
PlotmeAllowedT.transmitPlotmeAddedTable(Privilege.CAN_BUILD)
}
mlogger.info("Transmitting data from plotmedenied table")
transaction {
PlotmeDeniedT.transmitPlotmeAddedTable(AddedStatus.BANNED)
PlotmeDeniedT.transmitPlotmeAddedTable(Privilege.BANNED)
}
mlogger.warn("Data has been **transmitted**.")

View File

@@ -13,12 +13,12 @@ inline val OfflinePlayer.uuid get() = uniqueId
inline val OfflinePlayer.isValid
get() = isOnline() || hasPlayedBefore()
inline val Player.hasBanBypass get() = hasPermission("parcels.admin.bypass.ban")
inline val Player.hasGamemodeBypass get() = hasPermission("parcels.admin.bypass.gamemode")
inline val Player.hasBuildAnywhere get() = hasPermission("parcels.admin.bypass.build")
inline val Player.hasAdminManage get() = hasPermission("parcels.admin.manage")
inline val Player.hasPermBanBypass get() = hasPermission("parcels.admin.bypass.ban")
inline val Player.hasPermGamemodeBypass get() = hasPermission("parcels.admin.bypass.gamemode")
inline val Player.hasPermBuildAnywhere get() = hasPermission("parcels.admin.bypass.build")
inline val Player.hasPermAdminManage get() = hasPermission("parcels.admin.manage")
inline val Player.hasParcelHomeOthers get() = hasPermission("parcels.command.home.others")
inline val Player.hasRandomSpecific get() = hasPermission("parcels.command.random.specific")
inline val Player.hasPermRandomSpecific get() = hasPermission("parcels.command.random.specific")
val Player.parcelLimit: Int
get() {
for (info in effectivePermissions) {