minecraft-mod/Essentials/src/main/kotlin/com/beemer/essentials/gui/EssentialsMenuGui.kt

284 lines
11 KiB
Kotlin
Raw Normal View History

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 <T : Any> evaluate(
function:
java.util.function.BiFunction<
net.minecraft.world.level.Level,
net.minecraft.core.BlockPos,
T>
): java.util.Optional<T> {
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) }
)
)
}