Archived
0
This commit is contained in:
Dico
2018-09-27 04:41:58 +01:00
parent cdaba0ebd5
commit 307b7aee4a
19 changed files with 166 additions and 256 deletions

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View File

@@ -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"
}

View File

@@ -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)

View File

@@ -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)
}

View File

@@ -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)

View File

@@ -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)
}
}

View File

@@ -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()

View File

@@ -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
}

View File

@@ -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 ->
}

View File

@@ -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")

View 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 }

View File

@@ -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
}

View File

@@ -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()) {

View File

@@ -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:"