Archived
0

Fix privileges of *

This commit is contained in:
Dico
2018-09-27 02:58:06 +01:00
parent c486e99f1a
commit cdaba0ebd5
18 changed files with 392 additions and 254 deletions

View File

@@ -17,6 +17,10 @@ public class DefaultGroupCommand extends PredefinedCommand<DefaultGroupCommand>
this.modifiable = modifiable;
}
public DefaultGroupCommand() {
this(true);
}
@Override
protected DefaultGroupCommand newModifiableInstance() {
return new DefaultGroupCommand(true);

View File

@@ -38,7 +38,7 @@ interface Parcel : ParcelData, Privileges {
val homeLocation: Location get() = world.blockManager.getHomeLocation(id)
}
interface ParcelData : PrivilegesMinimal {
interface ParcelData : RawPrivileges {
var owner: PlayerProfile?
val lastClaimTime: DateTime?
var ownerSignOutdated: Boolean
@@ -60,12 +60,6 @@ class ParcelDataHolder(addedMap: MutablePrivilegeMap = mutableMapOf())
override var owner: PlayerProfile? = null
override var lastClaimTime: DateTime? = null
override var ownerSignOutdated = false
//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.hasPermBuildAnywhere)
override var interactableConfig: InteractableConfiguration = BitmaskInteractableConfiguration()
}

View File

@@ -115,7 +115,10 @@ interface PlayerProfile {
}
object Star : BaseImpl(), Real {
override val name: String = "*"
override val name get() = "*"
override val nameOrBukkitName get() = name
override val notNullName get() = name
// hopefully nobody will have this random UUID :)
override val uuid: UUID = UUID.fromString("7d09c4c6-117d-4f36-9778-c4d24618cee1")

View File

@@ -1,12 +1,17 @@
package io.dico.parcels2
import io.dico.parcels2.Privilege.*
import io.dico.parcels2.PrivilegeChangeResult.*
import io.dico.parcels2.util.ext.PERM_ADMIN_MANAGE
import io.dico.parcels2.util.ext.PERM_BAN_BYPASS
import io.dico.parcels2.util.ext.PERM_BUILD_ANYWHERE
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
import io.dico.parcels2.Privilege.DEFAULT
import java.util.Collections
typealias PrivilegeKey = PlayerProfile.Real
typealias PrivilegeMap = Map<PrivilegeKey, Privilege>
typealias MutablePrivilegeMap = MutableMap<PrivilegeKey, Privilege>
@Suppress("FunctionName")
fun MutablePrivilegeMap(): MutablePrivilegeMap = hashMapOf()
@Suppress("UNCHECKED_CAST")
val EmptyPrivilegeMap = Collections.emptyMap<Any, Any>() as MutablePrivilegeMap
enum class Privilege(
val number: Int,
@@ -21,7 +26,7 @@ enum class Privilege(
ADMIN(-1, transient = true);
fun isDistanceGrEq(other: Privilege): Boolean =
when { // used for example when disallowBuild is called and CAN_MANAGE is the privilege.
when {
other > DEFAULT -> this >= other
other == DEFAULT -> this == other
else -> this <= other
@@ -38,12 +43,6 @@ enum class Privilege(
return this
}
/*
fun canEnter() = this >= BANNED
fun canBuild() = this >= CAN_BUILD
fun canManage() = this >= CAN_MANAGE
*/
companion object {
fun getByNumber(id: Int) =
when (id) {
@@ -56,95 +55,44 @@ enum class Privilege(
}
}
typealias PrivilegeKey = PlayerProfile.Real
typealias MutablePrivilegeMap = MutableMap<PrivilegeKey, Privilege>
typealias PrivilegeMap = Map<PrivilegeKey, Privilege>
@Suppress("FunctionName")
fun MutablePrivilegeMap(): MutablePrivilegeMap = hashMapOf()
interface PrivilegesMinimal {
interface RawPrivileges {
val privilegeMap: PrivilegeMap
var privilegeOfStar: Privilege
fun getStoredPrivilege(key: PrivilegeKey): Privilege
fun setStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean
fun getRawStoredPrivilege(key: PrivilegeKey): Privilege
fun setRawStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean
}
interface Privileges : PrivilegesMinimal {
val keyOfOwner: PlayerProfile.Real?
open class PrivilegesHolder(override var privilegeMap: MutablePrivilegeMap = EmptyPrivilegeMap) : RawPrivileges {
private var _privilegeOfStar: Privilege = DEFAULT
fun privilege(player: OfflinePlayer): Privilege {
val key = player.privilegeKey
return if (key == keyOfOwner) OWNER
else getStoredPrivilege(key)
}
override var privilegeOfStar: Privilege
get() = _privilegeOfStar
set(value) = run { _privilegeOfStar = value }
fun privilege(player: OfflinePlayer, adminPerm: String): Privilege =
if (player is Player && player.hasPermission(adminPerm)) ADMIN
else {
val key = player.privilegeKey
if (key == keyOfOwner) OWNER
else getStoredPrivilege(key)
}
protected val isEmpty
inline get() = privilegeMap === EmptyPrivilegeMap
fun changePrivilege(key: PrivilegeKey, positive: Boolean, update: Privilege): PrivilegeChangeResult =
if (key == keyOfOwner) FAIL_OWNER
else if (getStoredPrivilege(key).isChangeInDirection(positive, update)
&& setStoredPrivilege(key, update)
) SUCCESS
else FAIL
override fun getRawStoredPrivilege(key: PrivilegeKey) =
if (key.isStar) _privilegeOfStar
else privilegeMap.getOrDefault(key, _privilegeOfStar)
fun canManage(player: OfflinePlayer) = privilege(player, PERM_ADMIN_MANAGE) >= CAN_MANAGE
fun allowManage(player: OfflinePlayer) = changePrivilege(player.privilegeKey, true, CAN_MANAGE)
fun disallowManage(player: OfflinePlayer) = changePrivilege(player.privilegeKey, false, CAN_BUILD)
fun canBuild(player: OfflinePlayer) = privilege(player, PERM_BUILD_ANYWHERE) >= CAN_BUILD
fun allowBuild(player: OfflinePlayer) = changePrivilege(player.privilegeKey, true, CAN_BUILD)
fun disallowBuild(player: OfflinePlayer) = changePrivilege(player.privilegeKey, false, DEFAULT)
fun canEnter(player: OfflinePlayer) = privilege(player, PERM_BAN_BYPASS) >= DEFAULT
fun ban(player: OfflinePlayer) = changePrivilege(player.privilegeKey, false, BANNED)
fun unban(player: OfflinePlayer) = changePrivilege(player.privilegeKey, true, DEFAULT)
/**
* same as [canBuild] but doesn't perform a permission check for admin perms
*/
fun canBuildFast(player: OfflinePlayer) = player.privilegeKey.let { if (it == keyOfOwner) OWNER else getStoredPrivilege(it)} >= CAN_BUILD
}
enum class PrivilegeChangeResult {
SUCCESS, FAIL, FAIL_OWNER
}
val OfflinePlayer.privilegeKey: PrivilegeKey
inline get() = PlayerProfile.nameless(this)
open class PrivilegesHolder(override var privilegeMap: MutablePrivilegeMap = MutablePrivilegeMap()) : PrivilegesMinimal {
private var privilegeOfStar: Privilege = DEFAULT
override fun getStoredPrivilege(key: PrivilegeKey) =
if (key.isStar) privilegeOfStar
else privilegeMap.getOrDefault(key, privilegeOfStar)
override fun setStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
override fun setRawStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
privilege.requireNonTransient()
if (key.isStar) {
if (privilegeOfStar == privilege) return false
privilegeOfStar = privilege
if (_privilegeOfStar == privilege) return false
_privilegeOfStar = privilege
return true
}
if (isEmpty) {
if (privilege == DEFAULT) return false
privilegeMap = MutablePrivilegeMap()
}
return if (privilege == DEFAULT) privilegeMap.remove(key) != null
else privilegeMap.put(key, privilege) != privilege
}
}
interface GlobalPrivileges : Privileges {
override val keyOfOwner: PlayerProfile.Real
}
interface GlobalPrivilegesManager {
operator fun get(owner: PlayerProfile.Real): GlobalPrivileges
operator fun get(owner: OfflinePlayer): GlobalPrivileges = get(owner.privilegeKey)
}

View File

@@ -0,0 +1,64 @@
package io.dico.parcels2
import io.dico.parcels2.PrivilegeChangeResult.*
import io.dico.parcels2.util.ext.PERM_ADMIN_MANAGE
import io.dico.parcels2.util.ext.PERM_BAN_BYPASS
import io.dico.parcels2.util.ext.PERM_BUILD_ANYWHERE
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
interface Privileges : RawPrivileges {
val keyOfOwner: PlayerProfile.Real?
fun getStoredPrivilege(key: PrivilegeKey): Privilege {
return if (key == keyOfOwner) Privilege.OWNER
else getRawStoredPrivilege(key)
}
override var privilegeOfStar: Privilege
get() = getStoredPrivilege(PlayerProfile.Star)
set(value) {
setRawStoredPrivilege(PlayerProfile.Star, value)
}
}
val OfflinePlayer.privilegeKey: PrivilegeKey
inline get() = PlayerProfile.nameless(this)
fun Privileges.getEffectivePrivilege(player: OfflinePlayer, adminPerm: String): Privilege =
if (player is Player && player.hasPermission(adminPerm)) Privilege.ADMIN
else getStoredPrivilege(player.privilegeKey)
fun Privileges.canManage(player: OfflinePlayer) = getEffectivePrivilege(player, PERM_ADMIN_MANAGE) >= Privilege.CAN_MANAGE
fun Privileges.canManageFast(player: OfflinePlayer) = getStoredPrivilege(player.privilegeKey) >= Privilege.CAN_MANAGE
fun Privileges.canBuild(player: OfflinePlayer) = getEffectivePrivilege(player, PERM_BUILD_ANYWHERE) >= Privilege.CAN_BUILD
fun Privileges.canBuildFast(player: OfflinePlayer) = getStoredPrivilege(player.privilegeKey) >= Privilege.CAN_BUILD
fun Privileges.canEnter(player: OfflinePlayer) = getEffectivePrivilege(player, PERM_BAN_BYPASS) >= Privilege.DEFAULT
fun Privileges.canEnterFast(player: OfflinePlayer) = getStoredPrivilege(player.privilegeKey) >= Privilege.DEFAULT
enum class PrivilegeChangeResult {
SUCCESS, FAIL, FAIL_OWNER
}
fun Privileges.changePrivilege(key: PrivilegeKey, positive: Boolean, update: Privilege): PrivilegeChangeResult =
when {
key == keyOfOwner -> FAIL_OWNER
getRawStoredPrivilege(key).isChangeInDirection(positive, update) && setRawStoredPrivilege(key, update) -> SUCCESS
else -> FAIL
}
fun Privileges.allowManage(key: PrivilegeKey) = changePrivilege(key, true, Privilege.CAN_MANAGE)
fun Privileges.disallowManage(key: PrivilegeKey) = changePrivilege(key, false, Privilege.CAN_BUILD)
fun Privileges.allowBuild(key: PrivilegeKey) = changePrivilege(key, true, Privilege.CAN_BUILD)
fun Privileges.disallowBuild(key: PrivilegeKey) = changePrivilege(key, false, Privilege.DEFAULT)
fun Privileges.allowEnter(key: PrivilegeKey) = changePrivilege(key, true, Privilege.DEFAULT)
fun Privileges.disallowEnter(key: PrivilegeKey) = changePrivilege(key, false, Privilege.BANNED)
interface GlobalPrivileges : RawPrivileges, Privileges {
override val keyOfOwner: PlayerProfile.Real
}
interface GlobalPrivilegesManager {
operator fun get(owner: PlayerProfile.Real): GlobalPrivileges
operator fun get(owner: OfflinePlayer): GlobalPrivileges = get(owner.privilegeKey)
}

View File

@@ -83,9 +83,9 @@ sealed class RegionTraverser {
private fun slice(region: Region, atY: Int): Pair<Region, Region?> {
if (atY < region.size.y + 1) {
val first = Region(region.origin, region.size.withY(atY + 1))
val second = Region(region.origin.withY(atY), region.size.addY(-atY - 1))
return first to second
val bottom = Region(region.origin, region.size.withY(atY + 1))
val top = Region(region.origin.withY(atY + 1), region.size.addY(-atY - 1))
return bottom to top
}
return region to null
}

View File

@@ -4,6 +4,8 @@ import io.dico.dicore.command.*
import io.dico.parcels2.ParcelWorld
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.PlayerProfile
import io.dico.parcels2.PlayerProfile.*
import io.dico.parcels2.PrivilegeKey
import io.dico.parcels2.blockvisitor.Worker
import io.dico.parcels2.util.ext.hasPermAdminManage
import io.dico.parcels2.util.ext.parcelLimit
@@ -37,6 +39,13 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei
}
}
protected suspend fun toPrivilegeKey(profile: PlayerProfile): PrivilegeKey = when (profile) {
is Real -> profile
is Unresolved -> profile.tryResolveSuspendedly(plugin.storage)
?: throw CommandException()
else -> throw CommandException()
}
protected fun areYouSureMessage(context: ExecutionContext) = "Are you sure? You cannot undo this action!\n" +
"Run \"/${context.route.joinToString(" ")} -sure\" if you want to go through with this."

View File

@@ -0,0 +1,110 @@
@file:Suppress("NON_EXHAUSTIVE_WHEN")
package io.dico.parcels2.command
import io.dico.dicore.command.ExecutionContext
import io.dico.dicore.command.Validate
import io.dico.dicore.command.annotation.Cmd
import io.dico.dicore.command.annotation.Desc
import io.dico.parcels2.*
import io.dico.parcels2.PrivilegeChangeResult.*
import io.dico.parcels2.util.ext.PERM_ADMIN_MANAGE
import io.dico.parcels2.util.ext.hasPermAdminManage
import org.bukkit.OfflinePlayer
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
class CommandsAdminPrivilegesGlobal(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
private val data
inline get() = plugin.globalPrivileges
private fun checkContext(context: ExecutionContext, owner: OfflinePlayer): OfflinePlayer {
val sender = context.sender
if (sender !== owner) {
Validate.isAuthorized(sender, PERM_ADMIN_MANAGE)
}
return owner
}
@Cmd("entrust")
@Desc(
"Allows a player to manage globally",
shortVersion = "allows a player to manage globally"
)
suspend fun cmdEntrust(context: ExecutionContext, owner: OfflinePlayer, player: PlayerProfile): Any? =
when (data[checkContext(context, owner)].allowManage(toPrivilegeKey(player))) {
FAIL_OWNER -> err("The target cannot be the owner themselves")
FAIL -> err("${player.name} is already allowed to manage globally")
SUCCESS -> "${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"
)
suspend fun cmdDistrust(context: ExecutionContext, owner: OfflinePlayer, player: PlayerProfile): Any? =
when (data[checkContext(context, owner)].disallowManage(toPrivilegeKey(player))) {
FAIL_OWNER -> err("The target cannot be the owner themselves")
FAIL -> err("${player.name} is not currently allowed to manage globally")
SUCCESS -> "${player.name} is not allowed to manage globally anymore"
}
@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"
)
suspend fun cmdAllow(context: ExecutionContext, owner: OfflinePlayer, player: PlayerProfile): Any? =
when (data[checkContext(context, owner)].allowBuild(toPrivilegeKey(player))) {
FAIL_OWNER -> err("The target cannot be the owner themselves")
FAIL -> err("${player.name} is already allowed globally")
SUCCESS -> "${player.name} is now allowed to build globally"
}
@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"
)
suspend fun cmdDisallow(context: ExecutionContext, owner: OfflinePlayer, player: PlayerProfile): Any? =
when (data[checkContext(context, owner)].disallowBuild(toPrivilegeKey(player))) {
FAIL_OWNER -> err("The target cannot be the owner themselves")
FAIL -> err("${player.name} is not currently allowed globally")
SUCCESS -> "${player.name} is not allowed to build globally 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"
)
suspend fun cmdBan(context: ExecutionContext, owner: OfflinePlayer, player: PlayerProfile): Any? =
when (data[checkContext(context, owner)].disallowEnter(toPrivilegeKey(player))) {
FAIL_OWNER -> err("The target cannot be the owner themselves")
FAIL -> err("${player.name} is already banned globally")
SUCCESS -> "${player.name} is now banned globally"
}
@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"
)
suspend fun cmdUnban(context: ExecutionContext, owner: OfflinePlayer, player: PlayerProfile): Any? =
when (data[checkContext(context, owner)].allowEnter(toPrivilegeKey(player))) {
FAIL_OWNER -> err("The target cannot be the owner themselves")
FAIL -> err("${player.name} is not currently banned globally")
SUCCESS -> "${player.name} is not banned globally anymore"
}
}

View File

@@ -1,29 +1,21 @@
@file:Suppress("NON_EXHAUSTIVE_WHEN")
package io.dico.parcels2.command
import io.dico.dicore.command.ExecutionContext
import io.dico.dicore.command.annotation.Cmd
import io.dico.dicore.command.annotation.Desc
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.PrivilegeChangeResult.*
import org.bukkit.OfflinePlayer
import io.dico.parcels2.PlayerProfile
import org.bukkit.entity.Player
class CommandsPrivilegesGlobal(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
private val data
inline get() = plugin.globalPrivileges
class CommandsPrivilegesGlobal(plugin: ParcelsPlugin,
val adminVersion: CommandsAdminPrivilegesGlobal) : AbstractParcelCommands(plugin) {
@Cmd("entrust")
@Desc(
"Allows a player to manage this parcel",
shortVersion = "allows a player to manage this parcel"
"Allows a player to manage globally",
shortVersion = "allows a player to manage globally"
)
fun cmdEntrust(sender: Player, player: OfflinePlayer): Any? =
when (data[sender].allowManage(player)) {
FAIL_OWNER -> err("The target cannot be yourself")
FAIL -> err("${player.name} is already allowed to manage globally")
SUCCESS -> "${player.name} is now allowed to manage globally"
}
suspend fun cmdEntrust(sender: Player, context: ExecutionContext, player: PlayerProfile) =
adminVersion.cmdEntrust(context, sender, player)
@Cmd("distrust")
@Desc(
@@ -31,12 +23,8 @@ class CommandsPrivilegesGlobal(plugin: ParcelsPlugin) : AbstractParcelCommands(p
"they will still be able to build",
shortVersion = "disallows a player to manage globally"
)
fun cmdDistrust(sender: Player, player: OfflinePlayer): Any? =
when (data[sender].disallowManage(player)) {
FAIL_OWNER -> err("The target cannot be yourself")
FAIL -> err("${player.name} is not currently allowed to manage globally")
SUCCESS -> "${player.name} is not allowed to manage globally anymore"
}
suspend fun cmdDistrust(sender: Player, context: ExecutionContext, player: PlayerProfile) =
adminVersion.cmdDistrust(context, sender, player)
@Cmd("allow", aliases = ["add", "permit"])
@Desc(
@@ -44,12 +32,8 @@ class CommandsPrivilegesGlobal(plugin: ParcelsPlugin) : AbstractParcelCommands(p
"the parcels that you own.",
shortVersion = "globally allows a player to build on your parcels"
)
fun cmdAllow(sender: Player, player: OfflinePlayer): Any? =
when (data[sender].allowBuild(player)) {
FAIL_OWNER -> err("The target cannot be yourself")
FAIL -> err("${player.name} is already allowed globally")
SUCCESS -> "${player.name} is now allowed to build on all your parcels"
}
suspend fun cmdAllow(sender: Player, context: ExecutionContext, player: PlayerProfile) =
adminVersion.cmdAllow(context, sender, player)
@Cmd("disallow", aliases = ["remove", "forbid"])
@Desc(
@@ -59,12 +43,8 @@ class CommandsPrivilegesGlobal(plugin: ParcelsPlugin) : AbstractParcelCommands(p
"parcels, they can still build there.",
shortVersion = "globally disallows a player to build on your parcels"
)
fun cmdDisallow(sender: Player, player: OfflinePlayer): Any? =
when (data[sender].disallowBuild(player)) {
FAIL_OWNER -> err("The target cannot be yourself")
FAIL -> err("${player.name} is not currently allowed globally")
SUCCESS -> "${player.name} is not allowed to build on all your parcels anymore"
}
suspend fun cmdDisallow(sender: Player, context: ExecutionContext, player: PlayerProfile) =
adminVersion.cmdDisallow(context, sender, player)
@Cmd("ban", aliases = ["deny"])
@Desc(
@@ -72,12 +52,8 @@ class CommandsPrivilegesGlobal(plugin: ParcelsPlugin) : AbstractParcelCommands(p
"that you own, making them unable to enter.",
shortVersion = "globally bans a player from your parcels"
)
fun cmdBan(sender: Player, player: OfflinePlayer): Any? =
when (data[sender].ban(player)) {
FAIL_OWNER -> err("The target cannot be yourself")
FAIL -> err("${player.name} is already banned from all your parcels")
SUCCESS -> "${player.name} is now banned from all your parcels"
}
suspend fun cmdBan(sender: Player, context: ExecutionContext, player: PlayerProfile) =
adminVersion.cmdBan(context, sender, player)
@Cmd("unban", aliases = ["undeny"])
@Desc(
@@ -87,11 +63,6 @@ class CommandsPrivilegesGlobal(plugin: ParcelsPlugin) : AbstractParcelCommands(p
"they will still be banned there.",
shortVersion = "globally unbans a player from your parcels"
)
fun cmdUnban(sender: Player, player: OfflinePlayer): Any? =
when (data[sender].unban(player)) {
FAIL_OWNER -> err("The target cannot be yourself")
FAIL -> err("${player.name} is not currently banned from all your parcels")
SUCCESS -> "${player.name} is not banned from all your parcels anymore"
}
suspend fun cmdUnban(sender: Player, context: ExecutionContext, player: PlayerProfile) =
adminVersion.cmdUnban(context, sender, player)
}

View File

@@ -3,20 +3,22 @@ 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.*
import io.dico.parcels2.PrivilegeChangeResult.*
import io.dico.parcels2.util.ext.PERM_ADMIN_MANAGE
import io.dico.parcels2.util.ext.hasPermAdminManage
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
private fun ParcelScope.checkPrivilege(sender: Player, player: OfflinePlayer) {
if (!sender.hasPermAdminManage) {
Validate.isTrue(parcel.owner != null, "This parcel is unowned")
Validate.isTrue(parcel.privilege(sender) > parcel.privilege(player), "You may not change the privilege of ${player.name}")
}
private fun ParcelScope.checkPrivilege(sender: Player, key: PrivilegeKey) {
val senderPrivilege = parcel.getEffectivePrivilege(sender, PERM_ADMIN_MANAGE)
val targetPrivilege = parcel.getStoredPrivilege(key)
Validate.isTrue(senderPrivilege > targetPrivilege, "You may not change the privilege of ${key.notNullName}")
}
private fun ParcelScope.checkOwned(sender: Player) {
Validate.isTrue(parcel.owner != null || sender.hasPermAdminManage, "This parcel is unowned")
}
@Cmd("entrust")
@@ -25,10 +27,11 @@ class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(pl
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")
suspend fun ParcelScope.cmdEntrust(sender: Player, player: PlayerProfile): Any? {
checkOwned(sender)
return when (parcel.allowManage(player)) {
val key = toPrivilegeKey(player)
return when (parcel.allowManage(key)) {
FAIL_OWNER -> err("The target already owns the parcel")
FAIL -> err("${player.name} is already allowed to manage this parcel")
SUCCESS -> "${player.name} is now allowed to manage this parcel"
@@ -42,10 +45,11 @@ class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(pl
shortVersion = "disallows a player to manage this parcel"
)
@RequireParcelPrivilege(Privilege.OWNER)
fun ParcelScope.cmdDistrust(sender: Player, player: OfflinePlayer): Any? {
Validate.isTrue(parcel.owner != null || sender.hasPermAdminManage, "This parcel is unowned")
suspend fun ParcelScope.cmdDistrust(sender: Player, player: PlayerProfile): Any? {
checkOwned(sender)
return when (parcel.disallowManage(player)) {
val key = toPrivilegeKey(player)
return when (parcel.disallowManage(key)) {
FAIL_OWNER -> err("The target owns the parcel and can't be distrusted")
FAIL -> err("${player.name} is not currently allowed to manage this parcel")
SUCCESS -> "${player.name} is not allowed to manage this parcel anymore"
@@ -58,10 +62,13 @@ class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(pl
shortVersion = "allows a player to build on this parcel"
)
@RequireParcelPrivilege(Privilege.CAN_MANAGE)
fun ParcelScope.cmdAllow(sender: Player, player: OfflinePlayer): Any? {
checkPrivilege(sender, player)
suspend fun ParcelScope.cmdAllow(sender: Player, player: PlayerProfile): Any? {
checkOwned(sender)
return when (parcel.allowBuild(player)) {
val key = toPrivilegeKey(player)
checkPrivilege(sender, key)
return when (parcel.allowBuild(key)) {
FAIL_OWNER -> err("The target already owns the parcel")
FAIL -> err("${player.name} is already allowed to build on this parcel")
SUCCESS -> "${player.name} is now allowed to build on this parcel"
@@ -75,10 +82,13 @@ class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(pl
shortVersion = "disallows a player to build on this parcel"
)
@RequireParcelPrivilege(Privilege.CAN_MANAGE)
fun ParcelScope.cmdDisallow(sender: Player, player: OfflinePlayer): Any? {
checkPrivilege(sender, player)
suspend fun ParcelScope.cmdDisallow(sender: Player, player: PlayerProfile): Any? {
checkOwned(sender)
return when (parcel.disallowBuild(player)) {
val key = toPrivilegeKey(player)
checkPrivilege(sender, key)
return when (parcel.disallowBuild(key)) {
FAIL_OWNER -> err("The target owns the parcel")
FAIL -> err("${player.name} is not currently allowed to build on this parcel")
SUCCESS -> "${player.name} is not allowed to build on this parcel anymore"
@@ -92,10 +102,13 @@ class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(pl
shortVersion = "bans a player from this parcel"
)
@RequireParcelPrivilege(Privilege.CAN_MANAGE)
fun ParcelScope.cmdBan(sender: Player, player: OfflinePlayer): Any? {
checkPrivilege(sender, player)
suspend fun ParcelScope.cmdBan(sender: Player, player: PlayerProfile): Any? {
checkOwned(sender)
return when (parcel.disallowBuild(player)) {
val key = toPrivilegeKey(player)
checkPrivilege(sender, key)
return when (parcel.disallowEnter(key)) {
FAIL_OWNER -> err("The target owns the parcel")
FAIL -> err("${player.name} is already banned from this parcel")
SUCCESS -> "${player.name} is now banned from this parcel"
@@ -109,10 +122,13 @@ class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(pl
shortVersion = "unbans a player from this parcel"
)
@RequireParcelPrivilege(Privilege.CAN_MANAGE)
fun ParcelScope.cmdUnban(sender: Player, player: OfflinePlayer): Any? {
checkPrivilege(sender, player)
suspend fun ParcelScope.cmdUnban(sender: Player, player: PlayerProfile): Any? {
checkOwned(sender)
return when (parcel.disallowBuild(player)) {
val key = toPrivilegeKey(player)
checkPrivilege(sender, key)
return when (parcel.allowEnter(key)) {
FAIL_OWNER -> err("The target owns the parcel")
FAIL -> err("${player.name} is not currently banned from this parcel")
SUCCESS -> "${player.name} is not banned from this parcel anymore"

View File

@@ -1,10 +1,13 @@
package io.dico.parcels2.command
import io.dico.dicore.command.*
import io.dico.dicore.command.predef.DefaultGroupCommand
import io.dico.dicore.command.registration.reflect.ReflectiveRegistration
import io.dico.parcels2.Interactables
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.logger
import io.dico.parcels2.util.ext.hasPermAdminManage
import org.bukkit.command.CommandSender
import java.util.LinkedList
import java.util.Queue
@@ -37,12 +40,19 @@ fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher = CommandBuilde
}
}
val adminPrivilegesGlobal = CommandsAdminPrivilegesGlobal(plugin)
group("global", "g") {
registerCommands(CommandsPrivilegesGlobal(plugin))
registerCommands(CommandsPrivilegesGlobal(plugin, adminVersion = adminPrivilegesGlobal))
}
group("admin", "a") {
setCommand(AdminGroupCommand())
registerCommands(CommandsAdmin(plugin))
group("global", "g") {
registerCommands(adminPrivilegesGlobal)
}
}
if (!logger.isDebugEnabled) return@group
@@ -118,3 +128,7 @@ class SpecialCommandAddress : ChildCommandAddress() {
}
}
private class AdminGroupCommand : DefaultGroupCommand() {
override fun isVisibleTo(sender: CommandSender) = sender.hasPermAdminManage
}

View File

@@ -4,10 +4,7 @@ import io.dico.dicore.command.CommandException
import io.dico.dicore.command.ExecutionContext
import io.dico.dicore.command.ICommandReceiver
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.Privilege
import io.dico.parcels2.*
import io.dico.parcels2.Privilege.*
import io.dico.parcels2.util.ext.hasPermAdminManage
import io.dico.parcels2.util.ext.uuid

View File

@@ -4,10 +4,7 @@ import io.dico.dicore.command.CommandException
import io.dico.dicore.command.parameter.ArgumentBuffer
import io.dico.dicore.command.parameter.Parameter
import io.dico.dicore.command.parameter.type.ParameterType
import io.dico.parcels2.Parcel
import io.dico.parcels2.ParcelProvider
import io.dico.parcels2.ParcelWorld
import io.dico.parcels2.PlayerProfile
import io.dico.parcels2.*
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player

View File

@@ -13,27 +13,16 @@ class GlobalPrivilegesManagerImpl(val plugin: ParcelsPlugin) : GlobalPrivilegesM
return map[owner] ?: GlobalPrivilegesImpl(owner).also { map[owner] = it }
}
private inner class GlobalPrivilegesImpl(
override val keyOfOwner: PlayerProfile.Real,
data: MutablePrivilegeMap = emptyData
) : PrivilegesHolder(data), GlobalPrivileges {
private inner class GlobalPrivilegesImpl(override val keyOfOwner: PlayerProfile.Real) : PrivilegesHolder(), GlobalPrivileges {
override var privilegeOfStar: Privilege
get() = super<GlobalPrivileges>.privilegeOfStar
set(value) = run { super<GlobalPrivileges>.privilegeOfStar = value }
private inline var data get() = privilegeMap; set(value) = run { privilegeMap = value }
private inline val isEmpty get() = data === emptyData
override fun setStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
if (isEmpty) {
if (privilege == Privilege.DEFAULT) return false
data = mutableMapOf()
}
return super.setStoredPrivilege(key, privilege).alsoIfTrue {
override fun setRawStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
return super.setRawStoredPrivilege(key, privilege).alsoIfTrue {
plugin.storage.setGlobalPrivilege(keyOfOwner, key, privilege)
}
}
}
private companion object {
val emptyData = Collections.emptyMap<Any, Any>() as MutablePrivilegeMap
}
}

View File

@@ -6,7 +6,6 @@ import io.dico.parcels2.Privilege.*
import io.dico.parcels2.util.Vec2i
import io.dico.parcels2.util.ext.alsoIfTrue
import org.bukkit.Material
import org.bukkit.OfflinePlayer
import org.joda.time.DateTime
import java.util.concurrent.atomic.AtomicInteger
@@ -36,34 +35,6 @@ class ParcelImpl(
world.storage.setParcelData(this, null)
}
override val privilegeMap: PrivilegeMap get() = data.privilegeMap
override fun getStoredPrivilege(key: PrivilegeKey) = data.getStoredPrivilege(key)
override fun setStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
return data.setStoredPrivilege(key, privilege).alsoIfTrue {
world.storage.setLocalPrivilege(this, key, privilege)
}
}
override fun privilege(player: OfflinePlayer, adminPerm: String): Privilege {
val privilege = super.privilege(player, adminPerm)
return if (privilege == DEFAULT) globalPrivileges?.privilege(player, adminPerm) ?: DEFAULT
else privilege
}
override val globalPrivileges: GlobalPrivileges?
get() = keyOfOwner?.let { world.globalPrivileges[it] }
override val lastClaimTime: DateTime? get() = data.lastClaimTime
override var ownerSignOutdated: Boolean
get() = data.ownerSignOutdated
set(value) {
if (data.ownerSignOutdated != value) {
world.storage.setParcelOwnerSignOutdated(this, value)
data.ownerSignOutdated = value
}
}
override var owner: PlayerProfile?
get() = data.owner
@@ -75,11 +46,44 @@ class ParcelImpl(
}
}
override val lastClaimTime: DateTime?
get() = data.lastClaimTime
override var ownerSignOutdated: Boolean
get() = data.ownerSignOutdated
set(value) {
if (data.ownerSignOutdated != value) {
world.storage.setParcelOwnerSignOutdated(this, value)
data.ownerSignOutdated = value
}
}
override val privilegeMap: PrivilegeMap
get() = data.privilegeMap
override val globalPrivileges: GlobalPrivileges?
get() = keyOfOwner?.let { world.globalPrivileges[it] }
override fun getRawStoredPrivilege(key: PrivilegeKey) = data.getRawStoredPrivilege(key)
override fun setRawStoredPrivilege(key: PrivilegeKey, privilege: Privilege) =
data.setRawStoredPrivilege(key, privilege).alsoIfTrue {
world.storage.setLocalPrivilege(this, key, privilege)
}
override fun getStoredPrivilege(key: PrivilegeKey): Privilege =
super.getStoredPrivilege(key).takeIf { it != DEFAULT }
?: globalPrivileges?.getStoredPrivilege(key)
?: DEFAULT
private var _interactableConfig: InteractableConfiguration? = null
private fun updateInteractableConfigStorage() {
world.storage.setParcelOptionsInteractConfig(this, data.interactableConfig)
}
private var _interactableConfig: InteractableConfiguration? = null
override var interactableConfig: InteractableConfiguration
get() {
if (_interactableConfig == null) {
@@ -103,6 +107,7 @@ class ParcelImpl(
}
}
private var blockVisitors = AtomicInteger(0)
override suspend fun withBlockVisitorPermit(block: suspend () -> Unit) {
@@ -117,9 +122,6 @@ class ParcelImpl(
override fun toString() = toStringExt()
}
private operator fun Formatting.plus(other: Formatting) = toString() + other
private operator fun Formatting.plus(other: String) = toString() + other
private object ParcelInfoStringComputer {
val infoStringColor1 = Formatting.GREEN
val infoStringColor2 = Formatting.AQUA
@@ -148,20 +150,34 @@ private object ParcelInfoStringComputer {
}, value)
}
private fun StringBuilder.appendAddedList(local: PrivilegeMap, global: PrivilegeMap, privilege: Privilege, fieldName: String) {
// local takes precedence over global
private fun processPrivileges(local: RawPrivileges, global: RawPrivileges?,
privilege: Privilege): Pair<LinkedHashMap<PrivilegeKey, Privilege>, Int> {
val map = linkedMapOf<PrivilegeKey, Privilege>()
local.privilegeOfStar.takeIf { it != DEFAULT }?.let { map[PlayerProfile.Star] = it }
map.values.retainAll { it.isDistanceGrEq(privilege) }
val localCount = map.size
val localFiltered = local.filterValues { it.isDistanceGrEq(privilege) }
// global keys are dropped here when merged with the local ones
val all = localFiltered + global.filterValues { it.isDistanceGrEq(privilege) }
if (all.isEmpty()) return
if (global != null) {
global.privilegeMap.forEach {
if (it.value.isDistanceGrEq(privilege))
map.putIfAbsent(it.key, it.value)
}
appendFieldWithCount(fieldName, all.size) {
val separator = "$infoStringColor1, $infoStringColor2"
global.privilegeOfStar.takeIf { it != DEFAULT && it.isDistanceGrEq(privilege) }
?.let { map.putIfAbsent(PlayerProfile.Star, it) }
}
return map to localCount
}
private fun StringBuilder.appendAddedList(local: RawPrivileges, global: RawPrivileges?, privilege: Privilege, fieldName: String) {
val (map, localCount) = processPrivileges(local, global, privilege)
if (map.isEmpty()) return
appendFieldWithCount(fieldName, map.size) {
// first [localCount] entries are local
val localCount = localFiltered.size
val iterator = all.iterator()
val separator = "$infoStringColor1, $infoStringColor2"
val iterator = map.iterator()
if (localCount != 0) {
appendPrivilegeEntry(false, iterator.next().toPair())
@@ -185,17 +201,17 @@ private object ParcelInfoStringComputer {
private fun StringBuilder.appendPrivilegeEntry(global: Boolean, pair: Pair<PrivilegeKey, Privilege>) {
val (key, priv) = pair
// prefix. Maybe T should be M for mod or something. T means they have CAN_MANAGE privilege.
append(key.notNullName)
// suffix. Maybe T should be M for mod or something. T means they have CAN_MANAGE privilege.
append(
when {
global && priv == CAN_MANAGE -> "(GT)"
global -> "(G)"
priv == CAN_MANAGE -> "(T)"
global && priv == CAN_MANAGE -> " (G) (T)"
global -> " (G)"
priv == CAN_MANAGE -> " (T)"
else -> ""
}
)
append(key.notNullName)
}
fun getInfoString(parcel: Parcel): String = buildString {
@@ -219,8 +235,8 @@ private object ParcelInfoStringComputer {
append('\n')
val local = parcel.privilegeMap
val global = parcel.globalPrivileges?.privilegeMap ?: emptyMap()
val local: RawPrivileges = parcel.data
val global = parcel.globalPrivileges
appendAddedList(local, global, CAN_BUILD, "Allowed") // includes CAN_MANAGE privilege
append('\n')
appendAddedList(local, global, BANNED, "Banned")

View File

@@ -14,6 +14,7 @@ import com.sk89q.worldedit.world.biome.BaseBiome
import com.sk89q.worldedit.world.block.BlockStateHolder
import io.dico.parcels2.ParcelWorld
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.canBuildFast
import io.dico.parcels2.util.ext.hasPermBuildAnywhere
import io.dico.parcels2.util.ext.sendParcelMessage
import org.bukkit.entity.Player

View File

@@ -1,5 +1,6 @@
package io.dico.parcels2.util.ext
import io.dico.dicore.Formatting
import io.dico.parcels2.logger
import java.io.File
@@ -70,3 +71,6 @@ class EditLoopScope<T, U>(val _map: MutableMap<T, U>) {
}
}
operator fun Formatting.plus(other: Formatting) = toString() + other
operator fun Formatting.plus(other: String) = toString() + other

View File

@@ -5,6 +5,7 @@ import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.logger
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
import org.bukkit.permissions.Permissible
import org.bukkit.plugin.java.JavaPlugin
inline val OfflinePlayer.uuid get() = uniqueId
@@ -17,12 +18,12 @@ const val PERM_BAN_BYPASS = "parcels.admin.bypass.ban"
const val PERM_BUILD_ANYWHERE = "parcels.admin.bypass.build"
const val PERM_ADMIN_MANAGE = "parcels.admin.manage"
inline val Player.hasPermBanBypass get() = hasPermission(PERM_BAN_BYPASS)
inline val Player.hasPermGamemodeBypass get() = hasPermission("parcels.admin.bypass.gamemode")
inline val Player.hasPermBuildAnywhere get() = hasPermission(PERM_BUILD_ANYWHERE)
inline val Player.hasPermAdminManage get() = hasPermission(PERM_ADMIN_MANAGE)
inline val Player.hasParcelHomeOthers get() = hasPermission("parcels.command.home.others")
inline val Player.hasPermRandomSpecific get() = hasPermission("parcels.command.random.specific")
inline val Permissible.hasPermBanBypass get() = hasPermission(PERM_BAN_BYPASS)
inline val Permissible.hasPermGamemodeBypass get() = hasPermission("parcels.admin.bypass.gamemode")
inline val Permissible.hasPermBuildAnywhere get() = hasPermission(PERM_BUILD_ANYWHERE)
inline val Permissible.hasPermAdminManage get() = hasPermission(PERM_ADMIN_MANAGE)
inline val Permissible.hasParcelHomeOthers get() = hasPermission("parcels.command.home.others")
inline val Permissible.hasPermRandomSpecific get() = hasPermission("parcels.command.random.specific")
val Player.parcelLimit: Int
get() {
for (info in effectivePermissions) {