diff --git a/build.gradle.kts b/build.gradle.kts index 124df56..144b657 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -21,8 +21,10 @@ dependencies { paperweight.foliaDevBundle("$mcVersion-R0.1-SNAPSHOT") compileOnly("me.clip:placeholderapi:2.11.5") - implementation("com.github.siroshun09.configapi:configapi-yaml:4.6.4") - implementation("com.github.siroshun09.translationloader:translationloader:2.0.2") + implementation("com.github.siroshun09.configapi:configapi-format-yaml:5.0.0-beta.3") { + exclude("org.yaml", "snakeyaml") + } + implementation("com.github.siroshun09.messages:messages-minimessage:0.6.0") } java { diff --git a/src/main/java/net/okocraft/scoreboard/ScoreboardPlugin.java b/src/main/java/net/okocraft/scoreboard/ScoreboardPlugin.java index 911d7a7..7676e02 100644 --- a/src/main/java/net/okocraft/scoreboard/ScoreboardPlugin.java +++ b/src/main/java/net/okocraft/scoreboard/ScoreboardPlugin.java @@ -1,9 +1,12 @@ package net.okocraft.scoreboard; -import com.github.siroshun09.configapi.api.util.ResourceUtils; -import com.github.siroshun09.configapi.yaml.YamlConfiguration; -import com.github.siroshun09.translationloader.directory.TranslationDirectory; -import net.kyori.adventure.key.Key; +import com.github.siroshun09.configapi.format.yaml.YamlFormat; +import com.github.siroshun09.messages.api.directory.DirectorySource; +import com.github.siroshun09.messages.api.directory.MessageProcessors; +import com.github.siroshun09.messages.api.source.StringMessageMap; +import com.github.siroshun09.messages.api.util.PropertiesFile; +import com.github.siroshun09.messages.minimessage.localization.MiniMessageLocalization; +import com.github.siroshun09.messages.minimessage.source.MiniMessageSource; import net.okocraft.scoreboard.command.ScoreboardCommand; import net.okocraft.scoreboard.config.BoardManager; import net.okocraft.scoreboard.display.line.LineDisplay; @@ -12,15 +15,20 @@ import net.okocraft.scoreboard.external.PlaceholderAPIHooker; import net.okocraft.scoreboard.listener.PlayerListener; import net.okocraft.scoreboard.listener.PluginListener; +import net.okocraft.scoreboard.message.Messages; import net.okocraft.scoreboard.util.PlatformHelper; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.Locale; +import java.util.Map; import java.util.Objects; +import java.util.function.Consumer; import java.util.logging.Level; public class ScoreboardPlugin extends JavaPlugin { @@ -31,15 +39,10 @@ public class ScoreboardPlugin extends JavaPlugin { return Objects.requireNonNull(INSTANCE); } - private final TranslationDirectory translationDirectory = - TranslationDirectory.newBuilder() - .setKey(Key.key("scoreboard:languages")) - .setDirectory(getDataFolder().toPath().resolve("languages")) - .setDefaultLocale(Locale.ENGLISH) - .onDirectoryCreated(this::saveDefaultLanguages) - .build(); + private final BoardManager boardManager = new BoardManager(this); - private BoardManager boardManager; + private boolean boardLoaded; + private MiniMessageLocalization localization; private DisplayManager displayManager; private PlayerListener playerListener; private PluginListener pluginListener; @@ -48,21 +51,8 @@ public class ScoreboardPlugin extends JavaPlugin { public void onLoad() { INSTANCE = this; - try { - saveDefaultFiles(); - } catch (IOException e) { - getLogger().log(Level.SEVERE, "Could not save default files", e); - } - - try { - translationDirectory.load(); - } catch (IOException e) { - getLogger().log(Level.SEVERE, "Could not load languages", e); - } - - loadConfig(); - boardManager = new BoardManager(this); - boardManager.reload(); + this.boardLoaded = this.reloadSettings(ex -> { + }); } @Override @@ -88,7 +78,9 @@ public void onEnable() { command.setTabCompleter(impl); } - PlatformHelper.runAsync(this::showDefaultBoardToOnlinePlayers); + if (this.boardLoaded) { + PlatformHelper.runAsync(this::showDefaultBoardToOnlinePlayers); + } } @Override @@ -107,32 +99,56 @@ public void onDisable() { } } - public void reload() { + public boolean reload(@NotNull Consumer exceptionConsumer) { displayManager.hideAllBoards(); + if (this.reloadSettings(exceptionConsumer)) { + PlatformHelper.runAsync(this::showDefaultBoardToOnlinePlayers); + return true; + } else { + return false; + } + } + + private boolean reloadSettings(@NotNull Consumer exceptionConsumer) { try { - translationDirectory.load(); + this.loadConfig(); + } catch (IOException e) { + getLogger().log(Level.SEVERE, "Could not load config.yml", e); + exceptionConsumer.accept(e); + return false; + } + + try { + this.loadMessages(); } catch (IOException e) { getLogger().log(Level.SEVERE, "Could not load languages", e); + exceptionConsumer.accept(e); + return false; + } + + try { + this.boardManager.reload(); + } catch (IOException e) { + getLogger().log(Level.SEVERE, "Could not load boards", e); + exceptionConsumer.accept(e); + return false; } - loadConfig(); - boardManager.reload(); + return true; + } - PlatformHelper.runAsync(this::showDefaultBoardToOnlinePlayers); + public @NotNull MiniMessageLocalization getLocalization() { + return this.localization; } @NotNull public BoardManager getBoardManager() { - if (boardManager == null) { - throw new IllegalStateException(); - } - return boardManager; } public DisplayManager getDisplayManager() { - if (boardManager == null) { + if (displayManager == null) { throw new IllegalStateException(); } @@ -143,31 +159,48 @@ public void printPlaceholderIsAvailable() { getLogger().info("PlaceholderAPI is available!"); } - private void saveDefaultFiles() throws IOException { - ResourceUtils.copyFromJarIfNotExists( - getFile().toPath(), "config.yml", getDataFolder().toPath().resolve("config.yml") - ); + public Path saveResource(String filename) throws IOException { + var filepath = this.getDataFolder().toPath().resolve(filename); + if (!Files.isRegularFile(filepath)) { + try (var input = this.getResource(filename)) { + if (input == null) { + throw new IllegalStateException(filename + " was not found in the jar."); + } + Files.copy(input, filepath); + } + } + return filepath; + } - ResourceUtils.copyFromJarIfNotExists( - getFile().toPath(), "default.yml", getDataFolder().toPath().resolve("default.yml") - ); + private void loadConfig() throws IOException { + var config = YamlFormat.DEFAULT.load(this.saveResource("config.yml")); + LineDisplay.globalLengthLimit = Math.max(config.getInteger("max-line-length", 32), 1); } - private void loadConfig() { - try (var config = YamlConfiguration.create(getDataFolder().toPath().resolve("config.yml"))) { - config.load(); - LineDisplay.globalLengthLimit = Math.max(config.getInteger("max-line-length", 32), 1); - } catch (IOException e) { - getLogger().log(Level.SEVERE, "Could not load config.yml", e); + private void loadMessages() throws IOException { + if (this.localization == null) { // on startup + this.localization = new MiniMessageLocalization(MiniMessageSource.create(StringMessageMap.create(Messages.defaultMessages())), Messages::getLocaleFrom); + } else { // on reload + this.localization.clearSources(); } - } - private void saveDefaultLanguages(@NotNull Path directory) throws IOException { - var english = "en.yml"; - ResourceUtils.copyFromJarIfNotExists(getFile().toPath(), english, directory.resolve(english)); + DirectorySource.forStringMessageMap(this.getDataFolder().toPath().resolve("languages")) + .fileExtension(PropertiesFile.FILE_EXTENSION) + .defaultLocale(Locale.ENGLISH, Locale.JAPANESE) + .messageLoader(PropertiesFile.DEFAULT_LOADER) + .messageProcessor(MessageProcessors.appendMissingStringMessages(this::loadDefaultMessageMap, PropertiesFile.DEFAULT_APPENDER)) + .messageProcessor(loaded -> MiniMessageSource.create(loaded.messageSource())) + .load(loaded -> this.localization.addSource(loaded.locale(), loaded.messageSource())); + } - var japanese = "ja_JP.yml"; - ResourceUtils.copyFromJarIfNotExists(getFile().toPath(), japanese, directory.resolve(japanese)); + private @Nullable Map loadDefaultMessageMap(@NotNull Locale locale) throws IOException { + if (locale.equals(Locale.ENGLISH)) { + return Messages.defaultMessages(); + } else { + try (var input = this.getResource(locale + ".properties")) { + return input != null ? PropertiesFile.load(input) : null; + } + } } private void showDefaultBoardToOnlinePlayers() { diff --git a/src/main/java/net/okocraft/scoreboard/command/Command.java b/src/main/java/net/okocraft/scoreboard/command/Command.java index 6e1b5eb..a154741 100644 --- a/src/main/java/net/okocraft/scoreboard/command/Command.java +++ b/src/main/java/net/okocraft/scoreboard/command/Command.java @@ -1,5 +1,6 @@ package net.okocraft.scoreboard.command; +import com.github.siroshun09.messages.minimessage.source.MiniMessageSource; import net.kyori.adventure.text.Component; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; @@ -39,7 +40,7 @@ public interface Command { * * @return the helps */ - @NotNull Component getHelp(); + @NotNull Component getHelp(@NotNull MiniMessageSource msgSrc); /** * Executes the command. @@ -50,7 +51,7 @@ public interface Command { * @param sender the executor * @param args the array of arguments */ - void onCommand(@NotNull CommandSender sender, @NotNull String[] args); + void onCommand(@NotNull CommandSender sender, @NotNull String[] args, @NotNull MiniMessageSource msgSrc); /** * Gets the tab-completion. diff --git a/src/main/java/net/okocraft/scoreboard/command/ScoreboardCommand.java b/src/main/java/net/okocraft/scoreboard/command/ScoreboardCommand.java index 0207f68..9727e2b 100644 --- a/src/main/java/net/okocraft/scoreboard/command/ScoreboardCommand.java +++ b/src/main/java/net/okocraft/scoreboard/command/ScoreboardCommand.java @@ -1,10 +1,14 @@ package net.okocraft.scoreboard.command; +import com.github.siroshun09.messages.minimessage.localization.MiniMessageLocalization; +import com.github.siroshun09.messages.minimessage.source.MiniMessageSource; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.JoinConfiguration; import net.okocraft.scoreboard.ScoreboardPlugin; import net.okocraft.scoreboard.command.subcommand.HideCommand; import net.okocraft.scoreboard.command.subcommand.ReloadCommand; import net.okocraft.scoreboard.command.subcommand.ShowCommand; -import net.okocraft.scoreboard.message.CommandMessage; +import net.okocraft.scoreboard.message.Messages; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; @@ -17,17 +21,15 @@ import java.util.Locale; import java.util.Objects; -import static net.kyori.adventure.text.Component.text; -import static net.kyori.adventure.text.format.NamedTextColor.DARK_GRAY; -import static net.kyori.adventure.text.format.NamedTextColor.GOLD; - public class ScoreboardCommand implements CommandExecutor, TabCompleter { private static final String COMMAND_PERMISSION = "scoreboard.command"; + private final MiniMessageLocalization localization; private final SubCommandHolder subCommandHolder; public ScoreboardCommand(@NotNull ScoreboardPlugin plugin) { + this.localization = plugin.getLocalization(); subCommandHolder = new SubCommandHolder( new ShowCommand(plugin.getBoardManager(), plugin.getDisplayManager()), new HideCommand(plugin.getDisplayManager()), @@ -38,29 +40,31 @@ public ScoreboardCommand(@NotNull ScoreboardPlugin plugin) { @Override public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + var msgSrc = this.localization.findSource(sender); + if (!(sender.hasPermission(COMMAND_PERMISSION))) { - sender.sendMessage(CommandMessage.NO_PERMISSION.apply(COMMAND_PERMISSION)); + Messages.NO_PERMISSION.apply(COMMAND_PERMISSION).source(msgSrc).send(sender); return true; } if (args.length == 0 || args[0].equalsIgnoreCase("help")) { - sendHelp(sender); + sendHelp(sender, msgSrc); return true; } var optionalSubCommand = subCommandHolder.search(args[0]); if (optionalSubCommand.isEmpty()) { - sendHelp(sender); + sendHelp(sender, msgSrc); return true; } var subCommand = optionalSubCommand.get(); if (sender.hasPermission(subCommand.getPermissionNode())) { - subCommand.onCommand(sender, args); + subCommand.onCommand(sender, args, msgSrc); } else { - sender.sendMessage(CommandMessage.NO_PERMISSION.apply(subCommand.getPermissionNode())); + Messages.NO_PERMISSION.apply(subCommand.getPermissionNode()).source(msgSrc).send(sender); } return true; @@ -89,16 +93,11 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command .orElse(Collections.emptyList()); } - private void sendHelp(@NotNull CommandSender sender) { - sender.sendMessage( - text("============================== ", DARK_GRAY) - .append(text("Scoreboard Help", GOLD)) - .append(text(" ============================== ", DARK_GRAY)) - ); - - subCommandHolder.getSubCommands() - .stream() - .map(net.okocraft.scoreboard.command.Command::getHelp) - .forEach(sender::sendMessage); + private void sendHelp(@NotNull CommandSender sender, @NotNull MiniMessageSource msgSrc) { + Messages.COMMAND_HELP_HEADER.source(msgSrc).send(sender); + sender.sendMessage(Component.join( + JoinConfiguration.newlines(), + ((Iterable) subCommandHolder.getSubCommands().stream().map(cmd -> cmd.getHelp(msgSrc))::iterator) + )); } } diff --git a/src/main/java/net/okocraft/scoreboard/command/subcommand/HideCommand.java b/src/main/java/net/okocraft/scoreboard/command/subcommand/HideCommand.java index d4d27f8..b0fd7a1 100644 --- a/src/main/java/net/okocraft/scoreboard/command/subcommand/HideCommand.java +++ b/src/main/java/net/okocraft/scoreboard/command/subcommand/HideCommand.java @@ -1,9 +1,10 @@ package net.okocraft.scoreboard.command.subcommand; +import com.github.siroshun09.messages.minimessage.source.MiniMessageSource; import net.kyori.adventure.text.Component; import net.okocraft.scoreboard.command.AbstractCommand; import net.okocraft.scoreboard.display.manager.DisplayManager; -import net.okocraft.scoreboard.message.CommandMessage; +import net.okocraft.scoreboard.message.Messages; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -18,6 +19,7 @@ public class HideCommand extends AbstractCommand { private static final String HIDE_PERMISSION = "scoreboard.command.hide"; private static final String HIDE_PERMISSION_OTHER = HIDE_PERMISSION + ".other"; + private final DisplayManager displayManager; public HideCommand(@NotNull DisplayManager displayManager) { @@ -26,31 +28,31 @@ public HideCommand(@NotNull DisplayManager displayManager) { } @Override - public @NotNull Component getHelp() { - return CommandMessage.HIDE_HELP; + public @NotNull Component getHelp(@NotNull MiniMessageSource msgSrc) { + return Messages.HIDE_HELP.create(msgSrc); } @Override - public void onCommand(@NotNull CommandSender sender, @NotNull String[] args) { + public void onCommand(@NotNull CommandSender sender, @NotNull String[] args, @NotNull MiniMessageSource msgSrc) { Player target; if (1 < args.length) { if (!sender.hasPermission(HIDE_PERMISSION_OTHER)) { - sender.sendMessage(CommandMessage.NO_PERMISSION.apply(HIDE_PERMISSION_OTHER)); + Messages.NO_PERMISSION.apply(HIDE_PERMISSION_OTHER).source(msgSrc).send(sender); return; } target = Bukkit.getPlayer(args[1]); if (target == null) { - sender.sendMessage(CommandMessage.PLAYER_NOT_FOUND.apply(args[1])); + Messages.PLAYER_NOT_FOUND.apply(args[1]).source(msgSrc).send(sender); return; } } else { if (sender instanceof Player player) { target = player; } else { - sender.sendMessage(CommandMessage.ONLY_PLAYER); + Messages.ONLY_PLAYER.source(msgSrc).send(sender); return; } } @@ -58,14 +60,14 @@ public void onCommand(@NotNull CommandSender sender, @NotNull String[] args) { if (displayManager.isDisplayed(target)) { displayManager.hideBoard(target); } else { - sender.sendMessage(CommandMessage.HIDE_ALREADY); + Messages.HIDE_ALREADY.source(msgSrc).send(sender); return; } if (sender.equals(target)) { - sender.sendMessage(CommandMessage.HIDE_SELF); + Messages.HIDE_SELF.source(msgSrc).send(sender); } else { - sender.sendMessage(CommandMessage.HIDE_OTHER.apply(target)); + Messages.HIDE_OTHER.apply(target).source(msgSrc).send(sender); } } diff --git a/src/main/java/net/okocraft/scoreboard/command/subcommand/ReloadCommand.java b/src/main/java/net/okocraft/scoreboard/command/subcommand/ReloadCommand.java index e30082d..5d7a38e 100644 --- a/src/main/java/net/okocraft/scoreboard/command/subcommand/ReloadCommand.java +++ b/src/main/java/net/okocraft/scoreboard/command/subcommand/ReloadCommand.java @@ -1,14 +1,13 @@ package net.okocraft.scoreboard.command.subcommand; +import com.github.siroshun09.messages.minimessage.source.MiniMessageSource; import net.kyori.adventure.text.Component; import net.okocraft.scoreboard.ScoreboardPlugin; import net.okocraft.scoreboard.command.AbstractCommand; -import net.okocraft.scoreboard.message.CommandMessage; +import net.okocraft.scoreboard.message.Messages; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; -import java.util.logging.Level; - public class ReloadCommand extends AbstractCommand { private final ScoreboardPlugin plugin; @@ -19,22 +18,14 @@ public ReloadCommand(@NotNull ScoreboardPlugin plugin) { } @Override - public @NotNull Component getHelp() { - return CommandMessage.RELOAD_HELP; + public @NotNull Component getHelp(@NotNull MiniMessageSource msgSrc) { + return Messages.RELOAD_HELP.create(msgSrc); } @Override - public void onCommand(@NotNull CommandSender sender, @NotNull String[] args) { - try { - plugin.reload(); - sender.sendMessage(CommandMessage.RELOAD_FINISH); - } catch (Throwable t) { - sender.sendMessage(CommandMessage.RELOAD_ERROR.apply(t)); - plugin.getLogger().log( - Level.SEVERE, - "Could not complete reloading.", - t - ); + public void onCommand(@NotNull CommandSender sender, @NotNull String[] args, @NotNull MiniMessageSource msgSrc) { + if (plugin.reload(ex -> Messages.RELOAD_ERROR.apply(ex).source(msgSrc).send(sender))) { + Messages.RELOAD_FINISH.source(msgSrc).send(sender); } } } diff --git a/src/main/java/net/okocraft/scoreboard/command/subcommand/ShowCommand.java b/src/main/java/net/okocraft/scoreboard/command/subcommand/ShowCommand.java index 0b1e61b..4731fc4 100644 --- a/src/main/java/net/okocraft/scoreboard/command/subcommand/ShowCommand.java +++ b/src/main/java/net/okocraft/scoreboard/command/subcommand/ShowCommand.java @@ -1,11 +1,12 @@ package net.okocraft.scoreboard.command.subcommand; +import com.github.siroshun09.messages.minimessage.source.MiniMessageSource; import net.kyori.adventure.text.Component; import net.okocraft.scoreboard.board.Board; import net.okocraft.scoreboard.command.AbstractCommand; import net.okocraft.scoreboard.config.BoardManager; import net.okocraft.scoreboard.display.manager.DisplayManager; -import net.okocraft.scoreboard.message.CommandMessage; +import net.okocraft.scoreboard.message.Messages; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -32,24 +33,24 @@ public ShowCommand(@NotNull BoardManager boardManager, @NotNull DisplayManager d } @Override - public @NotNull Component getHelp() { - return CommandMessage.SHOW_HELP; + public @NotNull Component getHelp(@NotNull MiniMessageSource msgSrc) { + return Messages.SHOW_HELP.create(msgSrc); } @Override - public void onCommand(@NotNull CommandSender sender, @NotNull String[] args) { + public void onCommand(@NotNull CommandSender sender, @NotNull String[] args, @NotNull MiniMessageSource msgSrc) { Board board; if (1 < args.length) { board = searchForBoard(args[1]); if (board == null) { - sender.sendMessage(CommandMessage.BOARD_NOT_FOUND.apply(args[1])); + Messages.BOARD_NOT_FOUND.apply(args[1]).source(msgSrc).send(sender); return; } - if (!args[1].equalsIgnoreCase("default") && !sender.hasPermission(board.getPermissionNode())) { - sender.sendMessage(CommandMessage.NO_PERMISSION.apply(board.getPermissionNode())); + if (!args[0].equalsIgnoreCase("default") && !sender.hasPermission(board.getPermissionNode())) { + Messages.NO_PERMISSION.apply(board.getPermissionNode()).source(msgSrc).send(sender); return; } } else { @@ -60,21 +61,21 @@ public void onCommand(@NotNull CommandSender sender, @NotNull String[] args) { if (2 < args.length) { if (!sender.hasPermission(SHOW_PERMISSION_OTHER)) { - sender.sendMessage(CommandMessage.NO_PERMISSION.apply(SHOW_PERMISSION_OTHER)); + Messages.NO_PERMISSION.apply(SHOW_PERMISSION_OTHER).source(msgSrc).send(sender); return; } target = Bukkit.getPlayer(args[2]); if (target == null) { - sender.sendMessage(CommandMessage.PLAYER_NOT_FOUND.apply(args[2])); + Messages.PLAYER_NOT_FOUND.apply(args[2]).source(msgSrc).send(sender); return; } } else { if (sender instanceof Player player) { target = player; } else { - sender.sendMessage(CommandMessage.ONLY_PLAYER); + Messages.ONLY_PLAYER.source(msgSrc).send(sender); return; } } @@ -82,9 +83,9 @@ public void onCommand(@NotNull CommandSender sender, @NotNull String[] args) { displayManager.showBoard(target, board); if (sender.equals(target)) { - sender.sendMessage(CommandMessage.SHOW_BOARD_SELF.apply(board)); + Messages.SHOW_SELF.apply(board).source(msgSrc).send(sender); } else { - sender.sendMessage(CommandMessage.SHOW_BOARD_OTHER.apply(board, target)); + Messages.SHOW_OTHER.apply(board, target).source(msgSrc).send(sender); } } diff --git a/src/main/java/net/okocraft/scoreboard/config/BoardLoader.java b/src/main/java/net/okocraft/scoreboard/config/BoardLoader.java index 025e74c..b4ac90e 100644 --- a/src/main/java/net/okocraft/scoreboard/config/BoardLoader.java +++ b/src/main/java/net/okocraft/scoreboard/config/BoardLoader.java @@ -1,7 +1,7 @@ package net.okocraft.scoreboard.config; -import com.github.siroshun09.configapi.api.Configuration; -import com.github.siroshun09.configapi.yaml.YamlConfiguration; +import com.github.siroshun09.configapi.core.node.MapNode; +import com.github.siroshun09.configapi.format.yaml.YamlFormat; import net.okocraft.scoreboard.ScoreboardPlugin; import net.okocraft.scoreboard.board.Board; import net.okocraft.scoreboard.board.Line; @@ -11,7 +11,6 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -22,26 +21,19 @@ final class BoardLoader { private static final String PATH_TITLE = "title"; - private static final String PATH_LINES = "lines"; private static final String LEGACY_PATH_LINE = "line"; - private static final String PATH_LIST_SUFFIX = ".list"; - private static final String PATH_INTERVAL_SUFFIX = ".interval"; - private static final String PATH_LENGTH_LIMIT_SUFFIX = ".length-limit"; + private static final String PATH_LINES = "lines"; + private static final String PATH_LIST = "list"; + private static final String PATH_INTERVAL = "interval"; + private static final String PATH_LENGTH_LIMIT = "length-limit"; private BoardLoader() { throw new UnsupportedOperationException(); } - static @NotNull Board loadDefaultBoard(@NotNull ScoreboardPlugin plugin) { - var yaml = YamlConfiguration.create(plugin.getDataFolder().toPath().resolve("default.yml")); - - try { - yaml.load(); - } catch (IOException e) { - plugin.getLogger().log(Level.SEVERE, "Could not load default.yml", e); - } - - return createBoardFromYaml(yaml); + static @NotNull Board loadDefaultBoard(@NotNull ScoreboardPlugin plugin) throws IOException { + var filepath = plugin.saveResource("default.yml"); + return createBoardFromNode(getBoardName(filepath), YamlFormat.DEFAULT.load(filepath)); } static @NotNull @Unmodifiable List loadCustomBoards(@NotNull ScoreboardPlugin plugin) { @@ -62,18 +54,15 @@ private BoardLoader() { .filter(Files::isRegularFile) .filter(Files::isReadable) .filter(p -> checkFilename(p.getFileName().toString())) - .map(YamlConfiguration::create) - .map(yaml -> { + .map(filepath -> { try { - yaml.load(); - return yaml; + return createBoardFromNode(getBoardName(filepath), YamlFormat.DEFAULT.load(filepath)); } catch (IOException e) { - plugin.getLogger().log(Level.SEVERE, "Could not load " + yaml.getPath().getFileName(), e); + plugin.getLogger().log(Level.SEVERE, "Could not load " + filepath.getFileName(), e); return null; } }) .filter(Objects::nonNull) - .map(BoardLoader::createBoardFromYaml) .collect(Collectors.toList()); } catch (IOException e) { plugin.getLogger().log(Level.SEVERE, "Could not load board files", e); @@ -81,31 +70,22 @@ private BoardLoader() { } } - private static @NotNull Board createBoardFromYaml(@NotNull YamlConfiguration yaml) { - Line title = createLine(yaml, PATH_TITLE); - - var section = yaml.getSection(LEGACY_PATH_LINE); - - if (section == null) { - section = yaml.getSection(PATH_LINES); - } + static @NotNull Board createBoardFromNode(@NotNull String name, @NotNull MapNode node) { + Line title = createLine(node.getMap(PATH_TITLE)); List lines; - if (section == null) { - lines = Collections.emptyList(); + if (node.getOrDefault(LEGACY_PATH_LINE, node.get(PATH_LINES)) instanceof MapNode linesSection) { + lines = linesSection.value().values().stream() + .filter(MapNode.class::isInstance) + .map(MapNode.class::cast) + .map(BoardLoader::createLine) + .toList(); } else { - var rootKeys = section.getKeyList(); - lines = new ArrayList<>(rootKeys.size()); - - for (String root : rootKeys) { - lines.add(createLine(section, root)); - } + lines = Collections.emptyList(); } - var name = yaml.getPath().getFileName().toString(); - - return new Board(name.substring(0, name.lastIndexOf('.')), title, lines); + return new Board(name, title, lines); } private static boolean checkFilename(String filename) { @@ -118,16 +98,17 @@ private static boolean isYaml(String filename) { return (checking.endsWith(".yml") && 4 < checking.length()) || (checking.endsWith(".yaml") && 5 < checking.length()); } - private static @NotNull Line createLine(@NotNull Configuration source, @NotNull String root) { - List lineList = source.getStringList(root + PATH_LIST_SUFFIX); + private static String getBoardName(Path filepath) { + var name = filepath.getFileName().toString(); + return name.substring(0, name.lastIndexOf('.')); + } + + private static @NotNull Line createLine(@NotNull MapNode source) { + List lineList = source.getList(PATH_LIST).asList(String.class); if (lineList.isEmpty()) { return Line.EMPTY; } else { - return new Line( - lineList, - source.getLong(root + PATH_INTERVAL_SUFFIX), - source.getInteger(root + PATH_LENGTH_LIMIT_SUFFIX, -1) - ); + return new Line(lineList, source.getLong(PATH_INTERVAL), source.getInteger(PATH_LENGTH_LIMIT, -1)); } } } diff --git a/src/main/java/net/okocraft/scoreboard/config/BoardManager.java b/src/main/java/net/okocraft/scoreboard/config/BoardManager.java index 1440e2b..c7e2316 100644 --- a/src/main/java/net/okocraft/scoreboard/config/BoardManager.java +++ b/src/main/java/net/okocraft/scoreboard/config/BoardManager.java @@ -1,17 +1,20 @@ package net.okocraft.scoreboard.config; +import com.github.siroshun09.configapi.core.node.MapNode; import net.okocraft.scoreboard.ScoreboardPlugin; import net.okocraft.scoreboard.board.Board; import org.jetbrains.annotations.NotNull; +import java.io.IOException; +import java.util.Collections; import java.util.List; public class BoardManager { private final ScoreboardPlugin plugin; - private Board defaultBoard; - private List customBoards; + private Board defaultBoard = BoardLoader.createBoardFromNode("default", MapNode.empty()); + private List customBoards = Collections.emptyList(); public BoardManager(@NotNull ScoreboardPlugin plugin) { this.plugin = plugin; @@ -27,7 +30,7 @@ public List getCustomBoards() { return customBoards; } - public void reload() { + public void reload() throws IOException { defaultBoard = BoardLoader.loadDefaultBoard(plugin); customBoards = BoardLoader.loadCustomBoards(plugin); } diff --git a/src/main/java/net/okocraft/scoreboard/message/CommandMessage.java b/src/main/java/net/okocraft/scoreboard/message/CommandMessage.java deleted file mode 100644 index 9efc706..0000000 --- a/src/main/java/net/okocraft/scoreboard/message/CommandMessage.java +++ /dev/null @@ -1,77 +0,0 @@ -package net.okocraft.scoreboard.message; - -import com.github.siroshun09.translationloader.argument.DoubleArgument; -import com.github.siroshun09.translationloader.argument.SingleArgument; -import net.kyori.adventure.text.Component; -import net.okocraft.scoreboard.board.Board; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -import static net.kyori.adventure.text.Component.text; -import static net.kyori.adventure.text.Component.translatable; -import static net.kyori.adventure.text.format.NamedTextColor.AQUA; -import static net.kyori.adventure.text.format.NamedTextColor.DARK_GRAY; -import static net.kyori.adventure.text.format.NamedTextColor.GRAY; -import static net.kyori.adventure.text.format.NamedTextColor.RED; -import static net.kyori.adventure.text.format.NamedTextColor.WHITE; - -public final class CommandMessage { - - public static final SingleArgument NO_PERMISSION = - permission -> - translatable() - .key("scoreboard.error.no-permission") - .arguments(text(permission, AQUA)) - .color(RED) - .build(); - - public static final SingleArgument BOARD_NOT_FOUND = - name -> translatable("scoreboard.error.board-not-found", RED).arguments(text(name, AQUA)); - - public static final SingleArgument PLAYER_NOT_FOUND = - name -> translatable("scoreboard.error.player-not-found", RED).arguments(text(name, AQUA)); - - public static final Component ONLY_PLAYER = - translatable("scoreboard.error.only-player", RED); - - public static final Component SHOW_HELP = createCommandHelp("/sb show {player}", "scoreboard.show.help"); - - public static final SingleArgument SHOW_BOARD_SELF = - board -> translatable("scoreboard.show.self", GRAY).arguments(text(board.getName(), AQUA)); - - public static final DoubleArgument SHOW_BOARD_OTHER = - (board, target) -> - translatable("scoreboard.show.other", GRAY) - .arguments( - text(board.getName(), AQUA), - text(target.getName(), AQUA) - ); - - public static final Component HIDE_HELP = createCommandHelp("/sb hide {player}", "scoreboard.hide.help"); - - public static final Component HIDE_ALREADY = translatable("scoreboard.hide.already", RED); - - public static final Component HIDE_SELF = translatable("scoreboard.hide.self", GRAY); - - public static final SingleArgument HIDE_OTHER = - target -> translatable("scoreboard.hide.other", GRAY).arguments(text(target.getName(), AQUA)); - - public static final Component RELOAD_HELP = createCommandHelp("/sb reload", "scoreboard.reload.help"); - - public static final SingleArgument RELOAD_ERROR = - throwable -> translatable("scoreboard.reload.error", RED).arguments(text(throwable.getMessage(), WHITE)); - - public static final Component RELOAD_FINISH = translatable("scoreboard.reload.finish", GRAY); - - private static @NotNull Component createCommandHelp(@NotNull String commandLine, @NotNull String helpKey) { - return text() - .append(text(commandLine, AQUA)) - .append(text(" - ", DARK_GRAY)) - .append(translatable(helpKey, GRAY)) - .build(); - } - - private CommandMessage() { - throw new UnsupportedOperationException(); - } -} diff --git a/src/main/java/net/okocraft/scoreboard/message/Messages.java b/src/main/java/net/okocraft/scoreboard/message/Messages.java new file mode 100644 index 0000000..5b9396c --- /dev/null +++ b/src/main/java/net/okocraft/scoreboard/message/Messages.java @@ -0,0 +1,85 @@ +package net.okocraft.scoreboard.message; + +import com.github.siroshun09.messages.minimessage.arg.Arg1; +import com.github.siroshun09.messages.minimessage.arg.Arg2; +import com.github.siroshun09.messages.minimessage.base.MiniMessageBase; +import com.github.siroshun09.messages.minimessage.base.Placeholder; +import net.kyori.adventure.text.Component; +import net.okocraft.scoreboard.board.Board; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.UnmodifiableView; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; + +import static com.github.siroshun09.messages.minimessage.arg.Arg1.arg1; +import static com.github.siroshun09.messages.minimessage.arg.Arg2.arg2; +import static com.github.siroshun09.messages.minimessage.base.MiniMessageBase.messageKey; +import static com.github.siroshun09.messages.minimessage.base.MiniMessageBase.withTagResolverBase; +import static com.github.siroshun09.messages.minimessage.base.Placeholder.messageBase; + +public final class Messages { + + private static final Map DEFAULT_MESSAGES = new LinkedHashMap<>(); + private static final Placeholder PERMISSION = Placeholder.component("permission", Component::text); + private static final Placeholder NAME = Placeholder.component("name", Component::text); + private static final Placeholder COMMANDLINE_PLACEHOLDER = messageBase("commandline", MiniMessageBase::messageKey); + private static final Placeholder HELP_PLACEHOLDER = messageBase("help", MiniMessageBase::messageKey); + private static final Placeholder BOARD = Placeholder.component("board", board -> Component.text(board.getName())); + private static final Placeholder PLAYER = Placeholder.component("board", player -> Component.text().content(player.getName()).hoverEvent(player).build()); + private static final Placeholder ERROR = Placeholder.component("error", ex -> Component.text(ex.getMessage())); + + public static final Arg1 NO_PERMISSION = arg1(def("scoreboard.error.no-permission", "You don't have the permission: "), PERMISSION); + public static final Arg1 BOARD_NOT_FOUND = arg1(def("scoreboard.error.board-not-found", "Board was not found."), NAME); + public static final Arg1 PLAYER_NOT_FOUND = arg1(def("scoreboard.error.player-not-found", "Player was not found."), NAME); + public static final MiniMessageBase ONLY_PLAYER = messageKey(def("scoreboard.error.only-player", "This command can only be executed by the player.")); + + public static final MiniMessageBase COMMAND_HELP_HEADER = withTagResolverBase(def("scoreboard.help.header", "========================= Scoreboard =========================")); + private static final String COMMAND_HELP_LINE_KEY = def("scoreboard.help.line", ": "); + + public static final MiniMessageBase SHOW_HELP = help(def("scoreboard.show.commandline", "/sb show {player}"), def("scoreboard.show.help", "Shows the board")); + public static final Arg1 SHOW_SELF = arg1(def("scoreboard.show.self", "Board is now displayed."), BOARD); + public static final Arg2 SHOW_OTHER = arg2(def("scoreboard.show.other", "Board is now displayed for player ."), BOARD, PLAYER); + + public static final MiniMessageBase HIDE_HELP = help(def("scoreboard.hide.commandline", "/sb hide {player}"), def("scoreboard.hide.help", "Hides the board")); + public static final MiniMessageBase HIDE_ALREADY = messageKey(def("scoreboard.hide.already", "The board is already hidden.")); + public static final MiniMessageBase HIDE_SELF = messageKey(def("scoreboard.hide.self", "The board is now hidden.")); + public static final Arg1 HIDE_OTHER = arg1(def("scoreboard.hide.other", "Player 's board is now hidden."), PLAYER); + + public static final MiniMessageBase RELOAD_HELP = help(def("scoreboard.reload.commandline", "/sb reload"), def("scoreboard.reload.help", "Reloads configurations.")); + public static final Arg1 RELOAD_ERROR = arg1(def("scoreboard.reload.error", "An error occurred while reloading configurations: "), ERROR); + public static final MiniMessageBase RELOAD_FINISH = messageKey(def("scoreboard.reload.finish", "Configurations have been reloaded!")); + + private static @NotNull String def(@NotNull String key, @NotNull String msg) { + DEFAULT_MESSAGES.put(key, msg); + return key; + } + + private static @NotNull MiniMessageBase help(String commandlineKey, String helpKey) { + return MiniMessageBase.withTagResolverBase(COMMAND_HELP_LINE_KEY, COMMANDLINE_PLACEHOLDER.apply(commandlineKey), HELP_PLACEHOLDER.apply(helpKey)); + } + + @Contract(pure = true) + public static @NotNull @UnmodifiableView Map defaultMessages() { + return Collections.unmodifiableMap(DEFAULT_MESSAGES); + } + + public static @Nullable Locale getLocaleFrom(@Nullable Object obj) { + if (obj instanceof Locale locale) { + return locale; + } else if (obj instanceof Player player) { + return player.locale(); + } else { + return Locale.getDefault(); + } + } + + private Messages() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/resources/en.yml b/src/main/resources/en.yml deleted file mode 100644 index a0ee30d..0000000 --- a/src/main/resources/en.yml +++ /dev/null @@ -1,19 +0,0 @@ -scoreboard: - error: - no-permission: "You don''t have the permission: {0}" - board-not-found: "Board {0} was not found." - player-not-found: "Player {0} was not found." - only-player: "This command can only be executed by the player." - show: - help: "Shows the board" - self: "Board {0} is now displayed." - other: "Board {0} is now displayed for player {1}." - hide: - help: "Hides the board" - already: "The board is already hidden." - self: "The board is now hidden." - other: "Player {0}''s board is now hidden." - reload: - help: "Reloads configurations." - error: "An error occurred while reloading configurations: {0}" - finish: "Configurations have been reloaded!" diff --git a/src/main/resources/ja.properties b/src/main/resources/ja.properties new file mode 100644 index 0000000..939ebf0 --- /dev/null +++ b/src/main/resources/ja.properties @@ -0,0 +1,19 @@ +scoreboard.error.no-permission=権限がありません\: +scoreboard.error.board-not-found=ボード は見つかりませんでした。 +scoreboard.error.player-not-found=プレイヤー は見つかりませんでした。 +scoreboard.error.only-player=このコマンドはプレイヤーのみ実行できます。 +scoreboard.help.header=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\= Scoreboard \=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\=\= +scoreboard.help.line=\: +scoreboard.show.commandline=/sb show <ボード名> {プレイヤー名} +scoreboard.show.help=ボードを表示する。 +scoreboard.show.self=ボード を表示しました。 +scoreboard.show.other= にボード を表示しました。 +scoreboard.hide.commandline=/sb hide {プレイヤー名} +scoreboard.hide.help=ボードを非表示にする。 +scoreboard.hide.already=すでにボードが非表示です。 +scoreboard.hide.self=ボードを非表示にしました。 +scoreboard.hide.other=プレイヤー のボードを非表示にしました。 +scoreboard.reload.commandline=/sb reload +scoreboard.reload.help=設定ファイルを再読み込みする +scoreboard.reload.error=設定ファイルの読み込み中にエラーが発生しました\: +scoreboard.reload.finish=設定ファイルを再読み込みしました\! diff --git a/src/main/resources/ja_JP.yml b/src/main/resources/ja_JP.yml deleted file mode 100644 index c32e563..0000000 --- a/src/main/resources/ja_JP.yml +++ /dev/null @@ -1,19 +0,0 @@ -scoreboard: - error: - no-permission: "権限がありません: {0}" - board-not-found: "ボード {0} は見つかりませんでした。" - player-not-found: "プレイヤー {0} は見つかりませんでした。" - only-player: "プレイヤーのみ実行可能です。" - show: - help: "ボードを表示します。" - self: "ボード {0} を表示しました。" - other: "プレイヤー {1} にボード {0} を表示しました。" - hide: - help: "ボードを非表示にします。" - already: "すでにボードが非表示です。" - self: "ボードを非表示にしました。" - other: "プレイヤー {0} のボードを非表示にしました。" - reload: - help: "設定ファイルを再読み込みします。" - error: "設定ファイルの読み込み中にエラーが発生しました: {0}" - finish: "設定ファイルを再読み込みしました。"