Archived
0

Cleanup of privilege and listeners

This commit is contained in:
Dico
2018-09-24 08:38:25 +01:00
parent a61e1d69b2
commit 68a0bb0539
13 changed files with 278 additions and 450 deletions

View File

@@ -1,7 +1,6 @@
@file:Suppress("RemoveRedundantBackticks", "IMPLICIT_CAST_TO_ANY", "UNUSED_VARIABLE") @file:Suppress("RemoveRedundantBackticks", "IMPLICIT_CAST_TO_ANY", "UNUSED_VARIABLE")
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.gradle.dsl.Coroutines.ENABLE
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformJvmPlugin import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformJvmPlugin
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.io.PrintWriter import java.io.PrintWriter
@@ -31,7 +30,7 @@ allprojects {
} }
dependencies { dependencies {
val spigotVersion = "1.13-R0.1-SNAPSHOT" val spigotVersion = "1.13.1-R0.1-SNAPSHOT"
c.provided("org.bukkit:bukkit:$spigotVersion") { isTransitive = false } c.provided("org.bukkit:bukkit:$spigotVersion") { isTransitive = false }
c.provided("org.spigotmc:spigot-api:$spigotVersion") { isTransitive = false } c.provided("org.spigotmc:spigot-api:$spigotVersion") { isTransitive = false }
@@ -46,7 +45,6 @@ allprojects {
project(":dicore3:dicore3-command") { project(":dicore3:dicore3-command") {
apply<KotlinPlatformJvmPlugin>() apply<KotlinPlatformJvmPlugin>()
kotlin.experimental.coroutines = ENABLE
dependencies { dependencies {
c.kotlinStd(kotlin("stdlib-jdk8")) c.kotlinStd(kotlin("stdlib-jdk8"))
@@ -70,6 +68,7 @@ dependencies {
// not on sk89q maven repo yet // not on sk89q maven repo yet
compileClasspath(files("$rootDir/debug/plugins/worldedit-bukkit-7.0.0-beta-01.jar")) compileClasspath(files("$rootDir/debug/plugins/worldedit-bukkit-7.0.0-beta-01.jar"))
compileClasspath(files("$rootDir/debug/lib/spigot-1.13.1.jar"))
compile("org.jetbrains.exposed:exposed:0.10.5") { isTransitive = false } compile("org.jetbrains.exposed:exposed:0.10.5") { isTransitive = false }
compile("joda-time:joda-time:2.10") compile("joda-time:joda-time:2.10")

View File

@@ -1,206 +0,0 @@
@file:Suppress("UNUSED_VARIABLE")
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.gradle.dsl.Coroutines.ENABLE
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformJvmPlugin
import java.io.PrintWriter
val firstImport = false
val stdout = PrintWriter(File("$rootDir/gradle-output.txt"))
buildscript {
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.2.51")
}
}
group = "io.dico"
version = "0.1"
inline fun <reified T : Plugin<out Project>> Project.apply() =
(this as PluginAware).apply<T>()
allprojects {
apply<JavaPlugin>()
repositories {
mavenCentral()
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots")
maven("https://hub.spigotmc.org/nexus/content/repositories/sonatype-nexus-snapshots")
}
dependencies {
val spigotVersion = "1.13-R0.1-SNAPSHOT"
compile("org.bukkit:bukkit:$spigotVersion") { isTransitive = false }
compile("org.spigotmc:spigot-api:$spigotVersion") { isTransitive = false }
compile("net.sf.trove4j:trove4j:3.0.3")
testCompile("junit:junit:4.12")
}
}
project(":dicore3:dicore3-command") {
apply<KotlinPlatformJvmPlugin>()
kotlin.experimental.coroutines = ENABLE
dependencies {
compile("org.jetbrains.kotlinx:kotlinx-coroutines-core:0.23.4")
compile(kotlin("reflect", version = "1.2.50"))
compile(kotlin("stdlib-jdk8", version = "1.2.51"))
compile(project(":dicore3:dicore3-core"))
compile("com.thoughtworks.paranamer:paranamer:2.8")
}
}
plugins {
kotlin("jvm") version "1.2.51"
id("com.github.johnrengelman.plugin-shadow") version "2.0.3"
}
kotlin.experimental.coroutines = ENABLE
repositories {
maven("https://dl.bintray.com/kotlin/exposed")
}
dependencies {
compile(project(":dicore3:dicore3-core"))
compile(project(":dicore3:dicore3-command"))
compile(kotlin("stdlib-jdk8"))
compile("org.jetbrains.exposed:exposed:0.10.3")
compile("org.jetbrains.kotlinx:kotlinx-coroutines-core:0.23.4")
compile("com.zaxxer:HikariCP:3.2.0")
compile("com.h2database:h2:1.4.197")
val jacksonVersion = "2.9.6"
compile("com.fasterxml.jackson.core:jackson-core:$jacksonVersion")
compile("com.fasterxml.jackson.core:jackson-databind:$jacksonVersion")
compile("com.fasterxml.jackson.module:jackson-module-kotlin:$jacksonVersion")
compile("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:$jacksonVersion")
//compile("org.yaml:snakeyaml:1.19")
compile("org.slf4j:slf4j-api:1.7.25")
compile("ch.qos.logback:logback-classic:1.2.3")
}
tasks {
val serverDir = "$rootDir/debug"
val jar by getting(Jar::class)
val kotlinStdlibJar by creating(Jar::class) {
destinationDir = file("$serverDir/lib")
archiveName = "kotlin-stdlib.jar"
packageDependencies("kotlin-stdlib-jdk8")
}
val debugEnvironment by creating(Exec::class) {
}
val releaseJar by creating(ShadowJar::class) {
destinationDir = file("$serverDir/plugins")
baseName = "parcels2-release"
with(jar)
packageArtifacts(
"jackson-core",
"jackson-databind",
"jackson-module-kotlin",
"jackson-annotations",
"jackson-dataformat-yaml",
"snakeyaml",
"slf4j-api",
"logback-core",
"logback-classic",
//"h2",
"HikariCP",
"kotlinx-coroutines-core",
"kotlinx-coroutines-core-common",
"atomicfu-common",
"exposed",
"dicore3-core",
"dicore3-command",
"paranamer",
"trove4j",
"joda-time",
"annotations",
"kotlin-stdlib-common",
"kotlin-stdlib",
"kotlin-stdlib-jdk7",
"kotlin-stdlib-jdk8",
"kotlin-reflect"
)
relocate("org.yaml.snakeyaml", "io.dico.parcels2.util.snakeyaml")
manifest.attributes["Class-Path"] = "lib/kotlin-stdlib.jar"
dependsOn(kotlinStdlibJar)
}
}
allprojects {
tasks.filter { it is Jar }.forEach { it.group = "artifacts" }
}
stdout.flush()
stdout.close()
fun Jar.packageDependencies(vararg names: String) {
if (!firstImport) {
from(*project.configurations.compile.resolvedConfiguration.firstLevelModuleDependencies
.filter { it.moduleName in names }
.flatMap { it.allModuleArtifacts }
.map { it.file }
.map(::zipTree)
.toTypedArray()
)
}
}
fun Jar.packageDependency(name: String, configure: ModuleDependency.() -> Unit) {
if (!firstImport) {
val configuration = project.configurations.compile.copyRecursive()
configuration.dependencies.removeIf {
if (it is ModuleDependency && it.name == name) {
it.configure()
false
} else true
}
from(*configuration.resolvedConfiguration.resolvedArtifacts
.map { it.file }
.map(::zipTree)
.toTypedArray())
}
}
@Suppress("IMPLICIT_CAST_TO_ANY")
fun Jar.packageArtifacts(vararg names: String) {
if (!firstImport) {
from(*project.configurations.compile.resolvedConfiguration.firstLevelModuleDependencies
.flatMap { dep -> dep.allModuleArtifacts.map { dep to it } }
.filter { pair ->
val (dep, art) = pair
val id = art.moduleVersion.id
(id.name in names).also {
val artName = art.moduleVersion.id.let {"${it.group}:${it.name}:${it.version}"}
val depName = dep.let { "${it.moduleGroup}:${it.moduleName}:${it.moduleVersion}" }
val name = "$artName \n from $depName"
stdout.println("${if (it) "Including" else "Not including"} artifact $name")
}
}
.map { pair -> pair.second.file }
.map { if (it.isDirectory()) it else zipTree(it) }
.toTypedArray())
}
}

View File

@@ -1,10 +1,7 @@
package io.dico.parcels2 package io.dico.parcels2
import io.dico.parcels2.util.Vec2i import io.dico.parcels2.util.Vec2i
import io.dico.parcels2.util.ext.hasPermBuildAnywhere
import org.bukkit.Location import org.bukkit.Location
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
import org.joda.time.DateTime import org.joda.time.DateTime
import java.util.UUID import java.util.UUID
@@ -16,7 +13,7 @@ import java.util.UUID
* However, this implementation is intentionally not thread-safe. * However, this implementation is intentionally not thread-safe.
* Therefore, database query callbacks should schedule their updates using the bukkit scheduler. * Therefore, database query callbacks should schedule their updates using the bukkit scheduler.
*/ */
interface Parcel : ParcelData { interface Parcel : ParcelData, Privileges {
val id: ParcelId val id: ParcelId
val world: ParcelWorld val world: ParcelWorld
val pos: Vec2i val pos: Vec2i
@@ -25,6 +22,10 @@ interface Parcel : ParcelData {
val data: ParcelData val data: ParcelData
val infoString: String val infoString: String
val hasBlockVisitors: Boolean val hasBlockVisitors: Boolean
val globalPrivileges: GlobalPrivileges?
override val keyOfOwner: PlayerProfile.Real?
get() = owner as? PlayerProfile.Real
fun copyDataIgnoringDatabase(data: ParcelData) fun copyDataIgnoringDatabase(data: ParcelData)
@@ -37,13 +38,13 @@ interface Parcel : ParcelData {
val homeLocation: Location get() = world.blockManager.getHomeLocation(id) val homeLocation: Location get() = world.blockManager.getHomeLocation(id)
} }
interface ParcelData : Privileges { interface ParcelData : PrivilegesMinimal {
var owner: PlayerProfile? var owner: PlayerProfile?
val lastClaimTime: DateTime? val lastClaimTime: DateTime?
var ownerSignOutdated: Boolean var ownerSignOutdated: Boolean
var interactableConfig: InteractableConfiguration var interactableConfig: InteractableConfiguration
fun canBuild(player: OfflinePlayer, checkAdmin: Boolean = true, checkGlobal: Boolean = true): Boolean //fun canBuild(player: OfflinePlayer, checkAdmin: Boolean = true, checkGlobal: Boolean = true): Boolean
fun isOwner(uuid: UUID): Boolean { fun isOwner(uuid: UUID): Boolean {
return owner?.uuid == uuid return owner?.uuid == uuid
@@ -59,10 +60,11 @@ class ParcelDataHolder(addedMap: MutablePrivilegeMap = mutableMapOf())
override var owner: PlayerProfile? = null override var owner: PlayerProfile? = null
override var lastClaimTime: DateTime? = null override var lastClaimTime: DateTime? = null
override var ownerSignOutdated = false override var ownerSignOutdated = false
override fun canBuild(player: OfflinePlayer, checkAdmin: Boolean, checkGlobal: Boolean) =
hasPrivilegeToBuild(player) //override fun canBuild(player: OfflinePlayer, checkAdmin: Boolean, checkGlobal: Boolean) =
|| owner.let { it != null && it.matches(player, allowNameMatch = false) } // hasPrivilegeToBuild(player)
|| (checkAdmin && player is Player && player.hasPermBuildAnywhere) // || owner.let { it != null && it.matches(player, allowNameMatch = false) }
// || (checkAdmin && player is Player && player.hasPermBuildAnywhere)
override var interactableConfig: InteractableConfiguration = BitmaskInteractableConfiguration() override var interactableConfig: InteractableConfiguration = BitmaskInteractableConfiguration()
} }

View File

@@ -0,0 +1,146 @@
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
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 isDistanceGrEq(other: Privilege): Boolean =
when { // used for example when disallowBuild is called and CAN_MANAGE is the privilege.
other > DEFAULT -> this >= other
other == DEFAULT -> this == other
else -> this <= other
}
fun isChangeInDirection(positiveDirection: Boolean, update: Privilege): Boolean =
if (positiveDirection) update > this
else update < this
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(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()
interface PrivilegesMinimal {
val map: PrivilegeMap
var privilegeOfStar: Privilege
fun getStoredPrivilege(key: PrivilegeKey): Privilege
fun setStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean
}
interface Privileges : PrivilegesMinimal {
val keyOfOwner: PlayerProfile.Real?
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)
}
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
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 map: MutablePrivilegeMap = MutablePrivilegeMap()) : PrivilegesMinimal {
override var privilegeOfStar: Privilege = DEFAULT
set(value) = run { field = value.requireNonTransient() }
override fun getStoredPrivilege(key: PrivilegeKey) =
if (key.isStar) privilegeOfStar
else map.getOrDefault(key, privilegeOfStar)
override fun setStoredPrivilege(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 {
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

@@ -1,128 +0,0 @@
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 isDistanceGrEq(other: Privilege): Boolean =
when { // used for example when disallowBuild is called and CAN_MANAGE is the privilege.
other > DEFAULT -> this >= other
other == DEFAULT -> this == other
else -> this <= other
}
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(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 =
privilege(key).isDistanceGrEq(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)
}
val OfflinePlayer.privilegeKey: PrivilegeKey
inline 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
operator fun get(owner: OfflinePlayer): GlobalPrivileges = get(owner.privilegeKey)
}

View File

@@ -20,9 +20,8 @@ import org.bukkit.block.Biome
import org.bukkit.block.BlockFace import org.bukkit.block.BlockFace
import org.bukkit.block.Skull import org.bukkit.block.Skull
import org.bukkit.block.data.BlockData import org.bukkit.block.data.BlockData
import org.bukkit.block.data.type.Sign
import org.bukkit.block.data.type.Slab import org.bukkit.block.data.type.Slab
import java.lang.IllegalArgumentException import org.bukkit.block.data.type.WallSign
import java.util.Random import java.util.Random
private val airType = Bukkit.createBlockData(Material.AIR) private val airType = Bukkit.createBlockData(Material.AIR)
@@ -201,8 +200,7 @@ class DefaultParcelGenerator(
o.wallType o.wallType
wallBlock.blockData = wallBlockType wallBlock.blockData = wallBlockType
signBlock.blockData = (Bukkit.createBlockData(Material.WALL_SIGN) as WallSign).apply { facing = BlockFace.NORTH }
signBlock.blockData = (Bukkit.createBlockData(Material.WALL_SIGN) as Sign).apply { rotation = BlockFace.NORTH }
val sign = signBlock.state as org.bukkit.block.Sign val sign = signBlock.state as org.bukkit.block.Sign
sign.setLine(0, "${parcel.x},${parcel.z}") sign.setLine(0, "${parcel.x},${parcel.z}")

View File

@@ -9,25 +9,25 @@ import java.util.Collections
class GlobalPrivilegesManagerImpl(val plugin: ParcelsPlugin) : GlobalPrivilegesManager { class GlobalPrivilegesManagerImpl(val plugin: ParcelsPlugin) : GlobalPrivilegesManager {
private val map = mutableMapOf<PlayerProfile, GlobalPrivileges>() private val map = mutableMapOf<PlayerProfile, GlobalPrivileges>()
override fun get(owner: PlayerProfile): GlobalPrivileges { override fun get(owner: PlayerProfile.Real): GlobalPrivileges {
return map[owner] ?: GlobalPrivilegesImpl(owner).also { map[owner] = it } return map[owner] ?: GlobalPrivilegesImpl(owner).also { map[owner] = it }
} }
private inner class GlobalPrivilegesImpl( private inner class GlobalPrivilegesImpl(
override val owner: PlayerProfile, override val keyOfOwner: PlayerProfile.Real,
data: MutablePrivilegeMap = emptyData data: MutablePrivilegeMap = emptyData
) : PrivilegesHolder(data), GlobalPrivileges { ) : PrivilegesHolder(data), GlobalPrivileges {
private inline var data get() = map; set(value) = run { map = value } private inline var data get() = map; set(value) = run { map = value }
private inline val isEmpty get() = data === emptyData private inline val isEmpty get() = data === emptyData
override fun setPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean { override fun setStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
if (isEmpty) { if (isEmpty) {
if (privilege == Privilege.DEFAULT) return false if (privilege == Privilege.DEFAULT) return false
data = mutableMapOf() data = mutableMapOf()
} }
return super<PrivilegesHolder>.setPrivilege(key, privilege).alsoIfTrue { return super.setStoredPrivilege(key, privilege).alsoIfTrue {
plugin.storage.setGlobalPrivilege(owner, key, privilege) plugin.storage.setGlobalPrivilege(keyOfOwner, key, privilege)
} }
} }
} }

View File

@@ -2,6 +2,7 @@ package io.dico.parcels2.defaultimpl
import io.dico.dicore.Formatting import io.dico.dicore.Formatting
import io.dico.parcels2.* import io.dico.parcels2.*
import io.dico.parcels2.Privilege.*
import io.dico.parcels2.util.Vec2i import io.dico.parcels2.util.Vec2i
import io.dico.parcels2.util.ext.alsoIfTrue import io.dico.parcels2.util.ext.alsoIfTrue
import org.bukkit.Material import org.bukkit.Material
@@ -36,19 +37,26 @@ class ParcelImpl(
} }
override val map: PrivilegeMap get() = data.map override val map: PrivilegeMap get() = data.map
override fun privilege(key: PrivilegeKey) = data.privilege(key) override fun getStoredPrivilege(key: PrivilegeKey) = data.getStoredPrivilege(key)
override fun isBanned(key: PrivilegeKey) = data.isBanned(key)
override fun hasPrivilegeToBuild(key: PrivilegeKey) = data.hasPrivilegeToBuild(key) override fun setStoredPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
override fun canBuild(player: OfflinePlayer, checkAdmin: Boolean, checkGlobal: Boolean): Boolean { return data.setStoredPrivilege(key, privilege).alsoIfTrue {
return (data.canBuild(player, checkAdmin, false)) world.storage.setLocalPrivilege(this, key, privilege)
|| checkGlobal && world.globalPrivileges[owner ?: return false].hasPrivilegeToBuild(player) }
}
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 var privilegeOfStar: Privilege override var privilegeOfStar: Privilege
get() = data.privilegeOfStar get() = data.privilegeOfStar.let { if (it == DEFAULT) globalPrivileges?.privilegeOfStar ?: DEFAULT else it }
set(value) = run { setPrivilege(PlayerProfile.Star, value) } set(value) = run { setStoredPrivilege(PlayerProfile.Star, value) }
val globalAddedMap: PrivilegeMap? get() = owner?.let { world.globalPrivileges[it].map } override val globalPrivileges: GlobalPrivileges?
get() = keyOfOwner?.let { world.globalPrivileges[it] }
override val lastClaimTime: DateTime? get() = data.lastClaimTime override val lastClaimTime: DateTime? get() = data.lastClaimTime
@@ -71,12 +79,6 @@ class ParcelImpl(
} }
} }
override fun setPrivilege(key: PrivilegeKey, privilege: Privilege): Boolean {
return data.setPrivilege(key, privilege).alsoIfTrue {
world.storage.setLocalPrivilege(this, key, privilege)
}
}
private fun updateInteractableConfigStorage() { private fun updateInteractableConfigStorage() {
world.storage.setParcelOptionsInteractConfig(this, data.interactableConfig) world.storage.setParcelOptionsInteractConfig(this, data.interactableConfig)
} }
@@ -188,12 +190,14 @@ private object ParcelInfoStringComputer {
val (key, priv) = pair val (key, priv) = pair
// prefix. Maybe T should be M for mod or something. T means they have CAN_MANAGE privilege. // prefix. Maybe T should be M for mod or something. T means they have CAN_MANAGE privilege.
append(when { append(
global && priv == Privilege.CAN_MANAGE -> "(GT)" when {
global -> "(G)" global && priv == CAN_MANAGE -> "(GT)"
priv == Privilege.CAN_MANAGE -> "(T)" global -> "(G)"
else -> "" priv == CAN_MANAGE -> "(T)"
}) else -> ""
}
)
append(key.notNullName) append(key.notNullName)
} }
@@ -219,11 +223,11 @@ private object ParcelInfoStringComputer {
append('\n') append('\n')
val global = owner?.let { parcel.world.globalPrivileges[owner].map } ?: emptyMap()
val local = parcel.map val local = parcel.map
appendAddedList(local, global, Privilege.CAN_BUILD, "Allowed") // includes CAN_MANAGE privilege val global = parcel.globalPrivileges?.map ?: emptyMap()
appendAddedList(local, global, CAN_BUILD, "Allowed") // includes CAN_MANAGE privilege
append('\n') append('\n')
appendAddedList(local, global, Privilege.BANNED, "Banned") appendAddedList(local, global, BANNED, "Banned")
if (!parcel.interactableConfig.isDefault()) { if (!parcel.interactableConfig.isDefault()) {
val interactables = parcel.interactableConfig.interactableClasses val interactables = parcel.interactableConfig.interactableClasses

View File

@@ -1,6 +1,7 @@
package io.dico.parcels2.listener package io.dico.parcels2.listener
import gnu.trove.TLongCollection import gnu.trove.TLongCollection
import gnu.trove.set.hash.TLongHashSet
import io.dico.dicore.ListenerMarker import io.dico.dicore.ListenerMarker
import io.dico.dicore.RegistratorListener import io.dico.dicore.RegistratorListener
import io.dico.parcels2.* import io.dico.parcels2.*
@@ -30,21 +31,23 @@ import org.bukkit.event.world.StructureGrowEvent
import org.bukkit.inventory.InventoryHolder import org.bukkit.inventory.InventoryHolder
import java.util.EnumSet import java.util.EnumSet
@Suppress("NOTHING_TO_INLINE")
class ParcelListeners( class ParcelListeners(
val parcelProvider: ParcelProvider, val parcelProvider: ParcelProvider,
val entityTracker: ParcelEntityTracker, val entityTracker: ParcelEntityTracker,
val storage: Storage val storage: Storage
) { ) {
private inline fun Parcel?.canBuildN(user: Player) = isPresentAnd { canBuild(user) } || user.hasPermBuildAnywhere private fun canBuildOnArea(user: Player, area: Parcel?) =
if (area == null) user.hasPermBuildAnywhere else area.canBuild(user)
private fun canInteract(user: Player, area: Parcel?, interactClass: String) =
canBuildOnArea(user, area) || (area != null && area.interactableConfig(interactClass))
/** /**
* Get the world and parcel that the block resides in * Get the world and parcel that the block resides in
* wo is the world, ppa is the parcel * the parcel is nullable, and often named area because that means path.
* ppa for possibly a parcel - it will be null if not in an existing parcel * returns null if not in a registered parcel world - should always return in that case to not affect other worlds.
* returns null if not in a registered parcel world
*/ */
private fun getWoAndPPa(block: Block): Pair<ParcelWorld, Parcel?>? { private fun getWorldAndArea(block: Block): Pair<ParcelWorld, Parcel?>? {
val world = parcelProvider.getWorld(block.world) ?: return null val world = parcelProvider.getWorld(block.world) ?: return null
return world to world.getParcelAt(block) return world to world.getParcelAt(block)
} }
@@ -57,7 +60,7 @@ class ParcelListeners(
val user = event.player val user = event.player
if (user.hasPermBanBypass) return@l if (user.hasPermBanBypass) return@l
val parcel = parcelProvider.getParcelAt(event.to) ?: return@l val parcel = parcelProvider.getParcelAt(event.to) ?: return@l
if (parcel.isBanned(user.privilegeKey)) { if (!parcel.canEnter(user)) {
parcelProvider.getParcelAt(event.from)?.also { parcelProvider.getParcelAt(event.from)?.also {
user.teleport(it.homeLocation) user.teleport(it.homeLocation)
user.sendParcelMessage(nopermit = true, message = "You are banned from this parcel") user.sendParcelMessage(nopermit = true, message = "You are banned from this parcel")
@@ -71,12 +74,12 @@ class ParcelListeners(
*/ */
@field:ListenerMarker(priority = NORMAL) @field:ListenerMarker(priority = NORMAL)
val onBlockBreakEvent = RegistratorListener<BlockBreakEvent> l@{ event -> val onBlockBreakEvent = RegistratorListener<BlockBreakEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.block) ?: return@l val (world, area) = getWorldAndArea(event.block) ?: return@l
if (!event.player.hasPermBuildAnywhere && ppa.isNullOr { !canBuild(event.player) }) { if (!canBuildOnArea(event.player, area)) {
event.isCancelled = true; return@l event.isCancelled = true; return@l
} }
if (!wo.options.dropEntityItems) { if (!world.options.dropEntityItems) {
val state = event.block.state val state = event.block.state
if (state is InventoryHolder) { if (state is InventoryHolder) {
state.inventory.clear() state.inventory.clear()
@@ -90,8 +93,8 @@ class ParcelListeners(
*/ */
@field:ListenerMarker(priority = NORMAL) @field:ListenerMarker(priority = NORMAL)
val onBlockPlaceEvent = RegistratorListener<BlockPlaceEvent> l@{ event -> val onBlockPlaceEvent = RegistratorListener<BlockPlaceEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.block) ?: return@l val (_, area) = getWorldAndArea(event.block) ?: return@l
if (!event.player.hasPermBuildAnywhere && ppa.isNullOr { !canBuild(event.player) }) { if (!canBuildOnArea(event.player, area)) {
event.isCancelled = true event.isCancelled = true
} }
} }
@@ -120,7 +123,7 @@ class ParcelListeners(
private fun checkPistonMovement(event: BlockPistonEvent, blocks: List<Block>) { private fun checkPistonMovement(event: BlockPistonEvent, blocks: List<Block>) {
val world = parcelProvider.getWorld(event.block.world) ?: return val world = parcelProvider.getWorld(event.block.world) ?: return
val direction = event.direction val direction = event.direction
val columns = gnu.trove.set.hash.TLongHashSet(blocks.size * 2) val columns = TLongHashSet(blocks.size * 2)
blocks.forEach { blocks.forEach {
columns.add(Column(it.x, it.z)) columns.add(Column(it.x, it.z))
@@ -128,8 +131,8 @@ class ParcelListeners(
} }
columns.troveForEach { columns.troveForEach {
val ppa = world.getParcelAt(it.columnX, it.columnZ) val area = world.getParcelAt(it.columnX, it.columnZ)
if (ppa.isNullOr { hasBlockVisitors }) { if (area == null || area.hasBlockVisitors) {
event.isCancelled = true event.isCancelled = true
return return
} }
@@ -141,10 +144,10 @@ class ParcelListeners(
*/ */
@field:ListenerMarker(priority = NORMAL) @field:ListenerMarker(priority = NORMAL)
val onExplosionPrimeEvent = RegistratorListener<ExplosionPrimeEvent> l@{ event -> val onExplosionPrimeEvent = RegistratorListener<ExplosionPrimeEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.entity.location.block) ?: return@l val (world, area) = getWorldAndArea(event.entity.location.block) ?: return@l
if (ppa?.hasBlockVisitors == true) { if (area != null && area.hasBlockVisitors) {
event.radius = 0F; event.isCancelled = true event.radius = 0F; event.isCancelled = true
} else if (wo.options.disableExplosions) { } else if (world.options.disableExplosions) {
event.radius = 0F event.radius = 0F
} }
} }
@@ -156,18 +159,18 @@ class ParcelListeners(
val onEntityExplodeEvent = RegistratorListener<EntityExplodeEvent> l@{ event -> val onEntityExplodeEvent = RegistratorListener<EntityExplodeEvent> l@{ event ->
entityTracker.untrack(event.entity) entityTracker.untrack(event.entity)
val world = parcelProvider.getWorld(event.entity.world) ?: return@l val world = parcelProvider.getWorld(event.entity.world) ?: return@l
if (world.options.disableExplosions || world.getParcelAt(event.entity).isPresentAnd { hasBlockVisitors }) { if (world.options.disableExplosions || world.getParcelAt(event.entity).let { it != null && it.hasBlockVisitors }) {
event.isCancelled = true event.isCancelled = true
} }
} }
/* /*
* Prevents creepers and tnt minecarts from exploding if explosions are disabled * Prevents liquids from flowing out of plots
*/ */
@field:ListenerMarker(priority = NORMAL) @field:ListenerMarker(priority = NORMAL)
val onBlockFromToEvent = RegistratorListener<BlockFromToEvent> l@{ event -> val onBlockFromToEvent = RegistratorListener<BlockFromToEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.toBlock) ?: return@l val (_, area) = getWorldAndArea(event.toBlock) ?: return@l
if (ppa.isNullOr { hasBlockVisitors }) event.isCancelled = true if (area == null || area.hasBlockVisitors) event.isCancelled = true
} }
private val bedTypes = EnumSet.copyOf(getMaterialsWithWoolColorPrefix("BED").toList()) private val bedTypes = EnumSet.copyOf(getMaterialsWithWoolColorPrefix("BED").toList())
@@ -185,7 +188,7 @@ class ParcelListeners(
val clickedBlock = event.clickedBlock val clickedBlock = event.clickedBlock
val parcel = clickedBlock?.let { world.getParcelAt(it) } val parcel = clickedBlock?.let { world.getParcelAt(it) }
if (!user.hasPermBuildAnywhere && parcel.isPresentAnd { isBanned(user.privilegeKey) }) { if (!user.hasPermBuildAnywhere && parcel != null && !parcel.canEnter(user)) {
user.sendParcelMessage(nopermit = true, message = "You cannot interact with parcels you're banned from") user.sendParcelMessage(nopermit = true, message = "You cannot interact with parcels you're banned from")
event.isCancelled = true; return@l event.isCancelled = true; return@l
} }
@@ -193,7 +196,8 @@ class ParcelListeners(
when (event.action) { when (event.action) {
Action.RIGHT_CLICK_BLOCK -> run { Action.RIGHT_CLICK_BLOCK -> run {
val type = clickedBlock.type val type = clickedBlock.type
val interactable = parcel.effectiveInteractableConfig.isInteractable(type) || parcel.isPresentAnd { canBuild(user) } val interactable = Interactables.listedMaterials.containsKey(type)
&& (parcel.effectiveInteractableConfig.isInteractable(type) || (parcel != null && parcel.canBuild(user)))
if (!interactable) { if (!interactable) {
val interactableClassName = Interactables[type]!!.name val interactableClassName = Interactables[type]!!.name
user.sendParcelMessage(nopermit = true, message = "You cannot interact with $interactableClassName in this parcel") user.sendParcelMessage(nopermit = true, message = "You cannot interact with $interactableClassName in this parcel")
@@ -206,19 +210,24 @@ class ParcelListeners(
val head = if (bed == Bed.Part.FOOT) clickedBlock.getRelative(bed.facing) else clickedBlock val head = if (bed == Bed.Part.FOOT) clickedBlock.getRelative(bed.facing) else clickedBlock
when (head.biome) { when (head.biome) {
Biome.NETHER, Biome.THE_END -> { Biome.NETHER, Biome.THE_END -> {
if (world.options.disableExplosions || parcel.isNullOr { !canBuild(user) }) { if (world.options.disableExplosions) {
user.sendParcelMessage(nopermit = true, message = "You cannot use this bed because it would explode") user.sendParcelMessage(nopermit = true, message = "You cannot use this bed because it would explode")
event.isCancelled = true; return@l event.isCancelled = true; return@l
} }
} }
} }
if (!canBuildOnArea(user, parcel)) {
user.sendParcelMessage(nopermit = true, message = "You may not sleep here")
event.isCancelled = true; return@l
}
} }
onPlayerInteractEvent_RightClick(event, world, parcel) onPlayerInteractEvent_RightClick(event, world, parcel)
} }
Action.RIGHT_CLICK_AIR -> onPlayerInteractEvent_RightClick(event, world, parcel) Action.RIGHT_CLICK_AIR -> onPlayerInteractEvent_RightClick(event, world, parcel)
Action.PHYSICAL -> if (!user.hasPermBuildAnywhere && !parcel.isPresentAnd { canBuild(user) || interactableConfig("pressure_plates") }) { Action.PHYSICAL -> if (!canBuildOnArea(user, parcel) && !(parcel != null && parcel.interactableConfig("pressure_plates"))) {
user.sendParcelMessage(nopermit = true, message = "You cannot use inputs in this parcel") user.sendParcelMessage(nopermit = true, message = "You cannot use inputs in this parcel")
event.isCancelled = true; return@l event.isCancelled = true; return@l
} }
@@ -234,7 +243,7 @@ class ParcelListeners(
event.isCancelled = true; return event.isCancelled = true; return
} }
if (!parcel.canBuildN(event.player)) { if (!canBuildOnArea(event.player, parcel)) {
when (item) { when (item) {
LAVA_BUCKET, WATER_BUCKET, BUCKET, FLINT_AND_STEEL -> event.isCancelled = true LAVA_BUCKET, WATER_BUCKET, BUCKET, FLINT_AND_STEEL -> event.isCancelled = true
} }
@@ -249,8 +258,8 @@ class ParcelListeners(
@Suppress("NON_EXHAUSTIVE_WHEN") @Suppress("NON_EXHAUSTIVE_WHEN")
@field:ListenerMarker(priority = NORMAL) @field:ListenerMarker(priority = NORMAL)
val onPlayerInteractEntityEvent = RegistratorListener<PlayerInteractEntityEvent> l@{ event -> val onPlayerInteractEntityEvent = RegistratorListener<PlayerInteractEntityEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.rightClicked.location.block) ?: return@l val (_, area) = getWorldAndArea(event.rightClicked.location.block) ?: return@l
if (ppa.canBuildN(event.player)) return@l if (canBuildOnArea(event.player, area)) return@l
when (event.rightClicked.type) { when (event.rightClicked.type) {
EntityType.BOAT, EntityType.BOAT,
EntityType.MINECART, EntityType.MINECART,
@@ -281,14 +290,14 @@ class ParcelListeners(
*/ */
@field:ListenerMarker(priority = NORMAL) @field:ListenerMarker(priority = NORMAL)
val onEntityChangeBlockEvent = RegistratorListener<EntityChangeBlockEvent> l@{ event -> val onEntityChangeBlockEvent = RegistratorListener<EntityChangeBlockEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.block) ?: return@l val (_, area) = getWorldAndArea(event.block) ?: return@l
if (event.entity.type == EntityType.ENDERMAN || ppa.isNullOr { hasBlockVisitors }) { if (event.entity.type == EntityType.ENDERMAN || area == null || area.hasBlockVisitors) {
event.isCancelled = true; return@l event.isCancelled = true; return@l
} }
if (event.entity.type == EntityType.FALLING_BLOCK) { if (event.entity.type == EntityType.FALLING_BLOCK) {
// a sand block started falling. Track it and delete it if it gets out of this parcel. // a sand block started falling. Track it and delete it if it gets out of this parcel.
entityTracker.track(event.entity, ppa) entityTracker.track(event.entity, area)
} }
} }
@@ -306,8 +315,8 @@ class ParcelListeners(
*/ */
@field:ListenerMarker(priority = NORMAL) @field:ListenerMarker(priority = NORMAL)
val onPlayerDropItemEvent = RegistratorListener<PlayerDropItemEvent> l@{ event -> val onPlayerDropItemEvent = RegistratorListener<PlayerDropItemEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.itemDrop.location.block) ?: return@l val (_, area) = getWorldAndArea(event.itemDrop.location.block) ?: return@l
if (!ppa.canBuildN(event.player) && !ppa.isPresentAnd { interactableConfig("containers") }) event.isCancelled = true if (!canInteract(event.player, area, "containers")) event.isCancelled = true
} }
/* /*
@@ -316,8 +325,8 @@ class ParcelListeners(
@field:ListenerMarker(priority = NORMAL) @field:ListenerMarker(priority = NORMAL)
val onEntityPickupItemEvent = RegistratorListener<EntityPickupItemEvent> l@{ event -> val onEntityPickupItemEvent = RegistratorListener<EntityPickupItemEvent> l@{ event ->
val user = event.entity as? Player ?: return@l val user = event.entity as? Player ?: return@l
val (wo, ppa) = getWoAndPPa(event.item.location.block) ?: return@l val (_, area) = getWorldAndArea(event.item.location.block) ?: return@l
if (!ppa.canBuildN(user)) event.isCancelled = true if (!canInteract(user, area, "containers")) event.isCancelled = true
} }
/* /*
@@ -327,8 +336,8 @@ class ParcelListeners(
val onInventoryClickEvent = RegistratorListener<InventoryInteractEvent> l@{ event -> val onInventoryClickEvent = RegistratorListener<InventoryInteractEvent> l@{ event ->
val user = event.whoClicked as? Player ?: return@l val user = event.whoClicked as? Player ?: return@l
if ((event.inventory ?: return@l).holder === user) return@l // inventory null: hotbar if ((event.inventory ?: return@l).holder === user) return@l // inventory null: hotbar
val (wo, ppa) = getWoAndPPa(event.inventory.location.block) ?: return@l val (_, area) = getWorldAndArea(event.inventory.location.block) ?: return@l
if (ppa.isNullOr { !canBuild(user) && !interactableConfig("containers") }) { if (!canInteract(user, area, "containers")) {
event.isCancelled = true event.isCancelled = true
} }
} }
@@ -358,10 +367,10 @@ class ParcelListeners(
@ListenerMarker(priority = NORMAL) @ListenerMarker(priority = NORMAL)
val onBlockFormEvent = RegistratorListener<BlockFormEvent> l@{ event -> val onBlockFormEvent = RegistratorListener<BlockFormEvent> l@{ event ->
val block = event.block val block = event.block
val (wo, ppa) = getWoAndPPa(block) ?: return@l val (world, area) = getWorldAndArea(block) ?: return@l
// prevent any generation whatsoever on paths // prevent any generation whatsoever on paths
if (ppa == null) { if (area == null) {
event.isCancelled = true; return@l event.isCancelled = true; return@l
} }
@@ -371,10 +380,10 @@ class ParcelListeners(
val cancel: Boolean = when (event.newState.type) { val cancel: Boolean = when (event.newState.type) {
// prevent ice generation from Frost Walkers enchantment // prevent ice generation from Frost Walkers enchantment
FROSTED_ICE -> player != null && !ppa.canBuild(player) FROSTED_ICE -> player != null && !area.canBuild(player)
// prevent snow generation from weather // prevent snow generation from weather
SNOW -> !hasEntity && wo.options.preventWeatherBlockChanges SNOW -> !hasEntity && world.options.preventWeatherBlockChanges
else -> false else -> false
} }
@@ -392,7 +401,7 @@ class ParcelListeners(
val world = parcelProvider.getWorld(event.entity.world) ?: return@l val world = parcelProvider.getWorld(event.entity.world) ?: return@l
if (event.entity is Creature && world.options.blockMobSpawning) { if (event.entity is Creature && world.options.blockMobSpawning) {
event.isCancelled = true event.isCancelled = true
} else if (world.getParcelAt(event.entity).isPresentAnd { hasBlockVisitors }) { } else if (world.getParcelAt(event.entity).let { it != null && it.hasBlockVisitors }) {
event.isCancelled = true event.isCancelled = true
} }
} }
@@ -402,8 +411,8 @@ class ParcelListeners(
*/ */
@field:ListenerMarker(priority = NORMAL) @field:ListenerMarker(priority = NORMAL)
val onVehicleMoveEvent = RegistratorListener<VehicleMoveEvent> l@{ event -> val onVehicleMoveEvent = RegistratorListener<VehicleMoveEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.to.block) ?: return@l val (_, area) = getWorldAndArea(event.to.block) ?: return@l
if (ppa == null) { if (area == null) {
event.vehicle.passengers.forEach { event.vehicle.passengers.forEach {
if (it.type == EntityType.PLAYER) { if (it.type == EntityType.PLAYER) {
(it as Player).sendParcelMessage(except = true, message = "Your ride ends here") (it as Player).sendParcelMessage(except = true, message = "Your ride ends here")
@@ -411,7 +420,7 @@ class ParcelListeners(
} }
event.vehicle.eject() event.vehicle.eject()
event.vehicle.remove() event.vehicle.remove()
} else if (ppa.hasBlockVisitors) { } else if (area.hasBlockVisitors) {
event.to.subtract(event.to).add(event.from) event.to.subtract(event.to).add(event.from)
} }
} }
@@ -432,7 +441,7 @@ class ParcelListeners(
?: (event.damager as? Projectile)?.let { it.shooter as? Player } ?: (event.damager as? Projectile)?.let { it.shooter as? Player }
?: return@l ?: return@l
if (!world.getParcelAt(event.entity).canBuildN(user)) { if (!canBuildOnArea(user, world.getParcelAt(event.entity))) {
event.isCancelled = true event.isCancelled = true
} }
} }
@@ -444,7 +453,7 @@ class ParcelListeners(
event.isCancelled = true; return@l event.isCancelled = true; return@l
} }
if (world.getParcelAt(event.entity).isPresentAnd { hasBlockVisitors }) { if (world.getParcelAt(event.entity).let { it != null && it.hasBlockVisitors }) {
event.isCancelled = true event.isCancelled = true
} }
} }
@@ -457,7 +466,7 @@ class ParcelListeners(
val onHangingBreakByEntityEvent = RegistratorListener<HangingBreakByEntityEvent> l@{ event -> val onHangingBreakByEntityEvent = RegistratorListener<HangingBreakByEntityEvent> l@{ event ->
val world = parcelProvider.getWorld(event.entity.world) ?: return@l val world = parcelProvider.getWorld(event.entity.world) ?: return@l
val user = event.remover as? Player ?: return@l val user = event.remover as? Player ?: return@l
if (!world.getParcelAt(event.entity).canBuildN(user)) { if (!canBuildOnArea(user, world.getParcelAt(event.entity))) {
event.isCancelled = true event.isCancelled = true
} }
} }
@@ -469,7 +478,7 @@ class ParcelListeners(
val onHangingPlaceEvent = RegistratorListener<HangingPlaceEvent> l@{ event -> val onHangingPlaceEvent = RegistratorListener<HangingPlaceEvent> l@{ event ->
val world = parcelProvider.getWorld(event.entity.world) ?: return@l val world = parcelProvider.getWorld(event.entity.world) ?: return@l
val block = event.block.getRelative(event.blockFace) val block = event.block.getRelative(event.blockFace)
if (!world.getParcelAt(block).canBuildN(event.player)) { if (!canBuildOnArea(event.player, world.getParcelAt(block))) {
event.isCancelled = true event.isCancelled = true
} }
} }
@@ -479,16 +488,16 @@ class ParcelListeners(
*/ */
@field:ListenerMarker(priority = NORMAL) @field:ListenerMarker(priority = NORMAL)
val onStructureGrowEvent = RegistratorListener<StructureGrowEvent> l@{ event -> val onStructureGrowEvent = RegistratorListener<StructureGrowEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.location.block) ?: return@l val (world, area) = getWorldAndArea(event.location.block) ?: return@l
if (ppa == null) { if (area == null) {
event.isCancelled = true; return@l event.isCancelled = true; return@l
} }
if (!event.player.hasPermBuildAnywhere && !ppa.canBuild(event.player)) { if (!event.player.hasPermBuildAnywhere && !area.canBuild(event.player)) {
event.isCancelled = true; return@l event.isCancelled = true; return@l
} }
event.blocks.removeIf { wo.getParcelAt(it.block) !== ppa } event.blocks.removeIf { world.getParcelAt(it.block) !== area }
} }
/* /*
@@ -511,9 +520,9 @@ class ParcelListeners(
*/ */
@field:ListenerMarker(priority = NORMAL) @field:ListenerMarker(priority = NORMAL)
val onItemSpawnEvent = RegistratorListener<ItemSpawnEvent> l@{ event -> val onItemSpawnEvent = RegistratorListener<ItemSpawnEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.location.block) ?: return@l val (_, area) = getWorldAndArea(event.location.block) ?: return@l
if (ppa == null) event.isCancelled = true if (area == null) event.isCancelled = true
else entityTracker.track(event.entity, ppa) else entityTracker.track(event.entity, area)
} }
/* /*
@@ -521,8 +530,8 @@ class ParcelListeners(
*/ */
@field:ListenerMarker(priority = NORMAL) @field:ListenerMarker(priority = NORMAL)
val onEntityTeleportEvent = RegistratorListener<EntityTeleportEvent> l@{ event -> val onEntityTeleportEvent = RegistratorListener<EntityTeleportEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.from.block) ?: return@l val (world, area) = getWorldAndArea(event.from.block) ?: return@l
if (ppa !== wo.getParcelAt(event.to)) { if (area !== world.getParcelAt(event.to)) {
event.isCancelled = true event.isCancelled = true
} }
} }
@@ -533,11 +542,11 @@ class ParcelListeners(
*/ */
@field:ListenerMarker(priority = NORMAL) @field:ListenerMarker(priority = NORMAL)
val onProjectileLaunchEvent = RegistratorListener<ProjectileLaunchEvent> l@{ event -> val onProjectileLaunchEvent = RegistratorListener<ProjectileLaunchEvent> l@{ event ->
val (wo, ppa) = getWoAndPPa(event.entity.location.block) ?: return@l val (_, area) = getWorldAndArea(event.entity.location.block) ?: return@l
if (ppa == null || (event.entity.shooter as? Player)?.let { !ppa.canBuildN(it) } == true) { if (area == null || (event.entity.shooter as? Player)?.let { !canBuildOnArea(it, area) } == true) {
event.isCancelled = true event.isCancelled = true
} else { } else {
entityTracker.track(event.entity, ppa) entityTracker.track(event.entity, area)
} }
} }

View File

@@ -43,7 +43,7 @@ class WorldEditListener(val parcels: ParcelsPlugin, val worldEdit: WorldEdit) {
private fun canBuild(x: Int, z: Int): Boolean { private fun canBuild(x: Int, z: Int): Boolean {
world.getParcelAt(x, z)?.let { parcel -> world.getParcelAt(x, z)?.let { parcel ->
if (parcel.canBuild(player, checkAdmin = false)) { if (parcel.canBuildFast(player)) {
return true return true
} }
} }

View File

@@ -7,8 +7,8 @@ import io.dico.parcels2.Privilege.DEFAULT
import kotlinx.coroutines.channels.SendChannel import kotlinx.coroutines.channels.SendChannel
import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.*
object PrivilegesLocalT : PrivilegesTable<ParcelId>("parcels_added_local", ParcelsT) object PrivilegesLocalT : PrivilegesTable<ParcelId>("parcels_privilege_local", ParcelsT)
object PrivilegesGlobalT : PrivilegesTable<PlayerProfile>("parcels_added_global", ProfilesT) object PrivilegesGlobalT : PrivilegesTable<PlayerProfile>("parcels_privilege_global", ProfilesT)
object ParcelOptionsT : Table("parcel_options") { object ParcelOptionsT : Table("parcel_options") {
val parcel_id = integer("parcel_id").primaryKey().references(ParcelsT.id, ReferenceOption.CASCADE) val parcel_id = integer("parcel_id").primaryKey().references(ParcelsT.id, ReferenceOption.CASCADE)

View File

@@ -20,8 +20,8 @@ inline fun Boolean.alsoIfFalse(block: () -> Unit): Boolean = also { if (!it) blo
inline fun <R> Any.synchronized(block: () -> R): R = synchronized(this, block) inline fun <R> Any.synchronized(block: () -> R): R = synchronized(this, block)
inline fun <T> T?.isNullOr(condition: T.() -> Boolean): Boolean = this == null || condition() //inline fun <T> T?.isNullOr(condition: T.() -> Boolean): Boolean = this == null || condition()
inline fun <T> T?.isPresentAnd(condition: T.() -> Boolean): Boolean = this != null && condition() //inline fun <T> T?.isPresentAnd(condition: T.() -> Boolean): Boolean = this != null && condition()
inline fun <T> T?.ifNullRun(block: () -> Unit): T? { inline fun <T> T?.ifNullRun(block: () -> Unit): T? {
if (this == null) block() if (this == null) block()
return this return this

View File

@@ -13,10 +13,14 @@ inline val OfflinePlayer.uuid get() = uniqueId
inline val OfflinePlayer.isValid inline val OfflinePlayer.isValid
get() = isOnline() || hasPlayedBefore() get() = isOnline() || hasPlayedBefore()
inline val Player.hasPermBanBypass get() = hasPermission("parcels.admin.bypass.ban") 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.hasPermGamemodeBypass get() = hasPermission("parcels.admin.bypass.gamemode")
inline val Player.hasPermBuildAnywhere get() = hasPermission("parcels.admin.bypass.build") inline val Player.hasPermBuildAnywhere get() = hasPermission(PERM_BUILD_ANYWHERE)
inline val Player.hasPermAdminManage get() = hasPermission("parcels.admin.manage") inline val Player.hasPermAdminManage get() = hasPermission(PERM_ADMIN_MANAGE)
inline val Player.hasParcelHomeOthers get() = hasPermission("parcels.command.home.others") inline val Player.hasParcelHomeOthers get() = hasPermission("parcels.command.home.others")
inline val Player.hasPermRandomSpecific get() = hasPermission("parcels.command.random.specific") inline val Player.hasPermRandomSpecific get() = hasPermission("parcels.command.random.specific")
val Player.parcelLimit: Int val Player.parcelLimit: Int