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
@ -29,240 +31,253 @@ class EssentialsMenuGui(
val viewer: ServerPlayer val viewer: ServerPlayer
) : AbstractContainerMenu(MenuType.GENERIC_9x3, syncId) { ) : AbstractContainerMenu(MenuType.GENERIC_9x3, syncId) {
companion object { companion object {
const val CONTAINER_SIZE = 27 const val CONTAINER_SIZE = 27
// 메뉴 아이템 슬롯 위치 // 메뉴 아이템 슬롯 위치
const val SLOT_SPAWN = 10 // 스폰 const val SLOT_SPAWN = 10 // 스폰
const val SLOT_COORDINATES = 12 // 좌표 const val SLOT_COORDINATES = 12 // 좌표
const val SLOT_WORKBENCH = 14 // 제작대 const val SLOT_WORKBENCH = 14 // 제작대
const val SLOT_TPA = 16 // TPA 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
}
)
} }
// 플레이어 인벤토리 슬롯 init {
for (row in 0 until 3) { // 컨테이너 슬롯 추가
for (col in 0 until 9) { for (i in 0 until CONTAINER_SIZE) {
val index = col + row * 9 + 9 val x = 8 + (i % 9) * 18
val x = 8 + col * 18 val y = 18 + (i / 9) * 18
val y = 86 + row * 18 addSlot(
addSlot(Slot(playerInv, index, x, y)) object : Slot(container, i, x, y) {
} override fun mayPickup(player: Player): Boolean = false
} override fun mayPlace(stack: ItemStack): Boolean = false
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(),
"스폰"
)
}
"coordinates" -> {
player.closeContainer()
// 좌표 GUI 열기
player.server.commands.performPrefixedCommand(
player.createCommandSourceStack(),
"좌표"
)
}
"workbench" -> {
player.closeContainer()
// 제작대 열기
openWorkbench(player)
}
"tpa" -> {
player.closeContainer()
// TPA GUI 열기
player.server.commands.performPrefixedCommand(
player.createCommandSourceStack(),
"tpa"
)
}
}
}
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( for (row in 0 until 3) {
{ containerId, inventory, _ -> for (col in 0 until 9) {
object : CraftingMenu(containerId, inventory, access) { val index = col + row * 9 + 9
override fun stillValid(player: Player): Boolean = true val x = 8 + col * 18
} val y = 86 + row * 18
}, addSlot(Slot(playerInv, index, x, y))
Component.translatable("container.crafting") }
) }
) for (col in 0 until 9) {
} val x = 8 + col * 18
val y = 144
addSlot(Slot(playerInv, col, x, y))
}
}
override fun stillValid(player: Player): Boolean = true override fun clicked(slotId: Int, button: Int, clickType: ClickType, player: Player) {
override fun quickMoveStack(player: Player, index: Int): ItemStack = ItemStack.EMPTY 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 { fun createEssentialsMenuContainer(): SimpleContainer {
val container = SimpleContainer(27) val container = SimpleContainer(27)
// 배경을 회색 유리판으로 채우기 // 배경을 회색 유리판으로 채우기
val fillerItem = ItemStack(Items.GRAY_STAINED_GLASS_PANE) val fillerItem = ItemStack(Items.GRAY_STAINED_GLASS_PANE)
fillerItem.set( fillerItem.set(
DataComponents.CUSTOM_NAME, DataComponents.CUSTOM_NAME,
Component.literal(" ").withStyle { it.withColor(ChatFormatting.DARK_GRAY) } Component.literal(" ").withStyle { it.withColor(ChatFormatting.DARK_GRAY) }
) )
for (i in 0 until 27) { for (i in 0 until 27) {
container.setItem(i, fillerItem.copy()) container.setItem(i, fillerItem.copy())
} }
// 스폰 버튼 // 스폰 버튼
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)
} }
) )
spawnItem.set( spawnItem.set(
DataComponents.LORE, DataComponents.LORE,
ItemLore( ItemLore(
listOf( listOf(
Component.literal("클릭하여 스폰으로 이동합니다.").withStyle { Component.literal("스폰으로 이동합니다.").withStyle {
it.withColor(ChatFormatting.GRAY) it.withColor(ChatFormatting.GRAY)
} }
) )
) )
) )
spawnItem.set( spawnItem.set(
DataComponents.CUSTOM_DATA, DataComponents.CUSTOM_DATA,
CustomData.of(CompoundTag().apply { putString("action", "spawn") }) CustomData.of(CompoundTag().apply { putString("action", "spawn") })
) )
container.setItem(EssentialsMenuGui.SLOT_SPAWN, spawnItem) container.setItem(EssentialsMenuGui.SLOT_SPAWN, spawnItem)
// 좌표 버튼 // 좌표 버튼
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)
} }
) )
coordItem.set( coordItem.set(
DataComponents.LORE, DataComponents.LORE,
ItemLore( ItemLore(
listOf( listOf(
Component.literal("클릭하여 좌표 목록을 엽니다.").withStyle { Component.literal("저장된 좌표 목록을 엽니다.").withStyle {
it.withColor(ChatFormatting.GRAY) it.withColor(ChatFormatting.GRAY)
} }
) )
) )
) )
coordItem.set( coordItem.set(
DataComponents.CUSTOM_DATA, DataComponents.CUSTOM_DATA,
CustomData.of(CompoundTag().apply { putString("action", "coordinates") }) CustomData.of(CompoundTag().apply { putString("action", "coordinates") })
) )
container.setItem(EssentialsMenuGui.SLOT_COORDINATES, coordItem) container.setItem(EssentialsMenuGui.SLOT_COORDINATES, coordItem)
// 제작대 버튼 // 제작대 버튼
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)
} }
) )
workbenchItem.set( workbenchItem.set(
DataComponents.LORE, DataComponents.LORE,
ItemLore( ItemLore(
listOf( listOf(
Component.literal("클릭하여 제작대를 엽니다.").withStyle { Component.literal("제작대를 엽니다.").withStyle {
it.withColor(ChatFormatting.GRAY) it.withColor(ChatFormatting.GRAY)
} }
) )
) )
) )
workbenchItem.set( workbenchItem.set(
DataComponents.CUSTOM_DATA, DataComponents.CUSTOM_DATA,
CustomData.of(CompoundTag().apply { putString("action", "workbench") }) CustomData.of(CompoundTag().apply { putString("action", "workbench") })
) )
container.setItem(EssentialsMenuGui.SLOT_WORKBENCH, workbenchItem) container.setItem(EssentialsMenuGui.SLOT_WORKBENCH, workbenchItem)
// TPA 버튼 // TPA 버튼
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)
} }
) )
tpaItem.set( tpaItem.set(
DataComponents.LORE, DataComponents.LORE,
ItemLore( ItemLore(
listOf( listOf(
Component.literal("클릭하여 다른 플레이어에게 이동합니다.").withStyle { Component.literal("다른 플레이어에게 이동합니다.").withStyle {
it.withColor(ChatFormatting.GRAY) it.withColor(ChatFormatting.GRAY)
} }
) )
) )
) )
tpaItem.set( tpaItem.set(
DataComponents.CUSTOM_DATA, DataComponents.CUSTOM_DATA,
CustomData.of(CompoundTag().apply { putString("action", "tpa") }) CustomData.of(CompoundTag().apply { putString("action", "tpa") })
) )
container.setItem(EssentialsMenuGui.SLOT_TPA, tpaItem) container.setItem(EssentialsMenuGui.SLOT_TPA, tpaItem)
return container return container
} }
/** 메뉴 GUI 열기 */ /** 메뉴 GUI 열기 */
fun openEssentialsMenu(player: ServerPlayer) { fun openEssentialsMenu(player: ServerPlayer) {
val container = createEssentialsMenuContainer() val container = createEssentialsMenuContainer()
player.openMenu( player.openMenu(
SimpleMenuProvider( SimpleMenuProvider(
{ windowId, inv, _ -> EssentialsMenuGui(windowId, inv, container, player) }, { windowId, inv, _ -> EssentialsMenuGui(windowId, inv, container, player) },
Component.literal("Essentials 메뉴").withStyle { it.withBold(true) } Component.literal("Essentials 메뉴").withStyle { it.withBold(true) }
) )
) )
} }

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,65 +79,78 @@ 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) {
val prevPos = player.blockPosition() return
val prevDimension = player.level().dimension().location().toString()
val prevBiome =
player.level()
.getBiome(prevPos)
.unwrapKey()
.map { it.location().toString() }
.orElse("minecraft:plains")
val previousLocation =
Location(
dimension = prevDimension,
biome = prevBiome,
x = prevPos.x.toDouble(),
y = prevPos.y.toDouble(),
z = prevPos.z.toDouble()
)
PlayerConfig.recordLastLocation(player, previousLocation)
val targetLevel = currentTargetPlayer.serverLevel()
player.teleportTo(
targetLevel,
currentTargetPlayer.x,
currentTargetPlayer.y,
currentTargetPlayer.z,
currentTargetPlayer.yRot,
currentTargetPlayer.xRot
)
// 닉네임이 있으면 닉네임 사용
val targetName =
NicknameDataStore.getNickname(currentTargetPlayer.uuid)
?: currentTargetPlayer.gameProfile.name
val playerName =
NicknameDataStore.getNickname(player.uuid)
?: player.gameProfile.name
MessageUtils.sendSuccess(player, "{$targetName}님에게 텔레포트 했습니다.")
MessageUtils.sendInfo(
currentTargetPlayer,
"{$playerName}님이 당신에게 텔레포트 했습니다."
)
} else {
MessageUtils.sendError(player, "해당 플레이어는 현재 오프라인입니다.")
} }
val prevPos = player.blockPosition()
val prevDimension = player.level().dimension().location().toString()
val prevBiome =
player.level()
.getBiome(prevPos)
.unwrapKey()
.map { it.location().toString() }
.orElse("minecraft:plains")
val previousLocation =
Location(
dimension = prevDimension,
biome = prevBiome,
x = prevPos.x.toDouble(),
y = prevPos.y.toDouble(),
z = prevPos.z.toDouble()
)
PlayerConfig.recordLastLocation(player, previousLocation)
val targetLevel = currentTargetPlayer.serverLevel()
player.teleportTo(
targetLevel,
currentTargetPlayer.x,
currentTargetPlayer.y,
currentTargetPlayer.z,
currentTargetPlayer.yRot,
currentTargetPlayer.xRot
)
// 소리 재생 (텔레포트 후)
playClickSound(player)
// 닉네임이 있으면 닉네임 사용
val targetName =
NicknameDataStore.getNickname(currentTargetPlayer.uuid)
?: currentTargetPlayer.gameProfile.name
val playerName =
NicknameDataStore.getNickname(player.uuid)
?: player.gameProfile.name
MessageUtils.sendSuccess(player, "{$targetName}님에게 텔레포트 했습니다.")
MessageUtils.sendInfo(
currentTargetPlayer,
"{$playerName}님이 당신에게 텔레포트 했습니다."
)
player.closeContainer() player.closeContainer()
return return
} }
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(