diff --git a/build.gradle b/build.gradle index f50a395..b374b75 100644 --- a/build.gradle +++ b/build.gradle @@ -17,7 +17,6 @@ repositories { // See https://docs.gradle.org/current/userguide/declaring_repositories.html // for more information about repositories. - maven { url 'https://maven.wispforest.io' } maven { url 'https://maven.nucleoid.xyz' } maven { url 'https://maven.reconnected.cc/releases' } } @@ -42,9 +41,6 @@ dependencies { // Fabric API. This is technically optional, but you probably want it anyway. modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" - annotationProcessor modImplementation("io.wispforest:owo-lib:${project.owo_version}") - include "io.wispforest:owo-sentinel:${project.owo_version}" - compileOnly "net.luckperms:api:${project.luckpermsapi_version}" include modImplementation("me.lucko:fabric-permissions-api:${project.permissions_api_version}") diff --git a/gradle.properties b/gradle.properties index 57276d4..e3398a5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,8 +16,6 @@ archives_base_name=rcc-server # Dependencies fabric_version=0.92.2+1.20.1 -owo_version=0.11.2+1.20 - luckpermsapi_version=5.4 permissions_api_version=0.2-SNAPSHOT diff --git a/src/main/java/cc/reconnected/server/RccServer.java b/src/main/java/cc/reconnected/server/RccServer.java index 802acf4..d7342d4 100644 --- a/src/main/java/cc/reconnected/server/RccServer.java +++ b/src/main/java/cc/reconnected/server/RccServer.java @@ -8,6 +8,8 @@ import cc.reconnected.server.commands.spawn.*; import cc.reconnected.server.commands.teleport.*; import cc.reconnected.server.commands.tell.*; import cc.reconnected.server.commands.warp.*; +import cc.reconnected.server.config.Config; +import cc.reconnected.server.config.ConfigManager; import cc.reconnected.server.core.*; import cc.reconnected.server.data.StateManager; import net.fabricmc.api.ModInitializer; @@ -36,7 +38,7 @@ public class RccServer implements ModInitializer { public static final String MOD_ID = "rcc-server"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - public static final cc.reconnected.server.RccServerConfig CONFIG = cc.reconnected.server.RccServerConfig.createAndLoad(); + public static Config CONFIG = ConfigManager.load(); public static final StateManager state = new StateManager(); diff --git a/src/main/java/cc/reconnected/server/commands/admin/RccCommand.java b/src/main/java/cc/reconnected/server/commands/admin/RccCommand.java index 8dff08f..9e7941a 100644 --- a/src/main/java/cc/reconnected/server/commands/admin/RccCommand.java +++ b/src/main/java/cc/reconnected/server/commands/admin/RccCommand.java @@ -2,6 +2,7 @@ package cc.reconnected.server.commands.admin; import cc.reconnected.server.RccServer; import cc.reconnected.server.api.events.RccEvents; +import cc.reconnected.server.config.ConfigManager; import com.mojang.brigadier.CommandDispatcher; import me.lucko.fabric.api.permissions.v0.Permissions; import net.minecraft.command.CommandRegistryAccess; @@ -21,7 +22,7 @@ public class RccCommand { context.getSource().sendFeedback(() -> Text.of("Reloading RCC config..."), true); try { - RccServer.CONFIG.load(); + RccServer.CONFIG = ConfigManager.load(); } catch(Exception e) { RccServer.LOGGER.error("Failed to load RCC config", e); context.getSource().sendFeedback(() -> Text.of("Failed to load RCC config. Check console for more info."), true); diff --git a/src/main/java/cc/reconnected/server/commands/admin/RestartCommand.java b/src/main/java/cc/reconnected/server/commands/admin/RestartCommand.java index 9ee012c..79db548 100644 --- a/src/main/java/cc/reconnected/server/commands/admin/RestartCommand.java +++ b/src/main/java/cc/reconnected/server/commands/admin/RestartCommand.java @@ -1,7 +1,6 @@ package cc.reconnected.server.commands.admin; import cc.reconnected.server.RccServer; -import cc.reconnected.server.api.events.RccEvents; import cc.reconnected.server.core.AutoRestart; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.IntegerArgumentType; @@ -37,7 +36,7 @@ public class RestartCommand { private static int schedule(CommandContext context, int seconds, @Nullable String message) { if (message == null) { - message = RccServer.CONFIG.autoRestart.restartBarLabel(); + message = RccServer.CONFIG.autoRestart.restartBarLabel; } AutoRestart.schedule(seconds, message); diff --git a/src/main/java/cc/reconnected/server/commands/home/SetHomeCommand.java b/src/main/java/cc/reconnected/server/commands/home/SetHomeCommand.java index 09791dc..ab67031 100644 --- a/src/main/java/cc/reconnected/server/commands/home/SetHomeCommand.java +++ b/src/main/java/cc/reconnected/server/commands/home/SetHomeCommand.java @@ -62,7 +62,7 @@ public class SetHomeCommand { return 1; } - var maxHomes = RccServer.CONFIG.homes.maxHomes(); + var maxHomes = RccServer.CONFIG.homes.maxHomes; if(homes.size() >= maxHomes && !exists) { context.getSource().sendFeedback(() -> Text.literal("You have reached the maximum amount of homes!").formatted(Formatting.RED), false); return 1; diff --git a/src/main/java/cc/reconnected/server/commands/misc/NearCommand.java b/src/main/java/cc/reconnected/server/commands/misc/NearCommand.java index 0dc1a07..a17cf3d 100644 --- a/src/main/java/cc/reconnected/server/commands/misc/NearCommand.java +++ b/src/main/java/cc/reconnected/server/commands/misc/NearCommand.java @@ -26,9 +26,9 @@ public class NearCommand { context.getSource().sendFeedback(() -> Text.of("This command can only be executed by players!"), false); return 1; } - return execute(context, RccServer.CONFIG.nearCommand.nearCommandDefaultRange(), context.getSource().getPlayer()); + return execute(context, RccServer.CONFIG.nearCommand.nearCommandDefaultRange, context.getSource().getPlayer()); }) - .then(argument("radius", IntegerArgumentType.integer(0, RccServer.CONFIG.nearCommand.nearCommandMaxRange())) + .then(argument("radius", IntegerArgumentType.integer(0, RccServer.CONFIG.nearCommand.nearCommandMaxRange)) .executes(context -> { if (!context.getSource().isExecutedByPlayer()) { context.getSource().sendFeedback(() -> Text.of("This command can only be executed by players!"), false); diff --git a/src/main/java/cc/reconnected/server/commands/tell/TellCommand.java b/src/main/java/cc/reconnected/server/commands/tell/TellCommand.java index 5db53b4..28ce8e4 100644 --- a/src/main/java/cc/reconnected/server/commands/tell/TellCommand.java +++ b/src/main/java/cc/reconnected/server/commands/tell/TellCommand.java @@ -71,17 +71,17 @@ public class TellCommand { var parsedMessage = MarkdownParser.defaultParser.parseNode(message); var you = Component.text("You", NamedTextColor.GRAY, TextDecoration.ITALIC); - var sourceText = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.directMessages.tellMessage(), + var sourceText = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.directMessages.tellMessage, Placeholder.component("source", you), Placeholder.component("target", targetDisplayName), Placeholder.component("message", parsedMessage.toText())); - var targetText = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.directMessages.tellMessage(), + var targetText = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.directMessages.tellMessage, Placeholder.component("source", source.getDisplayName()), Placeholder.component("target", you), Placeholder.component("message", parsedMessage.toText())); - var text = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.directMessages.tellMessage(), + var text = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.directMessages.tellMessage, Placeholder.component("source", source.getDisplayName()), Placeholder.component("target", targetDisplayName), Placeholder.component("message", parsedMessage.toText())); @@ -104,7 +104,7 @@ public class TellCommand { var lp = RccServer.getInstance().luckPerms(); var playerAdapter = lp.getPlayerAdapter(ServerPlayerEntity.class); - var spyText = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.directMessages.tellMessageSpy(), + var spyText = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.directMessages.tellMessageSpy, Placeholder.component("source", source.getDisplayName()), Placeholder.component("target", targetDisplayName), Placeholder.component("message", parsedMessage.toText())); diff --git a/src/main/java/cc/reconnected/server/RccServerConfigModel.java b/src/main/java/cc/reconnected/server/config/Config.java similarity index 68% rename from src/main/java/cc/reconnected/server/RccServerConfigModel.java rename to src/main/java/cc/reconnected/server/config/Config.java index 21d8e5b..12a61a2 100644 --- a/src/main/java/cc/reconnected/server/RccServerConfigModel.java +++ b/src/main/java/cc/reconnected/server/config/Config.java @@ -1,41 +1,21 @@ -package cc.reconnected.server; +package cc.reconnected.server.config; -import io.wispforest.owo.config.annotation.Config; -import io.wispforest.owo.config.annotation.Nest; +import java.util.ArrayList; +import java.util.List; -import java.util.*; +public class Config { + Config() { + } -@Config(name = "rcc-server-config", wrapperName = "RccServerConfig") -public class RccServerConfigModel { - @Nest public HttpApi httpApi = new HttpApi(); - - @Nest public Afk afk = new Afk(); - - @Nest public DirectMessages directMessages = new DirectMessages(); - - @Nest public TeleportRequests teleportRequests = new TeleportRequests(); - - @Nest public Homes homes = new Homes(); - - @Nest public CustomTabList customTabList = new CustomTabList(); - - @Nest public NearCommand nearCommand = new NearCommand(); - - @Nest public AutoRestart autoRestart = new AutoRestart(); - - @Nest - public CustomNameConfig customName = new CustomNameConfig(); - - @Nest - public CustomChatFormat customChatFormat = new CustomChatFormat(); + public TextFormats textFormats = new TextFormats(); public static class HttpApi { public boolean enableHttpApi = true; @@ -112,20 +92,24 @@ public class RccServerConfigModel { )); } - public static class CustomNameConfig { - public LinkedHashMap formats = new LinkedHashMap<>(Map.of( - "admin", "", - "default", "" + public static class TextFormats { + public record NameFormat(String group, String format) { + } + + public boolean enableChatMarkdown = true; + + public ArrayList nameFormats = new ArrayList<>(List.of( + new NameFormat("admin", "%player:name%"), + new NameFormat("default", "%player:name%") )); + + public String chatFormat = "${player}: ${message}"; + public String emoteFormat = "\uD83D\uDC64 ${player} ${message}"; + public String joinFormat = "+ ${player} joined!"; + public String joinRenamedFormat = "+ ${player} joined! (Previously known as ${previousName})"; + public String leaveFormat = "- ${player} left!"; + public String deathFormat = "\u2620 ${message}"; } - public static class CustomChatFormat { - public boolean enableMarkdown = true; - public String chatFormat = ": "; - public String emoteFormat = "\uD83D\uDC64 "; - public String joinFormat = "+ joined!"; - public String joinRenamedFormat = "+ joined! (Previously known as )"; - public String leaveFormat = "- left!"; - public String deathFormat = "\u2620 "; - } + } diff --git a/src/main/java/cc/reconnected/server/config/ConfigManager.java b/src/main/java/cc/reconnected/server/config/ConfigManager.java new file mode 100644 index 0000000..97f7040 --- /dev/null +++ b/src/main/java/cc/reconnected/server/config/ConfigManager.java @@ -0,0 +1,47 @@ +package cc.reconnected.server.config; + +import cc.reconnected.server.RccServer; +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import net.fabricmc.loader.api.FabricLoader; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.FileWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; + +public class ConfigManager { + private static final Gson gson = new GsonBuilder() + .disableHtmlEscaping() + .setPrettyPrinting() + .setDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX") + .create(); + private static final Path configFilePath = FabricLoader.getInstance().getConfigDir().resolve(RccServer.MOD_ID + ".json"); + private static Config config = null; + + public static Config load() { + if (!configFilePath.toFile().exists()) { + config = new Config(); + save(); + return config; + } + try (var bf = new BufferedReader(new FileReader(configFilePath.toFile(), StandardCharsets.UTF_8))) { + config = gson.fromJson(bf, Config.class); + save(); + } catch (Exception e) { + RccServer.LOGGER.error("Error loading the RccServer config file.", e); + } + return config; + } + + public static void save() { + var json = gson.toJson(config); + try (var fw = new FileWriter(configFilePath.toFile(), StandardCharsets.UTF_8)) { + fw.write(json); + } catch (Exception e) { + RccServer.LOGGER.error("Error saving the RccServer config file.", e); + } + } +} diff --git a/src/main/java/cc/reconnected/server/core/AfkTracker.java b/src/main/java/cc/reconnected/server/core/AfkTracker.java index a9919c7..41344f4 100644 --- a/src/main/java/cc/reconnected/server/core/AfkTracker.java +++ b/src/main/java/cc/reconnected/server/core/AfkTracker.java @@ -25,7 +25,7 @@ import java.util.concurrent.ConcurrentHashMap; public class AfkTracker { private static final int cycleDelay = 1; - private static final int absentTimeTrigger = RccServer.CONFIG.afk.afkTimeTrigger() * 20; // seconds * 20 ticks + private static final int absentTimeTrigger = RccServer.CONFIG.afk.afkTimeTrigger * 20; // seconds * 20 ticks private final ConcurrentHashMap playerActivityStates = new ConcurrentHashMap<>(); @@ -57,7 +57,7 @@ public class AfkTracker { var displayNameJson = Text.Serializer.toJson(player.getDisplayName()); var displayName = JSONComponentSerializer.json().deserialize(displayNameJson); - var message = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.afk.afkMessage(), + var message = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.afk.afkMessage, Placeholder.component("displayname", displayName), Placeholder.unparsed("username", player.getGameProfile().getName()), Placeholder.unparsed("uuid", player.getUuid().toString()) @@ -72,7 +72,7 @@ public class AfkTracker { var displayNameJson = Text.Serializer.toJson(player.getDisplayName()); var displayName = JSONComponentSerializer.json().deserialize(displayNameJson); - var message = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.afk.afkReturnMessage(), + var message = MiniMessage.miniMessage().deserialize(RccServer.CONFIG.afk.afkReturnMessage, Placeholder.component("displayname", displayName), Placeholder.unparsed("username", player.getGameProfile().getName()), Placeholder.unparsed("uuid", player.getUuid().toString()) @@ -85,7 +85,7 @@ public class AfkTracker { } private static void loadAfkTag() { - afkTag = Components.toText(MiniMessage.miniMessage().deserialize(RccServer.CONFIG.afk.afkTag())); + afkTag = Components.toText(MiniMessage.miniMessage().deserialize(RccServer.CONFIG.afk.afkTag)); } private AfkTracker() { diff --git a/src/main/java/cc/reconnected/server/core/AutoRestart.java b/src/main/java/cc/reconnected/server/core/AutoRestart.java index 1449967..bce8028 100644 --- a/src/main/java/cc/reconnected/server/core/AutoRestart.java +++ b/src/main/java/cc/reconnected/server/core/AutoRestart.java @@ -33,7 +33,7 @@ public class AutoRestart { var miniMessage = MiniMessage.miniMessage(); RccEvents.READY.register((server, luckPerms) -> { - if (RccServer.CONFIG.autoRestart.enableAutoRestart()) { + if (RccServer.CONFIG.autoRestart.enableAutoRestart) { scheduleNextRestart(); } }); @@ -42,7 +42,7 @@ public class AutoRestart { if (restartBar == null || !timeBar.getUuid().equals(restartBar.getUuid())) return; - var notificationTimes = RccServer.CONFIG.autoRestart.restartNotifications(); + var notificationTimes = RccServer.CONFIG.autoRestart.restartNotifications; var remainingSeconds = restartBar.getRemainingSeconds(); if (notificationTimes.contains(remainingSeconds)) { @@ -57,7 +57,7 @@ public class AutoRestart { return; final var text = Components.toText( - miniMessage.deserialize(RccServer.CONFIG.autoRestart.restartKickMessage()) + miniMessage.deserialize(RccServer.CONFIG.autoRestart.restartKickMessage) ); server.getPlayerManager().getPlayerList().forEach(player -> { player.networkHandler.disconnect(text); @@ -74,7 +74,7 @@ public class AutoRestart { } private static void setup() { - var soundName = RccServer.CONFIG.autoRestart.restartSound(); + var soundName = RccServer.CONFIG.autoRestart.restartSound; try { notificationKey = Key.key(soundName); } catch (InvalidKeyException e) { @@ -115,10 +115,10 @@ public class AutoRestart { private static void notifyRestart(MinecraftServer server, BossBarManager.TimeBar bar) { var rcc = RccServer.getInstance(); var audience = rcc.adventure().players(); - var sound = Sound.sound(notificationKey, Sound.Source.MASTER, 10f, RccServer.CONFIG.autoRestart.restartSoundPitch()); + var sound = Sound.sound(notificationKey, Sound.Source.MASTER, 10f, RccServer.CONFIG.autoRestart.restartSoundPitch); audience.playSound(sound, Sound.Emitter.self()); - var comp = bar.parseLabel(RccServer.CONFIG.autoRestart.restartChatMessage()); + var comp = bar.parseLabel(RccServer.CONFIG.autoRestart.restartChatMessage); rcc.broadcastMessage(server, comp); } @@ -133,7 +133,7 @@ public class AutoRestart { var barStartTime = delay - barTime; currentSchedule = scheduler.schedule(() -> { - schedule(barTime, RccServer.CONFIG.autoRestart.restartBarLabel()); + schedule(barTime, RccServer.CONFIG.autoRestart.restartBarLabel); }, barStartTime, TimeUnit.SECONDS); RccServer.LOGGER.info("Restart scheduled for in {} seconds", delay); @@ -142,7 +142,7 @@ public class AutoRestart { @Nullable private static Long getNextDelay() { - var restartTimeStrings = RccServer.CONFIG.autoRestart.restartAt(); + var restartTimeStrings = RccServer.CONFIG.autoRestart.restartAt; LocalDateTime now = LocalDateTime.now(); LocalDateTime nextRunTime = null; long shortestDelay = Long.MAX_VALUE; diff --git a/src/main/java/cc/reconnected/server/core/CustomNameFormat.java b/src/main/java/cc/reconnected/server/core/CustomNameFormat.java index 88c9d51..9e3af94 100644 --- a/src/main/java/cc/reconnected/server/core/CustomNameFormat.java +++ b/src/main/java/cc/reconnected/server/core/CustomNameFormat.java @@ -1,12 +1,10 @@ package cc.reconnected.server.core; import cc.reconnected.server.RccServer; -import cc.reconnected.server.util.Components; import eu.pb4.placeholders.api.PlaceholderContext; import eu.pb4.placeholders.api.Placeholders; +import eu.pb4.placeholders.api.TextParserUtils; import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.luckperms.api.model.group.Group; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.MutableText; @@ -14,7 +12,7 @@ import net.minecraft.text.MutableText; public class CustomNameFormat { private static final MiniMessage miniMessage = MiniMessage.miniMessage(); public static MutableText getNameForPlayer(ServerPlayerEntity player) { - var formats = RccServer.CONFIG.customName.formats().entrySet(); + var formats = RccServer.CONFIG.textFormats.nameFormats; var lp = RccServer.getInstance().luckPerms(); var playerContext = PlaceholderContext.of(player); @@ -23,21 +21,18 @@ public class CustomNameFormat { var groups = user.getInheritedGroups(user.getQueryOptions()).stream().map(Group::getName).toList(); String format = null; - for (var entry : formats) { - if (groups.contains(entry.getKey())) { - format = entry.getValue(); + for (var f : formats) { + if (groups.contains(f.group())) { + format = f.format(); break; } } if (format == null) { - format = ""; + format = "%player:name%"; } - var displayName = miniMessage.deserialize(format, TagResolver.resolver( - Placeholder.parsed("username", player.getGameProfile().getName()) - )); - - return Placeholders.parseText(Components.toText(displayName), playerContext).copy(); + var output = TextParserUtils.formatText(format); + return Placeholders.parseText(output, playerContext).copy(); } } diff --git a/src/main/java/cc/reconnected/server/core/HttpApiServer.java b/src/main/java/cc/reconnected/server/core/HttpApiServer.java index 3c26509..1192836 100644 --- a/src/main/java/cc/reconnected/server/core/HttpApiServer.java +++ b/src/main/java/cc/reconnected/server/core/HttpApiServer.java @@ -23,7 +23,7 @@ public class HttpApiServer { private static int currentPlayerCount = 0; public static void register() { - if (!RccServer.CONFIG.httpApi.enableHttpApi()) + if (!RccServer.CONFIG.httpApi.enableHttpApi) return; try { @@ -62,7 +62,7 @@ public class HttpApiServer { } private HttpApiServer() throws IOException { - server = HttpServer.create(new InetSocketAddress(RccServer.CONFIG.httpApi.httpPort()), 0); + server = HttpServer.create(new InetSocketAddress(RccServer.CONFIG.httpApi.httpPort), 0); server.createContext("/tps", new TPSHandler()); server.createContext("/mspt", new MSPTHandler()); server.createContext("/player", new PlayerCountHandler()); diff --git a/src/main/java/cc/reconnected/server/core/TabList.java b/src/main/java/cc/reconnected/server/core/TabList.java index 2f83982..7b4cc0d 100644 --- a/src/main/java/cc/reconnected/server/core/TabList.java +++ b/src/main/java/cc/reconnected/server/core/TabList.java @@ -10,23 +10,23 @@ import net.kyori.adventure.text.minimessage.MiniMessage; public class TabList { public static void register() { - if (!RccServer.CONFIG.customTabList.enableTabList()) + if (!RccServer.CONFIG.customTabList.enableTabList) return; var minimessage = MiniMessage.miniMessage(); ServerTickEvents.END_SERVER_TICK.register(server -> { - var delay = Math.max(RccServer.CONFIG.customTabList.tabListTickDelay(), 1); + var delay = Math.max(RccServer.CONFIG.customTabList.tabListTickDelay, 1); if(server.getTicks() % delay == 0) { - var period = Math.max(RccServer.CONFIG.customTabList.tabPhasePeriod(), 1); + var period = Math.max(RccServer.CONFIG.customTabList.tabPhasePeriod, 1); var phase = (Math.sin((server.getTicks() * Math.PI * 2) / period) + 1) / 2d; server.getPlayerManager().getPlayerList().forEach(player -> { var playerContext = PlaceholderContext.of(player); Component headerComponent = Component.empty(); - for (int i = 0; i < RccServer.CONFIG.customTabList.tabHeader().size(); i++) { - var line = RccServer.CONFIG.customTabList.tabHeader().get(i); + for (int i = 0; i < RccServer.CONFIG.customTabList.tabHeader.size(); i++) { + var line = RccServer.CONFIG.customTabList.tabHeader.get(i); line = line.replace("{phase}", String.valueOf(phase)); if (i > 0) { headerComponent = headerComponent.appendNewline(); @@ -36,8 +36,8 @@ public class TabList { } Component footerComponent = Component.empty(); - for (int i = 0; i < RccServer.CONFIG.customTabList.tabFooter().size(); i++) { - var line = RccServer.CONFIG.customTabList.tabFooter().get(i); + for (int i = 0; i < RccServer.CONFIG.customTabList.tabFooter.size(); i++) { + var line = RccServer.CONFIG.customTabList.tabFooter.get(i); line = line.replace("{phase}", String.valueOf(phase)); if (i > 0) { footerComponent = footerComponent.appendNewline(); diff --git a/src/main/java/cc/reconnected/server/core/TeleportTracker.java b/src/main/java/cc/reconnected/server/core/TeleportTracker.java index fd7fb25..0db968c 100644 --- a/src/main/java/cc/reconnected/server/core/TeleportTracker.java +++ b/src/main/java/cc/reconnected/server/core/TeleportTracker.java @@ -37,7 +37,7 @@ public class TeleportTracker { this.player = player; this.target = target; // Seconds in config per 20 ticks - this.remainingTicks = RccServer.CONFIG.teleportRequests.teleportRequestTimeout() * 20; + this.remainingTicks = RccServer.CONFIG.teleportRequests.teleportRequestTimeout * 20; } public void expire() { diff --git a/src/main/java/cc/reconnected/server/core/customChat/CustomChatMessage.java b/src/main/java/cc/reconnected/server/core/customChat/CustomChatMessage.java index 92af65e..1ff1f3a 100644 --- a/src/main/java/cc/reconnected/server/core/customChat/CustomChatMessage.java +++ b/src/main/java/cc/reconnected/server/core/customChat/CustomChatMessage.java @@ -3,6 +3,10 @@ package cc.reconnected.server.core.customChat; import cc.reconnected.server.RccServer; import cc.reconnected.server.parser.MarkdownParser; import cc.reconnected.server.util.Components; +import eu.pb4.placeholders.api.Placeholders; +import eu.pb4.placeholders.api.TextParserUtils; +import eu.pb4.placeholders.api.node.TextNode; +import eu.pb4.placeholders.api.parsers.PatternPlaceholderParser; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; @@ -12,6 +16,8 @@ import net.minecraft.registry.RegistryKeys; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; +import java.util.Map; + public class CustomChatMessage { private static final MiniMessage miniMessage = MiniMessage.miniMessage(); @@ -19,19 +25,16 @@ public class CustomChatMessage { var playerUuid = message.link().sender(); var player = RccServer.server.getPlayerManager().getPlayer(playerUuid); - Text messageText; - if (RccServer.CONFIG.customChatFormat.enableMarkdown()) { - messageText = MarkdownParser.defaultParser.parseNode(message.getSignedContent()).toText(); - } else { - messageText = message.getContent(); - } + Text messageText = Utils.formatChatMessage(message, player); - var component = miniMessage.deserialize(RccServer.CONFIG.customChatFormat.chatFormat(), TagResolver.resolver( - Placeholder.component("display_name", player.getDisplayName()), - Placeholder.component("message", messageText) - )); + var placeholders = Map.of( + "message", messageText, + "player", player.getDisplayName() + ); - var text = Components.toText(component); + + var format = TextParserUtils.formatText(RccServer.CONFIG.textFormats.chatFormat); + var text = Placeholders.parseText(format, PatternPlaceholderParser.PREDEFINED_PLACEHOLDER_PATTERN, placeholders); var msgType = RccServer.server.getRegistryManager().get(RegistryKeys.MESSAGE_TYPE).getOrThrow(RccServer.CHAT_TYPE); var newParams = new MessageType.Parameters(msgType, text, null); diff --git a/src/main/java/cc/reconnected/server/core/customChat/CustomConnectionMessage.java b/src/main/java/cc/reconnected/server/core/customChat/CustomConnectionMessage.java index 3bdb9a1..9da49c9 100644 --- a/src/main/java/cc/reconnected/server/core/customChat/CustomConnectionMessage.java +++ b/src/main/java/cc/reconnected/server/core/customChat/CustomConnectionMessage.java @@ -2,40 +2,46 @@ package cc.reconnected.server.core.customChat; import cc.reconnected.server.RccServer; import cc.reconnected.server.util.Components; +import eu.pb4.placeholders.api.Placeholders; +import eu.pb4.placeholders.api.TextParserUtils; +import eu.pb4.placeholders.api.node.TextNode; +import eu.pb4.placeholders.api.parsers.PatternPlaceholderParser; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; +import java.util.Map; + public class CustomConnectionMessage { private static final MiniMessage miniMessage = MiniMessage.miniMessage(); public static Text onJoin(ServerPlayerEntity player) { - var joinMessage = miniMessage.deserialize(RccServer.CONFIG.customChatFormat.joinFormat(), - TagResolver.resolver( - Placeholder.component("display_name", player.getDisplayName()) - )); + var placeholders = Map.of( + "player", player.getDisplayName() + ); - return Components.toText(joinMessage); + var format = TextParserUtils.formatText(RccServer.CONFIG.textFormats.joinFormat); + return Placeholders.parseText(format, PatternPlaceholderParser.PREDEFINED_PLACEHOLDER_PATTERN, placeholders); } public static Text onJoinRenamed(ServerPlayerEntity player, String previousName) { - var joinMessage = miniMessage.deserialize(RccServer.CONFIG.customChatFormat.joinRenamedFormat(), - TagResolver.resolver( - Placeholder.component("display_name", player.getDisplayName()), - Placeholder.component("previous_name", Text.of(previousName)) - )); + var placeholders = Map.of( + "previousName", Text.of(previousName), + "player", player.getDisplayName() + ); - return Components.toText(joinMessage); + var format = TextParserUtils.formatText(RccServer.CONFIG.textFormats.joinRenamedFormat); + return Placeholders.parseText(format, PatternPlaceholderParser.PREDEFINED_PLACEHOLDER_PATTERN, placeholders); } public static Text onLeave(ServerPlayerEntity player) { - var leaveMessage = miniMessage.deserialize(RccServer.CONFIG.customChatFormat.leaveFormat(), - TagResolver.resolver( - Placeholder.component("display_name", player.getDisplayName()) - )); + var placeholders = Map.of( + "player", player.getDisplayName() + ); - return Components.toText(leaveMessage); + var format = TextParserUtils.formatText(RccServer.CONFIG.textFormats.leaveFormat); + return Placeholders.parseText(format, PatternPlaceholderParser.PREDEFINED_PLACEHOLDER_PATTERN, placeholders); } } diff --git a/src/main/java/cc/reconnected/server/core/customChat/CustomDeathMessage.java b/src/main/java/cc/reconnected/server/core/customChat/CustomDeathMessage.java index caef5bc..e938d00 100644 --- a/src/main/java/cc/reconnected/server/core/customChat/CustomDeathMessage.java +++ b/src/main/java/cc/reconnected/server/core/customChat/CustomDeathMessage.java @@ -2,6 +2,11 @@ package cc.reconnected.server.core.customChat; import cc.reconnected.server.RccServer; import cc.reconnected.server.util.Components; +import eu.pb4.placeholders.api.PlaceholderContext; +import eu.pb4.placeholders.api.Placeholders; +import eu.pb4.placeholders.api.TextParserUtils; +import eu.pb4.placeholders.api.node.TextNode; +import eu.pb4.placeholders.api.parsers.PatternPlaceholderParser; import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; @@ -9,16 +14,20 @@ import net.minecraft.entity.damage.DamageTracker; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; +import java.util.Map; + public class CustomDeathMessage { private static final MiniMessage miniMessage = MiniMessage.miniMessage(); public static Text onDeath(ServerPlayerEntity player, DamageTracker instance) { var deathMessage = instance.getDeathMessage(); - var deathComponent = miniMessage.deserialize(RccServer.CONFIG.customChatFormat.deathFormat(), - TagResolver.resolver( - Placeholder.component("death_message", deathMessage) - )); - return Components.toText(deathComponent); + var placeholders = Map.of( + "message", deathMessage, + "player", player.getDisplayName() + ); + + var format = TextParserUtils.formatText(RccServer.CONFIG.textFormats.deathFormat); + return Placeholders.parseText(format, PatternPlaceholderParser.PREDEFINED_PLACEHOLDER_PATTERN, placeholders); } } diff --git a/src/main/java/cc/reconnected/server/core/customChat/CustomEmoteMessage.java b/src/main/java/cc/reconnected/server/core/customChat/CustomEmoteMessage.java index be95383..f039019 100644 --- a/src/main/java/cc/reconnected/server/core/customChat/CustomEmoteMessage.java +++ b/src/main/java/cc/reconnected/server/core/customChat/CustomEmoteMessage.java @@ -1,17 +1,18 @@ package cc.reconnected.server.core.customChat; import cc.reconnected.server.RccServer; -import cc.reconnected.server.parser.MarkdownParser; -import cc.reconnected.server.util.Components; +import eu.pb4.placeholders.api.Placeholders; +import eu.pb4.placeholders.api.TextParserUtils; +import eu.pb4.placeholders.api.parsers.PatternPlaceholderParser; import net.kyori.adventure.text.minimessage.MiniMessage; -import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; -import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; import net.minecraft.network.message.MessageType; import net.minecraft.network.message.SignedMessage; import net.minecraft.registry.RegistryKeys; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; +import java.util.Map; + public class CustomEmoteMessage { private static final MiniMessage miniMessage = MiniMessage.miniMessage(); @@ -19,19 +20,15 @@ public class CustomEmoteMessage { var playerUuid = message.link().sender(); var player = RccServer.server.getPlayerManager().getPlayer(playerUuid); - Text messageText; - if (RccServer.CONFIG.customChatFormat.enableMarkdown()) { - messageText = MarkdownParser.defaultParser.parseNode(message.getSignedContent()).toText(); - } else { - messageText = message.getContent(); - } + Text messageText = Utils.formatChatMessage(message, player); - var component = miniMessage.deserialize(RccServer.CONFIG.customChatFormat.emoteFormat(), TagResolver.resolver( - Placeholder.component("display_name", player.getDisplayName()), - Placeholder.component("message", messageText) - )); + var placeholders = Map.of( + "message", messageText, + "player", player.getDisplayName() + ); - var text = Components.toText(component); + var format = TextParserUtils.formatText(RccServer.CONFIG.textFormats.emoteFormat); + var text = Placeholders.parseText(format, PatternPlaceholderParser.PREDEFINED_PLACEHOLDER_PATTERN, placeholders); var msgType = RccServer.server.getRegistryManager().get(RegistryKeys.MESSAGE_TYPE).getOrThrow(RccServer.CHAT_TYPE); var newParams = new MessageType.Parameters(msgType, text, null); diff --git a/src/main/java/cc/reconnected/server/core/customChat/Utils.java b/src/main/java/cc/reconnected/server/core/customChat/Utils.java new file mode 100644 index 0000000..eb8f51b --- /dev/null +++ b/src/main/java/cc/reconnected/server/core/customChat/Utils.java @@ -0,0 +1,32 @@ +package cc.reconnected.server.core.customChat; + +import cc.reconnected.server.RccServer; +import cc.reconnected.server.parser.MarkdownParser; +import eu.pb4.placeholders.api.parsers.NodeParser; +import eu.pb4.placeholders.api.parsers.TextParserV1; +import net.minecraft.network.message.SignedMessage; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.text.Text; + +public class Utils { + public static Text formatChatMessage(SignedMessage message, ServerPlayerEntity player) { + var luckperms = RccServer.getInstance().luckPerms(); + + var permissions = luckperms.getPlayerAdapter(ServerPlayerEntity.class).getPermissionData(player); + var allowAdvancedChatFormat = permissions.checkPermission("rcc.chat.advanced").asBoolean(); + var enableMarkdown = RccServer.CONFIG.textFormats.enableChatMarkdown; + + if(!allowAdvancedChatFormat && !enableMarkdown) { + return message.getContent(); + } + + NodeParser parser; + if(allowAdvancedChatFormat) { + parser = NodeParser.merge(TextParserV1.DEFAULT, MarkdownParser.defaultParser); + } else { + parser = MarkdownParser.defaultParser; + } + + return parser.parseNode(message.getSignedContent()).toText(); + } +} diff --git a/src/main/java/cc/reconnected/server/mixin/ServerPlayNetworkManagerMixin.java b/src/main/java/cc/reconnected/server/mixin/ServerPlayNetworkManagerMixin.java index cf47672..3ef0c5d 100644 --- a/src/main/java/cc/reconnected/server/mixin/ServerPlayNetworkManagerMixin.java +++ b/src/main/java/cc/reconnected/server/mixin/ServerPlayNetworkManagerMixin.java @@ -2,13 +2,11 @@ package cc.reconnected.server.mixin; import cc.reconnected.server.RccServer; import cc.reconnected.server.core.customChat.CustomConnectionMessage; -import net.minecraft.network.packet.Packet; import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; import net.minecraft.server.MinecraftServer; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.text.Text; -import net.minecraft.text.TranslatableTextContent; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -30,7 +28,7 @@ public abstract class ServerPlayNetworkManagerMixin { @Inject(method = "tick", at = @At("TAIL")) private void rccServer$updatePlayerList(CallbackInfo ci) { - if(RccServer.CONFIG.customTabList.enableTabList()) { + if(RccServer.CONFIG.customTabList.enableTabList) { var packet = new PlayerListS2CPacket(EnumSet.of(PlayerListS2CPacket.Action.UPDATE_DISPLAY_NAME, PlayerListS2CPacket.Action.UPDATE_LISTED), List.of(this.player)); this.server.getPlayerManager().sendToAll(packet); } diff --git a/src/main/java/cc/reconnected/server/mixin/ServerPlayerEntityMixin.java b/src/main/java/cc/reconnected/server/mixin/ServerPlayerEntityMixin.java index 12c98dc..05248d1 100644 --- a/src/main/java/cc/reconnected/server/mixin/ServerPlayerEntityMixin.java +++ b/src/main/java/cc/reconnected/server/mixin/ServerPlayerEntityMixin.java @@ -23,10 +23,10 @@ public class ServerPlayerEntityMixin { @Inject(method = "getPlayerListName", at = @At("HEAD"), cancellable = true) private void rccServer$customizePlayerListName(CallbackInfoReturnable callback) { - if (RccServer.CONFIG.customTabList.enableTabList()) { + if (RccServer.CONFIG.customTabList.enableTabList) { var player = (ServerPlayerEntity) (Object) this; var playerContext = PlaceholderContext.of(player); - var text = Placeholders.parseText(parser.parseNode(RccServer.CONFIG.customTabList.playerTabName()), playerContext); + var text = Placeholders.parseText(parser.parseNode(RccServer.CONFIG.customTabList.playerTabName), playerContext); callback.setReturnValue(text); } } diff --git a/src/main/java/cc/reconnected/server/parser/MarkdownComponentParser.java b/src/main/java/cc/reconnected/server/parser/MarkdownComponentParser.java index 9b37057..17815da 100644 --- a/src/main/java/cc/reconnected/server/parser/MarkdownComponentParser.java +++ b/src/main/java/cc/reconnected/server/parser/MarkdownComponentParser.java @@ -1,10 +1,8 @@ package cc.reconnected.server.parser; import eu.pb4.placeholders.api.node.TextNode; -import eu.pb4.placeholders.api.node.parent.ClickActionNode; -import eu.pb4.placeholders.api.node.parent.FormattingNode; -import eu.pb4.placeholders.api.node.parent.HoverNode; -import net.minecraft.text.ClickEvent; +import eu.pb4.placeholders.api.node.parent.*; +import net.minecraft.text.*; import net.minecraft.util.Formatting; public class MarkdownComponentParser { @@ -32,7 +30,11 @@ public class MarkdownComponentParser { return new HoverNode<>(TextNode.array( new ClickActionNode( TextNode.array( - new FormattingNode(textNodes, Formatting.BLUE, Formatting.UNDERLINE)), + new StyledNode(textNodes, + Style.EMPTY.withColor(0x8888ff).withUnderline(true), + null, null, null + ) + ), ClickEvent.Action.OPEN_URL, url)), HoverNode.Action.TEXT, TextNode.of("Click to open: " + url.toText().getString()) );