diff --git a/src/main/java/pw/yumc/YumCore/config/AbstractConfig.java b/src/main/java/pw/yumc/YumCore/config/AbstractConfig.java new file mode 100644 index 0000000..ad38bd3 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/config/AbstractConfig.java @@ -0,0 +1,110 @@ +package pw.yumc.YumCore.config; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.nio.charset.Charset; +import java.util.Map; + +import org.apache.commons.lang.Validate; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.configuration.file.YamlConstructor; +import org.bukkit.configuration.file.YamlRepresenter; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.error.YAMLException; +import org.yaml.snakeyaml.representer.Representer; + +import com.google.common.io.Files; + +/** + * 抽象配置文件 + * + * @since 2016年3月12日 下午4:46:45 + * @author 喵♂呜 + */ +public class AbstractConfig extends YamlConfiguration { + public static final Charset UTF_8 = Charset.forName("UTF-8"); + protected final DumperOptions yamlOptions = new DumperOptions(); + protected final Representer yamlRepresenter = new YamlRepresenter(); + protected final Yaml yamlz = new Yaml(new YamlConstructor(), yamlRepresenter, yamlOptions); + + protected String data; + + @Override + public void load(final File file) throws FileNotFoundException, IOException, InvalidConfigurationException { + Validate.notNull(file, "文件不能为null"); + final FileInputStream stream = new FileInputStream(file); + load(new InputStreamReader(stream, UTF_8)); + } + + @Override + public void load(final Reader reader) throws IOException, InvalidConfigurationException { + final BufferedReader input = reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader); + final StringBuilder builder = new StringBuilder(); + try { + String line; + while ((line = input.readLine()) != null) { + builder.append(line); + builder.append('\n'); + } + } finally { + input.close(); + } + loadFromString(builder.toString()); + } + + @Override + public void loadFromString(final String contents) throws InvalidConfigurationException { + Validate.notNull(contents, "内容不能为 null"); + Map input; + try { + input = (Map) yamlz.load(contents); + } catch (final YAMLException e) { + throw new InvalidConfigurationException(e); + } catch (final ClassCastException e) { + throw new InvalidConfigurationException("顶层键值必须是Map."); + } + final String header = parseHeader(contents); + if (header.length() > 0) { + options().header(header); + } + if (input != null) { + convertMapsToSections(input, this); + } + } + + @Override + public void save(final File file) throws IOException { + Validate.notNull(file, "文件不得为 null"); + Files.createParentDirs(file); + final Writer writer = new OutputStreamWriter(new FileOutputStream(file), UTF_8); + try { + writer.write(data); + } finally { + writer.close(); + } + } + + @Override + public String saveToString() { + yamlOptions.setIndent(options().indent()); + yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + final String header = buildHeader(); + String dump = yamlz.dump(getValues(false)); + if (dump.equals(BLANK_CONFIG)) { + dump = ""; + } + data = header + dump; + return data; + } +} diff --git a/src/main/java/pw/yumc/YumCore/config/AbstractInjectConfig.java b/src/main/java/pw/yumc/YumCore/config/AbstractInjectConfig.java new file mode 100644 index 0000000..8e3b1e8 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/config/AbstractInjectConfig.java @@ -0,0 +1,79 @@ +package pw.yumc.YumCore.config; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.logging.Level; + +import org.bukkit.configuration.ConfigurationSection; + +import pw.yumc.YumCore.bukkit.Log; + +/** + * + * @since 2016年7月5日 上午10:11:22 + * @author 喵♂呜 + */ +public abstract class AbstractInjectConfig { + /** + * 注入配置数据 + */ + public void inject() { + for (final Field field : getClass().getDeclaredFields()) { + if (Modifier.isTransient(field.getModifiers()) || field.getType().isPrimitive()) { + continue; + } + final ConfigNode node = field.getAnnotation(ConfigNode.class); + String path = field.getName(); + if (node != null && !node.path().isEmpty()) { + path = node.path(); + } + field.setAccessible(true); + setField(path, field); + } + } + + /** + * 通用解析流程 + * + * @param path + * 配置路径 + * @param field + * 字段 + * @return 是否解析成功 + * @throws IllegalArgumentException + * @throws IllegalAccessException + */ + protected boolean commonParse(final ConfigurationSection config, final String path, final Field field) throws IllegalArgumentException, IllegalAccessException { + final String typeName = field.getType().getName(); + switch (typeName) { + case "java.util.Date": + final String format = "yyyy-MM-dd HH:mm:ss"; + final String value = config.getString(path); + try { + field.set(this, new SimpleDateFormat(format).parse(value)); + } catch (final ParseException e) { + final Object[] obj = new Object[] { path, format, value }; + Log.log(Level.INFO, "配置节点 {0} 日期解析失败 格式应该为: {1} 但输入值为: {2}!", obj); + } + return true; + case "java.util.List": + field.set(this, config.getList(path)); + return true; + default: + return false; + } + } + + /** + * 设置字段数据 + * + * @param path + * 配置路径 + * @param field + * 字段 + * @throws IllegalArgumentException + */ + protected abstract void setField(final String path, final Field field) throws IllegalArgumentException; +} diff --git a/src/main/java/pw/yumc/YumCore/config/CommentConfig.java b/src/main/java/pw/yumc/YumCore/config/CommentConfig.java new file mode 100644 index 0000000..ce39e34 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/config/CommentConfig.java @@ -0,0 +1,137 @@ +package pw.yumc.YumCore.config; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.bukkit.configuration.InvalidConfigurationException; +import org.yaml.snakeyaml.DumperOptions; + +public class CommentConfig extends AbstractConfig { + // 新增保留注释字段 + protected static final String commentPrefixSymbol = "'注释 "; + protected static final String commentSuffixSymbol = "': 注释"; + + protected static final String fromRegex = "( {0,})(#.*)"; + protected static final Pattern fromPattern = Pattern.compile(fromRegex); + + protected static final String toRegex = "( {0,})(- ){0,}" + "(" + commentPrefixSymbol + ")" + "(#.*)" + "(" + commentSuffixSymbol + ")"; + protected static final Pattern toPattern = Pattern.compile(toRegex); + + protected static final Pattern countSpacePattern = Pattern.compile("( {0,})(- ){0,}(.*)"); + + protected static final int commentSplitWidth = 90; + + protected static final String newLine = "\n"; + + private static String[] split(final String string, final int partLength) { + final String[] array = new String[string.length() / partLength + 1]; + for (int i = 0; i < array.length; i++) { + final int beginIndex = i * partLength; + int endIndex = beginIndex + partLength; + if (endIndex > string.length()) { + endIndex = string.length(); + } + array[i] = string.substring(beginIndex, endIndex); + } + return array; + } + + @Override + public void load(final Reader reader) throws IOException, InvalidConfigurationException { + final BufferedReader input = reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(reader); + final StringBuilder builder = new StringBuilder(); + try { + String line; + while ((line = input.readLine()) != null) { + builder.append(line); + builder.append(newLine); + } + } finally { + input.close(); + } + loadFromString(builder.toString()); + } + + @Override + public void loadFromString(final String contents) throws InvalidConfigurationException { + final String[] parts = contents.split(newLine); + final List lastComments = new ArrayList<>(); + final StringBuilder builder = new StringBuilder(); + for (final String part : parts) { + Matcher matcher = fromPattern.matcher(part); + if (matcher.find()) { + final String originComment = matcher.group(2); + final String[] splitComments = split(originComment, commentSplitWidth); + for (int i = 0; i < splitComments.length; i++) { + String comment = splitComments[i]; + if (i == 0) { + comment = comment.substring(1); + } + comment = COMMENT_PREFIX + comment; + lastComments.add(comment.replaceAll("\\.", ".").replaceAll("'", "'").replaceAll(":", ":")); + } + } else { + matcher = countSpacePattern.matcher(part); + if (matcher.find()) { + if (!lastComments.isEmpty()) { + for (final String comment : lastComments) { + builder.append(matcher.group(1)); + builder.append(this.checkNull(matcher.group(2))); + builder.append(commentPrefixSymbol); + builder.append(comment); + builder.append(commentSuffixSymbol); + builder.append(newLine); + } + lastComments.clear(); + } + } + builder.append(part); + builder.append(newLine); + } + } + super.loadFromString(builder.toString()); + } + + @Override + public String saveToString() { + yamlOptions.setIndent(options().indent()); + yamlOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + yamlRepresenter.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + final String header = buildHeader(); + String dump = yamlz.dump(getValues(false)); + if (dump.equals(BLANK_CONFIG)) { + dump = ""; + } + final String contents = header + dump; + final StringBuilder savcontent = new StringBuilder(); + final String[] parts = contents.split(newLine); + for (String part : parts) { + final Matcher matcher = toPattern.matcher(part); + if (matcher.find()) { + if (matcher.groupCount() == 5) { + part = this.checkNull(matcher.group(1)) + matcher.group(4); + } + } + savcontent.append(part.replaceAll(".", ".").replaceAll("'", "'").replaceAll(":", ":")); + savcontent.append(newLine); + } + data = savcontent.toString(); + return data; + } + + /** + * 检查字符串 + * + * @param string + * 检查字符串 + * @return 返回非null字符串 + */ + private String checkNull(final String string) { + return string == null ? "" : string; + } +} \ No newline at end of file diff --git a/src/main/java/pw/yumc/YumCore/config/ConfigNode.java b/src/main/java/pw/yumc/YumCore/config/ConfigNode.java new file mode 100644 index 0000000..d79f685 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/config/ConfigNode.java @@ -0,0 +1,24 @@ +package pw.yumc.YumCore.config; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Specializes a non-default path for config node + */ +@Target(ElementType.FIELD) +@Documented +@Retention(RetentionPolicy.RUNTIME) +public @interface ConfigNode { + + /** + * Defines the path to the node if it has another as the variable name. + * Every indention is separated with an dot ('.') + * + * @return the path to the node + */ + String path() default ""; +} diff --git a/src/main/java/pw/yumc/YumCore/config/FileConfig.java b/src/main/java/pw/yumc/YumCore/config/FileConfig.java new file mode 100644 index 0000000..163455f --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/config/FileConfig.java @@ -0,0 +1,567 @@ +package pw.yumc.YumCore.config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; + +import org.apache.commons.lang.Validate; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.Plugin; + +import com.google.common.io.Files; + +import pw.yumc.YumCore.bukkit.Log; +import pw.yumc.YumCore.bukkit.P; + +/** + * 一个继承于 {@link YamlConfiguration} 的配置文件类 + * 强制UTF-8编码处理所有的文件信息 + * + * @author 喵♂呜 + * @version 1.0 + * @since 2015年11月7日 下午2:36:07 + */ +@SuppressWarnings({ "unchecked" }) +public class FileConfig extends AbstractConfig { + protected static String CHECK_FIELD = "Version"; + protected static String PLUGINHELPER = "PluginHelper"; + + protected Logger loger = P.getLogger(); + + protected Plugin plugin; + protected File file; + + private CommentConfig commentConfig; + + /** + * 实例化空的配置文件 + */ + public FileConfig() { + } + + /** + * 从文件载入配置 + * + * @param file + * 配置文件 + */ + public FileConfig(final File file) { + this.file = file; + init(file); + } + + /** + * 从文件载入配置(默认为config.yml) + * + * @param plugin + * 插件 + */ + public FileConfig(final Plugin plugin) { + Validate.notNull(plugin, "插件不能为 null"); + this.plugin = plugin; + this.file = new File(plugin.getDataFolder(), "config.yml"); + check(file); + init(file); + } + + /** + * 从文件载入配置 + * + * @param plugin + * 插件 + * @param file + * 配置文件名称 + */ + public FileConfig(final Plugin plugin, final File file) { + Validate.notNull(file, "文件不能为 null"); + Validate.notNull(plugin, "插件不能为 null"); + this.plugin = plugin; + this.file = file; + check(file); + init(file); + } + + /** + * 从文件载入配置 + * + * @param plugin + * 插件 + * @param filename + * 配置文件名称 + */ + public FileConfig(final Plugin plugin, final String filename) { + this(plugin, new File(plugin.getDataFolder(), filename)); + } + + /** + * 从PluginHelper目录载入配置 + * + * @param filename + * 配置文件 + */ + public FileConfig(final String filename) { + this.file = new File(Bukkit.getUpdateFolderFile().getParentFile(), PLUGINHELPER + File.separator + filename); + if (!file.exists()) { + try { + loger.info("配置 " + file.getName() + " 不存在 创建新文件..."); + file.createNewFile(); + } catch (final IOException e) { + } + } + init(file); + } + + /** + * 从数据流载入配置文件 + * + * @param stream + * 数据流 + */ + private FileConfig(final InputStream stream) { + init(stream); + } + + /** + * 添加到List末尾 + * + * @param + * List内容类型 + * @param path + * 路径 + * @param obj + * 对象 + * @return {@link FileConfig} + */ + public FileConfig addToList(final String path, final E obj) { + List l = (List) this.getList(path); + if (null == l) { + l = new ArrayList(); + } + l.add(obj); + return this; + } + + /** + * 添加到StringList末尾 + * + * @param path + * 路径 + * @param obj + * 字符串 + * @return {@link FileConfig} + */ + public FileConfig addToStringList(final String path, final String obj) { + addToStringList(path, obj, true); + return this; + } + + /** + * 添加到StringList末尾 + * + * @param path + * 路径 + * @param obj + * 字符串 + * @return {@link FileConfig} + */ + public FileConfig addToStringList(final String path, final String obj, final boolean allowrepeat) { + List l = this.getStringList(path); + if (null == l) { + l = new ArrayList<>(); + } + if (allowrepeat || !l.contains(obj)) { + l.add(obj); + } + this.set(path, l); + return this; + } + + /** + * 获得已颜色转码的文本 + * + * @param cfgmsg + * 待转码的List + * @return 颜色转码后的文本 + */ + public List getColorList(final List cfgmsg) { + final List message = new ArrayList(); + if (cfgmsg == null) { + return null; + } + for (final String msg : cfgmsg) { + message.add(ChatColor.translateAlternateColorCodes('&', msg)); + } + return message; + } + + /** + * 获得配置文件名称 + * + * @return 配置文件名称 + */ + public String getConfigName() { + return file.getName(); + } + + /** + * 获得已颜色转码的文本 + * + * @param path + * 配置路径 + * @return 颜色转码后的文本 + */ + public String getMessage(final String path) { + String message = this.getString(path); + if (message != null) { + message = ChatColor.translateAlternateColorCodes('&', message); + } + return message; + } + + /** + * 获得已颜色转码的文本 + * + * @param path + * 配置路径 + * @param def + * 默认文本 + * @return 颜色转码后的文本 + */ + public String getMessage(final String path, final String def) { + String message = this.getString(path, def); + if (message != null) { + message = ChatColor.translateAlternateColorCodes('&', message); + } + return message; + } + + /** + * 获得已颜色转码的文本 + * + * @param path + * 配置路径 + * @return 颜色转码后的文本 + */ + public List getMessageList(final String path) { + final List message = new ArrayList(); + final List cfgmsg = this.getStringList(path); + if (cfgmsg == null) { + return null; + } + for (final String msg : cfgmsg) { + message.add(ChatColor.translateAlternateColorCodes('&', msg)); + } + return message; + } + + /** + * 获得字符串数组 + * + * @param path + * 配置路径 + * @return 字符串数组 + */ + public String[] getStringArray(final String path) { + return this.getStringList(path).toArray(new String[0]); + } + + @Override + public void loadFromString(final String contents) throws InvalidConfigurationException { + try { + commentConfig = new CommentConfig(); + commentConfig.loadFromString(contents); + } catch (final Exception e) { + Log.debug("读取配置文件注释信息失败!"); + commentConfig = null; + } + super.loadFromString(contents); + } + + /** + * 重新载入配置文件 + * + * @return 是否载入成功 + */ + public boolean reload() { + return init(file) != null; + } + + /** + * 从List移除对象 + * + * @param + * List内容对象类型 + * @param path + * 路径 + * @param obj + * 对象 + * @return {@link FileConfig} + */ + public FileConfig removeFromList(final String path, final E obj) { + final List l = (List) this.getList(path); + if (null != l) { + l.remove(obj); + } + return this; + } + + /** + * 从StringList移除对象 + * + * @param path + * 路径 + * @param obj + * 对象 + * @return {@link FileConfig} + */ + public FileConfig removeFromStringList(final String path, final String obj) { + final List l = this.getStringList(path); + if (null != l) { + l.remove(obj); + } + this.set(path, obj); + return this; + } + + /** + * 快速保存配置文件 + * + * @return 是否成功 + */ + public boolean save() { + try { + this.save(file); + return true; + } catch (final IOException e) { + loger.warning("配置 " + file.getName() + " 保存错误..."); + e.printStackTrace(); + return false; + } + } + + @Override + public void save(final File file) throws IOException { + Validate.notNull(file, "文件不得为 null"); + Files.createParentDirs(file); + if (commentConfig != null) { + data = commentConfig.saveToString(); + } else { + data = saveToString(); + } + super.save(file); + } + + @Override + public void set(final String path, final Object value) { + if (commentConfig != null) { + commentConfig.set(path, value); + } + super.set(path, value); + } + + /** + * 检查配置文件版本 + * + * @param newcfg + * 新配置文件 + * @param oldcfg + * 旧配置文件 + * @return 是否需要升级 + * @throws IOException + */ + private boolean needUpdate(final FileConfig newcfg, final FileConfig oldcfg) throws IOException { + final String newver = newcfg.getString(CHECK_FIELD); + final String oldver = oldcfg.getString(CHECK_FIELD); + return newver != null && !newver.equalsIgnoreCase(oldver); + } + + /** + * 从Jar保存配置文件 + */ + private void saveFromJar() { + if (plugin != null && file != null) { + try { + final String filename = file.getName(); + final InputStream filestream = plugin.getResource(file.getName()); + final String errFileName = this.getErrName(filename); + loger.warning("错误的配置文件: " + filename + " 已备份为 " + errFileName); + file.renameTo(new File(file.getParent(), errFileName)); + if (filestream == null) { + file.createNewFile(); + } else { + plugin.saveResource(filename, true); + } + loger.warning("从插件内部读取并保存正确的配置文件..."); + } catch (final IOException ex) { + loger.warning("从插件内部获取或保存配置文件时出错: " + ex.getMessage()); + } + } else { + loger.warning("从插件内部未找到预置的 " + (file != null ? file.getName() : "") + " 配置文件!"); + } + } + + protected void backupConfig(final FileConfig oldcfg) { + final String filename = oldcfg.getConfigName(); + try { + final String newCfgName = this.getBakName(filename); + oldcfg.save(new File(file.getParent(), newCfgName)); + loger.warning("配置: " + filename + " 已备份为 " + newCfgName); + } catch (final IOException e) { + loger.warning("配置: " + filename + "备份失败!"); + } + } + + /** + * 检查配置文件 + * + * @param file + * 配置文件 + */ + protected void check(final File file) { + final String filename = file.getName(); + final InputStream stream = plugin.getResource(filename); + try { + if (!file.exists()) { + file.getParentFile().mkdirs(); + if (stream == null) { + file.createNewFile(); + loger.info("配置 " + filename + " 不存在 创建新文件..."); + } else { + plugin.saveResource(filename, true); + loger.info("配置 " + filename + " 不存在 从插件释放..."); + } + } else { + if (stream == null) { + return; + } + final FileConfig newcfg = new FileConfig(stream); + final FileConfig oldcfg = new FileConfig(file); + if (needUpdate(newcfg, oldcfg)) { + backupConfig(oldcfg); + updateConfig(newcfg, oldcfg).save(file); + } + } + } catch (final IOException e) { + loger.warning("配置 " + filename + " 创建失败..."); + } + } + + protected String getBakName(final String cfgname) { + return cfgname + "." + getStringDate("yyyyMMddHHmmss") + ".bak"; + } + + protected String getErrName(final String cfgname) { + return cfgname + "." + getStringDate("yyyyMMddHHmmss") + ".err"; + } + + /** + * 获取现在时间 + * + * @return yyyy-MM-dd HH:mm:ss + */ + protected String getStringDate(String format) { + format = format == null ? format : "yyyy-MM-dd HH:mm:ss"; + final Date currentTime = new Date(); + return new SimpleDateFormat(format).format(currentTime); + } + + /** + * 初始化FileConfig + * + * @param file + * 配置文件 + * @return FileConfig + */ + protected FileConfig init(final File file) { + Validate.notNull(file, "文件不能为 null"); + FileInputStream stream; + try { + stream = new FileInputStream(file); + init(stream); + } catch (final FileNotFoundException e) { + loger.warning("配置 " + file.getName() + " 不存在..."); + } + return this; + } + + /** + * 初始化FileConfig + * + * @param stream + * 输入流 + * @return FileConfig + */ + protected FileConfig init(final InputStream stream) { + Validate.notNull(stream, "数据流不能为 null"); + try { + this.load(new InputStreamReader(stream, UTF_8)); + } catch (final InvalidConfigurationException | IllegalArgumentException ex) { + if (file == null) { + throw new RuntimeException("数据流转换格式时发生错误...", ex); + } + loger.warning("配置 " + file.getName() + " 格式错误..."); + loger.warning(ex.getMessage()); + saveFromJar(); + } catch (final IOException ex) { + if (file == null) { + throw new RuntimeException("数据流读取时发生错误...", ex); + } + loger.warning("配置 " + file.getName() + " 读取错误..."); + } + return this; + } + + /** + * @param newCfg + * @param oldCfg + * + * @return + */ + protected FileConfig updateConfig(final FileConfig newCfg, final FileConfig oldCfg) { + return updateConfig(newCfg, oldCfg, false); + } + + /** + * 更新配置文件 + * + * @param newCfg + * 新的配置文件 + * @param oldCfg + * 老的配置文件 + * @param force + * 是否强制更新 + * @return 更新以后的配置文件 + */ + protected FileConfig updateConfig(final FileConfig newCfg, final FileConfig oldCfg, final boolean force) { + final String filename = oldCfg.getConfigName(); + final String newver = newCfg.getString(CHECK_FIELD); + final String oldver = oldCfg.getString(CHECK_FIELD); + final Set oldConfigKeys = oldCfg.getKeys(true); + loger.warning("配置: " + filename + " 版本 " + oldver + " 过低 正在升级到 " + newver + " ..."); + // 保留版本字段 不更新 + oldConfigKeys.remove("Version"); + // 强制更新 去除新版本存在的字段 + if (force) { + loger.warning("配置: " + filename + " 将覆盖原有字段数据..."); + oldConfigKeys.removeAll(newCfg.getKeys(true)); + } + // 复制旧的数据 + for (final String string : oldConfigKeys) { + newCfg.set(string, oldCfg.get(string)); + } + loger.info("配置: " + filename + " 升级成功 版本 " + newver + " !"); + return newCfg; + } +} diff --git a/src/main/java/pw/yumc/YumCore/config/InjectConfig.java b/src/main/java/pw/yumc/YumCore/config/InjectConfig.java new file mode 100644 index 0000000..ceed5b7 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/config/InjectConfig.java @@ -0,0 +1,79 @@ +package pw.yumc.YumCore.config; + +import java.lang.reflect.Field; +import java.util.logging.Level; + +import pw.yumc.YumCore.bukkit.Log; +import pw.yumc.YumCore.bukkit.P; + +/** + * 配置自动载入类 + * + * @since 2016年7月5日 上午8:53:57 + * @author 喵♂呜 + */ +public abstract class InjectConfig extends AbstractInjectConfig { + protected FileConfig config; + + public InjectConfig() { + config = new FileConfig(P.instance); + inject(); + } + + public InjectConfig(final String name) { + config = new FileConfig(P.instance, name); + inject(); + } + + /** + * 获得配置文件 + * + * @return 配置文件 + */ + public FileConfig getConfig() { + return config; + } + + /** + * 重载配置文件 + */ + public void reload() { + config.reload(); + inject(); + } + + /** + * 设置字段数据 + * + * @param path + * 配置路径 + * @param field + * 字段 + * @throws IllegalArgumentException + */ + @Override + protected void setField(final String path, final Field field) throws IllegalArgumentException { + final String realPath = path.replace("_", "."); + if (config.isSet(realPath)) { + final Object value = config.get(realPath); + try { + if (!commonParse(config, realPath, field)) { + if (config.isString(realPath)) { + field.set(this, config.getMessage(realPath)); + } else if (config.isList(realPath)) { + field.set(this, config.getMessageList(realPath)); + } else { + field.set(this, value); + } + } + } catch (final IllegalArgumentException ex) { + final Object[] obj = new Object[] { realPath, field.getType().getName(), value.getClass().getName() }; + Log.log(Level.INFO, "配置节点 {0} 数据类型不匹配 应该为: {1} 但实际为: {2}!", obj); + } catch (final IllegalAccessException ex) { + Log.log(Level.SEVERE, "自动注入配置错误!", ex); + } + } else { + Log.debug("配置节点 {0} 丢失!", realPath); + } + } +} diff --git a/src/main/java/pw/yumc/YumCore/config/InjectConfigurationSection.java b/src/main/java/pw/yumc/YumCore/config/InjectConfigurationSection.java new file mode 100644 index 0000000..aa2b4db --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/config/InjectConfigurationSection.java @@ -0,0 +1,60 @@ +package pw.yumc.YumCore.config; + +import java.lang.reflect.Field; +import java.util.logging.Level; + +import org.bukkit.configuration.ConfigurationSection; + +import pw.yumc.YumCore.bukkit.Log; + +/** + * 配置自动载入类 + * + * @since 2016年7月5日 上午8:53:57 + * @author 喵♂呜 + */ +public class InjectConfigurationSection extends AbstractInjectConfig { + protected ConfigurationSection config; + + public InjectConfigurationSection(final ConfigurationSection config) { + this.config = config; + inject(); + } + + /** + * 重载配置文件 + */ + public void reload(final ConfigurationSection config) { + this.config = config; + inject(); + } + + /** + * 设置字段数据 + * + * @param path + * 配置路径 + * @param field + * 字段 + * @throws IllegalArgumentException + */ + @Override + protected void setField(final String path, final Field field) throws IllegalArgumentException { + final String realPath = path.replace("_", "."); + if (config.isSet(realPath)) { + final Object value = config.get(realPath); + try { + if (!commonParse(config, realPath, field)) { + field.set(this, value); + } + } catch (final IllegalArgumentException ex) { + final Object[] obj = new Object[] { realPath, field.getType().getName(), value.getClass().getName() }; + Log.log(Level.INFO, "配置节点 {0} 数据类型不匹配 应该为: {1} 但实际为: {2}!", obj); + } catch (final IllegalAccessException ex) { + Log.log(Level.SEVERE, "自动注入配置错误!", ex); + } + } else { + Log.debug("配置节点 {0} 丢失!", realPath); + } + } +} diff --git a/src/main/java/pw/yumc/YumCore/config/PlayerConfig.java b/src/main/java/pw/yumc/YumCore/config/PlayerConfig.java new file mode 100644 index 0000000..1049601 --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/config/PlayerConfig.java @@ -0,0 +1,61 @@ +package pw.yumc.YumCore.config; + +import java.io.File; + +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +/** + * 玩家配置管理类 + * + * @author 喵♂呜 + * @version 1.0 + */ +public class PlayerConfig extends FileConfig { + private static String CONFIG_FOLDER = "userdata"; + + /** + * 获得玩家配置(保存在 PLUGINHELPER 文件夹) + * + * @param playername + * 玩家名称 + */ + public PlayerConfig(final Player playername) { + super(playername.getName()); + } + + /** + * 获得玩家配置(保存在 CONFIG_FOLDER 文件夹) + * + * @param plugin + * 插件 + * @param playername + * 玩家名称 + */ + public PlayerConfig(final Plugin plugin, final Player playername) { + super(plugin, new File(plugin.getDataFolder(), CONFIG_FOLDER + File.separatorChar + playername.getName())); + } + + /** + * 获得玩家配置(保存在 CONFIG_FOLDER 文件夹) + * + * @param plugin + * 插件 + * @param player + * 玩家 + */ + public PlayerConfig(final Plugin plugin, final String player) { + super(plugin, new File(plugin.getDataFolder(), CONFIG_FOLDER + File.separatorChar + player)); + } + + /** + * 获得玩家配置(保存在 PLUGINHELPER 文件夹) + * + * @param player + * 玩家 + */ + public PlayerConfig(final String player) { + super(player); + } + +} diff --git a/src/main/java/pw/yumc/YumCore/config/RemoteConfig.java b/src/main/java/pw/yumc/YumCore/config/RemoteConfig.java new file mode 100644 index 0000000..bb5008f --- /dev/null +++ b/src/main/java/pw/yumc/YumCore/config/RemoteConfig.java @@ -0,0 +1,105 @@ +package pw.yumc.YumCore.config; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import com.google.common.base.Charsets; + +/** + * 远程配置文件类 + * + * @since 2016年2月22日 上午8:33:51 + * @author 喵♂呜 + */ +public class RemoteConfig extends FileConfig { + protected static String REMOTEFILECENTER = "http://data.yumc.pw/config/"; + + private static String fromYumc = "配置 %s 来自 YUMC 数据中心..."; + private static String createError = "尝试从 YUMC 数据中心下载 %s 失败 部分功能可能无法使用..."; + private static String updateError = "尝试从 YUMC 数据中心更新配置文件 %s 失败 部分数据可能已过时..."; + + public RemoteConfig(final String filename) { + this(filename, REMOTEFILECENTER + filename); + } + + public RemoteConfig(final String filename, final String url) { + this(filename, url, false); + } + + public RemoteConfig(final String filename, final String url, final boolean force) { + file = new File(Bukkit.getUpdateFolderFile().getParentFile(), PLUGINHELPER + File.separator + filename); + if (!file.exists()) { + try { + // 尝试从YUMC下载配置文件 + Files.copy(new URL(url).openStream(), file.toPath(), StandardCopyOption.REPLACE_EXISTING); + loger.info(String.format(fromYumc, filename)); + } catch (final IOException e) { + loger.warning(String.format(createError, filename)); + } + } else { + final FileConfig oldcfg = new FileConfig(file); + final FileConfig newcfg = getFileConfig(url); + final String newver = newcfg.getString(CHECK_FIELD); + final String oldver = oldcfg.getString(CHECK_FIELD); + if (newver != null && !newver.equals(oldver)) { + try { + file.renameTo(new File(Bukkit.getUpdateFolderFile().getParentFile(), PLUGINHELPER + File.separator + getBakName(filename))); + updateConfig(newcfg, oldcfg, force).save(file); + } catch (final IOException e) { + loger.warning(String.format(updateError, filename)); + } + } + } + init(file); + } + + /** + * 获得配置文件 + * + * @param url + * 配置文件地址 + * @return {@link FileConfig} + */ + public static FileConfig getFileConfig(final String url) { + final FileConfig config = new FileConfig(); + try { + final BufferedReader br = new BufferedReader(new InputStreamReader(new URL(url).openStream(), Charsets.UTF_8)); + config.load(br); + br.close(); + } catch (final Exception e) { + } + return config; + } + + /** + * 获得Yaml文件标签信息 + * + * @param url + * XML文件地址 + * @param tag + * 信息标签 + * @param def + * 默认值 + * @return 插件信息 + */ + public static String getYamlTag(final String url, final String tag, final String def) { + String result = def; + try { + final BufferedReader br = new BufferedReader(new InputStreamReader(new URL(url).openStream(), Charsets.UTF_8)); + final FileConfiguration config = YamlConfiguration.loadConfiguration(br); + br.close(); + result = config.getString(tag); + } catch (final Exception e) { + } + return result; + } +}