feat: GUI 클릭 소리 및 개선

- 모든 GUI에 bell 클릭 소리 추가 (playNotifySound로 해당 플레이어만 듣도록)
- TeleportGui: 다른 플레이어 없으면 메시지만 표시, 빈 공간 클릭 무시
- EssentialsMenuGui: 아이템 이름 간소화 (스폰/좌표/제작대/텔레포트)
- 설명 텍스트에서 '클릭하여' 제거, 좌표에 '저장된' 추가
This commit is contained in:
Caadiq 2025-12-29 17:27:49 +09:00
parent 791d6f2e9f
commit 4dba2a4803
5 changed files with 319 additions and 265 deletions

View file

@ -4,6 +4,7 @@ import com.beemer.essentials.gui.TeleportGui
import com.beemer.essentials.gui.TeleportGui.Companion.CONTAINER_SIZE import com.beemer.essentials.gui.TeleportGui.Companion.CONTAINER_SIZE
import com.beemer.essentials.nickname.NicknameDataStore import com.beemer.essentials.nickname.NicknameDataStore
import com.beemer.essentials.util.CommandUtils import com.beemer.essentials.util.CommandUtils
import com.beemer.essentials.util.MessageUtils
import com.beemer.essentials.util.TranslationUtils import com.beemer.essentials.util.TranslationUtils
import com.mojang.authlib.GameProfile import com.mojang.authlib.GameProfile
import net.minecraft.ChatFormatting import net.minecraft.ChatFormatting
@ -32,13 +33,22 @@ object TeleportCommand {
CommandUtils.getPlayerOrSendFailure(context.source) CommandUtils.getPlayerOrSendFailure(context.source)
?: return@executes 0 ?: return@executes 0
val container = SimpleContainer(9 * 3)
val targetPlayers = val targetPlayers =
player.server.playerList.players.filter { player.server.playerList.players.filter {
it != player it != player
} }
// 다른 플레이어가 없으면 메시지만 표시
if (targetPlayers.isEmpty()) {
MessageUtils.sendInfo(
player,
"현재 접속 중인 다른 플레이어가 없습니다."
)
return@executes 0
}
val container = SimpleContainer(9 * 3)
targetPlayers.take(CONTAINER_SIZE).forEachIndexed { targetPlayers.take(CONTAINER_SIZE).forEachIndexed {
idx, idx,
target -> target ->

View file

@ -5,6 +5,8 @@ import net.minecraft.ChatFormatting
import net.minecraft.core.component.DataComponents import net.minecraft.core.component.DataComponents
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer 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.Container
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.AbstractContainerMenu
@ -77,6 +79,7 @@ class AntimobGui(
) { ) {
if (player is ServerPlayer && slotId in 0 until CONTAINER_SIZE) { if (player is ServerPlayer && slotId in 0 until CONTAINER_SIZE) {
if (glassSlotToMob.containsKey(slotId)) { if (glassSlotToMob.containsKey(slotId)) {
playClickSound(player)
val mob = glassSlotToMob[slotId] ?: return val mob = glassSlotToMob[slotId] ?: return
AntimobConfig.toggle(mob) AntimobConfig.toggle(mob)
container.setItem(slotId, makeToggleGlass(mob)) container.setItem(slotId, makeToggleGlass(mob))
@ -94,6 +97,10 @@ class AntimobGui(
index: Int index: Int
): ItemStack = ItemStack.EMPTY ): ItemStack = ItemStack.EMPTY
private fun playClickSound(player: ServerPlayer) {
player.playNotifySound(SoundEvents.NOTE_BLOCK_BELL.value(), SoundSource.MASTER, 0.5f, 1.0f)
}
private fun makeMobHead(mob: String): ItemStack { private fun makeMobHead(mob: String): ItemStack {
val headItem = ItemStack(Items.PLAYER_HEAD) val headItem = ItemStack(Items.PLAYER_HEAD)

View file

@ -16,6 +16,8 @@ import net.minecraft.network.chat.Component
import net.minecraft.resources.ResourceKey import net.minecraft.resources.ResourceKey
import net.minecraft.resources.ResourceLocation import net.minecraft.resources.ResourceLocation
import net.minecraft.server.level.ServerPlayer 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.Container
import net.minecraft.world.SimpleContainer import net.minecraft.world.SimpleContainer
import net.minecraft.world.SimpleMenuProvider import net.minecraft.world.SimpleMenuProvider
@ -88,6 +90,7 @@ class Menu(
tag.getString("action") == "prev" tag.getString("action") == "prev"
) { ) {
if (currentPage > 0) { if (currentPage > 0) {
playClickSound(player)
openPage(player, currentPage - 1) openPage(player, currentPage - 1)
} }
return return
@ -100,6 +103,7 @@ class Menu(
) { ) {
val totalPages = getTotalPages() val totalPages = getTotalPages()
if (currentPage < totalPages - 1) { if (currentPage < totalPages - 1) {
playClickSound(player)
openPage(player, currentPage + 1) openPage(player, currentPage + 1)
} }
return return
@ -118,7 +122,6 @@ class Menu(
val level = dimension?.let { player.server.getLevel(it) } val level = dimension?.let { player.server.getLevel(it) }
if (level != null) { if (level != null) {
// 이전 위치 저장
val prevPos = player.blockPosition() val prevPos = player.blockPosition()
PlayerConfig.recordLastLocation( PlayerConfig.recordLastLocation(
player, player,
@ -137,12 +140,17 @@ class Menu(
) )
player.teleportTo(level, x, y, z, player.yRot, player.xRot) player.teleportTo(level, x, y, z, player.yRot, player.xRot)
playClickSound(player)
MessageUtils.sendSuccess(player, "{$coordName}(으)로 이동했습니다.") MessageUtils.sendSuccess(player, "{$coordName}(으)로 이동했습니다.")
} }
player.closeContainer() player.closeContainer()
} }
} }
private fun playClickSound(player: ServerPlayer) {
player.playNotifySound(SoundEvents.NOTE_BLOCK_BELL.value(), SoundSource.MASTER, 0.5f, 1.0f)
}
private fun getTotalPages(): Int { private fun getTotalPages(): Int {
val totalItems = CoordinateConfig.getCoordinates().size val totalItems = CoordinateConfig.getCoordinates().size
return if (totalItems == 0) 1 else (totalItems + ITEMS_PER_PAGE - 1) / ITEMS_PER_PAGE return if (totalItems == 0) 1 else (totalItems + ITEMS_PER_PAGE - 1) / ITEMS_PER_PAGE

View file

@ -5,6 +5,8 @@ import net.minecraft.core.component.DataComponents
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer 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.Container
import net.minecraft.world.SimpleContainer import net.minecraft.world.SimpleContainer
import net.minecraft.world.SimpleMenuProvider import net.minecraft.world.SimpleMenuProvider
@ -81,15 +83,15 @@ class EssentialsMenuGui(
when (action) { when (action) {
"spawn" -> { "spawn" -> {
player.closeContainer() player.closeContainer()
// 스폰 명령어 실행
player.server.commands.performPrefixedCommand( player.server.commands.performPrefixedCommand(
player.createCommandSourceStack(), player.createCommandSourceStack(),
"스폰" "스폰"
) )
playClickSound(player)
} }
"coordinates" -> { "coordinates" -> {
playClickSound(player)
player.closeContainer() player.closeContainer()
// 좌표 GUI 열기
player.server.commands.performPrefixedCommand( player.server.commands.performPrefixedCommand(
player.createCommandSourceStack(), player.createCommandSourceStack(),
"좌표" "좌표"
@ -97,12 +99,12 @@ class EssentialsMenuGui(
} }
"workbench" -> { "workbench" -> {
player.closeContainer() player.closeContainer()
// 제작대 열기
openWorkbench(player) openWorkbench(player)
playClickSound(player)
} }
"tpa" -> { "tpa" -> {
playClickSound(player)
player.closeContainer() player.closeContainer()
// TPA GUI 열기
player.server.commands.performPrefixedCommand( player.server.commands.performPrefixedCommand(
player.createCommandSourceStack(), player.createCommandSourceStack(),
"tpa" "tpa"
@ -111,6 +113,15 @@ class EssentialsMenuGui(
} }
} }
private fun playClickSound(player: ServerPlayer) {
player.playNotifySound(
SoundEvents.NOTE_BLOCK_BELL.value(),
SoundSource.MASTER,
0.5f,
1.0f
)
}
private fun openWorkbench(player: ServerPlayer) { private fun openWorkbench(player: ServerPlayer) {
val access = val access =
object : ContainerLevelAccess { object : ContainerLevelAccess {
@ -122,7 +133,10 @@ class EssentialsMenuGui(
T> T>
): java.util.Optional<T> { ): java.util.Optional<T> {
return java.util.Optional.ofNullable( return java.util.Optional.ofNullable(
function.apply(player.level(), player.blockPosition()) function.apply(
player.level(),
player.blockPosition()
)
) )
} }
} }
@ -131,7 +145,8 @@ class EssentialsMenuGui(
SimpleMenuProvider( SimpleMenuProvider(
{ containerId, inventory, _ -> { containerId, inventory, _ ->
object : CraftingMenu(containerId, inventory, access) { object : CraftingMenu(containerId, inventory, access) {
override fun stillValid(player: Player): Boolean = true override fun stillValid(player: Player): Boolean =
true
} }
}, },
Component.translatable("container.crafting") Component.translatable("container.crafting")
@ -161,7 +176,7 @@ fun createEssentialsMenuContainer(): SimpleContainer {
val spawnItem = ItemStack(Items.GRASS_BLOCK) val spawnItem = ItemStack(Items.GRASS_BLOCK)
spawnItem.set( spawnItem.set(
DataComponents.CUSTOM_NAME, DataComponents.CUSTOM_NAME,
Component.literal("스폰으로 이동").withStyle { Component.literal("스폰").withStyle {
it.withColor(ChatFormatting.GREEN).withBold(true) it.withColor(ChatFormatting.GREEN).withBold(true)
} }
) )
@ -169,7 +184,7 @@ fun createEssentialsMenuContainer(): SimpleContainer {
DataComponents.LORE, DataComponents.LORE,
ItemLore( ItemLore(
listOf( listOf(
Component.literal("클릭하여 스폰으로 이동합니다.").withStyle { Component.literal("스폰으로 이동합니다.").withStyle {
it.withColor(ChatFormatting.GRAY) it.withColor(ChatFormatting.GRAY)
} }
) )
@ -185,7 +200,7 @@ fun createEssentialsMenuContainer(): SimpleContainer {
val coordItem = ItemStack(Items.COMPASS) val coordItem = ItemStack(Items.COMPASS)
coordItem.set( coordItem.set(
DataComponents.CUSTOM_NAME, DataComponents.CUSTOM_NAME,
Component.literal("저장된 좌표").withStyle { Component.literal("좌표").withStyle {
it.withColor(ChatFormatting.YELLOW).withBold(true) it.withColor(ChatFormatting.YELLOW).withBold(true)
} }
) )
@ -193,7 +208,7 @@ fun createEssentialsMenuContainer(): SimpleContainer {
DataComponents.LORE, DataComponents.LORE,
ItemLore( ItemLore(
listOf( listOf(
Component.literal("클릭하여 좌표 목록을 엽니다.").withStyle { Component.literal("저장된 좌표 목록을 엽니다.").withStyle {
it.withColor(ChatFormatting.GRAY) it.withColor(ChatFormatting.GRAY)
} }
) )
@ -209,7 +224,7 @@ fun createEssentialsMenuContainer(): SimpleContainer {
val workbenchItem = ItemStack(Items.CRAFTING_TABLE) val workbenchItem = ItemStack(Items.CRAFTING_TABLE)
workbenchItem.set( workbenchItem.set(
DataComponents.CUSTOM_NAME, DataComponents.CUSTOM_NAME,
Component.literal("제작대 열기").withStyle { Component.literal("제작대").withStyle {
it.withColor(ChatFormatting.GOLD).withBold(true) it.withColor(ChatFormatting.GOLD).withBold(true)
} }
) )
@ -217,7 +232,7 @@ fun createEssentialsMenuContainer(): SimpleContainer {
DataComponents.LORE, DataComponents.LORE,
ItemLore( ItemLore(
listOf( listOf(
Component.literal("클릭하여 제작대를 엽니다.").withStyle { Component.literal("제작대를 엽니다.").withStyle {
it.withColor(ChatFormatting.GRAY) it.withColor(ChatFormatting.GRAY)
} }
) )
@ -233,7 +248,7 @@ fun createEssentialsMenuContainer(): SimpleContainer {
val tpaItem = ItemStack(Items.ENDER_PEARL) val tpaItem = ItemStack(Items.ENDER_PEARL)
tpaItem.set( tpaItem.set(
DataComponents.CUSTOM_NAME, DataComponents.CUSTOM_NAME,
Component.literal("플레이어 텔레포트").withStyle { Component.literal("텔레포트").withStyle {
it.withColor(ChatFormatting.AQUA).withBold(true) it.withColor(ChatFormatting.AQUA).withBold(true)
} }
) )
@ -241,7 +256,7 @@ fun createEssentialsMenuContainer(): SimpleContainer {
DataComponents.LORE, DataComponents.LORE,
ItemLore( ItemLore(
listOf( listOf(
Component.literal("클릭하여 다른 플레이어에게 이동합니다.").withStyle { Component.literal("다른 플레이어에게 이동합니다.").withStyle {
it.withColor(ChatFormatting.GRAY) it.withColor(ChatFormatting.GRAY)
} }
) )

View file

@ -2,10 +2,11 @@ package com.beemer.essentials.gui
import com.beemer.essentials.config.PlayerConfig import com.beemer.essentials.config.PlayerConfig
import com.beemer.essentials.data.Location import com.beemer.essentials.data.Location
import com.beemer.essentials.data.Player
import com.beemer.essentials.nickname.NicknameDataStore import com.beemer.essentials.nickname.NicknameDataStore
import com.beemer.essentials.util.MessageUtils import com.beemer.essentials.util.MessageUtils
import net.minecraft.server.level.ServerPlayer 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.Container
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.inventory.AbstractContainerMenu import net.minecraft.world.inventory.AbstractContainerMenu
@ -78,13 +79,17 @@ class TeleportGui(
player: net.minecraft.world.entity.player.Player player: net.minecraft.world.entity.player.Player
) { ) {
if (slotId in 0 until CONTAINER_SIZE && player is ServerPlayer) { if (slotId in 0 until CONTAINER_SIZE && player is ServerPlayer) {
// 해당 슬롯에 플레이어가 있는지 확인
val currentTargetPlayer = val currentTargetPlayer =
targetPlayers.getOrNull(slotId)?.let { targetPlayers.getOrNull(slotId)?.let {
player.server.playerList.getPlayer(it) player.server.playerList.getPlayer(it)
} }
if (currentTargetPlayer != null && player.uuid != currentTargetPlayer.uuid // 플레이어가 없으면 무시 (빈 공간 클릭)
) { if (currentTargetPlayer == null) {
return
}
val prevPos = player.blockPosition() val prevPos = player.blockPosition()
val prevDimension = player.level().dimension().location().toString() val prevDimension = player.level().dimension().location().toString()
val prevBiome = val prevBiome =
@ -114,6 +119,9 @@ class TeleportGui(
currentTargetPlayer.xRot currentTargetPlayer.xRot
) )
// 소리 재생 (텔레포트 후)
playClickSound(player)
// 닉네임이 있으면 닉네임 사용 // 닉네임이 있으면 닉네임 사용
val targetName = val targetName =
NicknameDataStore.getNickname(currentTargetPlayer.uuid) NicknameDataStore.getNickname(currentTargetPlayer.uuid)
@ -127,9 +135,6 @@ class TeleportGui(
currentTargetPlayer, currentTargetPlayer,
"{$playerName}님이 당신에게 텔레포트 했습니다." "{$playerName}님이 당신에게 텔레포트 했습니다."
) )
} else {
MessageUtils.sendError(player, "해당 플레이어는 현재 오프라인입니다.")
}
player.closeContainer() player.closeContainer()
return return
@ -137,6 +142,15 @@ class TeleportGui(
super.clicked(slotId, button, clickType, player) super.clicked(slotId, button, clickType, player)
} }
private fun playClickSound(player: ServerPlayer) {
player.playNotifySound(
SoundEvents.NOTE_BLOCK_BELL.value(),
SoundSource.MASTER,
0.5f,
1.0f
)
}
override fun stillValid(player: net.minecraft.world.entity.player.Player): Boolean = true override fun stillValid(player: net.minecraft.world.entity.player.Player): Boolean = true
override fun quickMoveStack( override fun quickMoveStack(