style: MessageUtils 도입 - 전체 채팅 스타일 개선

- MessageUtils 유틸리티 추가 (청록색 기본 + 흰색 강조)
- 모든 명령어 및 GUI에 통일된 메시지 스타일 적용
- 수정 파일: SpawnCommand, NicknameCommand, CoordinateCommand, HeadCommand, PlayerCommand, ProtectFarmlandCommand, ChatCommand, TeleportGui, CoordinateGui, ChatEvents
This commit is contained in:
Caadiq 2025-12-29 15:13:37 +09:00
parent d0d8d0650f
commit ee66dddd99
11 changed files with 395 additions and 415 deletions

View file

@ -2,11 +2,10 @@ package com.beemer.essentials.command
import com.beemer.essentials.config.ChatConfig import com.beemer.essentials.config.ChatConfig
import com.beemer.essentials.util.ChatUtils import com.beemer.essentials.util.ChatUtils
import com.beemer.essentials.util.MessageUtils
import com.mojang.brigadier.exceptions.CommandSyntaxException import com.mojang.brigadier.exceptions.CommandSyntaxException
import net.minecraft.ChatFormatting
import net.minecraft.commands.CommandSourceStack import net.minecraft.commands.CommandSourceStack
import net.minecraft.commands.Commands import net.minecraft.commands.Commands
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.neoforged.bus.api.SubscribeEvent import net.neoforged.bus.api.SubscribeEvent
import net.neoforged.neoforge.event.RegisterCommandsEvent import net.neoforged.neoforge.event.RegisterCommandsEvent
@ -31,11 +30,7 @@ object ChatCommand {
private fun hasPermissionOrSend(player: ServerPlayer?, requiredLevel: Int = 2): Boolean { private fun hasPermissionOrSend(player: ServerPlayer?, requiredLevel: Int = 2): Boolean {
if (player != null && !player.hasPermissions(requiredLevel)) { if (player != null && !player.hasPermissions(requiredLevel)) {
player.sendSystemMessage( MessageUtils.sendError(player, "해당 명령어를 실행할 권한이 없습니다.")
Component.literal("해당 명령어를 실행할 권한이 없습니다.").withStyle {
it.withColor(ChatFormatting.RED)
}
)
return false return false
} }
return true return true
@ -51,15 +46,15 @@ object ChatCommand {
ChatConfig.loadConfig() ChatConfig.loadConfig()
val success = if (player != null) {
Component.literal("채팅 형식을 새로고침했습니다.").withStyle { MessageUtils.sendSuccess(player, "채팅 형식을 새로고침했습니다.")
it.withColor(ChatFormatting.GOLD) } else {
context.source.sendSuccess(
{ MessageUtils.success("채팅 형식을 새로고침했습니다.") },
false
)
} }
if (player == null)
context.source.sendSuccess({ success }, false)
else player.sendSystemMessage(success)
1 1
} }
) )
@ -81,9 +76,7 @@ object ChatCommand {
ChatUtils.clearChatForAll(allPlayers) ChatUtils.clearChatForAll(allPlayers)
server.playerList.broadcastSystemMessage( server.playerList.broadcastSystemMessage(
Component.literal("\u00A0\u00A0채팅창을 비웠습니다.").withStyle { MessageUtils.info("채팅창을 비웠습니다."),
it.withColor(ChatFormatting.AQUA)
},
false false
) )

View file

@ -7,8 +7,8 @@ import com.beemer.essentials.data.Location
import com.beemer.essentials.gui.Menu import com.beemer.essentials.gui.Menu
import com.beemer.essentials.gui.createPageContainer import com.beemer.essentials.gui.createPageContainer
import com.beemer.essentials.util.DimensionUtils import com.beemer.essentials.util.DimensionUtils
import com.beemer.essentials.util.MessageUtils
import com.mojang.brigadier.arguments.StringArgumentType import com.mojang.brigadier.arguments.StringArgumentType
import net.minecraft.ChatFormatting
import net.minecraft.commands.Commands import net.minecraft.commands.Commands
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
@ -19,7 +19,7 @@ import net.neoforged.neoforge.event.RegisterCommandsEvent
object CoordinateCommand { object CoordinateCommand {
@SubscribeEvent @SubscribeEvent
fun onRegisterCommands(event: RegisterCommandsEvent) { fun onRegisterCommands(event: RegisterCommandsEvent) {
// /좌표 - GUI 열기 (페이지 0부터 시작) // /좌표 - GUI 열기
event.dispatcher.register( event.dispatcher.register(
Commands.literal("좌표").executes { context -> Commands.literal("좌표").executes { context ->
val player = context.source.playerOrException as ServerPlayer val player = context.source.playerOrException as ServerPlayer
@ -28,7 +28,7 @@ object CoordinateCommand {
} }
) )
// /좌표이동 <장소> - 바로 이동 // /좌표이동 <장소>
event.dispatcher.register( event.dispatcher.register(
Commands.literal("좌표이동") Commands.literal("좌표이동")
.then( .then(
@ -70,16 +70,9 @@ object CoordinateCommand {
) )
if (CoordinateConfig.isExist(name)) { if (CoordinateConfig.isExist(name)) {
player.sendSystemMessage( MessageUtils.sendError(
Component.literal( player,
"$name 좌표가 이미 존재합니다." "{$name} 좌표가 이미 존재합니다."
)
.withStyle {
it.withColor(
ChatFormatting
.RED
)
}
) )
return@executes 0 return@executes 0
} }
@ -116,16 +109,9 @@ object CoordinateCommand {
) )
CoordinateConfig.addCoordinate(coordinate) CoordinateConfig.addCoordinate(coordinate)
player.sendSystemMessage( MessageUtils.sendSuccess(
Component.literal( player,
"$name 좌표를 추가했습니다." "{$name} 좌표를 추가했습니다."
)
.withStyle {
it.withColor(
ChatFormatting
.GOLD
)
}
) )
1 1
} }
@ -155,31 +141,17 @@ object CoordinateCommand {
) )
if (!CoordinateConfig.isExist(name)) { if (!CoordinateConfig.isExist(name)) {
player.sendSystemMessage( MessageUtils.sendError(
Component.literal( player,
"$name 좌표가 존재하지 않습니다." "{$name} 좌표가 존재하지 않습니다."
)
.withStyle {
it.withColor(
ChatFormatting
.RED
)
}
) )
return@executes 0 return@executes 0
} }
CoordinateConfig.removeCoordinate(name) CoordinateConfig.removeCoordinate(name)
player.sendSystemMessage( MessageUtils.sendSuccess(
Component.literal( player,
"$name 좌표를 제거했습니다." "{$name} 좌표를 제거했습니다."
)
.withStyle {
it.withColor(
ChatFormatting
.GOLD
)
}
) )
1 1
} }
@ -207,21 +179,13 @@ object CoordinateCommand {
private fun teleportToCoordinate(player: ServerPlayer, name: String): Int { private fun teleportToCoordinate(player: ServerPlayer, name: String): Int {
val coord = CoordinateConfig.getCoordinate(name) val coord = CoordinateConfig.getCoordinate(name)
if (coord == null) { if (coord == null) {
player.sendSystemMessage( MessageUtils.sendError(player, "{$name} 좌표가 존재하지 않습니다.")
Component.literal("$name 좌표가 존재하지 않습니다.").withStyle {
it.withColor(ChatFormatting.RED)
}
)
return 0 return 0
} }
val level = DimensionUtils.getLevelById(player.server, coord.dimension) val level = DimensionUtils.getLevelById(player.server, coord.dimension)
if (level == null) { if (level == null) {
player.sendSystemMessage( MessageUtils.sendError(player, "존재하지 않는 차원입니다.")
Component.literal("존재하지 않는 차원입니다.").withStyle {
it.withColor(ChatFormatting.RED)
}
)
return 0 return 0
} }
@ -244,11 +208,7 @@ object CoordinateCommand {
) )
player.teleportTo(level, coord.x, coord.y, coord.z, player.yRot, player.xRot) player.teleportTo(level, coord.x, coord.y, coord.z, player.yRot, player.xRot)
player.sendSystemMessage( MessageUtils.sendSuccess(player, "{$name}(으)로 이동했습니다.")
Component.literal("$name (으)로 이동했습니다.").withStyle {
it.withColor(ChatFormatting.GOLD)
}
)
return 1 return 1
} }
} }

View file

@ -2,6 +2,7 @@ package com.beemer.essentials.command
import com.beemer.essentials.config.PlayerConfig import com.beemer.essentials.config.PlayerConfig
import com.beemer.essentials.nickname.NicknameDataStore import com.beemer.essentials.nickname.NicknameDataStore
import com.beemer.essentials.util.MessageUtils
import com.mojang.brigadier.arguments.StringArgumentType import com.mojang.brigadier.arguments.StringArgumentType
import java.util.Optional import java.util.Optional
import java.util.UUID import java.util.UUID
@ -30,8 +31,6 @@ object HeadCommand {
StringArgumentType.greedyString() StringArgumentType.greedyString()
) )
.suggests { _, builder -> .suggests { _, builder ->
// 서버에 접속한 적 있는 플레이어만 제안
// 닉네임이 있으면 닉네임, 없으면 원래 이름
val suggestions = val suggestions =
mutableListOf<String>() mutableListOf<String>()
PlayerConfig.getAllPlayers() PlayerConfig.getAllPlayers()
@ -93,11 +92,7 @@ object HeadCommand {
// 3. 서버에 접속한 적 없는 플레이어면 거부 // 3. 서버에 접속한 적 없는 플레이어면 거부
if (targetUuid == null || !PlayerConfig.isKnownPlayer(targetUuid)) { if (targetUuid == null || !PlayerConfig.isKnownPlayer(targetUuid)) {
player.sendSystemMessage( MessageUtils.sendError(player, "해당 플레이어는 서버에 접속한 적이 없습니다.")
Component.literal("해당 플레이어는 서버에 접속한 적이 없습니다.").withStyle {
it.withColor(ChatFormatting.RED)
}
)
return 0 return 0
} }
@ -130,21 +125,13 @@ object HeadCommand {
val added = player.inventory.add(headItem) val added = player.inventory.add(headItem)
if (added) { if (added) {
player.sendSystemMessage( MessageUtils.sendSuccess(player, "{$displayName}의 머리가 지급되었습니다.")
Component.literal(displayName)
.withStyle { it.withColor(ChatFormatting.GREEN) }
.append(
Component.literal("의 머리가 지급되었습니다.").withStyle {
it.withColor(ChatFormatting.GOLD)
}
)
)
} else { } else {
// 인벤토리가 가득 찬 경우 바닥에 드랍 // 인벤토리가 가득 찬 경우 바닥에 드랍
player.drop(headItem, false) player.drop(headItem, false)
player.sendSystemMessage( MessageUtils.sendWarning(
Component.literal("인벤토리가 가득 차서 ${displayName}의 머리를 바닥에 떨어뜨렸습니다.") player,
.withStyle { it.withColor(ChatFormatting.YELLOW) } "인벤토리가 가득 차서 {$displayName}의 머리를 바닥에 떨어뜨렸습니다."
) )
} }

View file

@ -3,9 +3,8 @@ package com.beemer.essentials.command
import com.beemer.essentials.config.PlayerConfig import com.beemer.essentials.config.PlayerConfig
import com.beemer.essentials.util.CommandUtils import com.beemer.essentials.util.CommandUtils
import com.beemer.essentials.util.DimensionUtils import com.beemer.essentials.util.DimensionUtils
import net.minecraft.ChatFormatting import com.beemer.essentials.util.MessageUtils
import net.minecraft.commands.Commands import net.minecraft.commands.Commands
import net.minecraft.network.chat.Component
import net.neoforged.bus.api.SubscribeEvent import net.neoforged.bus.api.SubscribeEvent
import net.neoforged.neoforge.event.RegisterCommandsEvent import net.neoforged.neoforge.event.RegisterCommandsEvent
@ -23,17 +22,10 @@ object PlayerCommand {
val lastLocation = val lastLocation =
info?.lastLocation info?.lastLocation
?: run { ?: run {
player.sendSystemMessage( MessageUtils.sendError(
Component.literal( player,
"이전 위치가 존재하지 않습니다." "이전 위치가 존재하지 않습니다."
) )
.withStyle {
it.withColor(
ChatFormatting
.RED
)
}
)
return@executes 0 return@executes 0
} }
@ -43,17 +35,10 @@ object PlayerCommand {
lastLocation.dimension lastLocation.dimension
) )
?: run { ?: run {
player.sendSystemMessage( MessageUtils.sendError(
Component.literal( player,
"존재하지 않는 차원입니다." "존재하지 않는 차원입니다."
) )
.withStyle {
it.withColor(
ChatFormatting
.RED
)
}
)
return@executes 0 return@executes 0
} }
@ -65,11 +50,7 @@ object PlayerCommand {
player.yRot, player.yRot,
player.xRot player.xRot
) )
player.sendSystemMessage( MessageUtils.sendSuccess(player, "이전 위치로 이동했습니다.")
Component.literal("이전 위치로 이동했습니다.").withStyle {
it.withColor(ChatFormatting.GOLD)
}
)
1 1
} }
) )

View file

@ -2,9 +2,8 @@ package com.beemer.essentials.command
import com.beemer.essentials.config.ProtectFarmlandConfig import com.beemer.essentials.config.ProtectFarmlandConfig
import com.beemer.essentials.util.CommandUtils import com.beemer.essentials.util.CommandUtils
import net.minecraft.ChatFormatting import com.beemer.essentials.util.MessageUtils
import net.minecraft.commands.Commands import net.minecraft.commands.Commands
import net.minecraft.network.chat.Component
import net.neoforged.bus.api.SubscribeEvent import net.neoforged.bus.api.SubscribeEvent
import net.neoforged.neoforge.event.RegisterCommandsEvent import net.neoforged.neoforge.event.RegisterCommandsEvent
@ -19,22 +18,9 @@ object ProtectFarmlandCommand {
?: return@executes 0 ?: return@executes 0
val enabled = ProtectFarmlandConfig.toggle() val enabled = ProtectFarmlandConfig.toggle()
val status = if (enabled) "활성화" else "비활성화"
player.sendSystemMessage( MessageUtils.sendSuccess(player, "밭 보호를 {$status}했습니다.")
Component.literal("밭 보호를 ")
.withStyle { it.withColor(ChatFormatting.GOLD) }
.append(
Component.literal(if (enabled) "활성화" else "비활성화")
.withStyle {
it.withColor(ChatFormatting.DARK_GREEN)
}
)
.append(
Component.literal("했습니다.").withStyle {
it.withColor(ChatFormatting.GOLD)
}
)
)
1 1
} }
) )

View file

@ -5,9 +5,8 @@ import com.beemer.essentials.config.SpawnConfig
import com.beemer.essentials.data.Location import com.beemer.essentials.data.Location
import com.beemer.essentials.util.CommandUtils import com.beemer.essentials.util.CommandUtils
import com.beemer.essentials.util.DimensionUtils import com.beemer.essentials.util.DimensionUtils
import net.minecraft.ChatFormatting import com.beemer.essentials.util.MessageUtils
import net.minecraft.commands.Commands import net.minecraft.commands.Commands
import net.minecraft.network.chat.Component
import net.neoforged.bus.api.SubscribeEvent import net.neoforged.bus.api.SubscribeEvent
import net.neoforged.neoforge.event.RegisterCommandsEvent import net.neoforged.neoforge.event.RegisterCommandsEvent
@ -23,8 +22,9 @@ object SpawnCommand {
val exactPos = player.position() val exactPos = player.position()
val blockPos = player.blockPosition() val blockPos = player.blockPosition()
val dimensionId = player.level().dimension().location().toString() val dimension =
val biomeId = player.level().dimension().location().toString()
val biome =
player.level() player.level()
.getBiome(blockPos) .getBiome(blockPos)
.unwrapKey() .unwrapKey()
@ -33,20 +33,15 @@ object SpawnCommand {
val location = val location =
Location( Location(
dimension = dimensionId, dimension = dimension,
biome = biomeId, biome = biome,
x = exactPos.x, x = exactPos.x,
y = exactPos.y, y = exactPos.y,
z = exactPos.z z = exactPos.z
) )
SpawnConfig.setCustomSpawn(location) SpawnConfig.setCustomSpawn(location)
MessageUtils.sendSuccess(player, "스폰 지점이 현재 위치로 설정되었습니다.")
player.sendSystemMessage(
Component.literal("스폰 지점이 현재 위치로 설정되었습니다.").withStyle {
it.withColor(ChatFormatting.GOLD)
}
)
1 1
} }
) )
@ -59,38 +54,60 @@ object SpawnCommand {
CommandUtils.getPlayerOrSendFailure(context.source) CommandUtils.getPlayerOrSendFailure(context.source)
?: return@executes 0 ?: return@executes 0
val target = SpawnConfig.getCustomSpawn() ?: SpawnConfig.getDefaultSpawn() val target =
SpawnConfig.getCustomSpawn()
?: SpawnConfig.getDefaultSpawn()
target?.let { t -> target?.let { t ->
val level = DimensionUtils.getLevelById(player.server, t.dimension) val level =
DimensionUtils.getLevelById(
player.server,
t.dimension
)
level?.let { l -> level?.let { l ->
val exactPos = player.position() val exactPos = player.position()
val blockPos = player.blockPosition() val blockPos = player.blockPosition()
val currentDimension = val currentDimension =
player.level().dimension().location().toString() player.level()
.dimension()
.location()
.toString()
val currentBiome = val currentBiome =
player.level() player.level()
.getBiome(blockPos) .getBiome(blockPos)
.unwrapKey() .unwrapKey()
.map { it.location().toString() } .map {
it.location()
.toString()
}
.orElse("minecraft:plains") .orElse("minecraft:plains")
val currentLocation = val currentLocation =
Location( Location(
dimension = currentDimension, dimension =
currentDimension,
biome = currentBiome, biome = currentBiome,
x = exactPos.x, x = exactPos.x,
y = exactPos.y, y = exactPos.y,
z = exactPos.z z = exactPos.z
) )
PlayerConfig.recordLastLocation(player, currentLocation) PlayerConfig.recordLastLocation(
player.teleportTo(l, t.x, t.y, t.z, player.yRot, player.xRot) player,
player.sendSystemMessage( currentLocation
Component.literal("스폰으로 이동했습니다.").withStyle { )
it.withColor(ChatFormatting.GOLD) player.teleportTo(
} l,
t.x,
t.y,
t.z,
player.yRot,
player.xRot
)
MessageUtils.sendSuccess(
player,
"스폰으로 이동했습니다."
) )
} }
} }
@ -107,11 +124,7 @@ object SpawnCommand {
?: return@executes 0 ?: return@executes 0
SpawnConfig.removeCustomSpawn() SpawnConfig.removeCustomSpawn()
player.sendSystemMessage( MessageUtils.sendInfo(player, "스폰 지점이 기본 스폰 지점으로 변경되었습니다.")
Component.literal("스폰 지점이 기본 스폰 지점으로 변경되었습니다.").withStyle {
it.withColor(ChatFormatting.GOLD)
}
)
1 1
} }
) )

View file

@ -1,7 +1,7 @@
package com.beemer.essentials.event package com.beemer.essentials.event
import com.beemer.essentials.util.ChatUtils import com.beemer.essentials.util.ChatUtils
import net.minecraft.network.chat.Component import com.beemer.essentials.util.MessageUtils
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.neoforged.bus.api.SubscribeEvent import net.neoforged.bus.api.SubscribeEvent
import net.neoforged.neoforge.event.ServerChatEvent import net.neoforged.neoforge.event.ServerChatEvent
@ -12,13 +12,11 @@ object ChatEvents {
val player = event.player as ServerPlayer val player = event.player as ServerPlayer
val raw = event.rawText val raw = event.rawText
if (raw.startsWith("/")) if (raw.startsWith("/")) return
return
if (ChatUtils.hasIllegalCharacter(raw)) { if (ChatUtils.hasIllegalCharacter(raw)) {
event.isCanceled = true event.isCanceled = true
player.sendSystemMessage(Component.literal("채팅에 허용되지 않는 문자가 포함되어 있습니다.") MessageUtils.sendError(player, "채팅에 허용되지 않는 문자가 포함되어 있습니다.")
.withStyle { it.withColor(net.minecraft.ChatFormatting.RED) })
return return
} }

View file

@ -4,6 +4,7 @@ import com.beemer.essentials.config.CoordinateConfig
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.nickname.NicknameDataStore import com.beemer.essentials.nickname.NicknameDataStore
import com.beemer.essentials.util.MessageUtils
import com.beemer.essentials.util.TranslationUtils.translateBiome import com.beemer.essentials.util.TranslationUtils.translateBiome
import com.beemer.essentials.util.TranslationUtils.translateDimension import com.beemer.essentials.util.TranslationUtils.translateDimension
import java.util.UUID import java.util.UUID
@ -109,6 +110,7 @@ class Menu(
val x = tag.getDouble("x") val x = tag.getDouble("x")
val y = tag.getDouble("y") val y = tag.getDouble("y")
val z = tag.getDouble("z") val z = tag.getDouble("z")
val coordName = tag.getString("name")
val dimension = val dimension =
ResourceLocation.tryParse(tag.getString("dimension"))?.let { ResourceLocation.tryParse(tag.getString("dimension"))?.let {
ResourceKey.create(Registries.DIMENSION, it) ResourceKey.create(Registries.DIMENSION, it)
@ -135,15 +137,7 @@ class Menu(
) )
player.teleportTo(level, x, y, z, player.yRot, player.xRot) player.teleportTo(level, x, y, z, player.yRot, player.xRot)
player.sendSystemMessage( MessageUtils.sendSuccess(player, "{$coordName}(으)로 이동했습니다.")
Component.literal(tag.getString("name"))
.withStyle { it.withColor(ChatFormatting.DARK_GREEN) }
.append(
Component.literal("(으)로 이동했습니다.").withStyle {
it.withColor(ChatFormatting.GOLD)
}
)
)
} }
player.closeContainer() player.closeContainer()
} }

View file

@ -4,8 +4,7 @@ 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.data.Player
import com.beemer.essentials.nickname.NicknameDataStore import com.beemer.essentials.nickname.NicknameDataStore
import net.minecraft.ChatFormatting import com.beemer.essentials.util.MessageUtils
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.Container import net.minecraft.world.Container
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
@ -80,9 +79,12 @@ class TeleportGui(
) { ) {
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 { player.server.playerList.getPlayer(it) } targetPlayers.getOrNull(slotId)?.let {
player.server.playerList.getPlayer(it)
}
if (currentTargetPlayer != null && player.uuid != currentTargetPlayer.uuid) { if (currentTargetPlayer != null && player.uuid != currentTargetPlayer.uuid
) {
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 =
@ -117,32 +119,16 @@ class TeleportGui(
NicknameDataStore.getNickname(currentTargetPlayer.uuid) NicknameDataStore.getNickname(currentTargetPlayer.uuid)
?: currentTargetPlayer.gameProfile.name ?: currentTargetPlayer.gameProfile.name
val playerName = val playerName =
NicknameDataStore.getNickname(player.uuid) ?: player.gameProfile.name NicknameDataStore.getNickname(player.uuid)
?: player.gameProfile.name
player.sendSystemMessage( MessageUtils.sendSuccess(player, "{$targetName}님에게 텔레포트 했습니다.")
Component.literal(targetName) MessageUtils.sendInfo(
.withStyle { it.withColor(ChatFormatting.AQUA) } currentTargetPlayer,
.append( "{$playerName}님이 당신에게 텔레포트 했습니다."
Component.literal("님에게 텔레포트 했습니다.").withStyle {
it.withColor(ChatFormatting.GOLD)
}
)
)
currentTargetPlayer.sendSystemMessage(
Component.literal(playerName)
.withStyle { it.withColor(ChatFormatting.AQUA) }
.append(
Component.literal("님이 당신에게 텔레포트 했습니다.").withStyle {
it.withColor(ChatFormatting.GOLD)
}
)
) )
} else { } else {
player.sendSystemMessage( MessageUtils.sendError(player, "해당 플레이어는 현재 오프라인입니다.")
Component.literal("해당 플레이어는 현재 오프라인입니다.").withStyle {
it.withColor(ChatFormatting.RED)
}
)
} }
player.closeContainer() player.closeContainer()

View file

@ -1,9 +1,8 @@
package com.beemer.essentials.nickname package com.beemer.essentials.nickname
import com.beemer.essentials.util.MessageUtils
import com.mojang.brigadier.arguments.StringArgumentType import com.mojang.brigadier.arguments.StringArgumentType
import net.minecraft.ChatFormatting
import net.minecraft.commands.Commands import net.minecraft.commands.Commands
import net.minecraft.network.chat.Component
import net.minecraft.server.level.ServerPlayer import net.minecraft.server.level.ServerPlayer
import net.neoforged.bus.api.SubscribeEvent import net.neoforged.bus.api.SubscribeEvent
import net.neoforged.neoforge.event.RegisterCommandsEvent import net.neoforged.neoforge.event.RegisterCommandsEvent
@ -29,7 +28,6 @@ object NicknameCommand {
.entity as? .entity as?
ServerPlayer ServerPlayer
?: return@executes 0 ?: return@executes 0
val nickname = val nickname =
StringArgumentType StringArgumentType
.getString( .getString(
@ -46,7 +44,6 @@ object NicknameCommand {
val player = val player =
context.source.entity as? ServerPlayer context.source.entity as? ServerPlayer
?: return@executes 0 ?: return@executes 0
executeReset(player) executeReset(player)
} }
) )
@ -69,7 +66,6 @@ object NicknameCommand {
.entity as? .entity as?
ServerPlayer ServerPlayer
?: return@executes 0 ?: return@executes 0
val nickname = val nickname =
StringArgumentType StringArgumentType
.getString( .getString(
@ -86,7 +82,6 @@ object NicknameCommand {
val player = val player =
context.source.entity as? ServerPlayer context.source.entity as? ServerPlayer
?: return@executes 0 ?: return@executes 0
executeReset(player) executeReset(player)
} }
) )
@ -96,65 +91,34 @@ object NicknameCommand {
private fun executeSet(player: ServerPlayer, nickname: String): Int { private fun executeSet(player: ServerPlayer, nickname: String): Int {
// 유효성 검사: 길이 // 유효성 검사: 길이
if (nickname.length < 2 || nickname.length > 16) { if (nickname.length < 2 || nickname.length > 16) {
player.sendSystemMessage( MessageUtils.sendError(player, "닉네임은 2~16자 사이여야 합니다.")
Component.literal("닉네임은 2~16자 사이여야 합니다.").withStyle {
it.withColor(ChatFormatting.RED)
}
)
return 0 return 0
} }
// 유효성 검사: 중복 // 유효성 검사: 중복
if (NicknameDataStore.isNicknameTaken(nickname, player.uuid)) { if (NicknameDataStore.isNicknameTaken(nickname, player.uuid)) {
player.sendSystemMessage( MessageUtils.sendError(player, "이미 사용 중인 닉네임입니다.")
Component.literal("이미 사용 중인 닉네임입니다.").withStyle {
it.withColor(ChatFormatting.RED)
}
)
return 0 return 0
} }
// 닉네임 저장 및 적용 (gameProfile.name = 실제 마인크래프트 이름) // 닉네임 저장 및 적용
NicknameDataStore.setNickname(player.uuid, player.gameProfile.name, nickname) NicknameDataStore.setNickname(player.uuid, player.gameProfile.name, nickname)
NicknameManager.applyNickname(player, nickname) NicknameManager.applyNickname(player, nickname)
player.sendSystemMessage( MessageUtils.sendSuccess(player, "닉네임이 {$nickname}(으)로 변경되었습니다.")
Component.literal("닉네임이 ")
.withStyle { it.withColor(ChatFormatting.GOLD) }
.append(
Component.literal(nickname).withStyle {
it.withColor(ChatFormatting.AQUA)
}
)
.append(
Component.literal("(으)로 변경되었습니다.").withStyle {
it.withColor(ChatFormatting.GOLD)
}
)
)
return 1 return 1
} }
private fun executeReset(player: ServerPlayer): Int { private fun executeReset(player: ServerPlayer): Int {
if (!NicknameDataStore.hasNickname(player.uuid)) { if (!NicknameDataStore.hasNickname(player.uuid)) {
player.sendSystemMessage( MessageUtils.sendError(player, "설정된 닉네임이 없습니다.")
Component.literal("설정된 닉네임이 없습니다.").withStyle {
it.withColor(ChatFormatting.RED)
}
)
return 0 return 0
} }
NicknameDataStore.removeNickname(player.uuid) NicknameDataStore.removeNickname(player.uuid)
NicknameManager.removeNickname(player) NicknameManager.removeNickname(player)
player.sendSystemMessage( MessageUtils.sendSuccess(player, "닉네임이 초기화되었습니다.")
Component.literal("닉네임이 초기화되었습니다.").withStyle {
it.withColor(ChatFormatting.GOLD)
}
)
return 1 return 1
} }
} }

View file

@ -0,0 +1,118 @@
package com.beemer.essentials.util
import net.minecraft.network.chat.Component
import net.minecraft.network.chat.MutableComponent
import net.minecraft.network.chat.Style
import net.minecraft.network.chat.TextColor
import net.minecraft.server.level.ServerPlayer
/** 메시지 스타일 유틸리티 기본 텍스트: 밝은 청록색 (#A8D8D8) 강조 텍스트: 흰색 (#FFFFFF) */
object MessageUtils {
// 기본 색상 (더 밝게)
private const val BASE_COLOR = 0xA8D8D8 // 밝은 청록색 (기본 텍스트)
private const val ACCENT_COLOR = 0xFFFFFF // 흰색 (강조)
private const val ERROR_COLOR = 0xFF8888 // 밝은 빨간색 (오류)
private const val WARNING_COLOR = 0xFFE066 // 밝은 노란색 (경고)
/**
* 기본 스타일 메시지 생성
* @param text 텍스트 (강조 부분은 {중괄호} 감싸기) : "스폰으로 이동했습니다." 또는 "{비머}님에게 텔레포트 요청을 보냈습니다."
*/
fun styled(text: String): MutableComponent {
return parseStyledText(text, BASE_COLOR, ACCENT_COLOR)
}
/** 성공 메시지 (아이콘 없이 기본 스타일) */
fun success(text: String): MutableComponent {
return styled(text)
}
/** 정보 메시지 (아이콘 없이 기본 스타일) */
fun info(text: String): MutableComponent {
return styled(text)
}
/** 오류 메시지 (빨간색 스타일) */
fun error(text: String): MutableComponent {
return parseStyledText(text, ERROR_COLOR, ACCENT_COLOR)
}
/** 경고 메시지 (노란색 스타일) */
fun warning(text: String): MutableComponent {
return parseStyledText(text, WARNING_COLOR, ACCENT_COLOR)
}
// === 플레이어에게 직접 전송 ===
fun sendSuccess(player: ServerPlayer, text: String) {
player.sendSystemMessage(success(text))
}
fun sendInfo(player: ServerPlayer, text: String) {
player.sendSystemMessage(info(text))
}
fun sendError(player: ServerPlayer, text: String) {
player.sendSystemMessage(error(text))
}
fun sendWarning(player: ServerPlayer, text: String) {
player.sendSystemMessage(warning(text))
}
/** 스타일 텍스트 파싱 {중괄호} 안의 텍스트는 강조 색상으로 표시 */
private fun parseStyledText(text: String, baseColor: Int, accentColor: Int): MutableComponent {
val result: MutableComponent = Component.empty()
var i = 0
val sb = StringBuilder()
while (i < text.length) {
when {
text[i] == '{' -> {
// 이전 텍스트 추가 (기본 색상)
if (sb.isNotEmpty()) {
result.append(
Component.literal(sb.toString())
.withStyle(
Style.EMPTY.withColor(TextColor.fromRgb(baseColor))
)
)
sb.clear()
}
// 강조 텍스트 찾기
val endIdx = text.indexOf('}', i)
if (endIdx != -1) {
val accentText = text.substring(i + 1, endIdx)
result.append(
Component.literal(accentText)
.withStyle(
Style.EMPTY.withColor(
TextColor.fromRgb(accentColor)
)
)
)
i = endIdx + 1
} else {
sb.append(text[i])
i++
}
}
else -> {
sb.append(text[i])
i++
}
}
}
// 남은 텍스트 추가
if (sb.isNotEmpty()) {
result.append(
Component.literal(sb.toString())
.withStyle(Style.EMPTY.withColor(TextColor.fromRgb(baseColor)))
)
}
return result
}
}