|
| 1 | +@file:OptIn(NmsUseWithCaution::class) |
| 2 | + |
| 3 | +package dev.slne.surf.surfapi.bukkit.test.command.subcommands |
| 4 | + |
| 5 | +import dev.jorel.commandapi.CommandAPICommand |
| 6 | +import dev.jorel.commandapi.arguments.AsyncPlayerProfileArgument |
| 7 | +import dev.jorel.commandapi.kotlindsl.argument |
| 8 | +import dev.jorel.commandapi.kotlindsl.getValue |
| 9 | +import dev.jorel.commandapi.kotlindsl.integerArgument |
| 10 | +import dev.jorel.commandapi.kotlindsl.subcommand |
| 11 | +import dev.slne.surf.api.paper.command.executors.anyExecutorSuspend |
| 12 | +import dev.slne.surf.api.paper.command.executors.playerExecutorSuspend |
| 13 | +import dev.slne.surf.api.paper.command.util.awaitAsyncPlayerProfile |
| 14 | +import dev.slne.surf.api.paper.command.util.idOrThrow |
| 15 | +import dev.slne.surf.api.paper.extensions.server |
| 16 | +import dev.slne.surf.api.paper.nms.NmsUseWithCaution |
| 17 | +import dev.slne.surf.api.paper.nms.bridges.SurfPaperNmsPlayerBridge |
| 18 | +import dev.slne.surf.surfapi.bukkit.test.command.args.EquipmentSlotArgument |
| 19 | +import org.bukkit.command.CommandSender |
| 20 | +import org.bukkit.inventory.EquipmentSlot |
| 21 | +import java.util.* |
| 22 | + |
| 23 | +class OfflineInventoryEditTest(name: String) : CommandAPICommand(name) { |
| 24 | + init { |
| 25 | + setSlotCommand() |
| 26 | + setEquipmentCommand() |
| 27 | + summaryCommand() |
| 28 | + clearCommand() |
| 29 | + } |
| 30 | + |
| 31 | + private fun setSlotCommand() = subcommand("set-slot") { |
| 32 | + argument(AsyncPlayerProfileArgument("player")) |
| 33 | + integerArgument("slot", 0, 35) |
| 34 | + |
| 35 | + playerExecutorSuspend { sender, args -> |
| 36 | + val target = args.awaitAsyncPlayerProfile("player").idOrThrow() |
| 37 | + val slot: Int by args |
| 38 | + val item = sender.inventory.itemInMainHand.clone() |
| 39 | + |
| 40 | + if (item.isEmpty) { |
| 41 | + sender.sendMessage("Hold an item in your main hand to copy it into the offline inventory.") |
| 42 | + return@playerExecutorSuspend |
| 43 | + } |
| 44 | + |
| 45 | + if (!runEdit(sender, target) { edit -> |
| 46 | + edit.items[slot] = item |
| 47 | + }) return@playerExecutorSuspend |
| 48 | + |
| 49 | + sender.sendMessage("Set slot $slot of $target to ${item.type.key.asString()} x${item.amount}.") |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | + private fun setEquipmentCommand() = subcommand("set-equipment") { |
| 54 | + argument(AsyncPlayerProfileArgument("player")) |
| 55 | + argument(EquipmentSlotArgument("slot")) |
| 56 | + |
| 57 | + playerExecutorSuspend { sender, args -> |
| 58 | + val target = args.awaitAsyncPlayerProfile("player").idOrThrow() |
| 59 | + val slot: EquipmentSlot by args |
| 60 | + val item = sender.inventory.itemInMainHand.clone() |
| 61 | + |
| 62 | + if (item.isEmpty) { |
| 63 | + sender.sendMessage("Hold an item in your main hand to copy it into the offline equipment.") |
| 64 | + return@playerExecutorSuspend |
| 65 | + } |
| 66 | + |
| 67 | + if (!runEdit(sender, target) { edit -> |
| 68 | + edit.equipment.setItem(slot, item) |
| 69 | + }) return@playerExecutorSuspend |
| 70 | + |
| 71 | + sender.sendMessage("Set equipment slot ${slot.name} of $target to ${item.type.key.asString()} x${item.amount}.") |
| 72 | + } |
| 73 | + } |
| 74 | + |
| 75 | + private fun summaryCommand() = subcommand("summary") { |
| 76 | + argument(AsyncPlayerProfileArgument("player")) |
| 77 | + |
| 78 | + anyExecutorSuspend { sender, args -> |
| 79 | + val target = args.awaitAsyncPlayerProfile("player").idOrThrow() |
| 80 | + var inventoryItems = emptyList<String>() |
| 81 | + var equipmentItems = emptyList<String>() |
| 82 | + |
| 83 | + if (!runEdit(sender, target) { edit -> |
| 84 | + inventoryItems = edit.items.withIndex() |
| 85 | + .filter { (_, item) -> !item.isEmpty } |
| 86 | + .map { (slot, item) -> "slot $slot=${item.type.key.asString()} x${item.amount}" } |
| 87 | + |
| 88 | + equipmentItems = EDITABLE_EQUIPMENT_SLOTS |
| 89 | + .map { slot -> slot to edit.equipment.getItem(slot) } |
| 90 | + .filter { (_, item) -> !item.isEmpty } |
| 91 | + .map { (slot, item) -> "${slot.name}=${item.type.key.asString()} x${item.amount}" } |
| 92 | + }) return@anyExecutorSuspend |
| 93 | + |
| 94 | + sender.sendMessage("Offline inventory summary for ${target}:") |
| 95 | + sender.sendMessage("Inventory: ${inventoryItems.ifEmpty { listOf("empty") }.joinToString()}") |
| 96 | + sender.sendMessage("Equipment: ${equipmentItems.ifEmpty { listOf("empty") }.joinToString()}") |
| 97 | + } |
| 98 | + } |
| 99 | + |
| 100 | + private fun clearCommand() = subcommand("clear") { |
| 101 | + argument(AsyncPlayerProfileArgument("player")) |
| 102 | + |
| 103 | + anyExecutorSuspend { sender, args -> |
| 104 | + val target = args.awaitAsyncPlayerProfile("player").idOrThrow() |
| 105 | + |
| 106 | + if (!runEdit(sender, target) { edit -> |
| 107 | + edit.items.clear() |
| 108 | + edit.equipment.clear() |
| 109 | + }) return@anyExecutorSuspend |
| 110 | + |
| 111 | + sender.sendMessage("Cleared offline inventory and equipment of ${target}.") |
| 112 | + } |
| 113 | + } |
| 114 | + |
| 115 | + private suspend fun runEdit( |
| 116 | + sender: CommandSender, |
| 117 | + target: UUID, |
| 118 | + edit: (SurfPaperNmsPlayerBridge.PlayerInventoryEdit) -> Unit |
| 119 | + ): Boolean { |
| 120 | + return runCatching { |
| 121 | + SurfPaperNmsPlayerBridge.editOfflineInventory(server.getOfflinePlayer(target), edit) |
| 122 | + }.onFailure { error -> |
| 123 | + sender.sendMessage("editOfflineInventory failed: ${error::class.simpleName}: ${error.message}") |
| 124 | + }.isSuccess |
| 125 | + } |
| 126 | + |
| 127 | + companion object { |
| 128 | + private val EDITABLE_EQUIPMENT_SLOTS = listOf( |
| 129 | + EquipmentSlot.HAND, |
| 130 | + EquipmentSlot.OFF_HAND, |
| 131 | + EquipmentSlot.HEAD, |
| 132 | + EquipmentSlot.CHEST, |
| 133 | + EquipmentSlot.LEGS, |
| 134 | + EquipmentSlot.FEET |
| 135 | + ) |
| 136 | + } |
| 137 | +} |
0 commit comments