package com.beemer.essentials.gui import net.minecraft.ChatFormatting import net.minecraft.core.component.DataComponents import net.minecraft.nbt.CompoundTag import net.minecraft.network.chat.Component import net.minecraft.server.level.ServerPlayer import net.minecraft.sounds.SoundEvents import net.minecraft.sounds.SoundSource import net.minecraft.world.Container import net.minecraft.world.SimpleContainer import net.minecraft.world.SimpleMenuProvider import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.ClickType import net.minecraft.world.inventory.ContainerLevelAccess import net.minecraft.world.inventory.CraftingMenu import net.minecraft.world.inventory.MenuType import net.minecraft.world.inventory.Slot import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items import net.minecraft.world.item.component.CustomData import net.minecraft.world.item.component.ItemLore /** Essentials 메뉴 GUI - Shift+F로 열기 스폰, 좌표, 제작대 등 주요 기능 바로가기 */ class EssentialsMenuGui( syncId: Int, playerInv: Inventory, val container: Container, val viewer: ServerPlayer ) : AbstractContainerMenu(MenuType.GENERIC_9x3, syncId) { companion object { const val CONTAINER_SIZE = 27 // 메뉴 아이템 슬롯 위치 const val SLOT_SPAWN = 10 // 스폰 const val SLOT_COORDINATES = 12 // 좌표 const val SLOT_WORKBENCH = 14 // 제작대 const val SLOT_TPA = 16 // TPA } init { // 컨테이너 슬롯 추가 for (i in 0 until CONTAINER_SIZE) { val x = 8 + (i % 9) * 18 val y = 18 + (i / 9) * 18 addSlot( object : Slot(container, i, x, y) { override fun mayPickup(player: Player): Boolean = false override fun mayPlace(stack: ItemStack): Boolean = false } ) } // 플레이어 인벤토리 슬롯 for (row in 0 until 3) { for (col in 0 until 9) { val index = col + row * 9 + 9 val x = 8 + col * 18 val y = 86 + row * 18 addSlot(Slot(playerInv, index, x, y)) } } for (col in 0 until 9) { val x = 8 + col * 18 val y = 144 addSlot(Slot(playerInv, col, x, y)) } } override fun clicked(slotId: Int, button: Int, clickType: ClickType, player: Player) { if (slotId !in 0 until CONTAINER_SIZE || player !is ServerPlayer) { super.clicked(slotId, button, clickType, player) return } val stack = slots[slotId].item val tag = stack.get(DataComponents.CUSTOM_DATA)?.copyTag() ?: return val action = tag.getString("action") when (action) { "spawn" -> { player.closeContainer() player.server.commands.performPrefixedCommand( player.createCommandSourceStack(), "스폰" ) playClickSound(player) } "coordinates" -> { playClickSound(player) player.closeContainer() player.server.commands.performPrefixedCommand( player.createCommandSourceStack(), "좌표" ) } "workbench" -> { player.closeContainer() openWorkbench(player) playClickSound(player) } "tpa" -> { playClickSound(player) player.closeContainer() player.server.commands.performPrefixedCommand( player.createCommandSourceStack(), "tpa" ) } } } private fun playClickSound(player: ServerPlayer) { player.playNotifySound( SoundEvents.NOTE_BLOCK_BELL.value(), SoundSource.MASTER, 0.5f, 1.0f ) } private fun openWorkbench(player: ServerPlayer) { val access = object : ContainerLevelAccess { override fun evaluate( function: java.util.function.BiFunction< net.minecraft.world.level.Level, net.minecraft.core.BlockPos, T> ): java.util.Optional { return java.util.Optional.ofNullable( function.apply( player.level(), player.blockPosition() ) ) } } player.openMenu( SimpleMenuProvider( { containerId, inventory, _ -> object : CraftingMenu(containerId, inventory, access) { override fun stillValid(player: Player): Boolean = true } }, Component.translatable("container.crafting") ) ) } override fun stillValid(player: Player): Boolean = true override fun quickMoveStack(player: Player, index: Int): ItemStack = ItemStack.EMPTY } /** 메뉴 컨테이너 생성 */ fun createEssentialsMenuContainer(): SimpleContainer { val container = SimpleContainer(27) // 배경을 회색 유리판으로 채우기 val fillerItem = ItemStack(Items.GRAY_STAINED_GLASS_PANE) fillerItem.set( DataComponents.CUSTOM_NAME, Component.literal(" ").withStyle { it.withColor(ChatFormatting.DARK_GRAY) } ) for (i in 0 until 27) { container.setItem(i, fillerItem.copy()) } // 스폰 버튼 val spawnItem = ItemStack(Items.GRASS_BLOCK) spawnItem.set( DataComponents.CUSTOM_NAME, Component.literal("스폰").withStyle { it.withColor(ChatFormatting.GREEN).withBold(true) } ) spawnItem.set( DataComponents.LORE, ItemLore( listOf( Component.literal("스폰으로 이동합니다.").withStyle { it.withColor(ChatFormatting.GRAY) } ) ) ) spawnItem.set( DataComponents.CUSTOM_DATA, CustomData.of(CompoundTag().apply { putString("action", "spawn") }) ) container.setItem(EssentialsMenuGui.SLOT_SPAWN, spawnItem) // 좌표 버튼 val coordItem = ItemStack(Items.COMPASS) coordItem.set( DataComponents.CUSTOM_NAME, Component.literal("좌표").withStyle { it.withColor(ChatFormatting.YELLOW).withBold(true) } ) coordItem.set( DataComponents.LORE, ItemLore( listOf( Component.literal("저장된 좌표 목록을 엽니다.").withStyle { it.withColor(ChatFormatting.GRAY) } ) ) ) coordItem.set( DataComponents.CUSTOM_DATA, CustomData.of(CompoundTag().apply { putString("action", "coordinates") }) ) container.setItem(EssentialsMenuGui.SLOT_COORDINATES, coordItem) // 제작대 버튼 val workbenchItem = ItemStack(Items.CRAFTING_TABLE) workbenchItem.set( DataComponents.CUSTOM_NAME, Component.literal("제작대").withStyle { it.withColor(ChatFormatting.GOLD).withBold(true) } ) workbenchItem.set( DataComponents.LORE, ItemLore( listOf( Component.literal("제작대를 엽니다.").withStyle { it.withColor(ChatFormatting.GRAY) } ) ) ) workbenchItem.set( DataComponents.CUSTOM_DATA, CustomData.of(CompoundTag().apply { putString("action", "workbench") }) ) container.setItem(EssentialsMenuGui.SLOT_WORKBENCH, workbenchItem) // TPA 버튼 val tpaItem = ItemStack(Items.ENDER_PEARL) tpaItem.set( DataComponents.CUSTOM_NAME, Component.literal("텔레포트").withStyle { it.withColor(ChatFormatting.AQUA).withBold(true) } ) tpaItem.set( DataComponents.LORE, ItemLore( listOf( Component.literal("다른 플레이어에게 이동합니다.").withStyle { it.withColor(ChatFormatting.GRAY) } ) ) ) tpaItem.set( DataComponents.CUSTOM_DATA, CustomData.of(CompoundTag().apply { putString("action", "tpa") }) ) container.setItem(EssentialsMenuGui.SLOT_TPA, tpaItem) return container } /** 메뉴 GUI 열기 */ fun openEssentialsMenu(player: ServerPlayer) { val container = createEssentialsMenuContainer() player.openMenu( SimpleMenuProvider( { windowId, inv, _ -> EssentialsMenuGui(windowId, inv, container, player) }, Component.literal("Essentials 메뉴").withStyle { it.withBold(true) } ) ) }