Archived
0

Add todo.md

This commit is contained in:
Dico
2018-08-06 02:53:59 +01:00
parent ba347a8053
commit 0b8deb4c54
11 changed files with 150 additions and 47 deletions

View File

@@ -17,7 +17,7 @@ interface AddedData {
fun setAddedStatus(key: StatusKey, status: AddedStatus): Boolean
fun compareAndSetAddedStatus(key: StatusKey, expect: AddedStatus, status: AddedStatus): Boolean =
(getAddedStatus(key) == expect).also { if (it) setAddedStatus(key, status) }
getAddedStatus(key) == expect && setAddedStatus(key, status)
fun isAllowed(key: StatusKey) = getAddedStatus(key) == AddedStatus.ALLOWED
fun allow(key: StatusKey) = setAddedStatus(key, AddedStatus.ALLOWED)
@@ -36,7 +36,7 @@ interface AddedData {
inline val OfflinePlayer.statusKey get() = PlayerProfile.nameless(this)
open class AddedDataHolder(override var addedMap: MutableAddedDataMap = mutableMapOf()) : AddedData {
open class AddedDataHolder(override var addedMap: MutableAddedDataMap = MutableAddedDataMap()) : AddedData {
override var addedStatusOfStar: AddedStatus = AddedStatus.DEFAULT
override fun getAddedStatus(key: StatusKey): AddedStatus = addedMap.getOrDefault(key, addedStatusOfStar)

View File

@@ -44,6 +44,10 @@ interface ParcelData : AddedData {
fun isOwner(uuid: UUID): Boolean {
return owner?.uuid == uuid
}
fun isOwner(profile: PlayerProfile?): Boolean {
return owner == profile
}
}
class ParcelDataHolder(addedMap: MutableAddedDataMap = mutableMapOf()) : AddedDataHolder(addedMap), ParcelData {

View File

@@ -12,7 +12,7 @@ import java.util.UUID
interface ParcelWorldId {
val name: String
val uid: UUID?
fun equals(id: ParcelWorldId): Boolean = name == name || (uid != null && uid == id.uid)
fun equals(id: ParcelWorldId): Boolean = name == id.name || (uid != null && uid == id.uid)
val bukkitWorld: World? get() = Bukkit.getWorld(name) ?: uid?.let { Bukkit.getWorld(it) }

View File

@@ -18,6 +18,7 @@ interface PlayerProfile {
val name: String?
val notNullName: String
val isStar: Boolean get() = false
val exists: Boolean get() = this is RealImpl
fun matches(player: OfflinePlayer, allowNameMatch: Boolean = false): Boolean

View File

@@ -6,8 +6,8 @@ import io.dico.dicore.command.annotation.Cmd
import io.dico.dicore.command.annotation.Desc
import io.dico.dicore.command.annotation.Flag
import io.dico.dicore.command.annotation.RequireParameters
import io.dico.parcels2.PlayerProfile
import io.dico.parcels2.ParcelsPlugin
import io.dico.parcels2.PlayerProfile
import io.dico.parcels2.util.hasAdminManage
import io.dico.parcels2.util.hasParcelHomeOthers
import io.dico.parcels2.util.uuid
@@ -44,24 +44,34 @@ class CommandsGeneral(plugin: ParcelsPlugin) : AbstractParcelCommands(plugin) {
shortVersion = "teleports you to parcels")
@RequireParameters(0)
suspend fun cmdHome(player: Player, @ParcelTarget.Kind(ParcelTarget.OWNER_REAL) target: ParcelTarget): Any? {
val ownerTarget = target as ParcelTarget.ByOwner
if (!ownerTarget.owner.matches(player) && !player.hasParcelHomeOthers) {
error("You do not have permission to teleport to other people's parcels")
return cmdGoto(player, target)
}
@Cmd("tp", aliases = ["teleport"])
suspend fun cmdTp(player: Player, @ParcelTarget.Kind(ParcelTarget.ID) target: ParcelTarget): Any? {
return cmdGoto(player, target)
}
@Cmd("goto")
suspend fun cmdGoto(player: Player, @ParcelTarget.Kind(ParcelTarget.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")
}
}
val ownedParcelsResult = plugin.storage.getOwnedParcels(ownerTarget.owner).await()
val ownedParcels = ownedParcelsResult
.map { worlds.getParcelById(it) }
.filter { it != null && ownerTarget.world == it.world }
val targetMatch = ownedParcels.getOrNull(target.index)
val match = target.getParcelSuspend(plugin.storage)
?: error("The specified parcel could not be matched")
player.teleport(targetMatch.world.getHomeLocation(targetMatch.id))
player.teleport(match.world.getHomeLocation(match.id))
return ""
}
@Cmd("goto_fake")
suspend fun cmdGotoFake(player: Player, @ParcelTarget.Kind(ParcelTarget.OWNER_FAKE) target: ParcelTarget): Any? {
return cmdGoto(player, target)
}
@Cmd("claim")
@Desc("If this parcel is unowned, makes you the owner",
shortVersion = "claims this parcel")

View File

@@ -5,20 +5,21 @@ 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.storage.Storage
import io.dico.parcels2.util.Vec2i
import io.dico.parcels2.util.floor
import kotlinx.coroutines.experimental.Deferred
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
sealed class ParcelTarget(val world: ParcelWorld, val isDefault: Boolean) {
sealed class ParcelTarget(val world: ParcelWorld, val parsedKind: Int, val isDefault: Boolean) {
abstract suspend fun ParcelsPlugin.getParcelSuspend(): Parcel?
abstract suspend fun getParcelSuspend(storage: Storage): Parcel?
fun ParcelsPlugin.getParcelDeferred(): Deferred<Parcel?> = functionHelper.deferUndispatchedOnMainThread { getParcelSuspend() }
fun ParcelsPlugin.getParcelDeferred(): Deferred<Parcel?> = functionHelper.deferUndispatchedOnMainThread { getParcelSuspend(storage) }
class ByID(world: ParcelWorld, val id: Vec2i?, isDefault: Boolean) : ParcelTarget(world, isDefault) {
override suspend fun ParcelsPlugin.getParcelSuspend(): Parcel? = getParcel()
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) }
val isPath: Boolean get() = id == null
}
@@ -26,31 +27,31 @@ sealed class ParcelTarget(val world: ParcelWorld, val isDefault: Boolean) {
class ByOwner(world: ParcelWorld,
owner: PlayerProfile,
val index: Int,
parsedKind: Int,
isDefault: Boolean,
val onResolveFailure: (() -> Unit)? = null) : ParcelTarget(world, isDefault) {
val onResolveFailure: (() -> Unit)? = null) : ParcelTarget(world, parsedKind, isDefault) {
init {
if (index < 0) throw IllegalArgumentException("Invalid parcel home index: $index")
}
var owner = owner; private set
override suspend fun ParcelsPlugin.getParcelSuspend(): Parcel? {
onResolveFailure?.let { onFail ->
val owner = owner
if (owner is PlayerProfile.Unresolved) {
val new = owner.tryResolveSuspendedly(storage)
if (new == null) {
onFail()
return@let
}
this@ByOwner.owner = new
}
suspend fun resolveOwner(storage: Storage): Boolean {
val owner = owner
if (owner is PlayerProfile.Unresolved) {
this.owner = owner.tryResolveSuspendedly(storage) ?: if (parsedKind and OWNER_FAKE != 0) PlayerProfile.Fake(owner.name)
else run { onResolveFailure?.invoke(); return false }
}
return true
}
override suspend fun getParcelSuspend(storage: Storage): Parcel? {
onResolveFailure?.let { resolveOwner(storage) }
val ownedParcelsSerialized = storage.getOwnedParcels(owner).await()
val ownedParcels = ownedParcelsSerialized
.map { parcelProvider.getParcelById(it) }
.filter { it != null && world == it.world && owner == it.owner }
.filter { it.worldId.equals(world.id) }
.map { world.getParcelById(it.x, it.z) }
return ownedParcels.getOrNull(index)
}
@@ -65,7 +66,7 @@ sealed class ParcelTarget(val world: ParcelWorld, val isDefault: Boolean) {
const val ID = 1 // ID
const val OWNER_REAL = 2 // an owner backed by a UUID
const val OWNER_FAKE = 3 // an owner not 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
@@ -73,7 +74,7 @@ sealed class ParcelTarget(val world: ParcelWorld, val isDefault: Boolean) {
const val DEFAULT_KIND = REAL
const val PREFER_OWNED_FOR_DEFAULT = 4 // if the kind can be ID and OWNER_REAL, prefer OWNER_REAL for default
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
}
@@ -95,12 +96,12 @@ sealed class ParcelTarget(val world: ParcelWorld, val isDefault: Boolean) {
val kind = parameter.paramInfo ?: DEFAULT_KIND
if (input.contains(',')) {
if (kind and ID == 0) invalidInput(parameter, "You must specify a parcel by OWNER, that is, an owner and index")
return ByID(world, getId(parameter, input), false)
return ByID(world, getId(parameter, input), kind, false)
}
if (kind and OWNER == 0) invalidInput(parameter, "You must specify a parcel by ID, that is, the x and z component separated by a comma")
val (owner, index) = getHomeIndex(parameter, kind, sender, input)
return ByOwner(world, owner, index, false, onResolveFailure = { invalidInput(parameter, "The player $input does not exist") })
return ByOwner(world, owner, index, kind, false, onResolveFailure = { invalidInput(parameter, "The player $input does not exist") })
}
private fun getId(parameter: Parameter<*, *>, input: String): Vec2i {
@@ -156,10 +157,10 @@ sealed class ParcelTarget(val world: ParcelWorld, val isDefault: Boolean) {
val world = parcelProvider.getWorld(player.world) ?: invalidInput(parameter, "You must be in a parcel world to omit the parcel")
if (useLocation) {
val id = player.location.let { world.getParcelIdAt(it.x.floor(), it.z.floor())?.pos }
return ByID(world, id, true)
return ByID(world, id, kind, true)
}
return ByOwner(world, PlayerProfile(player), 0, true)
return ByOwner(world, PlayerProfile(player), 0, kind, true)
}
}

View File

@@ -4,10 +4,8 @@ import io.dico.dicore.Formatting
import io.dico.parcels2.*
import io.dico.parcels2.util.Vec2i
import io.dico.parcels2.util.alsoIfTrue
import io.dico.parcels2.util.getPlayerName
import org.bukkit.OfflinePlayer
import org.joda.time.DateTime
import java.util.UUID
import kotlin.reflect.KProperty
class ParcelImpl(override val world: ParcelWorld,

View File

@@ -92,8 +92,9 @@ class ExposedBacking(private val dataSourceFactory: () -> DataSource, val poolSi
}
}
@Suppress("RedundantObjectTypeCheck")
private fun PlayerProfile.toOwnerProfile(): PlayerProfile {
if (this is PlayerProfile.Star) return PlayerProfile.Fake(PlayerProfile.Star.name)
if (this is PlayerProfile.Star) return PlayerProfile.Fake(name)
return this
}

View File

@@ -91,15 +91,19 @@ object ParcelsT : IdTransactionsTable<ParcelsT, ParcelId>("parcels", "parcel_id"
object ProfilesT : IdTransactionsTable<ProfilesT, PlayerProfile>("parcel_profiles", "owner_id") {
val uuid = binary("uuid", 16).nullable()
val name = varchar("name", 32)
val name = varchar("name", 32).nullable()
// MySQL dialect MUST permit multiple null values for this to work
val uuid_constraint = uniqueIndexR("uuid_constraint", uuid)
val index_pair = uniqueIndexR("index_pair", uuid, name)
private inline fun getId(binaryUuid: ByteArray) = getId { uuid eq binaryUuid }
private inline fun getId(uuid: UUID) = getId(uuid.toByteArray())
private inline fun getId(nameIn: String) = getId { uuid.isNull() and (name.lowerCase() eq nameIn.toLowerCase()) }
private inline fun getRealId(nameIn: String) = getId { uuid.isNotNull() and (name.lowerCase() eq nameIn.toLowerCase()) }
private inline fun getOrInitId(uuid: UUID, name: String) = uuid.toByteArray().let { binaryUuid -> getOrInitId(
private inline fun getOrInitId(uuid: UUID, name: String?) = uuid.toByteArray().let { binaryUuid -> getOrInitId(
{ getId(binaryUuid) },
{ it[this@ProfilesT.uuid] = binaryUuid; it[this@ProfilesT.name] = name },
{ "profile(uuid = $uuid, name = $name)" })
@@ -119,7 +123,7 @@ object ProfilesT : IdTransactionsTable<ProfilesT, PlayerProfile>("parcel_profile
}
override fun getOrInitId(profile: PlayerProfile): Int = when (profile) {
is PlayerProfile.Real -> getOrInitId(profile.uuid, profile.notNullName)
is PlayerProfile.Real -> getOrInitId(profile.uuid, profile.name)
is PlayerProfile.Fake -> getOrInitId(profile.name)
else -> throw IllegalArgumentException()
}

View File

@@ -22,6 +22,10 @@ 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?.isPresentAnd(condition: T.() -> Boolean): Boolean = this != null && condition()
inline fun <T> T?.ifNullRun(block: () -> Unit): T? {
if (this == null) block()
return this
}
inline fun <T, U> MutableMap<T, U>.editLoop(block: EditLoopScope<T, U>.(T, U) -> Unit) {
return EditLoopScope(this).doEditLoop(block)