Archived
0

Add /p global list, tweaks/fixes

This commit is contained in:
Dico
2018-09-28 05:47:32 +01:00
parent 09aaa9ff72
commit bb6ae7d370
34 changed files with 384 additions and 281 deletions

View File

@@ -121,6 +121,8 @@ interface PlayerProfile {
override fun matches(player: OfflinePlayer, allowNameMatch: Boolean): Boolean {
return true
}
override fun toString() = "Star"
}
abstract class NameOnly(override val name: String) : BaseImpl() {
@@ -130,6 +132,8 @@ interface PlayerProfile {
override fun matches(player: OfflinePlayer, allowNameMatch: Boolean): Boolean {
return allowNameMatch && player.name == name
}
override fun toString() = "${javaClass.simpleName}($name)"
}
class Fake(name: String) : NameOnly(name) {
@@ -166,7 +170,9 @@ interface PlayerProfile {
}
}
private class RealImpl(override val uuid: UUID, override val name: String?) : BaseImpl(), Real
private class RealImpl(override val uuid: UUID, override val name: String?) : BaseImpl(), Real {
override fun toString() = "Real($notNullName)"
}
}

View File

@@ -25,7 +25,7 @@ enum class Privilege(
OWNER(-1, transient = true),
ADMIN(-1, transient = true);
fun isDistanceGrEq(other: Privilege): Boolean =
fun implies(other: Privilege): Boolean =
when {
other > DEFAULT -> this >= other
other == DEFAULT -> this == other
@@ -61,6 +61,7 @@ interface RawPrivileges {
fun getRawStoredPrivilege(key: PrivilegeKey): Privilege
fun setRawStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean
fun hasAnyDeclaredPrivileges(): Boolean
}
open class PrivilegesHolder(override var privilegeMap: MutablePrivilegeMap = EmptyPrivilegeMap) : RawPrivileges {
@@ -95,9 +96,30 @@ open class PrivilegesHolder(override var privilegeMap: MutablePrivilegeMap = Emp
else privilegeMap.put(key, privilege) != privilege
}
override fun hasAnyDeclaredPrivileges(): Boolean {
return privilegeMap.isNotEmpty() || privilegeOfStar != DEFAULT
}
fun copyPrivilegesFrom(other: PrivilegesHolder) {
privilegeMap = other.privilegeMap
privilegeOfStar = other.privilegeOfStar
}
}
private fun <K, V> MutableMap<K, V>.put(key: K, value: V, override: Boolean) {
if (override) this[key] = value
else putIfAbsent(key, value)
}
fun RawPrivileges.filterProfilesWithPrivilegeTo(map: MutableMap<PrivilegeKey, Privilege>, privilege: Privilege) {
if (privilegeOfStar.implies(privilege)) {
map.putIfAbsent(PlayerProfile.Star, privilegeOfStar)
}
for ((profile, declaredPrivilege) in privilegeMap) {
if (declaredPrivilege.implies(privilege)) {
map.putIfAbsent(profile, declaredPrivilege)
}
}
}

View File

@@ -7,7 +7,10 @@ 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.Privilege.BANNED
import io.dico.parcels2.Privilege.CAN_BUILD
import io.dico.parcels2.PrivilegeChangeResult.*
import io.dico.parcels2.defaultimpl.InfoBuilder
import io.dico.parcels2.util.ext.PERM_ADMIN_MANAGE
import org.bukkit.OfflinePlayer
@@ -15,8 +18,10 @@ class CommandsAdminPrivilegesGlobal(plugin: ParcelsPlugin) : AbstractParcelComma
private val data
inline get() = plugin.globalPrivileges
private fun checkContext(context: ExecutionContext, owner: OfflinePlayer): OfflinePlayer {
checkConnected("have privileges changed")
private fun checkContext(context: ExecutionContext, owner: OfflinePlayer, changing: Boolean = true): OfflinePlayer {
if (changing) {
checkConnected("have privileges changed")
}
val sender = context.sender
if (sender !== owner) {
Validate.isAuthorized(sender, PERM_ADMIN_MANAGE)
@@ -24,6 +29,25 @@ class CommandsAdminPrivilegesGlobal(plugin: ParcelsPlugin) : AbstractParcelComma
return owner
}
@Cmd("list", aliases = ["l"])
@Desc(
"List globally declared privileges, players you",
"allowed to build on or banned from all your parcels",
shortVersion = "lists globally declared privileges"
)
fun cmdList(context: ExecutionContext, owner: OfflinePlayer): Any? {
checkContext(context, owner, changing = false)
val map = plugin.globalPrivileges[owner]
Validate.isTrue(map.hasAnyDeclaredPrivileges(), "This user has not declared any global privileges")
return StringBuilder().apply {
with(InfoBuilder) {
appendProfilesWithPrivilege("Globally Allowed", map, null, CAN_BUILD)
appendProfilesWithPrivilege("Globally Banned", map, null, BANNED)
}
}.toString()
}
@Cmd("entrust")
@Desc(
"Allows a player to manage globally",

View File

@@ -9,6 +9,15 @@ import org.bukkit.entity.Player
class CommandsPrivilegesGlobal(plugin: ParcelsPlugin,
val adminVersion: CommandsAdminPrivilegesGlobal) : AbstractParcelCommands(plugin) {
@Cmd("list", aliases = ["l"])
@Desc(
"List globally declared privileges, players you",
"allowed to build on or banned from all your parcels",
shortVersion = "lists globally declared privileges"
)
fun cmdList(sender: Player, context: ExecutionContext) =
adminVersion.cmdList(context, sender)
@Cmd("entrust")
@Desc(
"Allows a player to manage globally",

View File

@@ -15,7 +15,7 @@ import java.util.Queue
fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher = CommandBuilder().apply {
val parcelsAddress = SpecialCommandAddress()
setChatController(ParcelsChatController())
setChatHandler(ParcelsChatHandler())
addParameterType(false, ParcelParameterType(plugin.parcelProvider))
addParameterType(false, ProfileParameterType())
addParameterType(true, ParcelTarget.PType(plugin.parcelProvider, parcelsAddress))

View File

@@ -3,7 +3,6 @@ package io.dico.parcels2.command
import io.dico.dicore.command.*
import io.dico.dicore.command.parameter.type.ParameterTypes
import io.dico.parcels2.Interactables
import io.dico.parcels2.ParcelProvider
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.Privilege
import org.bukkit.command.CommandSender
@@ -33,9 +32,9 @@ class ParcelOptionsInteractCommand(val plugin: ParcelsPlugin) : Command() {
val setting = parcel.interactableConfig.isInteractable(interactableClass)
val default = setting == interactableClass.interactableByDefault
val canColor = context.address.chatController.getChatFormatForType(EMessageType.BAD_NEWS)
val cannotColor = context.address.chatController.getChatFormatForType(EMessageType.GOOD_NEWS)
val resetColor = context.address.chatController.getChatFormatForType(EMessageType.RESULT)
val canColor = context.address.chatHandler.getChatFormatForType(EMessageType.BAD_NEWS)
val cannotColor = context.address.chatHandler.getChatFormatForType(EMessageType.GOOD_NEWS)
val resetColor = context.address.chatHandler.getChatFormatForType(EMessageType.RESULT)
val settingString = (if (setting) "${canColor}can" else "${cannotColor}cannot") + resetColor
val defaultString = if (default) " (default)" else ""

View File

@@ -51,7 +51,7 @@ annotation class ProfileKind(val kind: Int) {
companion object : ParameterConfig<ProfileKind, Int>(ProfileKind::class.java) {
const val REAL = 1
const val FAKE = 2
const val ANY = 4
const val ANY = REAL or FAKE
override fun toParameterInfo(annotation: ProfileKind): Int {
return annotation.kind
@@ -63,8 +63,8 @@ class ProfileParameterType : ParameterType<PlayerProfile, Int>(PlayerProfile::cl
override fun parse(parameter: Parameter<PlayerProfile, Int>, sender: CommandSender, buffer: ArgumentBuffer): PlayerProfile {
val info = parameter.paramInfo ?: REAL
val allowReal = info and REAL != 0
val allowFake = info and FAKE != 0
val allowReal = (info and REAL) != 0
val allowFake = (info and FAKE) != 0
val input = buffer.next()
return PlayerProfile.byName(input, allowReal, allowFake)

View File

@@ -1,11 +0,0 @@
package io.dico.parcels2.command
import io.dico.dicore.command.chat.AbstractChatController
class ParcelsChatController : AbstractChatController() {
override fun filterMessage(message: String?): String {
return "[Parcels] $message"
}
}

View File

@@ -0,0 +1,24 @@
package io.dico.parcels2.command
import io.dico.dicore.Formatting
import io.dico.dicore.command.EMessageType
import io.dico.dicore.command.ExecutionContext
import io.dico.dicore.command.chat.AbstractChatHandler
import io.dico.parcels2.util.ext.plus
class ParcelsChatHandler : AbstractChatHandler() {
override fun getMessagePrefixForType(type: EMessageType?): String {
return Formatting.RED + "[Parcels] "
}
override fun createMessage(context: ExecutionContext, type: EMessageType, message: String?): String? {
if (message.isNullOrEmpty()) return null
var result = getChatFormatForType(type) + message
if (context.address.mainKey != "info") {
result = getMessagePrefixForType(type) + result
}
return result
}
}

View File

@@ -52,6 +52,7 @@ class DefaultParcelContainer(val world: ParcelWorld) : ParcelContainer {
private fun walkInCircle(): Iterable<Parcel> = Iterable {
iterator {
val center = world.options.axisLimit
yield(parcels[center][center])
for (radius in 0..center) {
var x = center - radius;
var z = center - radius

View File

@@ -0,0 +1,88 @@
package io.dico.parcels2.defaultimpl
import io.dico.dicore.Formatting
import io.dico.parcels2.Privilege
import io.dico.parcels2.PrivilegeKey
import io.dico.parcels2.RawPrivileges
import io.dico.parcels2.filterProfilesWithPrivilegeTo
object InfoBuilder {
val infoStringColor1 = Formatting.GREEN
val infoStringColor2 = Formatting.AQUA
inline fun StringBuilder.appendField(field: StringBuilder.() -> Unit, value: StringBuilder.() -> Unit) {
append(infoStringColor1)
field()
append(": ")
append(infoStringColor2)
value()
append(' ')
}
inline fun StringBuilder.appendField(name: String, value: StringBuilder.() -> Unit) {
appendField({ append(name) }, value)
}
inline fun StringBuilder.appendFieldWithCount(name: String, count: Int, value: StringBuilder.() -> Unit) {
appendField({
append(name)
append('(')
append(infoStringColor2)
append(count)
append(infoStringColor1)
append(')')
}, value)
}
fun StringBuilder.appendProfilesWithPrivilege(fieldName: String, local: RawPrivileges, global: RawPrivileges?, privilege: Privilege) {
val map = linkedMapOf<PrivilegeKey, Privilege>()
local.filterProfilesWithPrivilegeTo(map, privilege)
val localCount = map.size
global?.filterProfilesWithPrivilegeTo(map, privilege)
appendPrivilegeProfiles(fieldName, map, localCount)
}
fun StringBuilder.appendPrivilegeProfiles(fieldName: String, map: LinkedHashMap<PrivilegeKey, Privilege>, localCount: Int) {
if (map.isEmpty()) return
appendFieldWithCount(fieldName, map.size) {
// first [localCount] entries are local
val separator = "$infoStringColor1, $infoStringColor2"
val iterator = map.iterator()
if (localCount != 0) {
appendPrivilegeEntry(false, iterator.next().toPair())
repeat(localCount - 1) {
append(separator)
appendPrivilegeEntry(false, iterator.next().toPair())
}
} else if (iterator.hasNext()) {
// ensure there is never a leading or trailing separator
appendPrivilegeEntry(true, iterator.next().toPair())
}
iterator.forEach { next ->
append(separator)
appendPrivilegeEntry(true, next.toPair())
}
}
}
fun StringBuilder.appendPrivilegeEntry(global: Boolean, pair: Pair<PrivilegeKey, Privilege>) {
val (key, priv) = pair
append(key.notNullName)
// suffix. Maybe T should be M for mod or something. T means they have CAN_MANAGE privilege.
append(
when {
global && priv == Privilege.CAN_MANAGE -> " (G) (T)"
global -> " (G)"
priv == Privilege.CAN_MANAGE -> " (T)"
else -> ""
}
)
}
}

View File

@@ -1,10 +1,9 @@
package io.dico.parcels2.defaultimpl
import io.dico.dicore.Formatting
import io.dico.parcels2.*
import io.dico.parcels2.Privilege.*
import io.dico.parcels2.util.math.Vec2i
import io.dico.parcels2.util.ext.alsoIfTrue
import io.dico.parcels2.util.math.Vec2i
import org.bukkit.Material
import org.joda.time.DateTime
import java.util.concurrent.atomic.AtomicInteger
@@ -17,7 +16,6 @@ class ParcelImpl(
override val id: ParcelId = this
override val pos get() = Vec2i(x, z)
override var data: ParcelDataHolder = ParcelDataHolder(); private set
override val infoString get() = ParcelInfoStringComputer.getInfoString(this)
override val hasBlockVisitors get() = blockVisitors.get() > 0
override val worldId: ParcelWorldId get() = world.id
@@ -77,6 +75,7 @@ class ParcelImpl(
?: globalPrivileges?.getStoredPrivilege(key)
?: DEFAULT
override fun hasAnyDeclaredPrivileges() = data.hasAnyDeclaredPrivileges()
private var _interactableConfig: InteractableConfiguration? = null
@@ -120,108 +119,20 @@ class ParcelImpl(
}
override fun toString() = toStringExt()
override val infoString: String
get() = getInfoString()
}
private object ParcelInfoStringComputer {
val infoStringColor1 = Formatting.GREEN
val infoStringColor2 = Formatting.AQUA
private inline fun StringBuilder.appendField(field: StringBuilder.() -> Unit, value: StringBuilder.() -> Unit) {
append(infoStringColor1)
field()
append(": ")
append(infoStringColor2)
value()
append(' ')
}
private inline fun StringBuilder.appendField(name: String, value: StringBuilder.() -> Unit) {
appendField({ append(name) }, value)
}
private inline fun StringBuilder.appendFieldWithCount(name: String, count: Int, value: StringBuilder.() -> Unit) {
appendField({
append(name)
append('(')
append(infoStringColor2)
append(count)
append(infoStringColor1)
append(')')
}, value)
}
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
if (global != null) {
global.privilegeMap.forEach {
if (it.value.isDistanceGrEq(privilege))
map.putIfAbsent(it.key, it.value)
}
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 separator = "$infoStringColor1, $infoStringColor2"
val iterator = map.iterator()
if (localCount != 0) {
appendPrivilegeEntry(false, iterator.next().toPair())
repeat(localCount - 1) {
append(separator)
appendPrivilegeEntry(false, iterator.next().toPair())
}
} else if (iterator.hasNext()) {
// ensure there is never a leading or trailing separator
appendPrivilegeEntry(true, iterator.next().toPair())
}
iterator.forEach { next ->
append(separator)
appendPrivilegeEntry(true, next.toPair())
}
}
}
private fun StringBuilder.appendPrivilegeEntry(global: Boolean, pair: Pair<PrivilegeKey, Privilege>) {
val (key, priv) = pair
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 -> " (G) (T)"
global -> " (G)"
priv == CAN_MANAGE -> " (T)"
else -> ""
}
)
}
fun getInfoString(parcel: Parcel): String = buildString {
private fun Parcel.getInfoString() = StringBuilder().apply {
with(InfoBuilder) {
appendField("ID") {
append(parcel.x)
append(x)
append(',')
append(parcel.z)
append(z)
}
val owner = parcel.owner
val owner = owner
appendField("Owner") {
if (owner == null) {
append(infoStringColor1)
@@ -235,18 +146,17 @@ private object ParcelInfoStringComputer {
append('\n')
val local: RawPrivileges = parcel.data
val global = parcel.globalPrivileges
appendAddedList(local, global, CAN_BUILD, "Allowed") // includes CAN_MANAGE privilege
val local: RawPrivileges = data
val global = globalPrivileges
appendProfilesWithPrivilege("Allowed", local, global, CAN_BUILD) // includes CAN_MANAGE privilege
append('\n')
appendAddedList(local, global, BANNED, "Banned")
appendProfilesWithPrivilege("Banned", local, global, BANNED)
if (!parcel.interactableConfig.isDefault()) {
val interactables = parcel.interactableConfig.interactableClasses
if (!interactableConfig.isDefault()) {
val interactables = interactableConfig.interactableClasses
appendFieldWithCount("Interactables", interactables.size) {
interactables.asSequence().map { it.name }.joinTo(this)
}
}
}
}
}.toString()

View File

@@ -106,8 +106,11 @@ class ParcelProviderImpl(val plugin: ParcelsPlugin) : ParcelProvider {
val channel2 = plugin.storage.transmitAllGlobalPrivileges()
while (true) {
val (profile, data) = channel2.receiveOrNull() ?: break
val key = profile as? PrivilegeKey ?: continue
(plugin.globalPrivileges[key] as PrivilegesHolder).copyPrivilegesFrom(data)
if (profile !is PrivilegeKey) {
logger.error("Received profile that is not a privilege key: ${profile.javaClass}, $profile")
continue
}
(plugin.globalPrivileges[profile] as PrivilegesHolder).copyPrivilegesFrom(data)
}
logger.info("Loading data completed")

View File

@@ -237,7 +237,7 @@ class ParcelListeners(
if (bedTypes.contains(type)) {
val bed = clickedBlock.blockData as Bed
val head = if (bed == Bed.Part.FOOT) clickedBlock.getRelative(bed.facing) else clickedBlock
val head = if (bed.part == Bed.Part.FOOT) clickedBlock.getRelative(bed.facing) else clickedBlock
when (head.biome) {
Biome.NETHER, Biome.THE_END -> {
if (world.options.disableExplosions) {

View File

@@ -4,13 +4,14 @@ package io.dico.parcels2.storage.exposed
import io.dico.parcels2.*
import io.dico.parcels2.Privilege.DEFAULT
import io.dico.parcels2.util.ext.alsoIfTrue
import kotlinx.coroutines.channels.SendChannel
import org.jetbrains.exposed.sql.*
object PrivilegesLocalT : PrivilegesTable<ParcelId>("parcels_privilege_local", ParcelsT)
object PrivilegesGlobalT : PrivilegesTable<PlayerProfile>("parcels_privilege_global", ProfilesT)
object ParcelOptionsT : Table("parcel_options") {
object ParcelOptionsT : Table("parcels_options") {
val parcel_id = integer("parcel_id").primaryKey().references(ParcelsT.id, ReferenceOption.CASCADE)
val interact_bitmask = binary("interact_bitmask", 4)
}
@@ -57,8 +58,8 @@ sealed class PrivilegesTable<AttachT>(name: String, val idTable: IdTransactionsT
val iterator = selectAll().orderBy(attach_id).iterator()
if (iterator.hasNext()) {
val firstRow = iterator.next()
var id: Int = firstRow[attach_id]
var row = iterator.next()
var id: Int = row[attach_id]
var attach: AttachT? = null
var map: PrivilegesHolder? = null
@@ -77,7 +78,7 @@ sealed class PrivilegesTable<AttachT>(name: String, val idTable: IdTransactionsT
initAttachAndMap()
for (row in iterator) {
do {
val rowId = row[attach_id]
if (rowId != id) {
sendIfPresent()
@@ -89,10 +90,19 @@ sealed class PrivilegesTable<AttachT>(name: String, val idTable: IdTransactionsT
continue // owner not found for this owner id
}
val profile = ProfilesT.getRealItem(row[profile_id]) ?: continue
val privilege = Privilege.getByNumber(row[privilege]) ?: continue
val profile = ProfilesT.getRealItem(row[profile_id])
if (profile == null) {
logger.error("Privilege from database is null, id ${row[profile_id]}")
continue
}
val privilege = Privilege.getByNumber(row[privilege])
if (privilege == null) {
logger.error("Privilege from database is null, number ${row[this.privilege]}")
continue
}
map!!.setRawStoredPrivilege(profile, privilege)
}
} while (iterator.hasNext().alsoIfTrue { row = iterator.next() })
sendIfPresent()
}