From c573617a019103f135f84b6cf5d6cbee18c0acb0 Mon Sep 17 00:00:00 2001 From: Izzel_Aliz Date: Sun, 22 Apr 2018 13:30:50 +0800 Subject: [PATCH] =?UTF-8?q?=E8=88=B9=E6=96=B0=20I18n=20=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=20=E4=BF=AE=E4=BA=86=E4=B8=80=E4=B8=AA=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=B0=8Fbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/dictionaries/csh20.xml | 3 + ..._com_ilummc_eagletdl_EagletCore_1_1_2.xml} | 8 +- ...l => Maven__com_zaxxer_HikariCP_3_1_0.xml} | 8 +- pom.xml | 12 +-- src/main/java/com/ilummc/tlib/TLib.java | 25 ++++- .../com/ilummc/tlib/annotations/Config.java | 2 + .../tlib/compat/PlaceholderApiHook.java | 40 ++++++++ .../ilummc/tlib/dependency/TDependency.java | 12 +-- .../tlib/inject/DependencyInjector.java | 6 +- .../ilummc/tlib/inject/TConfigInjector.java | 45 +++++++-- .../ilummc/tlib/resources/LocaleInstance.java | 65 +++++++++++++ .../ilummc/tlib/resources/LocaleLoader.java | 76 +++++++++++++++ .../com/ilummc/tlib/resources/Sendable.java | 21 ++++ .../tlib/resources/SimpleChatMessage.java | 95 +++++++++++++++++++ .../com/ilummc/tlib/resources/TLocale.java | 54 +++++++++++ src/main/java/com/ilummc/tlib/util/Ref.java | 44 ++++++++- .../java/com/ilummc/tlib/util/Strings.java | 1 + src/main/resources/lang/zh_CN.yml | 0 18 files changed, 479 insertions(+), 38 deletions(-) rename .idea/libraries/{Maven__com_ilummc_eagletdl_EagletCore_1_1.xml => Maven__com_ilummc_eagletdl_EagletCore_1_1_2.xml} (62%) rename .idea/libraries/{Maven__com_zaxxer_HikariCP_3_0_0.xml => Maven__com_zaxxer_HikariCP_3_1_0.xml} (68%) create mode 100644 src/main/java/com/ilummc/tlib/compat/PlaceholderApiHook.java create mode 100644 src/main/java/com/ilummc/tlib/resources/LocaleInstance.java create mode 100644 src/main/java/com/ilummc/tlib/resources/LocaleLoader.java create mode 100644 src/main/java/com/ilummc/tlib/resources/Sendable.java create mode 100644 src/main/java/com/ilummc/tlib/resources/SimpleChatMessage.java create mode 100644 src/main/java/com/ilummc/tlib/resources/TLocale.java create mode 100644 src/main/resources/lang/zh_CN.yml diff --git a/.idea/dictionaries/csh20.xml b/.idea/dictionaries/csh20.xml index 7fec0b9..e6ef750 100644 --- a/.idea/dictionaries/csh20.xml +++ b/.idea/dictionaries/csh20.xml @@ -1,6 +1,9 @@ + mvdw + papi + sendable unserialize unserializer diff --git a/.idea/libraries/Maven__com_ilummc_eagletdl_EagletCore_1_1.xml b/.idea/libraries/Maven__com_ilummc_eagletdl_EagletCore_1_1_2.xml similarity index 62% rename from .idea/libraries/Maven__com_ilummc_eagletdl_EagletCore_1_1.xml rename to .idea/libraries/Maven__com_ilummc_eagletdl_EagletCore_1_1_2.xml index ab97cb6..bc3a043 100644 --- a/.idea/libraries/Maven__com_ilummc_eagletdl_EagletCore_1_1.xml +++ b/.idea/libraries/Maven__com_ilummc_eagletdl_EagletCore_1_1_2.xml @@ -1,13 +1,13 @@ - + - + - + - + \ No newline at end of file diff --git a/.idea/libraries/Maven__com_zaxxer_HikariCP_3_0_0.xml b/.idea/libraries/Maven__com_zaxxer_HikariCP_3_1_0.xml similarity index 68% rename from .idea/libraries/Maven__com_zaxxer_HikariCP_3_0_0.xml rename to .idea/libraries/Maven__com_zaxxer_HikariCP_3_1_0.xml index f69ad99..3f79c94 100644 --- a/.idea/libraries/Maven__com_zaxxer_HikariCP_3_0_0.xml +++ b/.idea/libraries/Maven__com_zaxxer_HikariCP_3_1_0.xml @@ -1,13 +1,13 @@ - + - + - + - + \ No newline at end of file diff --git a/pom.xml b/pom.xml index a92e266..0f99a1e 100644 --- a/pom.xml +++ b/pom.xml @@ -58,15 +58,15 @@ - - com.ilummc.eagletdl - EagletCore - 1.1 - com.zaxxer HikariCP - 3.0.0 + 3.1.0 + + + com.ilummc.eagletdl + EagletCore + 1.1.2 org.ow2.asm diff --git a/src/main/java/com/ilummc/tlib/TLib.java b/src/main/java/com/ilummc/tlib/TLib.java index 62261f6..a235b22 100644 --- a/src/main/java/com/ilummc/tlib/TLib.java +++ b/src/main/java/com/ilummc/tlib/TLib.java @@ -3,9 +3,12 @@ package com.ilummc.tlib; import com.ilummc.tlib.annotations.Config; import com.ilummc.tlib.annotations.Dependency; import com.ilummc.tlib.annotations.Logger; +import com.ilummc.tlib.compat.PlaceholderApiHook; import com.ilummc.tlib.inject.DependencyInjector; import com.ilummc.tlib.inject.TConfigWatcher; import com.ilummc.tlib.inject.TLibPluginManager; +import com.ilummc.tlib.resources.LocaleLoader; +import com.ilummc.tlib.resources.TLocale; import com.ilummc.tlib.util.TLogger; import me.skymc.taboolib.Main; import org.bukkit.Bukkit; @@ -21,7 +24,7 @@ public class TLib { private static TLib tLib; @Logger("§8[§3§lTabooLib§8][§r{1}§8] §f{2}") - private TLogger tLogger; + private TLogger tLogger = new TLogger("§8[§3§lTabooLib§8][§r{1}§8] §f{2}", Main.getInst(), TLogger.FINE); private TLibConfig config; @@ -60,11 +63,17 @@ public class TLib { public static void init() { new File(Main.getInst().getDataFolder(), "/libs").mkdirs(); tLib = new TLib(); + LocaleLoader.init(); + PlaceholderApiHook.init(); DependencyInjector.inject(Main.getInst(), tLib); if (Bukkit.getPluginManager() instanceof TLibPluginManager) tLib.getLogger().info("注入成功"); else tLib.getLogger().fatal("注入失败"); + TLocale.sendToConsole("test1"); + TLocale.sendToConsole("test2"); + TLocale.sendToConsole("test3"); + TLocale.sendToConsole("test4.node1", "Hello", "world"); } public static void unload() { @@ -72,7 +81,7 @@ public class TLib { DependencyInjector.eject(Main.getInst(), tLib); } - @Config(name = "tlib.yml", listenChanges = true) + @Config(name = "tlib.yml", listenChanges = true, readOnly = false) public static class TLibConfig { private int downloadPoolSize = 4; @@ -80,5 +89,17 @@ public class TLib { public int getDownloadPoolSize() { return downloadPoolSize; } + + private String[] locale = {"zh_CN", "en_US"}; + + public String[] getLocale() { + return locale; + } + + private boolean enablePapiByDefault = false; + + public boolean isEnablePapiByDefault() { + return enablePapiByDefault; + } } } diff --git a/src/main/java/com/ilummc/tlib/annotations/Config.java b/src/main/java/com/ilummc/tlib/annotations/Config.java index b4ebd42..62af121 100644 --- a/src/main/java/com/ilummc/tlib/annotations/Config.java +++ b/src/main/java/com/ilummc/tlib/annotations/Config.java @@ -18,6 +18,8 @@ public @interface Config { boolean saveOnExit() default false; + boolean readOnly() default true; + String charset() default "UTF-8"; boolean listenChanges() default false; diff --git a/src/main/java/com/ilummc/tlib/compat/PlaceholderApiHook.java b/src/main/java/com/ilummc/tlib/compat/PlaceholderApiHook.java new file mode 100644 index 0000000..728ee4c --- /dev/null +++ b/src/main/java/com/ilummc/tlib/compat/PlaceholderApiHook.java @@ -0,0 +1,40 @@ +package com.ilummc.tlib.compat; + +import me.clip.placeholderapi.PlaceholderAPI; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public abstract class PlaceholderApiHook { + + private static PlaceholderApiHook impl; + + public static void init() { + if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) + impl = new PlaceholderImpl(); + else impl = new AbstractImpl(); + } + + public static String replace(CommandSender sender, String text) { + return sender instanceof Player ? impl.replace(((Player) sender), text) : text; + } + + abstract String replace(Player player, String text); + + private static class PlaceholderImpl extends PlaceholderApiHook { + + @Override + String replace(Player player, String text) { + return PlaceholderAPI.setPlaceholders(player, text); + } + } + + private static class AbstractImpl extends PlaceholderApiHook { + + @Override + String replace(Player player, String text) { + return text; + } + } + +} diff --git a/src/main/java/com/ilummc/tlib/dependency/TDependency.java b/src/main/java/com/ilummc/tlib/dependency/TDependency.java index 8ce20c5..ab8b631 100644 --- a/src/main/java/com/ilummc/tlib/dependency/TDependency.java +++ b/src/main/java/com/ilummc/tlib/dependency/TDependency.java @@ -7,7 +7,6 @@ import me.skymc.taboolib.Main; import java.io.File; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantLock; public class TDependency { @@ -56,14 +55,12 @@ public class TDependency { TLib.getTLib().getLogger().warn("已启用离线模式, 将不会下载第三方依赖库"); return false; } - ReentrantLock lock = new ReentrantLock(); AtomicBoolean failed = new AtomicBoolean(false); String link = dl.length() == 0 ? url + "/" + groupId.replace('.', '/') + "/" + artifactId + "/" + version + "/" + artifactId + "-" + version + ".jar" : dl; - EagletTask task = new EagletTask() + new EagletTask() .url(link) .file(target) .setThreads(TLib.getTLib().getConfig().getDownloadPoolSize()) - .setOnStart(event -> lock.lock()) .setOnError(event -> { }) .setOnConnected(event -> TLib.getTLib().getLogger().info(" 正在下载 " + String.join(":", @@ -79,12 +76,7 @@ public class TDependency { TLib.getTLib().getLogger().error(" 下载 " + String.join(":", new String[]{groupId, artifactId, version}) + " 失败"); TLib.getTLib().getLogger().error(" 请手动下载 " + link + " 并重命名为 " + target.getName() + " 后放在 /TabooLib/libs 文件夹内"); } - lock.unlock(); - }); - task.start(); - while (lock.tryLock()) lock.unlock(); - lock.lock(); - lock.unlock(); + }).start().waitUntil(); return !failed.get(); } diff --git a/src/main/java/com/ilummc/tlib/inject/DependencyInjector.java b/src/main/java/com/ilummc/tlib/inject/DependencyInjector.java index 04b4030..b528cf3 100644 --- a/src/main/java/com/ilummc/tlib/inject/DependencyInjector.java +++ b/src/main/java/com/ilummc/tlib/inject/DependencyInjector.java @@ -3,6 +3,7 @@ package com.ilummc.tlib.inject; import com.ilummc.tlib.TLib; import com.ilummc.tlib.annotations.*; import com.ilummc.tlib.dependency.TDependency; +import com.ilummc.tlib.resources.LocaleLoader; import com.ilummc.tlib.util.Ref; import com.ilummc.tlib.util.TLogger; import org.bukkit.Bukkit; @@ -15,10 +16,11 @@ import java.lang.reflect.Field; public class DependencyInjector { public static void inject(Plugin plugin, Object o) { + injectDependencies(plugin, o); injectLogger(plugin, o); injectConfig(plugin, o); injectPluginInstance(plugin, o); - injectDependencies(plugin, o); + LocaleLoader.load(plugin, true); } static void injectOnEnable(Plugin plugin) { @@ -39,7 +41,7 @@ public class DependencyInjector { private static void ejectConfig(Plugin plugin, Object o) { for (Field field : Ref.getDeclaredFields(o.getClass())) { Config config; - if ((config = field.getType().getAnnotation(Config.class)) != null) { + if ((config = field.getType().getAnnotation(Config.class)) != null && config.saveOnExit()) { try { field.setAccessible(true); TConfigInjector.saveConfig(plugin, field.get(o)); diff --git a/src/main/java/com/ilummc/tlib/inject/TConfigInjector.java b/src/main/java/com/ilummc/tlib/inject/TConfigInjector.java index 6d2e4bf..7a14c74 100644 --- a/src/main/java/com/ilummc/tlib/inject/TConfigInjector.java +++ b/src/main/java/com/ilummc/tlib/inject/TConfigInjector.java @@ -1,5 +1,6 @@ package com.ilummc.tlib.inject; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.io.Files; import com.google.gson.Gson; @@ -9,6 +10,7 @@ import com.ilummc.tlib.TLib; import com.ilummc.tlib.annotations.Config; import com.ilummc.tlib.bean.Property; import org.apache.commons.lang3.Validate; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.configuration.serialization.ConfigurationSerialization; import org.bukkit.plugin.Plugin; @@ -17,7 +19,6 @@ import org.yaml.snakeyaml.Yaml; import java.io.File; import java.io.IOException; -import java.lang.reflect.Array; import java.lang.reflect.Field; import java.nio.charset.Charset; import java.util.*; @@ -25,6 +26,36 @@ import java.util.stream.Collectors; public class TConfigInjector { + public static void fixUnicode(YamlConfiguration configuration) { + try { + Field field = YamlConfiguration.class.getDeclaredField("yamlOptions"); + field.setAccessible(true); + field.set(configuration, NoUnicodeDumperOption.INSTANCE); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + private static final class NoUnicodeDumperOption extends DumperOptions { + + private static final NoUnicodeDumperOption INSTANCE = new NoUnicodeDumperOption(); + + @Override + public void setAllowUnicode(boolean allowUnicode) { + super.setAllowUnicode(false); + } + + @Override + public boolean isAllowUnicode() { + return false; + } + + @Override + public void setLineBreak(LineBreak lineBreak) { + super.setLineBreak(LineBreak.getPlatformLineBreak()); + } + } + public static Object loadConfig(Plugin plugin, Class clazz) { try { Config config = clazz.getAnnotation(Config.class); @@ -32,7 +63,9 @@ public class TConfigInjector { File file = new File(plugin.getDataFolder(), config.name()); if (!file.exists()) if (config.fromJar()) plugin.saveResource(config.name(), true); else saveConfig(plugin, clazz.newInstance()); - return unserialize(plugin, clazz); + Object obj = unserialize(plugin, clazz); + if (!config.readOnly()) saveConfig(plugin, obj); + return obj; } catch (NullPointerException e) { TLib.getTLib().getLogger().warn("插件 " + plugin + " 的配置类 " + clazz.getSimpleName() + " 加载失败:没有 @Config 注解"); } catch (Exception e) { @@ -83,6 +116,7 @@ public class TConfigInjector { if (!target.exists()) target.createNewFile(); DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + options.setAllowUnicode(false); Yaml yaml = new Yaml(options); String str = yaml.dump(obj); byte[] arr = str.getBytes(config.charset()); @@ -124,12 +158,7 @@ public class TConfigInjector { if (o.getClass().isPrimitive() || primitiveType.contains(o.getClass())) { return o; } else if (o.getClass().isArray()) { - List list = new ArrayList<>(); - int len = (int) o.getClass().getField("length").get(o); - for (int i = 0; i < len; i++) { - list.add(serialize(Array.get(o, i))); - } - return list; + return ImmutableList.copyOf(((Object[]) o)); } else if (o instanceof Collection) { return ((Collection) o).stream().map(this::serialize).collect(Collectors.toList()); } else if (o instanceof Map) { diff --git a/src/main/java/com/ilummc/tlib/resources/LocaleInstance.java b/src/main/java/com/ilummc/tlib/resources/LocaleInstance.java new file mode 100644 index 0000000..aec3862 --- /dev/null +++ b/src/main/java/com/ilummc/tlib/resources/LocaleInstance.java @@ -0,0 +1,65 @@ +package com.ilummc.tlib.resources; + +import com.google.common.collect.ImmutableList; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; + +import javax.annotation.concurrent.ThreadSafe; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.stream.Collectors; + +@ThreadSafe +class LocaleInstance { + + private static final Function TO_SENDABLE = o -> { + if (o instanceof Sendable) return ((Sendable) o); + else if (o instanceof String) return SimpleChatMessage.of(((String) o)); + else return SimpleChatMessage.of(String.valueOf(o)); + }; + + LocaleInstance() { + } + + private final Map> map = new ConcurrentHashMap<>(); + + void sendTo(String path, CommandSender sender) { + map.getOrDefault(path, ImmutableList.of(Sendable.EMPTY)).forEach(sendable -> sendable.sendTo(sender)); + } + + void sendTo(String path, CommandSender sender, String... args) { + map.getOrDefault(path, ImmutableList.of(Sendable.EMPTY)).forEach(sendable -> sendable.sendTo(sender, args)); + System.out.println(map.toString()); + } + + void load(YamlConfiguration configuration) { + configuration.getKeys(false).forEach(s -> { + Object object = configuration.get(s); + if (object instanceof ConfigurationSection) + loadRecursively(s, (ConfigurationSection) object); + else if (object instanceof Sendable) + map.put(s, Collections.singletonList((Sendable) object)); + else if (object instanceof List && !((List) object).isEmpty()) + map.put(s, ((List) object).stream().map(TO_SENDABLE).collect(Collectors.toList())); + else map.put(s, Collections.singletonList(SimpleChatMessage.of(String.valueOf(object)))); + }); + } + + private void loadRecursively(String path, ConfigurationSection section) { + section.getKeys(false).forEach(s -> { + Object object = section.get(path + "." + s); + if (object instanceof ConfigurationSection) + loadRecursively(path + "." + s, (ConfigurationSection) object); + else if (object instanceof Sendable) + map.put(path + "." + s, Collections.singletonList((Sendable) object)); + else if (object instanceof List && !((List) object).isEmpty()) + map.put(path + "." + s, ((List) object).stream().map(TO_SENDABLE).collect(Collectors.toList())); + else map.put(path + "." + s, Collections.singletonList(SimpleChatMessage.of(String.valueOf(object)))); + }); + } + +} diff --git a/src/main/java/com/ilummc/tlib/resources/LocaleLoader.java b/src/main/java/com/ilummc/tlib/resources/LocaleLoader.java new file mode 100644 index 0000000..9767d43 --- /dev/null +++ b/src/main/java/com/ilummc/tlib/resources/LocaleLoader.java @@ -0,0 +1,76 @@ +package com.ilummc.tlib.resources; + +import com.ilummc.tlib.TLib; +import com.ilummc.tlib.inject.TConfigInjector; +import me.skymc.taboolib.Main; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.configuration.serialization.ConfigurationSerialization; +import org.bukkit.plugin.Plugin; + +import java.io.File; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +public class LocaleLoader { + + private static final Map map = new HashMap<>(); + + static void sendTo(Plugin plugin, String path, CommandSender sender, String... args) { + Optional.ofNullable(map.get(plugin.getName())).ifPresent(localeInstance -> localeInstance.sendTo(path, sender, args)); + } + + static void sendTo(Plugin plugin, String path, CommandSender sender) { + Optional.ofNullable(map.get(plugin.getName())).ifPresent(localeInstance -> localeInstance.sendTo(path, sender)); + } + + public static void init() { + ConfigurationSerialization.registerClass(SimpleChatMessage.class); + ConfigurationSerialization.registerClass(SimpleChatMessage.class, "Message"); + ConfigurationSerialization.registerClass(SimpleChatMessage.class, "MESSAGE"); + ConfigurationSerialization.registerClass(SimpleChatMessage.class, "TEXT"); + ConfigurationSerialization.registerClass(SimpleChatMessage.class, "Text"); + } + + public static void load(Plugin plugin, boolean ignoreLoaded) { + try { + if ((!ignoreLoaded || !map.containsKey(plugin.getName())) && plugin == Main.getInst() || + plugin.getDescription().getDepend().contains("TabooLib") || plugin.getDescription().getSoftDepend().contains("TabooLib")) { + InputStream inputStream = null; + File file = null; + String lang = null; + for (String s : TLib.getTLib().getConfig().getLocale()) { + lang = s; + file = new File(plugin.getDataFolder(), "/lang/" + s + ".yml"); + if (file.exists()) { + inputStream = Files.newInputStream(file.toPath(), StandardOpenOption.READ); + break; + } else if ((inputStream = plugin.getClass().getResourceAsStream("/lang/" + s + ".yml")) != null) + break; + } + if (inputStream == null) return; + TLib.getTLib().getLogger().info("尝试加载 " + lang + ".yml 作为语言文件"); + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(new InputStreamReader(inputStream, Charset.forName("utf-8"))); + LocaleInstance localeInstance = new LocaleInstance(); + localeInstance.load(configuration); + map.put(plugin.getName(), localeInstance); + TConfigInjector.fixUnicode(configuration); + if (!file.exists()) { + file.getParentFile().mkdirs(); + file.createNewFile(); + } + configuration.save(file); + TLib.getTLib().getLogger().info("成功加载 " + lang + " 语言文件"); + } + } catch (Exception e) { + TLib.getTLib().getLogger().error("载入语言文件发生异常:" + e.toString()); + } + } + +} diff --git a/src/main/java/com/ilummc/tlib/resources/Sendable.java b/src/main/java/com/ilummc/tlib/resources/Sendable.java new file mode 100644 index 0000000..e033cb4 --- /dev/null +++ b/src/main/java/com/ilummc/tlib/resources/Sendable.java @@ -0,0 +1,21 @@ +package com.ilummc.tlib.resources; + +import org.bukkit.command.CommandSender; + +public interface Sendable { + + Sendable EMPTY = new Sendable() { + @Override + public void sendTo(CommandSender sender) { + } + + @Override + public void sendTo(CommandSender sender, String... args) { + } + }; + + void sendTo(CommandSender sender); + + void sendTo(CommandSender sender, String... args); + +} diff --git a/src/main/java/com/ilummc/tlib/resources/SimpleChatMessage.java b/src/main/java/com/ilummc/tlib/resources/SimpleChatMessage.java new file mode 100644 index 0000000..7e8781d --- /dev/null +++ b/src/main/java/com/ilummc/tlib/resources/SimpleChatMessage.java @@ -0,0 +1,95 @@ +package com.ilummc.tlib.resources; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; +import com.ilummc.tlib.TLib; +import com.ilummc.tlib.compat.PlaceholderApiHook; +import com.ilummc.tlib.util.Strings; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.configuration.serialization.SerializableAs; + +import javax.annotation.concurrent.Immutable; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +@Immutable +@SerializableAs("TEXT") +@SuppressWarnings("unchecked") +public class SimpleChatMessage implements Sendable, ConfigurationSerializable { + + private final Object text; + + private final boolean usePlaceholder; + + private SimpleChatMessage(Object text, boolean usePlaceholder) { + this.usePlaceholder = usePlaceholder; + if (text instanceof String) + this.text = text; + else if (text instanceof List) + this.text = ImmutableList.copyOf(((List) text)); + else + throw new IllegalArgumentException("Param 'text' can only be an instance of String or String[] or List"); + } + + @Override + public void sendTo(CommandSender sender) { + if (text instanceof String) + sender.sendMessage(replaceMsg(sender, (String) text)); + else if (text instanceof List) + ((List) text).forEach(s -> sender.sendMessage(replaceMsg(sender, String.valueOf(s)))); + } + + @Override + public void sendTo(CommandSender sender, String... args) { + if (text instanceof String) + sender.sendMessage(replaceMsg(sender, Strings.replaceWithOrder((String) text, args))); + else if (text instanceof List) + ((List) text).forEach(s -> sender.sendMessage(replaceMsg(sender, Strings.replaceWithOrder(String.valueOf(s), args)))); + } + + private String replaceMsg(CommandSender sender, String s) { + return usePlaceholder ? PlaceholderApiHook.replace(sender, s) : s; + } + + @Override + public String toString() { + if (text instanceof String[]) return Arrays.toString((String[]) text); + else return text.toString(); + } + + @Override + public Map serialize() { + if (usePlaceholder) return Maps.newHashMap(ImmutableMap.of("text", text, "papi", true)); + return Maps.newHashMap(ImmutableMap.of("text", text)); + } + + public static SimpleChatMessage valueOf(Map map) { + if (map.containsKey("text")) { + Object object = map.get("text"); + Object objPapi = map.getOrDefault("papi", TLib.getTLib().getConfig().isEnablePapiByDefault()); + boolean papi = objPapi instanceof Boolean ? (boolean) objPapi : objPapi instanceof String && objPapi.equals("true"); + if (object instanceof List) + return new SimpleChatMessage(((List) object).stream() + .map(s -> ChatColor.translateAlternateColorCodes('&', s)) + .collect(Collectors.toList()), papi); + else if (object instanceof String[]) + return new SimpleChatMessage(Arrays.stream(((String[]) object)) + .map(s -> ChatColor.translateAlternateColorCodes('&', s)) + .collect(Collectors.toList()), papi); + else + return new SimpleChatMessage(ChatColor.translateAlternateColorCodes('&', Objects.toString(object)), papi); + } + return new SimpleChatMessage("§cError chat message loaded.", TLib.getTLib().getConfig().isEnablePapiByDefault()); + } + + public static SimpleChatMessage of(String s) { + return new SimpleChatMessage(ChatColor.translateAlternateColorCodes('&', s), TLib.getTLib().getConfig().isEnablePapiByDefault()); + } + +} diff --git a/src/main/java/com/ilummc/tlib/resources/TLocale.java b/src/main/java/com/ilummc/tlib/resources/TLocale.java new file mode 100644 index 0000000..99fc5ca --- /dev/null +++ b/src/main/java/com/ilummc/tlib/resources/TLocale.java @@ -0,0 +1,54 @@ +package com.ilummc.tlib.resources; + +import com.ilummc.tlib.util.Ref; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; + +import java.lang.reflect.Field; + +public final class TLocale { + + private TLocale() { + throw new AssertionError(); + } + + private static void sendTo(String path, CommandSender sender, String[] args, Class callerClass) { + try { + Field pluginField = callerClass.getClassLoader().getClass().getDeclaredField("plugin"); + pluginField.setAccessible(true); + JavaPlugin plugin = (JavaPlugin) pluginField.get(callerClass.getClassLoader()); + if (args.length == 0) + LocaleLoader.sendTo(plugin, path, sender); + else + LocaleLoader.sendTo(plugin, path, sender, args); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void sendTo(String path, CommandSender sender, String... args) { + Ref.getCallerClass(3).ifPresent(clazz -> sendTo(path, sender, args, clazz)); + } + + public static void sendTo(String path, CommandSender sender) { + Ref.getCallerClass(3).ifPresent(clazz -> sendTo(path, sender, new String[0], clazz)); + } + + public static void sendTo(CommandSender sender, String path, String... args) { + Ref.getCallerClass(3).ifPresent(clazz -> sendTo(path, sender, args, clazz)); + } + + public static void sendTo(CommandSender sender, String path) { + Ref.getCallerClass(3).ifPresent(clazz -> sendTo(path, sender, new String[0], clazz)); + } + + public static void sendToConsole(String path, String... args) { + Ref.getCallerClass(3).ifPresent(clazz -> sendTo(path, Bukkit.getConsoleSender(), args, clazz)); + } + + public static void sendToConsole(String path) { + Ref.getCallerClass(3).ifPresent(clazz -> sendTo(path, Bukkit.getConsoleSender(), new String[0], clazz)); + } + +} diff --git a/src/main/java/com/ilummc/tlib/util/Ref.java b/src/main/java/com/ilummc/tlib/util/Ref.java index b9d4f1a..3aa0990 100644 --- a/src/main/java/com/ilummc/tlib/util/Ref.java +++ b/src/main/java/com/ilummc/tlib/util/Ref.java @@ -4,6 +4,7 @@ import com.ilummc.tlib.TLib; import com.ilummc.tlib.util.asm.AsmAnalyser; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; +import sun.reflect.Reflection; import javax.annotation.concurrent.ThreadSafe; import java.lang.reflect.Field; @@ -46,11 +47,10 @@ public class Ref { classReader.accept(analyser, ClassReader.SKIP_DEBUG); fields = analyser.getFields().stream().map(name -> { try { - System.out.println(name); return clazz.getDeclaredField(name); } catch (Throwable ignored) { + return null; } - return null; }).filter(Objects::nonNull).collect(Collectors.toList()); if (cache) cachedFields.putIfAbsent(clazz.getName(), fields); return fields; @@ -59,4 +59,44 @@ public class Ref { } } + public static Optional> getCallerClass(int depth) { + return Optional.ofNullable(CallerClass.impl.getCallerClass(depth + 1)); + } + + private static abstract class CallerClass { + + private static CallerClass impl; + + static { + try { + Class.forName("sun.reflect.Reflection"); + impl = new ReflectionImpl(); + } catch (ClassNotFoundException e) { + impl = new StackTraceImpl(); + } + } + + abstract Class getCallerClass(int i); + + private static class ReflectionImpl extends CallerClass { + @Override + Class getCallerClass(int i) { + return Reflection.getCallerClass(i); + } + } + + private static class StackTraceImpl extends CallerClass { + + @Override + Class getCallerClass(int i) { + StackTraceElement[] elements = Thread.currentThread().getStackTrace(); + try { + return Class.forName(elements[i].getClassName()); + } catch (ClassNotFoundException e) { + return null; + } + } + } + } + } diff --git a/src/main/java/com/ilummc/tlib/util/Strings.java b/src/main/java/com/ilummc/tlib/util/Strings.java index 050c43a..3e5bba3 100644 --- a/src/main/java/com/ilummc/tlib/util/Strings.java +++ b/src/main/java/com/ilummc/tlib/util/Strings.java @@ -10,6 +10,7 @@ public class Strings { * @return 替换好的字符串 */ public static String replaceWithOrder(String template, String... args) { + if (args.length == 0) return template; char[] arr = template.toCharArray(); StringBuilder stringBuilder = new StringBuilder(template.length()); for (int i = 0; i < arr.length; i++) { diff --git a/src/main/resources/lang/zh_CN.yml b/src/main/resources/lang/zh_CN.yml new file mode 100644 index 0000000..e69de29