From 494e2c530f7712e5d3d0a32822f38c9d23ef3da0 Mon Sep 17 00:00:00 2001 From: Micalhl Date: Fri, 16 Aug 2024 15:57:49 +0800 Subject: [PATCH] Update --- .../com/mcstarrysky/land/LandCommands.kt | 3 +- .../kotlin/com/mcstarrysky/land/data/Land.kt | 9 +- .../com/mcstarrysky/land/data/LandChunk.kt | 27 ++++++ .../mcstarrysky/land/listener/PosSelection.kt | 97 ++++++++----------- .../mcstarrysky/land/manager/LandManager.kt | 5 +- .../land/serializers/ChunkSerializer.kt | 61 +++++++++--- .../com/mcstarrysky/land/util/ChunkUtils.kt | 17 ++-- .../mcstarrysky/land/util/LocationUtils.kt | 8 +- .../kotlin/com/mcstarrysky/land/util/Utils.kt | 4 - src/main/resources/1.json | 27 ++++++ 10 files changed, 162 insertions(+), 96 deletions(-) create mode 100644 src/main/kotlin/com/mcstarrysky/land/data/LandChunk.kt create mode 100644 src/main/resources/1.json diff --git a/src/main/kotlin/com/mcstarrysky/land/LandCommands.kt b/src/main/kotlin/com/mcstarrysky/land/LandCommands.kt index 88c2eb9..1c630d0 100644 --- a/src/main/kotlin/com/mcstarrysky/land/LandCommands.kt +++ b/src/main/kotlin/com/mcstarrysky/land/LandCommands.kt @@ -1,5 +1,6 @@ package com.mcstarrysky.land +import com.mcstarrysky.land.data.toLandChunk import com.mcstarrysky.land.manager.LandManager import com.mcstarrysky.land.menu.LandMainMenu import com.mcstarrysky.land.util.prettyInfo @@ -79,7 +80,7 @@ object LandCommands { command("landdelete", permission = "admin") { exec { val land = LandManager.getLand(sender.location) ?: return@exec - land.area -= sender.location.chunk + land.area -= sender.location.chunk.toLandChunk() } } } diff --git a/src/main/kotlin/com/mcstarrysky/land/data/Land.kt b/src/main/kotlin/com/mcstarrysky/land/data/Land.kt index a747b1b..a9aac4b 100644 --- a/src/main/kotlin/com/mcstarrysky/land/data/Land.kt +++ b/src/main/kotlin/com/mcstarrysky/land/data/Land.kt @@ -5,7 +5,6 @@ import com.mcstarrysky.land.flag.PermAdmin import com.mcstarrysky.land.flag.PermTeleport import com.mcstarrysky.land.flag.Permission import com.mcstarrysky.land.manager.LandManager -import com.mcstarrysky.land.serializers.ChunkSerializer import com.mcstarrysky.land.serializers.LocationSerializer import com.mcstarrysky.land.serializers.UUIDSerializer import com.mcstarrysky.land.util.* @@ -15,7 +14,6 @@ import kotlinx.serialization.encodeToString import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer import org.bukkit.Bukkit -import org.bukkit.Chunk import org.bukkit.Location import org.bukkit.OfflinePlayer import org.bukkit.entity.Player @@ -44,7 +42,8 @@ data class Land( val timestamp: Long, val world: String, var description: String = "没有介绍", - val area: MutableList<@Serializable(with = ChunkSerializer::class) Chunk>, +// val area: MutableList<@Serializable(with = ChunkSerializer::class) Chunk>, + val area: MutableList, var enterMessage: String? = "你进入了 &{#8abcd1}$name", var leaveMessage: String? = "你离开了 &{#8abcd1}$name", @Serializable(with = LocationSerializer::class) @@ -70,7 +69,7 @@ data class Land( val date = DATE_FORMAT.format(Date(timestamp)) fun isInArea(location: Location): Boolean { - return area.any { it == location.chunk } + return area.any { it.isEqualBkChunk(location.chunk) } } fun tryClaim(player: Player) { @@ -89,7 +88,7 @@ data class Land( } if (player.checkItem(Land.crystal, 3)) { player.inventory.takeItem(3) { it.isSimilar(Land.crystal) } - area += location.chunk + area += location.chunk.toLandChunk() player.prettyInfo("占领区块成功!") } else { // 这里用到一个奇怪的操作 diff --git a/src/main/kotlin/com/mcstarrysky/land/data/LandChunk.kt b/src/main/kotlin/com/mcstarrysky/land/data/LandChunk.kt new file mode 100644 index 0000000..90ab104 --- /dev/null +++ b/src/main/kotlin/com/mcstarrysky/land/data/LandChunk.kt @@ -0,0 +1,27 @@ +package com.mcstarrysky.land.data + +import kotlinx.serialization.Serializable +import org.bukkit.Chunk + +/** + * Land + * com.mcstarrysky.land.data.LandChunk + * + * @author mical + * @since 2024/8/16 14:02 + */ +@Serializable +data class LandChunk( + val world: String, + val x: Int, + val z: Int +) { + + constructor(bkChunk: Chunk) : this(bkChunk.world.name, bkChunk.x, bkChunk.z) + + fun isEqualBkChunk(bkChunk: Chunk): Boolean { + return world == bkChunk.world.name && x == bkChunk.x && z == bkChunk.z + } +} + +fun Chunk.toLandChunk(): LandChunk = LandChunk(this) \ No newline at end of file diff --git a/src/main/kotlin/com/mcstarrysky/land/listener/PosSelection.kt b/src/main/kotlin/com/mcstarrysky/land/listener/PosSelection.kt index 1e1aae5..6306780 100644 --- a/src/main/kotlin/com/mcstarrysky/land/listener/PosSelection.kt +++ b/src/main/kotlin/com/mcstarrysky/land/listener/PosSelection.kt @@ -7,6 +7,7 @@ import com.mcstarrysky.land.util.prettyInfo import org.bukkit.Chunk import org.bukkit.event.player.PlayerInteractEvent import taboolib.common.platform.event.SubscribeEvent +import taboolib.common.platform.function.submitAsync import taboolib.platform.util.isLeftClickBlock import taboolib.platform.util.isMainhand import taboolib.platform.util.isRightClickBlock @@ -22,8 +23,8 @@ import java.util.concurrent.ConcurrentHashMap */ object PosSelection { - val pos1 = ConcurrentHashMap() - val pos2 = ConcurrentHashMap() + val record1 = ConcurrentHashMap() + val record2 = ConcurrentHashMap() @SubscribeEvent fun e(e: PlayerInteractEvent) { @@ -32,77 +33,61 @@ object PosSelection { if (e.isMainhand()) { // 是选择棒 if (player.equipment.itemInMainHand.isSimilar(Land.tool)) { - // 判断左右键 when { e.isLeftClickBlock() -> { e.isCancelled = true - val pos = e.clickedBlock!!.location.chunk - pos1.computeIfAbsent(player.uniqueId) { pos } - if (pos2[player.uniqueId] == null) { + val pos1 = e.clickedBlock!!.location.chunk + // 首先存入刚才的点 + record1 += player.uniqueId to pos1 + // 尝试获取第二个点 + val pos2 = record2[player.uniqueId] + if (pos2 == null || pos2.world != pos1.world) { listOf( "+========选择的范围信息========+", - "世界: &{#8cc269}" + LandSettings.worldAliases[pos.world.name], - "点1: &{#8cc269}(${pos.x}, ${pos.z})", + "世界: &{#8cc269}" + LandSettings.worldAliases[pos1.world.name], + "点1: &{#8cc269}(${pos1.x}, ${pos1.z})", "+===========================+" ).forEach { player.prettyInfo(it) } -// player.prettyInfo("+========选择的范围信息========+[](br)" + -// "世界: &{#8cc269}" + LandSettings.worldAliases[pos.world.name] + "[](br)" + -// "点1: &{#8cc269}(${pos.x}, ${pos.z})[](br)" + -// "+===================================+") - //"+==(输入/land进入领地主菜单)==+") } else { - val p2 = pos2[player.uniqueId]!! - val chunks = ChunkUtils.getChunksInRectangle(pos.world, pos, p2) - listOf( - "+========选择的范围信息========+", - "世界: &{#8cc269}" + LandSettings.worldAliases[pos.world.name], - "点1: &{#8cc269}(${pos.x}, ${pos.z})", - "点2: &{#8cc269}(${p2.x}, ${p2.z})", - "范围花费: 每区块3*共${chunks.size}个区块=${3*chunks.size}个开拓水晶", - "+====(输入/land进入领地主菜单)====+" - ).forEach { player.prettyInfo(it) } -// player.prettyInfo("+========选择的范围信息========+[](br)" + -// "世界: &{#8cc269}" + LandSettings.worldAliases[pos.world.name] + "[](br)" + -// "点1: &{#8cc269}(${pos.x}, ${pos.z})[](br)" + -// "点2: &{#8cc269}(${p2.x}, ${p2.z})[](br)" + -// "范围花费: 每区块3*共${chunks.size}个区块=${3*chunks.size}个开拓水晶[](br)" + -// "+==(输入/land进入领地主菜单)==+") + submitAsync { + val chunks = ChunkUtils.getChunksInRectangle(pos1.world, pos1, pos2) + listOf( + "+========选择的范围信息========+", + "世界: &{#8cc269}" + LandSettings.worldAliases[pos1.world.name], + "点1: &{#8cc269}(${pos1.x}, ${pos1.z})", + "点2: &{#8cc269}(${pos2.x}, ${pos2.z})", + "范围花费: 每区块3*共${chunks.size}个区块=${3*chunks.size}个开拓水晶", + "+====(输入/land进入领地主菜单)====+" + ).forEach { player.prettyInfo(it) } + } } } e.isRightClickBlock() -> { e.isCancelled = true - val pos = e.clickedBlock!!.location.chunk - pos2.computeIfAbsent(player.uniqueId) { pos } - if (pos1[player.uniqueId] == null) { + val pos2 = e.clickedBlock!!.location.chunk + // 首先存入刚才的点 + record2 += player.uniqueId to pos2 + // 尝试获取第一个点 + val pos1 = record1[player.uniqueId] + if (pos1 == null || pos1.world != pos2.world) { listOf( "+========选择的范围信息========+", - "世界: &{#8cc269}" + LandSettings.worldAliases[pos.world.name], - "点2: &{#8cc269}(${pos.x}, ${pos.z})", + "世界: &{#8cc269}" + LandSettings.worldAliases[pos2.world.name], + "点2: &{#8cc269}(${pos2.x}, ${pos2.z})", "+===========================+" ).forEach { player.prettyInfo(it) } -// player.prettyInfo("+========选择的范围信息========+[](br)" + -// "世界: &{#8cc269}" + LandSettings.worldAliases[pos.world.name] + "[](br)" + -// "点2: &{#8cc269}(${pos.x}, ${pos.z})[](br)" + -// "+===================================+") - //"+==(输入/land进入领地主菜单)==+") } else { - val p1 = pos1[player.uniqueId]!! - val chunks = ChunkUtils.getChunksInRectangle(pos.world, pos, p1) - listOf( - "+========选择的范围信息========+", - "世界: &{#8cc269}" + LandSettings.worldAliases[pos.world.name], - "点1: &{#8cc269}(${p1.x}, ${p1.z})", - "点2: &{#8cc269}(${pos.x}, ${pos.z})", - "范围花费: 每区块3*共${chunks.size}个区块=${3*chunks.size}个开拓水晶", - "+====(输入/land进入领地主菜单)====+" - ).forEach { player.prettyInfo(it) } - -// player.prettyInfo("+========选择的范围信息========+[](br)" + -// "世界: &{#8cc269}" + LandSettings.worldAliases[pos.world.name] + "[](br)" + -// "点1: &{#8cc269}(${p1.x}, ${p1.z})[](br)" + -// "点2: &{#8cc269}(${pos.x}, ${pos.z})[](br)" + -// "范围花费: 每区块3*区块数${chunks.size}=${3*chunks.size}个开拓水晶[](br)" + -// "+==(输入/land进入领地主菜单)==+") + submitAsync { + val chunks = ChunkUtils.getChunksInRectangle(pos1.world, pos1, pos2) + listOf( + "+========选择的范围信息========+", + "世界: &{#8cc269}" + LandSettings.worldAliases[pos1.world.name], + "点1: &{#8cc269}(${pos1.x}, ${pos1.z})", + "点2: &{#8cc269}(${pos2.x}, ${pos2.z})", + "范围花费: 每区块3*共${chunks.size}个区块=${3*chunks.size}个开拓水晶", + "+====(输入/land进入领地主菜单)====+" + ).forEach { player.prettyInfo(it) } + } } } } diff --git a/src/main/kotlin/com/mcstarrysky/land/manager/LandManager.kt b/src/main/kotlin/com/mcstarrysky/land/manager/LandManager.kt index e06344f..526ffe8 100644 --- a/src/main/kotlin/com/mcstarrysky/land/manager/LandManager.kt +++ b/src/main/kotlin/com/mcstarrysky/land/manager/LandManager.kt @@ -19,7 +19,6 @@ import taboolib.platform.util.checkItem import taboolib.platform.util.takeItem import java.nio.charset.StandardCharsets import java.util.LinkedList -import kotlin.math.ceil /** * Land @@ -106,8 +105,8 @@ object LandManager { } fun create(player: Player, name: String) { - val chunk1 = PosSelection.pos1[player.uniqueId] - val chunk2 = PosSelection.pos2[player.uniqueId] + val chunk1 = PosSelection.record1[player.uniqueId] + val chunk2 = PosSelection.record2[player.uniqueId] if (chunk1 == null || chunk2 == null) { player.prettyInfo("你尚未选择点! 请先用领地棒选择两个点!") return diff --git a/src/main/kotlin/com/mcstarrysky/land/serializers/ChunkSerializer.kt b/src/main/kotlin/com/mcstarrysky/land/serializers/ChunkSerializer.kt index 7722361..ec3281a 100644 --- a/src/main/kotlin/com/mcstarrysky/land/serializers/ChunkSerializer.kt +++ b/src/main/kotlin/com/mcstarrysky/land/serializers/ChunkSerializer.kt @@ -1,31 +1,60 @@ package com.mcstarrysky.land.serializers -import com.mcstarrysky.land.util.deserializeToChunk -import com.mcstarrysky.land.util.serializeToString +import com.mcstarrysky.land.data.LandChunk import kotlinx.serialization.KSerializer -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder -import org.bukkit.Chunk +import kotlinx.serialization.SerializationException +import kotlinx.serialization.descriptors.* +import kotlinx.serialization.encoding.* /** - * Land - * com.mcstarrysky.land.serializers.ChunkSerializer + * 保留旧版本区块序列化兼容性 * * @author mical * @since 2024/8/2 22:45 */ -object ChunkSerializer : KSerializer { +object ChunkSerializer : KSerializer { - override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("org.bukkit.Chunk", PrimitiveKind.STRING) + override val descriptor: SerialDescriptor = buildClassSerialDescriptor("LandChunk") { + element("world") + element("x") + element("z") + } - override fun serialize(encoder: Encoder, value: Chunk) { - encoder.encodeString(value.serializeToString()) + override fun serialize(encoder: Encoder, value: LandChunk) { + // 全部正常序列化成 Json + encoder.encodeStructure(descriptor) { + encodeStringElement(descriptor, 0, value.world) + encodeIntElement(descriptor, 1, value.x) + encodeIntElement(descriptor, 2, value.z) + } } - override fun deserialize(decoder: Decoder): Chunk { - return decoder.decodeString().deserializeToChunk() + override fun deserialize(decoder: Decoder): LandChunk { + val input = decoder.decodeString() + + return if (input.contains("~") && input.contains(",")) { + // 旧版本格式解析 + val data = input.split("~") + val world = data[0] + val (x, z) = data[1].split(",").map { it.toInt() } + LandChunk(world, x, z) + } else { + // 新版本格式解析 + decoder.decodeStructure(descriptor) { + var world = "" + var x = 0 + var z = 0 + while (true) { + when (val index = decodeElementIndex(descriptor)) { + 0 -> world = decodeStringElement(descriptor, 0) + 1 -> x = decodeIntElement(descriptor, 1) + 2 -> z = decodeIntElement(descriptor, 2) + CompositeDecoder.DECODE_DONE -> break + else -> throw SerializationException("Unknown index $index") + } + } + LandChunk(world, x, z) + } + } } } \ No newline at end of file diff --git a/src/main/kotlin/com/mcstarrysky/land/util/ChunkUtils.kt b/src/main/kotlin/com/mcstarrysky/land/util/ChunkUtils.kt index 8ff8deb..0d72d71 100644 --- a/src/main/kotlin/com/mcstarrysky/land/util/ChunkUtils.kt +++ b/src/main/kotlin/com/mcstarrysky/land/util/ChunkUtils.kt @@ -1,5 +1,6 @@ package com.mcstarrysky.land.util +import com.mcstarrysky.land.data.LandChunk import org.bukkit.Chunk import org.bukkit.Location import org.bukkit.World @@ -14,8 +15,8 @@ import kotlin.math.abs */ object ChunkUtils { - fun getCenteredChunks(location: Location, m: Int): List { - val chunks = mutableListOf() + fun getCenteredChunks(location: Location, m: Int): List { + val chunks = mutableListOf() val playerChunk = location.chunk val playerChunkX = playerChunk.x val playerChunkZ = playerChunk.z @@ -24,7 +25,7 @@ object ChunkUtils { // Iterate through an m*m grid of chunks around the player's chunk for (dz in -radius..radius) { // Iterate vertically for (dx in -radius..radius) { // Iterate horizontally - val chunk = location.world.getChunkAt(playerChunkX + dx, playerChunkZ + dz) + val chunk = LandChunk(location.world.name, playerChunkX + dx, playerChunkZ + dz) chunks.add(chunk) } } @@ -32,19 +33,19 @@ object ChunkUtils { return chunks } - fun getChunksInRectangle(world: World, chunk1: Chunk, chunk2: Chunk): List { + fun getChunksInRectangle(world: World, chunk1: Chunk, chunk2: Chunk): List { // 获取 chunk1 和 chunk2 的边界 val minX = minOf(chunk1.x, chunk2.x) val minZ = minOf(chunk1.z, chunk2.z) val maxX = maxOf(chunk1.x, chunk2.x) val maxZ = maxOf(chunk1.z, chunk2.z) - val chunks = mutableListOf() + val chunks = mutableListOf() // 遍历矩形内的所有 Chunk for (x in minX..maxX) { for (z in minZ..maxZ) { - val chunk = world.getChunkAt(x, z) + val chunk = LandChunk(world.name, x, z) chunks.add(chunk) } } @@ -52,8 +53,8 @@ object ChunkUtils { return chunks } - fun isAdjacentToAnyChunk(chunk: Chunk, chunkList: List): Boolean { - return chunkList.all { it.world == chunk.world } && chunkList.any { neighborChunk -> + fun isAdjacentToAnyChunk(chunk: Chunk, chunkList: List): Boolean { + return chunkList.all { it.world == chunk.world.name } && chunkList.any { neighborChunk -> val dx = abs(chunk.x - neighborChunk.x) val dz = abs(chunk.z - neighborChunk.z) (dx <= 1 && dz <= 1) && (dx != 0 || dz != 0) diff --git a/src/main/kotlin/com/mcstarrysky/land/util/LocationUtils.kt b/src/main/kotlin/com/mcstarrysky/land/util/LocationUtils.kt index eeba2cf..6ced95e 100644 --- a/src/main/kotlin/com/mcstarrysky/land/util/LocationUtils.kt +++ b/src/main/kotlin/com/mcstarrysky/land/util/LocationUtils.kt @@ -1,5 +1,7 @@ package com.mcstarrysky.land.util +import com.mcstarrysky.land.data.LandChunk +import org.bukkit.Bukkit import org.bukkit.Chunk import org.bukkit.Location import org.bukkit.World @@ -20,7 +22,7 @@ object LocationUtils { * @return 地面上的一个位置 * @throws IllegalArgumentException 如果区块列表为空 */ - fun calculateLandCenter(chunks: List, world: World): Location { + fun calculateLandCenter(chunks: List, world: World): Location { require(chunks.isNotEmpty()) { "区块列表不能为空" } var totalX = 0.0 @@ -58,10 +60,10 @@ object LocationUtils { * @param chunk 区块对象 * @return 区块中心的位置 */ - fun getChunkCenter(chunk: Chunk): Location { + fun getChunkCenter(chunk: LandChunk): Location { val x = (chunk.x shl 4) + 8 val z = (chunk.z shl 4) + 8 - return Location(chunk.world, x.toDouble(), 0.0, z.toDouble()) + return Location(Bukkit.getWorld(chunk.world), x.toDouble(), 0.0, z.toDouble()) } /** diff --git a/src/main/kotlin/com/mcstarrysky/land/util/Utils.kt b/src/main/kotlin/com/mcstarrysky/land/util/Utils.kt index 0587453..59605fb 100644 --- a/src/main/kotlin/com/mcstarrysky/land/util/Utils.kt +++ b/src/main/kotlin/com/mcstarrysky/land/util/Utils.kt @@ -60,10 +60,6 @@ fun String.deserializeToLocation(): Location { return Location(Bukkit.getWorld(world), x, y, z, yaw, pitch) } -fun Chunk.serializeToString(): String { - return "${world.name}~$x,$z" -} - fun String.deserializeToChunk(): Chunk { val (world, pos) = split("~") val (x, z) = pos.split(",").map { it.toInt() } diff --git a/src/main/resources/1.json b/src/main/resources/1.json new file mode 100644 index 0000000..515d0b1 --- /dev/null +++ b/src/main/resources/1.json @@ -0,0 +1,27 @@ +{ + "id": 10, + "name": "沼泽一体刷怪塔", + "owner": "5e06510c-27d3-4176-950a-0d8fbab3238d", + "timestamp": 1723737461771, + "world": "world", + "description": "沼泽一体刷怪塔", + "area": [ + { + "world": "world", + "x": 9, + "z": -214 + } + ], + "tpLocation": "world~152.49297951285712,56.0,-3410.90566511774~179.43254,2.0205872", + "flags": { + "bucket": false, + "build": false, + "container": true, + "entity_explosion": true, + "interact": true, + "teleport": true, + "mob_spawn": true, + "teleport_in": true + }, + "users": [] +} \ No newline at end of file