Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
Micalhl committed Aug 16, 2024
1 parent 2d52ff4 commit 494e2c5
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 96 deletions.
3 changes: 2 additions & 1 deletion src/main/kotlin/com/mcstarrysky/land/LandCommands.kt
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -79,7 +80,7 @@ object LandCommands {
command("landdelete", permission = "admin") {
exec<Player> {
val land = LandManager.getLand(sender.location) ?: return@exec
land.area -= sender.location.chunk
land.area -= sender.location.chunk.toLandChunk()
}
}
}
Expand Down
9 changes: 4 additions & 5 deletions src/main/kotlin/com/mcstarrysky/land/data/Land.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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.*
Expand All @@ -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
Expand Down Expand Up @@ -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<LandChunk>,
var enterMessage: String? = "你进入了 &{#8abcd1}$name",
var leaveMessage: String? = "你离开了 &{#8abcd1}$name",
@Serializable(with = LocationSerializer::class)
Expand All @@ -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) {
Expand All @@ -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 {
// 这里用到一个奇怪的操作
Expand Down
27 changes: 27 additions & 0 deletions src/main/kotlin/com/mcstarrysky/land/data/LandChunk.kt
Original file line number Diff line number Diff line change
@@ -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)
97 changes: 41 additions & 56 deletions src/main/kotlin/com/mcstarrysky/land/listener/PosSelection.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -22,8 +23,8 @@ import java.util.concurrent.ConcurrentHashMap
*/
object PosSelection {

val pos1 = ConcurrentHashMap<UUID, Chunk>()
val pos2 = ConcurrentHashMap<UUID, Chunk>()
val record1 = ConcurrentHashMap<UUID, Chunk>()
val record2 = ConcurrentHashMap<UUID, Chunk>()

@SubscribeEvent
fun e(e: PlayerInteractEvent) {
Expand All @@ -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) }
}
}
}
}
Expand Down
5 changes: 2 additions & 3 deletions src/main/kotlin/com/mcstarrysky/land/manager/LandManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
61 changes: 45 additions & 16 deletions src/main/kotlin/com/mcstarrysky/land/serializers/ChunkSerializer.kt
Original file line number Diff line number Diff line change
@@ -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<Chunk> {
object ChunkSerializer : KSerializer<LandChunk> {

override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("org.bukkit.Chunk", PrimitiveKind.STRING)
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("LandChunk") {
element<String>("world")
element<Int>("x")
element<Int>("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)
}
}
}
}
17 changes: 9 additions & 8 deletions src/main/kotlin/com/mcstarrysky/land/util/ChunkUtils.kt
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -14,8 +15,8 @@ import kotlin.math.abs
*/
object ChunkUtils {

fun getCenteredChunks(location: Location, m: Int): List<Chunk> {
val chunks = mutableListOf<Chunk>()
fun getCenteredChunks(location: Location, m: Int): List<LandChunk> {
val chunks = mutableListOf<LandChunk>()
val playerChunk = location.chunk
val playerChunkX = playerChunk.x
val playerChunkZ = playerChunk.z
Expand All @@ -24,36 +25,36 @@ 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)
}
}

return chunks
}

fun getChunksInRectangle(world: World, chunk1: Chunk, chunk2: Chunk): List<Chunk> {
fun getChunksInRectangle(world: World, chunk1: Chunk, chunk2: Chunk): List<LandChunk> {
// 获取 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<Chunk>()
val chunks = mutableListOf<LandChunk>()

// 遍历矩形内的所有 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)
}
}

return chunks
}

fun isAdjacentToAnyChunk(chunk: Chunk, chunkList: List<Chunk>): Boolean {
return chunkList.all { it.world == chunk.world } && chunkList.any { neighborChunk ->
fun isAdjacentToAnyChunk(chunk: Chunk, chunkList: List<LandChunk>): 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)
Expand Down
Loading

0 comments on commit 494e2c5

Please sign in to comment.