2025-12-17 18:41:31 +09:00
|
|
|
package com.beemer.essentials.gui
|
|
|
|
|
|
|
|
|
|
import com.beemer.essentials.config.AntimobConfig
|
|
|
|
|
import net.minecraft.ChatFormatting
|
|
|
|
|
import net.minecraft.core.component.DataComponents
|
|
|
|
|
import net.minecraft.network.chat.Component
|
|
|
|
|
import net.minecraft.server.level.ServerPlayer
|
|
|
|
|
import net.minecraft.world.Container
|
|
|
|
|
import net.minecraft.world.entity.player.Inventory
|
|
|
|
|
import net.minecraft.world.inventory.AbstractContainerMenu
|
|
|
|
|
import net.minecraft.world.inventory.ClickType
|
|
|
|
|
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.ResolvableProfile
|
|
|
|
|
|
2025-12-18 21:47:11 +09:00
|
|
|
class AntimobGui(
|
|
|
|
|
syncId: Int,
|
|
|
|
|
playerInv: Inventory,
|
|
|
|
|
val container: Container,
|
|
|
|
|
viewer: ServerPlayer
|
|
|
|
|
) : AbstractContainerMenu(MenuType.GENERIC_9x2, syncId) {
|
2025-12-17 18:41:31 +09:00
|
|
|
companion object {
|
|
|
|
|
const val CONTAINER_COLUMNS = 9
|
|
|
|
|
const val CONTAINER_ROWS = 2
|
|
|
|
|
const val CONTAINER_SIZE = CONTAINER_COLUMNS * CONTAINER_ROWS
|
|
|
|
|
|
|
|
|
|
const val SLOT_SIZE = 18
|
|
|
|
|
const val LEFT_PADDING = 8
|
|
|
|
|
const val TOP_PADDING = 18
|
|
|
|
|
|
|
|
|
|
const val PLAYER_INV_TOP = 58
|
|
|
|
|
const val HOTBAR_Y = 116
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private val headSlotToMob = mapOf(0 to "크리퍼", 1 to "가스트", 2 to "엔더맨")
|
|
|
|
|
private val glassSlotToMob = mapOf(9 to "크리퍼", 10 to "가스트", 11 to "엔더맨")
|
|
|
|
|
|
|
|
|
|
init {
|
|
|
|
|
for (i in 0 until CONTAINER_SIZE) {
|
|
|
|
|
val x = LEFT_PADDING + (i % CONTAINER_COLUMNS) * SLOT_SIZE
|
|
|
|
|
val y = TOP_PADDING + (i / CONTAINER_COLUMNS) * SLOT_SIZE
|
2025-12-18 21:47:11 +09:00
|
|
|
addSlot(
|
|
|
|
|
object : Slot(container, i, x, y) {
|
|
|
|
|
override fun mayPickup(
|
|
|
|
|
player: net.minecraft.world.entity.player.Player
|
|
|
|
|
): Boolean = false
|
|
|
|
|
override fun mayPlace(stack: ItemStack): Boolean = false
|
|
|
|
|
}
|
|
|
|
|
)
|
2025-12-17 18:41:31 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (row in 0 until 3) {
|
|
|
|
|
for (col in 0 until 9) {
|
|
|
|
|
val index = col + row * 9 + 9
|
|
|
|
|
val x = LEFT_PADDING + col * SLOT_SIZE
|
|
|
|
|
val y = PLAYER_INV_TOP + row * SLOT_SIZE
|
|
|
|
|
addSlot(Slot(playerInv, index, x, y))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (col in 0 until 9) {
|
|
|
|
|
val x = LEFT_PADDING + col * SLOT_SIZE
|
|
|
|
|
val y = HOTBAR_Y
|
|
|
|
|
addSlot(Slot(playerInv, col, x, y))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
refreshContainerContents()
|
|
|
|
|
}
|
|
|
|
|
|
2025-12-18 21:47:11 +09:00
|
|
|
override fun clicked(
|
|
|
|
|
slotId: Int,
|
|
|
|
|
button: Int,
|
|
|
|
|
clickType: ClickType,
|
|
|
|
|
player: net.minecraft.world.entity.player.Player
|
|
|
|
|
) {
|
2025-12-17 18:41:31 +09:00
|
|
|
if (player is ServerPlayer && slotId in 0 until CONTAINER_SIZE) {
|
|
|
|
|
if (glassSlotToMob.containsKey(slotId)) {
|
|
|
|
|
val mob = glassSlotToMob[slotId] ?: return
|
|
|
|
|
AntimobConfig.toggle(mob)
|
|
|
|
|
container.setItem(slotId, makeToggleGlass(mob))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
super.clicked(slotId, button, clickType, player)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun stillValid(player: net.minecraft.world.entity.player.Player): Boolean = true
|
|
|
|
|
|
2025-12-18 21:47:11 +09:00
|
|
|
override fun quickMoveStack(
|
|
|
|
|
player: net.minecraft.world.entity.player.Player,
|
|
|
|
|
index: Int
|
|
|
|
|
): ItemStack = ItemStack.EMPTY
|
2025-12-17 18:41:31 +09:00
|
|
|
|
2025-12-18 21:47:11 +09:00
|
|
|
private fun makeMobHead(mob: String): ItemStack {
|
2025-12-17 18:41:31 +09:00
|
|
|
val headItem = ItemStack(Items.PLAYER_HEAD)
|
|
|
|
|
|
2025-12-18 21:47:11 +09:00
|
|
|
// MHF_ 스킨 이름 사용 (네트워크 요청 없음)
|
|
|
|
|
val skinName =
|
|
|
|
|
when (mob) {
|
|
|
|
|
"크리퍼" -> "MHF_Creeper"
|
|
|
|
|
"가스트" -> "MHF_Ghast"
|
|
|
|
|
"엔더맨" -> "MHF_Enderman"
|
|
|
|
|
else -> "MHF_Steve"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
val resolvableProfile =
|
|
|
|
|
ResolvableProfile(
|
|
|
|
|
java.util.Optional.of(skinName),
|
|
|
|
|
java.util.Optional.empty<java.util.UUID>(),
|
|
|
|
|
com.mojang.authlib.properties.PropertyMap()
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
headItem.set(
|
|
|
|
|
DataComponents.CUSTOM_NAME,
|
|
|
|
|
Component.literal(mob).withStyle { it.withColor(ChatFormatting.YELLOW) }
|
|
|
|
|
)
|
2025-12-17 18:41:31 +09:00
|
|
|
headItem.set(DataComponents.PROFILE, resolvableProfile)
|
|
|
|
|
return headItem
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun makeToggleGlass(mob: String): ItemStack {
|
|
|
|
|
val enabled = AntimobConfig.get(mob)
|
2025-12-18 21:47:11 +09:00
|
|
|
val glass =
|
|
|
|
|
if (enabled) ItemStack(Items.GREEN_STAINED_GLASS_PANE)
|
|
|
|
|
else ItemStack(Items.RED_STAINED_GLASS_PANE)
|
2025-12-17 18:41:31 +09:00
|
|
|
val statusText = if (enabled) "활성화" else "비활성화"
|
2025-12-18 21:47:11 +09:00
|
|
|
glass.set(
|
|
|
|
|
DataComponents.CUSTOM_NAME,
|
|
|
|
|
Component.literal(statusText).withStyle {
|
|
|
|
|
it.withColor(if (enabled) ChatFormatting.GREEN else ChatFormatting.RED)
|
|
|
|
|
}
|
|
|
|
|
)
|
2025-12-17 18:41:31 +09:00
|
|
|
return glass
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun refreshContainerContents() {
|
2025-12-18 21:47:11 +09:00
|
|
|
headSlotToMob.forEach { (slot, mob) -> container.setItem(slot, makeMobHead(mob)) }
|
|
|
|
|
glassSlotToMob.forEach { (slot, mob) -> container.setItem(slot, makeToggleGlass(mob)) }
|
2025-12-17 18:41:31 +09:00
|
|
|
}
|
2025-12-18 21:47:11 +09:00
|
|
|
}
|