127 lines
5.2 KiB
Kotlin
127 lines
5.2 KiB
Kotlin
|
|
package com.beemer.essentials.gui
|
||
|
|
|
||
|
|
import com.beemer.essentials.config.AntimobConfig
|
||
|
|
import com.mojang.authlib.GameProfile
|
||
|
|
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
|
||
|
|
import java.util.*
|
||
|
|
|
||
|
|
class AntimobGui(syncId: Int, playerInv: Inventory, val container: Container, private val viewer: ServerPlayer) : AbstractContainerMenu(MenuType.GENERIC_9x2, syncId) {
|
||
|
|
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
|
||
|
|
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
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
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()
|
||
|
|
}
|
||
|
|
|
||
|
|
override fun clicked(slotId: Int, button: Int, clickType: ClickType, player: net.minecraft.world.entity.player.Player) {
|
||
|
|
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
|
||
|
|
|
||
|
|
override fun quickMoveStack(player: net.minecraft.world.entity.player.Player, index: Int): ItemStack = ItemStack.EMPTY
|
||
|
|
|
||
|
|
private fun makeMobHead(mob: String, player: ServerPlayer): ItemStack {
|
||
|
|
val headItem = ItemStack(Items.PLAYER_HEAD)
|
||
|
|
|
||
|
|
val uuid = when (mob) {
|
||
|
|
"크리퍼" -> UUID.fromString("057b1c47-1321-4863-a6fe-8887f9ec265f")
|
||
|
|
"가스트" -> UUID.fromString("063085a6-797f-4785-be1a-21cd7580f752")
|
||
|
|
"엔더맨" -> UUID.fromString("40ffb372-12f6-4678-b3f2-2176bf56dd4b")
|
||
|
|
else -> UUID.fromString("c06f8906-4c8a-4911-9c29-ea1dbd1aab82")
|
||
|
|
}
|
||
|
|
|
||
|
|
val filledProfile: GameProfile = try {
|
||
|
|
player.server.sessionService.fetchProfile(uuid, true)?.profile ?: player.gameProfile
|
||
|
|
} catch (_: Exception) {
|
||
|
|
player.gameProfile
|
||
|
|
}
|
||
|
|
|
||
|
|
val resolvableProfile = try {
|
||
|
|
ResolvableProfile(filledProfile)
|
||
|
|
} catch (_: NoSuchMethodError) {
|
||
|
|
val ctor = ResolvableProfile::class.java.getDeclaredConstructor(GameProfile::class.java)
|
||
|
|
ctor.isAccessible = true
|
||
|
|
ctor.newInstance(filledProfile)
|
||
|
|
}
|
||
|
|
|
||
|
|
headItem.set(DataComponents.CUSTOM_NAME, Component.literal(mob).withStyle { it.withColor(ChatFormatting.YELLOW) })
|
||
|
|
headItem.set(DataComponents.PROFILE, resolvableProfile)
|
||
|
|
return headItem
|
||
|
|
}
|
||
|
|
|
||
|
|
private fun makeToggleGlass(mob: String): ItemStack {
|
||
|
|
val enabled = AntimobConfig.get(mob)
|
||
|
|
val glass = if (enabled) ItemStack(Items.GREEN_STAINED_GLASS_PANE) else ItemStack(Items.RED_STAINED_GLASS_PANE)
|
||
|
|
val statusText = if (enabled) "활성화" else "비활성화"
|
||
|
|
glass.set(DataComponents.CUSTOM_NAME, Component.literal(statusText).withStyle { it.withColor(if (enabled) ChatFormatting.GREEN else ChatFormatting.RED) })
|
||
|
|
return glass
|
||
|
|
}
|
||
|
|
|
||
|
|
private fun refreshContainerContents() {
|
||
|
|
headSlotToMob.forEach { (slot, mob) ->
|
||
|
|
container.setItem(slot, makeMobHead(mob, viewer))
|
||
|
|
}
|
||
|
|
glassSlotToMob.forEach { (slot, mob) ->
|
||
|
|
container.setItem(slot, makeToggleGlass(mob))
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|