diff --git a/src/main/kotlin/com/mcstarrysky/land/listener/PosSelection.kt b/src/main/kotlin/com/mcstarrysky/land/listener/PosSelection.kt index fb729a2..a70f282 100644 --- a/src/main/kotlin/com/mcstarrysky/land/listener/PosSelection.kt +++ b/src/main/kotlin/com/mcstarrysky/land/listener/PosSelection.kt @@ -1,6 +1,9 @@ package com.mcstarrysky.land.listener import com.mcstarrysky.land.Land +import com.mcstarrysky.land.LandSettings +import com.mcstarrysky.land.util.ChunkUtils +import com.mcstarrysky.land.util.prettyInfo import org.bukkit.Chunk import org.bukkit.event.player.PlayerInteractEvent import taboolib.common.platform.event.SubscribeEvent @@ -31,8 +34,46 @@ object PosSelection { if (player.equipment.itemInMainHand.isSimilar(Land.tool)) { // 判断左右键 when { - e.isLeftClickBlock() -> pos1.computeIfAbsent(player.uniqueId) { e.clickedBlock!!.location.chunk } - e.isRightClickBlock() -> pos2.computeIfAbsent(player.uniqueId) { e.clickedBlock!!.location.chunk } + e.isLeftClickBlock() -> { + val pos = e.clickedBlock!!.location.chunk + pos1.computeIfAbsent(player.uniqueId) { pos } + if (pos2[player.uniqueId] == null) { + player.prettyInfo("+========选择的范围信息========+[](br)" + + "世界: &b" + LandSettings.worldAliases[pos.world.name] + "[](br)" + + "点1: &b(${pos.x}, ${pos.z})[](br)" + + "+===================================+") + //"+==(输入/land进入领地主菜单)==+") + } else { + val p2 = pos2[player.uniqueId]!! + val chunks = ChunkUtils.getChunksInRectangle(pos.world, pos, p2) + player.prettyInfo("+========选择的范围信息========+[](br)" + + "世界: &b" + LandSettings.worldAliases[pos.world.name] + "[](br)" + + "点1: &b(${pos.x}, ${pos.z})[](br)" + + "点2: &b(${p2.x}, ${p2.z})[](br)" + + "范围花费: 每区块3*区块数${chunks.size}=${3*chunks.size}个开拓水晶[](br)" + + "+==(输入/land进入领地主菜单)==+") + } + } + e.isRightClickBlock() -> { + val pos = e.clickedBlock!!.location.chunk + pos2.computeIfAbsent(player.uniqueId) { pos } + if (pos1[player.uniqueId] == null) { + player.prettyInfo("+========选择的范围信息========+[](br)" + + "世界: &b" + LandSettings.worldAliases[pos.world.name] + "[](br)" + + "点2: &b(${pos.x}, ${pos.z})[](br)" + + "+===================================+") + //"+==(输入/land进入领地主菜单)==+") + } else { + val p1 = pos1[player.uniqueId]!! + val chunks = ChunkUtils.getChunksInRectangle(pos.world, pos, p1) + player.prettyInfo("+========选择的范围信息========+[](br)" + + "世界: &b" + LandSettings.worldAliases[pos.world.name] + "[](br)" + + "点1: &b(${p1.x}, ${p1.z})[](br)" + + "点2: &b(${pos.x}, ${pos.z})[](br)" + + "范围花费: 每区块3*区块数${chunks.size}=${3*chunks.size}个开拓水晶[](br)" + + "+==(输入/land进入领地主菜单)==+") + } + } } } } diff --git a/src/main/kotlin/com/mcstarrysky/land/manager/LandManager.kt b/src/main/kotlin/com/mcstarrysky/land/manager/LandManager.kt index e108af3..4a135fd 100644 --- a/src/main/kotlin/com/mcstarrysky/land/manager/LandManager.kt +++ b/src/main/kotlin/com/mcstarrysky/land/manager/LandManager.kt @@ -1,18 +1,25 @@ package com.mcstarrysky.land.manager import com.mcstarrysky.land.data.Land -import com.mcstarrysky.land.flag.Permission +import com.mcstarrysky.land.flag.* +import com.mcstarrysky.land.listener.PosSelection import com.mcstarrysky.land.util.* -import org.bukkit.Chunk +import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer +import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer import org.bukkit.Location import org.bukkit.entity.Player import org.bukkit.persistence.PersistentDataType import taboolib.common.io.newFile import taboolib.common.io.newFolder import taboolib.common.platform.Schedule +import taboolib.common.platform.function.adaptPlayer import taboolib.common.platform.function.getDataFolder +import taboolib.module.chat.Components +import taboolib.platform.util.checkItem +import taboolib.platform.util.takeItem import java.nio.charset.StandardCharsets import java.util.LinkedList +import kotlin.math.ceil /** * Land @@ -38,17 +45,25 @@ object LandManager { // "banPotionHurt" to true // ) - val defaultFlags = mapOf( - "bucket" to false, - "build" to false, - "container" to false, - "entity_explosion" to true, - "interact" to false, - "mob_spawn" to true, - "teleport" to true, - "move" to true, - "teleport_in" to true, - "teleport_out" to true +// val defaultFlags = mapOf( +// "bucket" to false, +// "build" to false, +// "container" to false, +// "entity_explosion" to true, +// "interact" to false, +// "mob_spawn" to true, +// "teleport" to true, +// "move" to true, +// "teleport_in" to true, +// "teleport_out" to true +// ) + val defaultFlags = listOf( + PermBucket, + PermBuild, + PermContainer, + PermEntityExplosion, + PermInteract, + PermTeleport ) val lands = LinkedList() @@ -89,8 +104,76 @@ object LandManager { return lands.any { it.name == name } } - fun create(player: Player, name: String, chunk1: Chunk, chunk2: Chunk) { + fun create(player: Player, name: String) { + val chunk1 = PosSelection.pos1[player.uniqueId] + val chunk2 = PosSelection.pos2[player.uniqueId] + if (chunk1 == null || chunk2 == null) { + player.prettyInfo("你尚未选择点! 请先用领地棒选择两个点!") + return + } + + if (chunk1.world != chunk2.world) { + player.prettyInfo("你选择的两个区块必须要在同一个世界!") + return + } + + + val area = ChunkUtils.getChunksInRectangle(chunk1.world, chunk1, chunk2) + if (area.any { chunk -> lands.any { it.area.contains(chunk) } }) { + player.prettyInfo("你的领地区域与现有领地区域重叠, 请重新选择位置!") + return + } + if (!name.isValidLandName()) { + player.prettyInfo("为避免与领地编号混淆, 名字不能是纯数字!") + return + } + if (hasLand(name)) { + player.prettyInfo("你输入的名字已存在! 请重新操作") + return + } + + val crystalNeeds = area.size * 3 + if (player.checkItem(com.mcstarrysky.land.Land.crystal, crystalNeeds)) { + player.inventory.takeItem(crystalNeeds) { it.isSimilar(com.mcstarrysky.land.Land.crystal) } + } else { + // 这里用到一个奇怪的操作 + Components.parseRaw( + GsonComponentSerializer.gson() + .serialize( + GsonComponentSerializer.gson() + .deserialize(cacheMessageWithPrefix("抱歉, 你要准备 $crystalNeeds 个").toRawMessage()) + .append( + LegacyComponentSerializer.legacyAmpersand().deserialize("&b开拓水晶") + .hoverEvent(com.mcstarrysky.land.Land.crystal.clone().asHoverEvent()) + ) + ) + ).append(cacheMessageWithPrefixColor(" 才能占领你选中的这 ${area.size} 个区块")) + .sendTo(adaptPlayer(player)) + } + + val centre = LocationUtils.calculateLandCenter(area, player.world) + player.prettyInfo("自动设置领地传送点为领地中央位置.") + val land = Land( + newId(), + name, + player.uniqueId, + System.currentTimeMillis(), + centre.world.name, + name, + area = area.toMutableList(), + tpLocation = centre, + cooperators = mutableListOf(), + users = mutableMapOf() + ) + for (perm in defaultFlags) { + val flag = perm.id + val value = perm.default + player.prettyInfo("自动添加标记 [{0}](color=#8abcd1) &7\\(值: {1}\\)", flag, value) + land.flags += flag to value + } + lands += land + player.prettyInfo("创建领地 (ID: ${land.id}) 成功.") } fun createFree(player: Player, clickedLocation: Location) { @@ -126,12 +209,18 @@ object LandManager { cooperators = mutableListOf(), users = mutableMapOf() ) - for ((flag, value) in defaultFlags) { + for (perm in defaultFlags) { + val flag = perm.id + val value = perm.default player.prettyInfo("自动添加标记 [{0}](color=#8abcd1) &7\\(值: {1}\\)", flag, value) land.flags += flag to value } +// for ((flag, value) in defaultFlags) { +// player.prettyInfo("自动添加标记 [{0}](color=#8abcd1) &7\\(值: {1}\\)", flag, value) +// land.flags += flag to value +// } lands += land - player.prettyInfo("创建免费领地成功.") + player.prettyInfo("创建免费领地 (ID: ${land.id}) 成功.") player["land_free_created", PersistentDataType.BOOLEAN] = true } diff --git a/src/main/kotlin/com/mcstarrysky/land/menu/LandSelectionMenu.kt b/src/main/kotlin/com/mcstarrysky/land/menu/LandSelectionMenu.kt index 601b848..eaa658d 100644 --- a/src/main/kotlin/com/mcstarrysky/land/menu/LandSelectionMenu.kt +++ b/src/main/kotlin/com/mcstarrysky/land/menu/LandSelectionMenu.kt @@ -1,6 +1,7 @@ package com.mcstarrysky.land.menu import com.mcstarrysky.land.Land +import com.mcstarrysky.land.manager.LandManager import com.mcstarrysky.land.util.MenuRegistry import com.mcstarrysky.land.util.MenuRegistry.markBoard import com.mcstarrysky.land.util.MenuRegistry.markHeader @@ -11,6 +12,7 @@ import taboolib.module.ui.openMenu import taboolib.module.ui.type.Chest import taboolib.platform.util.buildItem import taboolib.platform.util.giveItem +import taboolib.platform.util.nextChat import java.util.function.Consumer /** @@ -24,11 +26,11 @@ object LandSelectionMenu { fun openMenu(player: Player, back: Consumer?) { player.openMenu("选择范围") { - virtualize() + // virtualize() map( "b========", - " f ", // 免费领地棒 + " f g h ", // 免费领地棒 "=========" ) @@ -55,6 +57,39 @@ object LandSelectionMenu { clicker.giveItem(Land.freeLandTool.clone()) clicker.prettyInfo("获取免费领地棒成功.") } + + set('g', buildItem(XMaterial.STICK) { + name = "&a选择棒" + lore += listOf( + "&e单击领取", + "&7", + "&7左键任意方块选择区块1", + "&7右键任意方块选择区块2", + "&7输入&{#8abcd1}/land&7进入领地主菜单" + ) + colored() + }) { + clicker.closeInventory() + clicker.giveItem(Land.tool.clone()) + clicker.prettyInfo("获取选择棒成功.") + } + + set('h', buildItem(XMaterial.FILLED_MAP) { + name = "&d创建领地" + lore += listOf( + "&7花费: &33开拓水晶*区块数", + "&7(领地是私人+自由性质的)", + "&7(需要输入)" + ) + colored() + }) { + clicker.closeInventory() + clicker.prettyInfo("请在聊天框输入领地名字, 输入'取消'来取消!") + clicker.nextChat { + if (it == "取消") return@nextChat + LandManager.create(clicker, it) + } + } } } } \ 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 6b58765..aeb86af 100644 --- a/src/main/kotlin/com/mcstarrysky/land/util/ChunkUtils.kt +++ b/src/main/kotlin/com/mcstarrysky/land/util/ChunkUtils.kt @@ -2,6 +2,7 @@ package com.mcstarrysky.land.util import org.bukkit.Chunk import org.bukkit.Location +import org.bukkit.World /** * Land @@ -29,4 +30,24 @@ object ChunkUtils { return chunks } + + 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() + + // 遍历矩形内的所有 Chunk + for (x in minX..maxX) { + for (z in minZ..maxZ) { + val chunk = world.getChunkAt(x, z) + chunks.add(chunk) + } + } + + return chunks + } } \ No newline at end of file