Tweaks
This commit is contained in:
@@ -3,13 +3,11 @@
|
||||
package io.dico.parcels2
|
||||
|
||||
import io.dico.parcels2.storage.Storage
|
||||
import io.dico.parcels2.util.PLAYER_NAME_PLACEHOLDER
|
||||
import io.dico.parcels2.util.getPlayerName
|
||||
import io.dico.parcels2.util.ext.PLAYER_NAME_PLACEHOLDER
|
||||
import io.dico.parcels2.util.ext.isValid
|
||||
import io.dico.parcels2.util.ext.uuid
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Unconfined
|
||||
import kotlinx.coroutines.async
|
||||
import io.dico.parcels2.util.getOfflinePlayer
|
||||
import io.dico.parcels2.util.getPlayerName
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.OfflinePlayer
|
||||
import java.util.UUID
|
||||
@@ -70,8 +68,7 @@ interface PlayerProfile {
|
||||
|
||||
if (input == Star.name) return Star
|
||||
|
||||
return Bukkit.getOfflinePlayer(input).takeIf { it.isValid }?.let { PlayerProfile(it) }
|
||||
?: Unresolved(input)
|
||||
return getOfflinePlayer(input)?.let { PlayerProfile(it) } ?: Unresolved(input)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,8 +80,7 @@ interface PlayerProfile {
|
||||
override val notNullName: String
|
||||
get() = nameOrBukkitName ?: PLAYER_NAME_PLACEHOLDER
|
||||
|
||||
val player: OfflinePlayer? get() = Bukkit.getOfflinePlayer(uuid).takeIf { it.isValid }
|
||||
val playerUnchecked: OfflinePlayer get() = Bukkit.getOfflinePlayer(uuid)
|
||||
val player: OfflinePlayer? get() = getOfflinePlayer(uuid)
|
||||
|
||||
override fun matches(player: OfflinePlayer, allowNameMatch: Boolean): Boolean {
|
||||
return uuid == player.uuid || (allowNameMatch && name?.let { it == player.name } == true)
|
||||
@@ -147,10 +143,6 @@ interface PlayerProfile {
|
||||
return other is Unresolved && name == other.name
|
||||
}
|
||||
|
||||
fun tryResolve(storage: Storage): Deferred<Real?> {
|
||||
return async(Unconfined) { tryResolveSuspendedly(storage) }
|
||||
}
|
||||
|
||||
suspend fun tryResolveSuspendedly(storage: Storage): Real? {
|
||||
return storage.getPlayerUuidForName(name).await()?.let { resolve(it) }
|
||||
}
|
||||
@@ -178,120 +170,9 @@ interface PlayerProfile {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
/**
|
||||
* This class can represent:
|
||||
*
|
||||
* An existing player
|
||||
* A fake player (with only a name)
|
||||
* An existing player who must have its uuid resolved from the database (after checking against Bukkit OfflinePlayer)
|
||||
* STAR profile, which matches everyone. This profile is considered a REAL player, because it can have a privilege.
|
||||
*/
|
||||
class PlayerProfile2 private constructor(uuid: UUID?,
|
||||
val name: String?,
|
||||
val isReal: Boolean = uuid != null) {
|
||||
private var _uuid: UUID? = uuid
|
||||
val notNullName: String get() = name ?: getPlayerNameOrDefault(uuid!!)
|
||||
|
||||
val uuid: UUID? get() = _uuid ?: if (isReal) throw IllegalStateException("This PlayerProfile must be resolved first") else null
|
||||
|
||||
companion object {
|
||||
// below uuid is just a randomly generated one (version 4). Hopefully no minecraft player will ever have it :)
|
||||
val star = PlayerProfile(UUID.fromString("7d09c4c6-117d-4f36-9778-c4d24618cee1"), "*", true)
|
||||
|
||||
fun nameless(player: OfflinePlayer): PlayerProfile {
|
||||
if (!player.isValid) throw IllegalArgumentException("The given OfflinePlayer is not valid")
|
||||
return PlayerProfile(player.uuid)
|
||||
}
|
||||
|
||||
fun fromNameAndUuid(name: String?, uuid: UUID?): PlayerProfile? {
|
||||
if (name == null && uuid == null) return null
|
||||
if (star.name == name && star._uuid == uuid) return star
|
||||
return PlayerProfile(uuid, name)
|
||||
}
|
||||
|
||||
fun realPlayerByName(name: String): PlayerProfile {
|
||||
return fromString(name, allowReal = true, allowFake = false)
|
||||
}
|
||||
|
||||
fun fromString(input: String, allowReal: Boolean = true, allowFake: Boolean = false): PlayerProfile {
|
||||
if (!allowReal) {
|
||||
if (!allowFake) throw IllegalArgumentException("at least one of allowReal and allowFake must be true")
|
||||
return PlayerProfile(input)
|
||||
}
|
||||
|
||||
if (input == star.name) return star
|
||||
|
||||
return Bukkit.getOfflinePlayer(input).takeIf { it.isValid }?.let { PlayerProfile(it) }
|
||||
?: PlayerProfile(null, input, !allowFake)
|
||||
}
|
||||
|
||||
operator fun createWith(name: String): PlayerProfile {
|
||||
if (name == star.name) return star
|
||||
return PlayerProfile(null, name)
|
||||
}
|
||||
|
||||
operator fun createWith(uuid: UUID): PlayerProfile {
|
||||
if (uuid == star.uuid) return star
|
||||
return PlayerProfile(uuid, null)
|
||||
}
|
||||
|
||||
operator fun createWith(player: OfflinePlayer): PlayerProfile {
|
||||
// avoid UUID comparison against STAR
|
||||
return if (player.isValid) PlayerProfile(player.uuid, player.name) else createWith(player.name)
|
||||
}
|
||||
}
|
||||
|
||||
val isStar: Boolean get() = this === star || (name == star.name && _uuid == star._uuid)
|
||||
val hasUUID: Boolean get() = _uuid != null
|
||||
val mustBeResolved: Boolean get() = isReal && _uuid == null
|
||||
|
||||
val onlinePlayer: Player? get() = uuid?.let { Bukkit.getPlayer(uuid) }
|
||||
|
||||
val onlinePlayerAllowingNameMatch: Player? get() = onlinePlayer ?: name?.let { Bukkit.getPlayerExact(name) }
|
||||
val offlinePlayer: OfflinePlayer? get() = uuid?.let { Bukkit.getOfflinePlayer(it).takeIf { it.isValid } }
|
||||
val offlinePlayerAllowingNameMatch: OfflinePlayer?
|
||||
get() = offlinePlayer ?: Bukkit.getOfflinePlayer(name).takeIf { it.isValid }
|
||||
|
||||
fun matches(player: OfflinePlayer, allowNameMatch: Boolean = false): Boolean {
|
||||
if (isStar) return true
|
||||
return uuid?.let { it == player.uniqueId } ?: false
|
||||
|| (allowNameMatch && name?.let { it == player.name } ?: false)
|
||||
}
|
||||
|
||||
fun equals(other: PlayerProfile): Boolean {
|
||||
return if (_uuid != null) _uuid == other._uuid
|
||||
else other._uuid == null && isReal == other.isReal && name == other.name
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
return other is PlayerProfile && equals(other)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return _uuid?.hashCode() ?: name!!.hashCode()
|
||||
}
|
||||
|
||||
/**
|
||||
* resolve the uuid of this player profile if [mustBeResolved], using specified [storage].
|
||||
* returns true if the PlayerProfile has a uuid after this call.
|
||||
*/
|
||||
suspend fun resolve(storage: Storage): Boolean {
|
||||
if (mustBeResolved) {
|
||||
val uuid = storage.getPlayerUuidForName(name!!).await()
|
||||
_uuid = uuid
|
||||
return uuid != null
|
||||
}
|
||||
return _uuid != null
|
||||
}
|
||||
|
||||
fun resolve(uuid: UUID) {
|
||||
if (isReal && _uuid == null) {
|
||||
_uuid = uuid
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
suspend fun PlayerProfile.resolved(storage: Storage, resolveToFake: Boolean = false): PlayerProfile? =
|
||||
when (this) {
|
||||
is PlayerProfile.Unresolved -> tryResolveSuspendedly(storage)
|
||||
?: if (resolveToFake) PlayerProfile.Fake(name) else null
|
||||
else -> this
|
||||
}
|
||||
@@ -24,7 +24,6 @@ data class TickWorktimeOptions(var workTime: Int, var tickInterval: Int)
|
||||
interface WorkDispatcher {
|
||||
/**
|
||||
* Submit a [task] that should be run synchronously, but limited such that it does not stall the server
|
||||
* a bunch
|
||||
*/
|
||||
fun dispatch(task: WorkerTask): Worker
|
||||
|
||||
@@ -89,11 +88,6 @@ interface Worker : WorkerAndScopeMembersUnion {
|
||||
* Await completion of this worker
|
||||
*/
|
||||
suspend fun awaitCompletion()
|
||||
|
||||
/**
|
||||
* An object attached to this worker
|
||||
*/
|
||||
//val attachment: Any?
|
||||
}
|
||||
|
||||
interface WorkerScope : WorkerAndScopeMembersUnion {
|
||||
@@ -114,7 +108,7 @@ interface WorkerScope : WorkerAndScopeMembersUnion {
|
||||
|
||||
/**
|
||||
* Get a [WorkerScope] that is responsible for [portion] part of the progress
|
||||
* If [portion] is negative, the remainder of the progress is used
|
||||
* If [portion] is negative, the remaining progress is used
|
||||
*/
|
||||
fun delegateWork(portion: Double = -1.0): WorkerScope
|
||||
}
|
||||
|
||||
@@ -20,12 +20,8 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei
|
||||
return getParcelCommandReceiver(plugin.parcelProvider, context, target, cmdName)
|
||||
}
|
||||
|
||||
protected fun error(message: String): Nothing {
|
||||
throw CommandException(message)
|
||||
}
|
||||
|
||||
protected fun checkConnected(action: String) {
|
||||
if (!plugin.storage.isConnected) error("Parcels cannot $action right now because of a database error")
|
||||
if (!plugin.storage.isConnected) err("Parcels cannot $action right now because of a database error")
|
||||
}
|
||||
|
||||
protected suspend fun checkParcelLimit(player: Player, world: ParcelWorld) {
|
||||
@@ -35,7 +31,7 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei
|
||||
|
||||
val limit = player.parcelLimit
|
||||
if (numOwnedParcels >= limit) {
|
||||
error("You have enough plots for now")
|
||||
err("You have enough plots for now")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,10 +61,7 @@ abstract class AbstractParcelCommands(val plugin: ParcelsPlugin) : ICommandRecei
|
||||
}
|
||||
}
|
||||
|
||||
protected fun err(message: String): Nothing = throw CommandException(message)
|
||||
|
||||
override fun getCoroutineContext() = plugin.coroutineContext
|
||||
|
||||
|
||||
}
|
||||
|
||||
fun err(message: String): Nothing = throw CommandException(message)
|
||||
@@ -8,18 +8,19 @@ import io.dico.dicore.command.annotation.Flag
|
||||
import io.dico.parcels2.ParcelsPlugin
|
||||
import io.dico.parcels2.PlayerProfile
|
||||
import io.dico.parcels2.Privilege
|
||||
import io.dico.parcels2.command.ParcelTarget.Companion.ID
|
||||
import io.dico.parcels2.command.ParcelTarget.Kind
|
||||
import io.dico.parcels2.command.ParcelTarget.TargetKind
|
||||
import io.dico.parcels2.resolved
|
||||
|
||||
class CommandsAdmin(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||
|
||||
@Cmd("setowner")
|
||||
@RequireParcelPrivilege(Privilege.ADMIN)
|
||||
fun ParcelScope.cmdSetowner(target: PlayerProfile): Any? {
|
||||
parcel.owner = target
|
||||
suspend fun ParcelScope.cmdSetowner(@ProfileKind(ProfileKind.ANY) target: PlayerProfile): Any? {
|
||||
val profile = target.resolved(plugin.storage, resolveToFake = true)!!
|
||||
parcel.owner = profile
|
||||
|
||||
val fakeString = if (target.isFake) " (fake)" else ""
|
||||
return "${target.notNullName}$fakeString is the new owner of (${parcel.id.idString})"
|
||||
val fakeString = if (profile.isFake) " (fake)" else ""
|
||||
return "${profile.notNullName}$fakeString is the new owner of (${parcel.id.idString})"
|
||||
}
|
||||
|
||||
@Cmd("dispose")
|
||||
@@ -43,7 +44,7 @@ class CommandsAdmin(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||
@Cmd("swap")
|
||||
@RequireParcelPrivilege(Privilege.ADMIN)
|
||||
fun ParcelScope.cmdSwap(context: ExecutionContext,
|
||||
@Kind(ID) target: ParcelTarget,
|
||||
@TargetKind(TargetKind.ID) target: ParcelTarget,
|
||||
@Flag sure: Boolean): Any? {
|
||||
Validate.isTrue(!parcel.hasBlockVisitors, "A process is already running in this parcel")
|
||||
if (!sure) return areYouSureMessage(context)
|
||||
|
||||
@@ -9,16 +9,14 @@ 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 {
|
||||
checkConnected("have privileges changed")
|
||||
val sender = context.sender
|
||||
if (sender !== owner) {
|
||||
Validate.isAuthorized(sender, PERM_ADMIN_MANAGE)
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package io.dico.parcels2.command
|
||||
|
||||
import io.dico.dicore.command.*
|
||||
import io.dico.dicore.command.IContextFilter.Priority.*
|
||||
import io.dico.dicore.command.IContextFilter.Priority.PERMISSION
|
||||
import io.dico.dicore.command.annotation.Cmd
|
||||
import io.dico.dicore.command.annotation.PreprocessArgs
|
||||
import io.dico.dicore.command.annotation.RequireParameters
|
||||
import io.dico.dicore.command.parameter.ArgumentBuffer
|
||||
import io.dico.parcels2.ParcelsPlugin
|
||||
import io.dico.parcels2.Privilege
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.blockvisitor.RegionTraverser
|
||||
import io.dico.parcels2.doBlockOperation
|
||||
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 kotlinx.coroutines.launch
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.block.BlockFace
|
||||
@@ -29,7 +32,7 @@ class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||
if (worldName == "list") {
|
||||
return Bukkit.getWorlds().joinToString("\n- ", "- ", "")
|
||||
}
|
||||
val world = Bukkit.getWorld(worldName) ?: throw CommandException("World $worldName is not loaded")
|
||||
val world = Bukkit.getWorld(worldName) ?: err("World $worldName is not loaded")
|
||||
sender.teleport(world.spawnLocation)
|
||||
return "Teleported you to $worldName spawn"
|
||||
}
|
||||
@@ -76,44 +79,64 @@ class CommandsDebug(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
|
||||
blockData.javaClass.interfaces!!.contentToString()
|
||||
}
|
||||
|
||||
@Cmd("visitors")
|
||||
fun cmdVisitors(): Any? {
|
||||
@Cmd("jobs")
|
||||
fun cmdJobs(): Any? {
|
||||
val workers = plugin.workDispatcher.workers
|
||||
println(workers.map { it.job }.joinToString(separator = "\n"))
|
||||
return "Task count: ${workers.size}"
|
||||
}
|
||||
|
||||
@Cmd("force_visitors")
|
||||
fun cmdForceVisitors(): Any? {
|
||||
val workers = plugin.workDispatcher.workers
|
||||
plugin.workDispatcher.completeAllTasks()
|
||||
return "Completed task count: ${workers.size}"
|
||||
}
|
||||
|
||||
@Cmd("hasperm")
|
||||
fun cmdHasperm(sender: CommandSender, target: Player, permission: String): Any? {
|
||||
return target.hasPermission(permission).toString()
|
||||
@Cmd("complete_jobs")
|
||||
fun cmdCompleteJobs(): Any? = cmdJobs().also {
|
||||
plugin.launch { plugin.workDispatcher.completeAllTasks() }
|
||||
}
|
||||
|
||||
@Cmd("message")
|
||||
@PreprocessArgs
|
||||
fun cmdMessage(sender: CommandSender, message: String): Any? {
|
||||
// testing @PreprocessArgs which merges "hello there" into a single argument
|
||||
sender.sendMessage(message)
|
||||
return null
|
||||
}
|
||||
|
||||
@Cmd("permissions")
|
||||
fun cmdPermissions(context: ExecutionContext, vararg address: String): Any? {
|
||||
val target = context.address.dispatcherForTree.getDeepChild(ArgumentBuffer(address))
|
||||
Validate.isTrue(target.depth == address.size && target.hasCommand(), "Not found: /${address.joinToString(separator = " ")}")
|
||||
|
||||
val permissions = getPermissionsOf(target)
|
||||
return permissions.joinToString(separator = "\n")
|
||||
@Cmd("hasperm")
|
||||
fun cmdHasperm(target: Player, permission: String): Any? {
|
||||
return target.hasPermission(permission).toString()
|
||||
}
|
||||
|
||||
private fun getPermissionsOf(address: ICommandAddress,
|
||||
path: Array<String> = emptyArray(),
|
||||
result: MutableList<String> = mutableListOf()): List<String> {
|
||||
@Cmd("permissions")
|
||||
fun cmdPermissions(context: ExecutionContext, of: Player, vararg address: String): Any? {
|
||||
val target = context.address.dispatcherForTree.getDeepChild(ArgumentBuffer(address))
|
||||
Validate.isTrue(target.depth == address.size && target.hasCommand(), "Not found: /${address.joinToString(separator = " ")}")
|
||||
return getPermissionsOf(target).joinToString(separator = "\n") { "$it: ${of.hasPermission(it)}" }
|
||||
}
|
||||
|
||||
@Cmd("privilege")
|
||||
@RequireParameters(1)
|
||||
suspend fun ParcelScope.cmdPrivilege(target: PlayerProfile, adminPerm: String?): Any? {
|
||||
val key = toPrivilegeKey(target)
|
||||
|
||||
val perm = when (adminPerm) {
|
||||
"none" -> null
|
||||
"build" -> PERM_BUILD_ANYWHERE
|
||||
"manage", null -> PERM_ADMIN_MANAGE
|
||||
"enter" -> PERM_BAN_BYPASS
|
||||
else -> err("adminPerm should be build, manager or enter")
|
||||
}
|
||||
|
||||
val privilege = if (perm == null) {
|
||||
parcel.getStoredPrivilege(key)
|
||||
} else {
|
||||
if (key is PlayerProfile.Star) err("* can't have permissions")
|
||||
parcel.getEffectivePrivilege(key.player!!, perm)
|
||||
}
|
||||
|
||||
return privilege.toString()
|
||||
}
|
||||
|
||||
private fun getPermissionsOf(address: ICommandAddress) = getPermissionsOf(address, emptyArray(), mutableListOf())
|
||||
|
||||
private fun getPermissionsOf(address: ICommandAddress, path: Array<String>, result: MutableList<String>): List<String> {
|
||||
val command = address.command ?: return result
|
||||
|
||||
var inherited = false
|
||||
|
||||
@@ -9,7 +9,7 @@ import io.dico.dicore.command.annotation.RequireParameters
|
||||
import io.dico.parcels2.ParcelsPlugin
|
||||
import io.dico.parcels2.PlayerProfile
|
||||
import io.dico.parcels2.Privilege
|
||||
import io.dico.parcels2.command.ParcelTarget.Kind
|
||||
import io.dico.parcels2.command.ParcelTarget.TargetKind
|
||||
import io.dico.parcels2.util.ext.hasParcelHomeOthers
|
||||
import io.dico.parcels2.util.ext.hasPermAdminManage
|
||||
import io.dico.parcels2.util.ext.uuid
|
||||
@@ -29,7 +29,7 @@ class CommandsGeneral(plugin: ParcelsPlugin, parent: SpecialCommandAddress) : Ab
|
||||
checkParcelLimit(player, world)
|
||||
|
||||
val parcel = world.nextEmptyParcel()
|
||||
?: error("This world is full, please ask an admin to upsize it")
|
||||
?: err("This world is full, please ask an admin to upsize it")
|
||||
parcel.owner = PlayerProfile(uuid = player.uuid)
|
||||
player.teleport(parcel.homeLocation)
|
||||
return "Enjoy your new parcel!"
|
||||
@@ -58,7 +58,7 @@ class CommandsGeneral(plugin: ParcelsPlugin, parent: SpecialCommandAddress) : Ab
|
||||
@RequireParameters(0)
|
||||
suspend fun cmdHome(
|
||||
player: Player,
|
||||
@Kind(ParcelTarget.OWNER_REAL) target: ParcelTarget
|
||||
@TargetKind(TargetKind.OWNER_REAL) target: ParcelTarget
|
||||
): Any? {
|
||||
return cmdGoto(player, target)
|
||||
}
|
||||
@@ -66,7 +66,7 @@ class CommandsGeneral(plugin: ParcelsPlugin, parent: SpecialCommandAddress) : Ab
|
||||
@Cmd("tp", aliases = ["teleport"])
|
||||
suspend fun cmdTp(
|
||||
player: Player,
|
||||
@Kind(ParcelTarget.ID) target: ParcelTarget
|
||||
@TargetKind(TargetKind.ID) target: ParcelTarget
|
||||
): Any? {
|
||||
return cmdGoto(player, target)
|
||||
}
|
||||
@@ -74,17 +74,17 @@ class CommandsGeneral(plugin: ParcelsPlugin, parent: SpecialCommandAddress) : Ab
|
||||
@Cmd("goto")
|
||||
suspend fun cmdGoto(
|
||||
player: Player,
|
||||
@Kind(ParcelTarget.ANY) target: ParcelTarget
|
||||
@TargetKind(TargetKind.ANY) target: ParcelTarget
|
||||
): Any? {
|
||||
if (target is ParcelTarget.ByOwner) {
|
||||
target.resolveOwner(plugin.storage)
|
||||
if (!target.owner.matches(player) && !player.hasParcelHomeOthers) {
|
||||
error("You do not have permission to teleport to other people's parcels")
|
||||
err("You do not have permission to teleport to other people's parcels")
|
||||
}
|
||||
}
|
||||
|
||||
val match = target.getParcelSuspend(plugin.storage)
|
||||
?: error("The specified parcel could not be matched")
|
||||
?: err("The specified parcel could not be matched")
|
||||
player.teleport(match.homeLocation)
|
||||
return null
|
||||
}
|
||||
@@ -92,7 +92,7 @@ class CommandsGeneral(plugin: ParcelsPlugin, parent: SpecialCommandAddress) : Ab
|
||||
@Cmd("goto_fake")
|
||||
suspend fun cmdGotoFake(
|
||||
player: Player,
|
||||
@Kind(ParcelTarget.OWNER_FAKE) target: ParcelTarget
|
||||
@TargetKind(TargetKind.OWNER_FAKE) target: ParcelTarget
|
||||
): Any? {
|
||||
return cmdGoto(player, target)
|
||||
}
|
||||
@@ -105,7 +105,7 @@ class CommandsGeneral(plugin: ParcelsPlugin, parent: SpecialCommandAddress) : Ab
|
||||
suspend fun ParcelScope.cmdClaim(player: Player): Any? {
|
||||
checkConnected("be claimed")
|
||||
parcel.owner.takeIf { !player.hasPermAdminManage }?.let {
|
||||
error(if (it.matches(player)) "You already own this parcel" else "This parcel is not available")
|
||||
err(if (it.matches(player)) "You already own this parcel" else "This parcel is not available")
|
||||
}
|
||||
|
||||
checkParcelLimit(player, world)
|
||||
@@ -117,6 +117,7 @@ class CommandsGeneral(plugin: ParcelsPlugin, parent: SpecialCommandAddress) : Ab
|
||||
@Desc("Unclaims this parcel")
|
||||
@RequireParcelPrivilege(Privilege.OWNER)
|
||||
fun ParcelScope.cmdUnclaim(player: Player): Any? {
|
||||
checkConnected("be unclaimed")
|
||||
parcel.dispose()
|
||||
return "Your parcel has been disposed"
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(pl
|
||||
)
|
||||
@RequireParcelPrivilege(Privilege.OWNER)
|
||||
suspend fun ParcelScope.cmdEntrust(sender: Player, player: PlayerProfile): Any? {
|
||||
checkConnected("have privileges changed")
|
||||
checkOwned(sender)
|
||||
|
||||
val key = toPrivilegeKey(player)
|
||||
@@ -46,6 +47,7 @@ class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(pl
|
||||
)
|
||||
@RequireParcelPrivilege(Privilege.OWNER)
|
||||
suspend fun ParcelScope.cmdDistrust(sender: Player, player: PlayerProfile): Any? {
|
||||
checkConnected("have privileges changed")
|
||||
checkOwned(sender)
|
||||
|
||||
val key = toPrivilegeKey(player)
|
||||
@@ -63,6 +65,7 @@ class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(pl
|
||||
)
|
||||
@RequireParcelPrivilege(Privilege.CAN_MANAGE)
|
||||
suspend fun ParcelScope.cmdAllow(sender: Player, player: PlayerProfile): Any? {
|
||||
checkConnected("have privileges changed")
|
||||
checkOwned(sender)
|
||||
|
||||
val key = toPrivilegeKey(player)
|
||||
@@ -83,6 +86,7 @@ class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(pl
|
||||
)
|
||||
@RequireParcelPrivilege(Privilege.CAN_MANAGE)
|
||||
suspend fun ParcelScope.cmdDisallow(sender: Player, player: PlayerProfile): Any? {
|
||||
checkConnected("have privileges changed")
|
||||
checkOwned(sender)
|
||||
|
||||
val key = toPrivilegeKey(player)
|
||||
@@ -103,6 +107,7 @@ class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(pl
|
||||
)
|
||||
@RequireParcelPrivilege(Privilege.CAN_MANAGE)
|
||||
suspend fun ParcelScope.cmdBan(sender: Player, player: PlayerProfile): Any? {
|
||||
checkConnected("have privileges changed")
|
||||
checkOwned(sender)
|
||||
|
||||
val key = toPrivilegeKey(player)
|
||||
@@ -123,6 +128,7 @@ class CommandsPrivilegesLocal(plugin: ParcelsPlugin) : AbstractParcelCommands(pl
|
||||
)
|
||||
@RequireParcelPrivilege(Privilege.CAN_MANAGE)
|
||||
suspend fun ParcelScope.cmdUnban(sender: Player, player: PlayerProfile): Any? {
|
||||
checkConnected("have privileges changed")
|
||||
checkOwned(sender)
|
||||
|
||||
val key = toPrivilegeKey(player)
|
||||
|
||||
@@ -33,7 +33,7 @@ fun getParcelCommands(plugin: ParcelsPlugin): ICommandDispatcher = CommandBuilde
|
||||
)
|
||||
|
||||
group("interact", "i") {
|
||||
val command = ParcelOptionsInteractCommand(plugin.parcelProvider)
|
||||
val command = ParcelOptionsInteractCommand(plugin)
|
||||
Interactables.classesById.forEach {
|
||||
addSubCommand(it.name, command)
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@ 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
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
class ParcelOptionsInteractCommand(val parcelProvider: ParcelProvider) : Command() {
|
||||
class ParcelOptionsInteractCommand(val plugin: ParcelsPlugin) : Command() {
|
||||
|
||||
init {
|
||||
setShortDescription("View and/or change the setting")
|
||||
@@ -20,10 +21,12 @@ class ParcelOptionsInteractCommand(val parcelProvider: ParcelProvider) : Command
|
||||
}
|
||||
|
||||
override fun execute(sender: CommandSender, context: ExecutionContext): String? {
|
||||
if (!plugin.storage.isConnected) err("Parcels cannot have their options changed right now because of a database error")
|
||||
|
||||
val interactableClass = Interactables[context.address.mainKey]
|
||||
val allowed: Boolean? = context.get("allowed")
|
||||
|
||||
val parcel = parcelProvider.getParcelRequired(sender as Player,
|
||||
val parcel = plugin.parcelProvider.getParcelRequired(sender as Player,
|
||||
if (allowed == null) Privilege.DEFAULT else Privilege.CAN_MANAGE)
|
||||
|
||||
if (allowed == null) {
|
||||
@@ -52,5 +55,3 @@ class ParcelOptionsInteractCommand(val parcelProvider: ParcelProvider) : Command
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun err(message: String): Nothing = throw CommandException(message)
|
||||
@@ -3,8 +3,12 @@ package io.dico.parcels2.command
|
||||
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.ParameterConfig
|
||||
import io.dico.dicore.command.parameter.type.ParameterType
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.command.ProfileKind.Companion.ANY
|
||||
import io.dico.parcels2.command.ProfileKind.Companion.FAKE
|
||||
import io.dico.parcels2.command.ProfileKind.Companion.REAL
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
@@ -43,11 +47,27 @@ class ParcelParameterType(val parcelProvider: ParcelProvider) : ParameterType<Pa
|
||||
|
||||
}
|
||||
|
||||
class ProfileParameterType : ParameterType<PlayerProfile, Void>(PlayerProfile::class.java) {
|
||||
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
|
||||
|
||||
override fun toParameterInfo(annotation: ProfileKind): Int {
|
||||
return annotation.kind
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ProfileParameterType : ParameterType<PlayerProfile, Int>(PlayerProfile::class.java, ProfileKind) {
|
||||
|
||||
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
|
||||
|
||||
override fun parse(parameter: Parameter<PlayerProfile, Void>, sender: CommandSender, buffer: ArgumentBuffer): PlayerProfile {
|
||||
val input = buffer.next()
|
||||
return PlayerProfile.byName(input, allowReal = true, allowFake = true)
|
||||
return PlayerProfile.byName(input, allowReal, allowFake)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,13 +4,20 @@ import io.dico.dicore.command.parameter.ArgumentBuffer
|
||||
import io.dico.dicore.command.parameter.Parameter
|
||||
import io.dico.dicore.command.parameter.type.ParameterConfig
|
||||
import io.dico.dicore.command.parameter.type.ParameterType
|
||||
import io.dico.parcels2.*
|
||||
import io.dico.parcels2.Parcel
|
||||
import io.dico.parcels2.ParcelProvider
|
||||
import io.dico.parcels2.ParcelWorld
|
||||
import io.dico.parcels2.PlayerProfile
|
||||
import io.dico.parcels2.command.ParcelTarget.TargetKind.Companion.DEFAULT_KIND
|
||||
import io.dico.parcels2.command.ParcelTarget.TargetKind.Companion.ID
|
||||
import io.dico.parcels2.command.ParcelTarget.TargetKind.Companion.OWNER
|
||||
import io.dico.parcels2.command.ParcelTarget.TargetKind.Companion.OWNER_FAKE
|
||||
import io.dico.parcels2.command.ParcelTarget.TargetKind.Companion.OWNER_REAL
|
||||
import io.dico.parcels2.command.ParcelTarget.TargetKind.Companion.PREFER_OWNED_FOR_DEFAULT
|
||||
import io.dico.parcels2.command.ParcelTarget.TargetKind.Companion.REAL
|
||||
import io.dico.parcels2.storage.Storage
|
||||
import io.dico.parcels2.util.Vec2i
|
||||
import io.dico.parcels2.util.ext.floor
|
||||
import kotlinx.coroutines.CoroutineStart.UNDISPATCHED
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.async
|
||||
import org.bukkit.command.CommandSender
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
@@ -18,8 +25,6 @@ sealed class ParcelTarget(val world: ParcelWorld, val parsedKind: Int, val isDef
|
||||
|
||||
abstract suspend fun getParcelSuspend(storage: Storage): Parcel?
|
||||
|
||||
fun ParcelsPlugin.getParcelDeferred(): Deferred<Parcel?> = async(start = UNDISPATCHED) { getParcelSuspend(storage) }
|
||||
|
||||
class ByID(world: ParcelWorld, val id: Vec2i?, parsedKind: Int, isDefault: Boolean) : ParcelTarget(world, parsedKind, isDefault) {
|
||||
override suspend fun getParcelSuspend(storage: Storage): Parcel? = getParcel()
|
||||
fun getParcel() = id?.let { world.getParcelById(it) }
|
||||
@@ -61,29 +66,29 @@ sealed class ParcelTarget(val world: ParcelWorld, val parsedKind: Int, val isDef
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val ID = 1 // ID
|
||||
const val OWNER_REAL = 2 // an owner backed by a UUID
|
||||
const val OWNER_FAKE = 4 // an owner not backed by a UUID
|
||||
annotation class TargetKind(val kind: Int) {
|
||||
companion object : ParameterConfig<TargetKind, Int>(TargetKind::class.java) {
|
||||
const val ID = 1 // ID
|
||||
const val OWNER_REAL = 2 // an owner backed by a UUID
|
||||
const val OWNER_FAKE = 4 // an owner not backed by a UUID
|
||||
|
||||
const val OWNER = OWNER_REAL or OWNER_FAKE // any owner
|
||||
const val ANY = ID or OWNER_REAL or OWNER_FAKE // any
|
||||
const val REAL = ID or OWNER_REAL // no owner not backed by a UUID
|
||||
const val OWNER = OWNER_REAL or OWNER_FAKE // any owner
|
||||
const val ANY = ID or OWNER_REAL or OWNER_FAKE // any
|
||||
const val REAL = ID or OWNER_REAL // no owner not backed by a UUID
|
||||
|
||||
const val DEFAULT_KIND = REAL
|
||||
const val DEFAULT_KIND = REAL
|
||||
|
||||
const val PREFER_OWNED_FOR_DEFAULT = 8 // if the kind can be ID and OWNER_REAL, prefer OWNER_REAL for default
|
||||
// instead of parcel that the player is in
|
||||
}
|
||||
const val PREFER_OWNED_FOR_DEFAULT = 8 // if the kind can be ID and OWNER_REAL, prefer OWNER_REAL for default
|
||||
// instead of parcel that the player is in
|
||||
|
||||
annotation class Kind(val kind: Int)
|
||||
private object Config : ParameterConfig<Kind, Int>(Kind::class.java) {
|
||||
override fun toParameterInfo(annotation: Kind): Int {
|
||||
return annotation.kind
|
||||
override fun toParameterInfo(annotation: TargetKind): Int {
|
||||
return annotation.kind
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PType(val parcelProvider: ParcelProvider, val parcelAddress: SpecialCommandAddress? = null) : ParameterType<ParcelTarget, Int>(ParcelTarget::class.java, Config) {
|
||||
class PType(val parcelProvider: ParcelProvider, val parcelAddress: SpecialCommandAddress? = null) :
|
||||
ParameterType<ParcelTarget, Int>(ParcelTarget::class.java, TargetKind) {
|
||||
|
||||
override fun parse(parameter: Parameter<ParcelTarget, Int>, sender: CommandSender, buffer: ArgumentBuffer): ParcelTarget {
|
||||
var input = buffer.next()
|
||||
|
||||
@@ -219,7 +219,7 @@ class DefaultParcelGenerator(
|
||||
skullBlock.type = Material.PLAYER_HEAD
|
||||
val skull = skullBlock.state as Skull
|
||||
if (owner is PlayerProfile.Real) {
|
||||
skull.owningPlayer = owner.playerUnchecked
|
||||
skull.owningPlayer = Bukkit.getOfflinePlayer(owner.uuid)
|
||||
} else {
|
||||
skull.owner = owner.name
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package io.dico.parcels2.listener
|
||||
|
||||
import io.dico.dicore.RegistratorListener
|
||||
import io.dico.parcels2.ParcelsPlugin
|
||||
import org.bukkit.event.Event
|
||||
|
||||
interface HasPlugin {
|
||||
val plugin: ParcelsPlugin
|
||||
}
|
||||
|
||||
inline fun <reified T : Event> HasPlugin.listener(crossinline block: suspend (T) -> Unit) = RegistratorListener<T> { event ->
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ class ParcelListeners(
|
||||
val user = event.player
|
||||
if (user.hasPermBanBypass) return@l
|
||||
val parcel = parcelProvider.getParcelAt(event.to) ?: return@l
|
||||
if (!parcel.canEnter(user)) {
|
||||
if (!parcel.canEnterFast(user)) {
|
||||
parcelProvider.getParcelAt(event.from)?.also {
|
||||
user.teleport(it.homeLocation)
|
||||
user.sendParcelMessage(nopermit = true, message = "You are banned from this parcel")
|
||||
|
||||
12
src/main/kotlin/io/dico/parcels2/util/BukkitUtil.kt
Normal file
12
src/main/kotlin/io/dico/parcels2/util/BukkitUtil.kt
Normal file
@@ -0,0 +1,12 @@
|
||||
package io.dico.parcels2.util
|
||||
|
||||
import io.dico.parcels2.util.ext.isValid
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.OfflinePlayer
|
||||
import java.util.UUID
|
||||
|
||||
fun getPlayerName(uuid: UUID): String? = getOfflinePlayer(uuid)?.name
|
||||
|
||||
fun getOfflinePlayer(uuid: UUID): OfflinePlayer? = Bukkit.getOfflinePlayer(uuid).takeIf { it.isValid }
|
||||
|
||||
fun getOfflinePlayer(name: String): OfflinePlayer? = Bukkit.getOfflinePlayer(name).takeIf { it.isValid }
|
||||
@@ -1,14 +0,0 @@
|
||||
package io.dico.parcels2.util
|
||||
|
||||
import io.dico.parcels2.util.ext.isValid
|
||||
import org.bukkit.Bukkit
|
||||
import java.nio.ByteBuffer
|
||||
import java.util.UUID
|
||||
|
||||
const val PLAYER_NAME_PLACEHOLDER = ":unknown_name:"
|
||||
|
||||
fun getPlayerName(uuid: UUID): String? {
|
||||
return Bukkit.getOfflinePlayer(uuid)?.takeIf { it.isValid }?.name
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,10 @@ package io.dico.parcels2.util.ext
|
||||
|
||||
import io.dico.dicore.Formatting
|
||||
import io.dico.parcels2.logger
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.OfflinePlayer
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
|
||||
fun File.tryCreate(): Boolean {
|
||||
if (exists()) {
|
||||
|
||||
@@ -52,4 +52,6 @@ fun Player.sendParcelMessage(except: Boolean = false, nopermit: Boolean = false,
|
||||
} else {
|
||||
sendMessage(prefix + Formatting.translateChars('&', message))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const val PLAYER_NAME_PLACEHOLDER = ":unknown_name:"
|
||||
|
||||
Reference in New Issue
Block a user