diff --git a/Essentials/build.gradle b/Essentials/build.gradle index b73674c63..09c3147a1 100644 --- a/Essentials/build.gradle +++ b/Essentials/build.gradle @@ -12,6 +12,10 @@ dependencies { api 'org.bstats:bstats-bukkit:1.8' + implementation 'org.spongepowered:configurate-yaml:4.1.1' + implementation 'org.yaml:snakeyaml:1.+' + testImplementation 'org.checkerframework:checker-qual:3.7.1' + // Providers api project(':providers:BaseProviders') api project(':providers:PaperProvider') @@ -27,6 +31,10 @@ shadowJar { dependencies { include (dependency('io.papermc:paperlib')) include (dependency('org.bstats:bstats-bukkit')) + include (dependency('org.spongepowered:configurate-yaml')) + include (dependency('org.spongepowered:configurate-core')) + include (dependency('org.yaml:snakeyaml')) + include (dependency('io.leangen.geantyref:geantyref')) include (project(':providers:BaseProviders')) include (project(':providers:PaperProvider')) include (project(':providers:NMSReflectionProvider')) @@ -34,4 +42,7 @@ shadowJar { } relocate 'io.papermc.lib', 'com.earth2me.essentials.paperlib' relocate 'org.bstats.bukkit', 'com.earth2me.essentials.metrics' + relocate 'org.spongepowered.configurate', 'com.earth2me.essentials.libs.configurate' + relocate 'org.yaml.snakeyaml', 'com.earth2me.essentials.libs.snakeyaml' + relocate 'io.leangen.geantyref', 'com.earth2me.essentials.libs.geantyref' } diff --git a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java index 71d135256..6215883ec 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Essentials.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Essentials.java @@ -107,7 +107,6 @@ import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPluginLoader; import org.bukkit.scheduler.BukkitScheduler; import org.bukkit.scheduler.BukkitTask; -import org.yaml.snakeyaml.error.YAMLException; import java.io.File; import java.io.IOException; @@ -263,151 +262,141 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { } } - try { - final EssentialsUpgrade upgrade = new EssentialsUpgrade(this); - upgrade.beforeSettings(); - execTimer.mark("Upgrade"); + final EssentialsUpgrade upgrade = new EssentialsUpgrade(this); + upgrade.beforeSettings(); + execTimer.mark("Upgrade"); - confList = new ArrayList<>(); - settings = new Settings(this); - confList.add(settings); - execTimer.mark("Settings"); + confList = new ArrayList<>(); + settings = new Settings(this); + confList.add(settings); + execTimer.mark("Settings"); - userMap = new UserMap(this); - confList.add(userMap); - execTimer.mark("Init(Usermap)"); + userMap = new UserMap(this); + confList.add(userMap); + execTimer.mark("Init(Usermap)"); - balanceTop = new BalanceTopImpl(this); - execTimer.mark("Init(BalanceTop)"); + balanceTop = new BalanceTopImpl(this); + execTimer.mark("Init(BalanceTop)"); - kits = new Kits(this); - confList.add(kits); - upgrade.convertKits(); - execTimer.mark("Kits"); + kits = new Kits(this); + confList.add(kits); + upgrade.convertKits(); + execTimer.mark("Kits"); - upgrade.afterSettings(); - execTimer.mark("Upgrade2"); + upgrade.afterSettings(); + execTimer.mark("Upgrade2"); - warps = new Warps(getServer(), this.getDataFolder()); - confList.add(warps); - execTimer.mark("Init(Warp)"); + warps = new Warps(this.getDataFolder()); + confList.add(warps); + execTimer.mark("Init(Warp)"); - worth = new Worth(this.getDataFolder()); - confList.add(worth); - execTimer.mark("Init(Worth)"); + worth = new Worth(this.getDataFolder()); + confList.add(worth); + execTimer.mark("Init(Worth)"); - itemDb = getItemDbFromConfig(); - confList.add(itemDb); - execTimer.mark("Init(ItemDB)"); + itemDb = getItemDbFromConfig(); + confList.add(itemDb); + execTimer.mark("Init(ItemDB)"); - randomTeleport = new RandomTeleport(this); - if (randomTeleport.getPreCache()) { - randomTeleport.cacheRandomLocations(randomTeleport.getCenter(), randomTeleport.getMinRange(), randomTeleport.getMaxRange()); - } - confList.add(randomTeleport); - execTimer.mark("Init(RandomTeleport)"); - - customItemResolver = new CustomItemResolver(this); - try { - itemDb.registerResolver(this, "custom_items", customItemResolver); - confList.add(customItemResolver); - } catch (final Exception e) { - e.printStackTrace(); - customItemResolver = null; - } - execTimer.mark("Init(CustomItemResolver)"); - - jails = new Jails(this); - confList.add(jails); - execTimer.mark("Init(Jails)"); - - //Spawner item provider only uses one but it's here for legacy... - spawnerItemProvider = new BlockMetaSpawnerItemProvider(); - - //Spawner block providers - if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_12_0_R01)) { - spawnerBlockProvider = new ReflSpawnerBlockProvider(); - } else { - spawnerBlockProvider = new BukkitSpawnerBlockProvider(); - } - - //Spawn Egg Providers - if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_9_R01)) { - spawnEggProvider = new LegacySpawnEggProvider(); - } else if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_12_2_R01)) { - spawnEggProvider = new ReflSpawnEggProvider(); - } else { - spawnEggProvider = new FlatSpawnEggProvider(); - } - - //Potion Meta Provider - if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_9_R01)) { - potionMetaProvider = new LegacyPotionMetaProvider(); - } else { - potionMetaProvider = new BasePotionDataProvider(); - } - - //Server State Provider - //Container Provider - if (PaperLib.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_2_R01)) { - serverStateProvider = new PaperServerStateProvider(); - containerProvider = new PaperContainerProvider(); - } else { - serverStateProvider = new ReflServerStateProvider(); - } - - //Event Providers - if (PaperLib.isPaper()) { - try { - Class.forName("com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent"); - recipeBookEventProvider = new PaperRecipeBookListener(event -> { - if (this.getUser(((PlayerEvent) event).getPlayer()).isRecipeSee()) { - ((Cancellable) event).setCancelled(true); - } - }); - } catch (final ClassNotFoundException ignored) { - } - } - - //Known Commands Provider - if (PaperLib.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_11_2_R01)) { - knownCommandsProvider = new PaperKnownCommandsProvider(); - } else { - knownCommandsProvider = new ReflKnownCommandsProvider(); - } - - // Command aliases provider - formattedCommandAliasProvider = new ReflFormattedCommandAliasProvider(PaperLib.isPaper()); - - // Material Tag Providers - if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_13_0_R01)) { - materialTagProvider = PaperLib.isPaper() ? new PaperMaterialTagProvider() : new BukkitMaterialTagProvider(); - } - - // Sync Commands Provider - syncCommandsProvider = new ReflSyncCommandsProvider(); - - if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_14_4_R01)) { - persistentDataProvider = new ModernPersistentDataProvider(this); - } else { - persistentDataProvider = new ReflPersistentDataProvider(this); - } - - execTimer.mark("Init(Providers)"); - reload(); - - // The item spawn blacklist is loaded with all other settings, before the item - // DB, but it depends on the item DB, so we need to reload it again here: - ((Settings) settings)._lateLoadItemSpawnBlacklist(); - } catch (final YAMLException exception) { - if (pm.getPlugin("EssentialsUpdate") != null) { - LOGGER.log(Level.SEVERE, tl("essentialsHelp2")); - } else { - LOGGER.log(Level.SEVERE, tl("essentialsHelp1")); - } - handleCrash(exception); - return; + randomTeleport = new RandomTeleport(this); + if (randomTeleport.getPreCache()) { + randomTeleport.cacheRandomLocations(randomTeleport.getCenter(), randomTeleport.getMinRange(), randomTeleport.getMaxRange()); } + confList.add(randomTeleport); + execTimer.mark("Init(RandomTeleport)"); + + customItemResolver = new CustomItemResolver(this); + try { + itemDb.registerResolver(this, "custom_items", customItemResolver); + confList.add(customItemResolver); + } catch (final Exception e) { + e.printStackTrace(); + customItemResolver = null; + } + execTimer.mark("Init(CustomItemResolver)"); + + jails = new Jails(this); + confList.add(jails); + execTimer.mark("Init(Jails)"); + + //Spawner item provider only uses one but it's here for legacy... + spawnerItemProvider = new BlockMetaSpawnerItemProvider(); + + //Spawner block providers + if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_12_0_R01)) { + spawnerBlockProvider = new ReflSpawnerBlockProvider(); + } else { + spawnerBlockProvider = new BukkitSpawnerBlockProvider(); + } + + //Spawn Egg Providers + if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_9_R01)) { + spawnEggProvider = new LegacySpawnEggProvider(); + } else if (VersionUtil.getServerBukkitVersion().isLowerThanOrEqualTo(VersionUtil.v1_12_2_R01)) { + spawnEggProvider = new ReflSpawnEggProvider(); + } else { + spawnEggProvider = new FlatSpawnEggProvider(); + } + + //Potion Meta Provider + if (VersionUtil.getServerBukkitVersion().isLowerThan(VersionUtil.v1_9_R01)) { + potionMetaProvider = new LegacyPotionMetaProvider(); + } else { + potionMetaProvider = new BasePotionDataProvider(); + } + + //Server State Provider + //Container Provider + if (PaperLib.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_2_R01)) { + serverStateProvider = new PaperServerStateProvider(); + containerProvider = new PaperContainerProvider(); + } else { + serverStateProvider = new ReflServerStateProvider(); + } + + //Event Providers + if (PaperLib.isPaper()) { + try { + Class.forName("com.destroystokyo.paper.event.player.PlayerRecipeBookClickEvent"); + recipeBookEventProvider = new PaperRecipeBookListener(event -> { + if (this.getUser(((PlayerEvent) event).getPlayer()).isRecipeSee()) { + ((Cancellable) event).setCancelled(true); + } + }); + } catch (final ClassNotFoundException ignored) { + } + } + + //Known Commands Provider + if (PaperLib.isPaper() && VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_11_2_R01)) { + knownCommandsProvider = new PaperKnownCommandsProvider(); + } else { + knownCommandsProvider = new ReflKnownCommandsProvider(); + } + + // Command aliases provider + formattedCommandAliasProvider = new ReflFormattedCommandAliasProvider(PaperLib.isPaper()); + + // Material Tag Providers + if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_13_0_R01)) { + materialTagProvider = PaperLib.isPaper() ? new PaperMaterialTagProvider() : new BukkitMaterialTagProvider(); + } + + // Sync Commands Provider + syncCommandsProvider = new ReflSyncCommandsProvider(); + + if (VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_14_4_R01)) { + persistentDataProvider = new ModernPersistentDataProvider(this); + } else { + persistentDataProvider = new ReflPersistentDataProvider(this); + } + + execTimer.mark("Init(Providers)"); + reload(); + + // The item spawn blacklist is loaded with all other settings, before the item + // DB, but it depends on the item DB, so we need to reload it again here: + ((Settings) settings)._lateLoadItemSpawnBlacklist(); backup = new Backup(this); permissionsHandler = new PermissionsHandler(this, settings.useBukkitPermissions()); alternativeCommandsHandler = new AlternativeCommandsHandler(this); @@ -1192,7 +1181,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { public void onWorldLoad(final WorldLoadEvent event) { PermissionsDefaults.registerBackDefaultFor(event.getWorld()); - ess.getJails().onReload(); + ess.getJails().reloadConfig(); ess.getWarps().reloadConfig(); for (final IConf iConf : ((Essentials) ess).confList) { if (iConf instanceof IEssentialsModule) { @@ -1203,7 +1192,7 @@ public class Essentials extends JavaPlugin implements net.ess3.api.IEssentials { @EventHandler(priority = EventPriority.LOW) public void onWorldUnload(final WorldUnloadEvent event) { - ess.getJails().onReload(); + ess.getJails().reloadConfig(); ess.getWarps().reloadConfig(); for (final IConf iConf : ((Essentials) ess).confList) { if (iConf instanceof IEssentialsModule) { diff --git a/Essentials/src/main/java/com/earth2me/essentials/EssentialsUpgrade.java b/Essentials/src/main/java/com/earth2me/essentials/EssentialsUpgrade.java index d8d660087..16fe6e9f8 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/EssentialsUpgrade.java +++ b/Essentials/src/main/java/com/earth2me/essentials/EssentialsUpgrade.java @@ -1,8 +1,9 @@ package com.earth2me.essentials; +import com.earth2me.essentials.config.ConfigurateUtil; +import com.earth2me.essentials.config.EssentialsConfiguration; +import com.earth2me.essentials.config.EssentialsUserConfiguration; import com.earth2me.essentials.craftbukkit.BanLookup; -import com.earth2me.essentials.settings.Spawns; -import com.earth2me.essentials.storage.YamlStorageWriter; import com.earth2me.essentials.utils.StringUtil; import com.google.common.base.Charsets; import com.google.common.collect.Maps; @@ -11,7 +12,7 @@ import org.bukkit.BanList; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; -import org.bukkit.configuration.ConfigurationSection; +import org.spongepowered.configurate.CommentedConfigurationNode; import java.io.BufferedInputStream; import java.io.BufferedReader; @@ -51,14 +52,14 @@ public class EssentialsUpgrade { private static final String PATTERN_CONFIG_NAME_REGEX = "(?mi)^lastAccountName:\\s*[\"\']?(\\w+)[\"\']?\\s*$"; private static final Pattern PATTERN_CONFIG_NAME = Pattern.compile(PATTERN_CONFIG_NAME_REGEX); private final transient IEssentials ess; - private final transient EssentialsConf doneFile; + private final transient EssentialsConfiguration doneFile; EssentialsUpgrade(final IEssentials essentials) { ess = essentials; if (!ess.getDataFolder().exists()) { ess.getDataFolder().mkdirs(); } - doneFile = new EssentialsConf(new File(ess.getDataFolder(), "upgrades-done.yml")); + doneFile = new EssentialsConfiguration(new File(ess.getDataFolder(), "upgrades-done.yml")); doneFile.load(); } @@ -92,13 +93,13 @@ public class EssentialsUpgrade { countFiles++; final String name = string.substring(0, string.length() - 4); - final EssentialsUserConf config; + final EssentialsUserConfiguration config; UUID uuid = null; try { uuid = UUID.fromString(name); } catch (final IllegalArgumentException ex) { final File file = new File(userdir, string); - final EssentialsConf conf = new EssentialsConf(file); + final EssentialsConfiguration conf = new EssentialsConfiguration(file); conf.load(); conf.setProperty("lastAccountName", name); conf.save(); @@ -129,8 +130,8 @@ public class EssentialsUpgrade { } if (uuid != null) { - conf.forceSave(); - config = new EssentialsUserConf(name, uuid, new File(userdir, uuid + ".yml")); + conf.blockingSave(); + config = new EssentialsUserConfiguration(name, uuid, new File(userdir, uuid + ".yml")); config.convertLegacyFile(); ess.getUserMap().trackUUID(uuid, name, false); continue; @@ -145,6 +146,60 @@ public class EssentialsUpgrade { ess.getLogger().info("To rerun the conversion type /essentials uuidconvert"); } + public void convertStupidCamelCaseUserdataKeys() { + if (doneFile.getBoolean("updateUsersLegacyPathNames", false)) { + return; + } + + LOGGER.info("Attempting to migrate legacy userdata keys to Configurate"); + + final File userdataFolder = new File(ess.getDataFolder(), "userdata"); + if (!userdataFolder.exists() || !userdataFolder.isDirectory()) { + return; + } + final File[] userFiles = userdataFolder.listFiles(); + + for (final File file : userFiles) { + if (!file.isFile() || !file.getName().endsWith(".yml")) { + continue; + } + final EssentialsConfiguration config = new EssentialsConfiguration(file); + try { + config.load(); + + if (config.hasProperty("muteReason")) { + final String reason = config.getString("muteReason", null); + config.removeProperty("muteReason"); + config.setProperty("mute-reason", reason); + } + + if (config.hasProperty("ipAddress")) { + final String ip = config.getString("ipAddress", null); + config.removeProperty("ipAddress"); + config.setProperty("ip-address", ip); + } + + if (config.hasProperty("lastAccountName")) { + final String name = config.getString("lastAccountName", null); + config.removeProperty("lastAccountName"); + config.setProperty("last-account-name", name); + } + + if (config.hasProperty("acceptingPay")) { + final boolean isPay = config.getBoolean("acceptingPay", true); + config.removeProperty("acceptingPay"); + config.setProperty("accepting-pay", isPay); + } + } catch (final RuntimeException ex) { + LOGGER.log(Level.INFO, "File: " + file.toString()); + throw ex; + } + } + doneFile.setProperty("updateUsersLegacyPathNames", true); + doneFile.save(); + LOGGER.info("Done converting legacy userdata keys to Configurate."); + } + public void convertIgnoreList() { final Pattern pattern = Pattern.compile("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"); if (doneFile.getBoolean("updateUsersIgnoreListUUID", false)) { @@ -163,12 +218,12 @@ public class EssentialsUpgrade { if (!file.isFile() || !file.getName().endsWith(".yml")) { continue; } - final EssentialsConf config = new EssentialsConf(file); + final EssentialsConfiguration config = new EssentialsConfiguration(file); try { config.load(); if (config.hasProperty("ignore")) { final List migratedIgnores = new ArrayList<>(); - for (final String name : Collections.synchronizedList(config.getStringList("ignore"))) { + for (final String name : Collections.synchronizedList(config.getList("ignore", String.class))) { if (name == null) { continue; } @@ -183,7 +238,7 @@ public class EssentialsUpgrade { } config.removeProperty("ignore"); config.setProperty("ignore", migratedIgnores); - config.forceSave(); + config.blockingSave(); } } catch (final RuntimeException ex) { LOGGER.log(Level.INFO, "File: " + file.toString()); @@ -197,24 +252,24 @@ public class EssentialsUpgrade { public void convertKits() { final Kits kits = ess.getKits(); - final EssentialsConf config = kits.getConfig(); + final EssentialsConfiguration config = kits.getConfig(); if (doneFile.getBoolean("kitsyml", false)) { return; } LOGGER.info("Attempting to convert old kits in config.yml to new kits.yml"); - final ConfigurationSection section = ess.getSettings().getKitSection(); + final CommentedConfigurationNode section = ess.getSettings().getKitSection(); if (section == null) { LOGGER.info("No kits found to migrate."); return; } - final Map legacyKits = ess.getSettings().getKitSection().getValues(true); + final Map legacyKits = ConfigurateUtil.getRawMap(section); for (final Map.Entry entry : legacyKits.entrySet()) { LOGGER.info("Converting " + entry.getKey()); - config.set("kits." + entry.getKey(), entry.getValue()); + config.setRaw("kits." + entry.getKey(), entry.getValue()); } config.save(); @@ -236,9 +291,9 @@ public class EssentialsUpgrade { if (!configFile.exists()) { return; } - final EssentialsConf conf = new EssentialsConf(configFile); + final EssentialsConfiguration conf = new EssentialsConfiguration(configFile); conf.load(); - final List lines = conf.getStringList(name); + final List lines = conf.getList(name, String.class); if (lines != null && !lines.isEmpty()) { if (!file.createNewFile()) { throw new IOException("Failed to create file " + file); @@ -312,12 +367,12 @@ public class EssentialsUpgrade { if (!file.isFile() || !file.getName().endsWith(".yml")) { continue; } - final EssentialsConf config = new EssentialsConf(file); + final EssentialsConfiguration config = new EssentialsConfiguration(file); try { config.load(); if (config.hasProperty("powertools")) { - final Map powertools = config.getConfigurationSection("powertools").getValues(false); - if (powertools == null) { + final Map powertools = ConfigurateUtil.getRawMap(config.getSection("powertools")); + if (powertools.isEmpty()) { continue; } for (final Map.Entry entry : powertools.entrySet()) { @@ -327,7 +382,8 @@ public class EssentialsUpgrade { powertools.put(entry.getKey(), temp); } } - config.forceSave(); + config.setRaw("powertools", powertools); + config.blockingSave(); } } catch (final RuntimeException ex) { LOGGER.log(Level.INFO, "File: " + file.toString()); @@ -352,39 +408,37 @@ public class EssentialsUpgrade { if (!file.isFile() || !file.getName().endsWith(".yml")) { continue; } - final EssentialsConf config = new EssentialsConf(file); + final EssentialsConfiguration config = new EssentialsConfiguration(file); try { config.load(); if (config.hasProperty("home") && config.hasProperty("home.default")) { - final String defworld = (String) config.getProperty("home.default"); - final Location defloc = getFakeLocation(config, "home.worlds." + defworld); + final String defworld = config.getString("home.default", null); + final Location defloc = getFakeLocation(config.getRootNode(), "home.worlds." + defworld); if (defloc != null) { config.setProperty("homes.home", defloc); } - final Set worlds = config.getConfigurationSection("home.worlds").getKeys(false); + final Set worlds = ConfigurateUtil.getKeys(config.getSection("home.worlds")); Location loc; String worldName; - if (worlds == null) { + if (worlds.isEmpty()) { continue; } for (final String world : worlds) { if (defworld.equalsIgnoreCase(world)) { continue; } - loc = getFakeLocation(config, "home.worlds." + world); + loc = getFakeLocation(config.getRootNode(), "home.worlds." + world); if (loc == null) { continue; } worldName = loc.getWorld().getName().toLowerCase(Locale.ENGLISH); - if (worldName != null && !worldName.isEmpty()) { - config.setProperty("homes." + worldName, loc); - } + config.setProperty("homes." + worldName, loc); } config.removeProperty("home"); - config.forceSave(); + config.blockingSave(); } } catch (final RuntimeException ex) { @@ -441,7 +495,7 @@ public class EssentialsUpgrade { return null; } - public Location getFakeLocation(final EssentialsConf config, final String path) { + public Location getFakeLocation(final CommentedConfigurationNode config, final String path) { final String worldName = config.getString((path != null ? path + "." : "") + "world"); if (worldName == null || worldName.isEmpty()) { return null; @@ -450,7 +504,8 @@ public class EssentialsUpgrade { if (world == null) { return null; } - return new Location(world, config.getDouble((path != null ? path + "." : "") + "x", 0), config.getDouble((path != null ? path + "." : "") + "y", 0), config.getDouble((path != null ? path + "." : "") + "z", 0), (float) config.getDouble((path != null ? path + "." : "") + "yaw", 0), (float) config.getDouble((path != null ? path + "." : "") + "pitch", 0)); + return new Location(world, config.node("x").getDouble(0), config.node("y").getDouble(0), + config.node("z").getDouble(0), config.node("yaw").getFloat(0), config.node("pitch").getFloat(0)); } private void deleteOldItemsCsv() { @@ -493,22 +548,18 @@ public class EssentialsUpgrade { final File configFile = new File(ess.getDataFolder(), "spawn.yml"); if (configFile.exists()) { - final EssentialsConf config = new EssentialsConf(configFile); + final EssentialsConfiguration config = new EssentialsConfiguration(configFile); try { config.load(); if (!config.hasProperty("spawns")) { - final Spawns spawns = new Spawns(); - final Set keys = config.getKeys(false); - for (final String group : keys) { - final Location loc = getFakeLocation(config, group); - spawns.getSpawns().put(group.toLowerCase(Locale.ENGLISH), loc); + for (final Map.Entry entry : config.getMap().entrySet()) { + final Location loc = getFakeLocation(entry.getValue(), entry.getKey()); + config.setProperty(entry.getKey(), loc); } if (!configFile.renameTo(new File(ess.getDataFolder(), "spawn.yml.old"))) { throw new Exception(tl("fileRenameError", "spawn.yml")); } - try (final PrintWriter writer = new PrintWriter(configFile)) { - new YamlStorageWriter(writer).save(spawns); - } + config.blockingSave(); } } catch (final Exception ex) { Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); @@ -525,22 +576,18 @@ public class EssentialsUpgrade { final File configFile = new File(ess.getDataFolder(), "jail.yml"); if (configFile.exists()) { - final EssentialsConf config = new EssentialsConf(configFile); + final EssentialsConfiguration config = new EssentialsConfiguration(configFile); try { config.load(); if (!config.hasProperty("jails")) { - final com.earth2me.essentials.settings.Jails jails = new com.earth2me.essentials.settings.Jails(); - final Set keys = config.getKeys(false); - for (final String jailName : keys) { - final Location loc = getFakeLocation(config, jailName); - jails.getJails().put(jailName.toLowerCase(Locale.ENGLISH), loc); + for (final Map.Entry entry : config.getMap().entrySet()) { + final Location loc = getFakeLocation(entry.getValue(), entry.getKey()); + config.setProperty(entry.getKey(), loc); } if (!configFile.renameTo(new File(ess.getDataFolder(), "jail.yml.old"))) { throw new Exception(tl("fileRenameError", "jail.yml")); } - try (final PrintWriter writer = new PrintWriter(configFile)) { - new YamlStorageWriter(writer).save(jails); - } + config.blockingSave(); } } catch (final Exception ex) { Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); @@ -641,23 +688,23 @@ public class EssentialsUpgrade { countFiles++; final File pFile = new File(userdir, string); - final EssentialsConf conf = new EssentialsConf(pFile); + final EssentialsConfiguration conf = new EssentialsConfiguration(pFile); conf.load(); - String banReason; + final String banReason; long banTimeout; - try { - banReason = conf.getConfigurationSection("ban").getString("reason"); - } catch (final NullPointerException n) { + if (conf.hasProperty("ban.reason")) { + banReason = conf.getString("ban.reason", null); + } else { banReason = null; } - final String playerName = conf.getString("lastAccountName"); + final String playerName = conf.getString("lastAccountName", null); if (playerName != null && playerName.length() > 1 && banReason != null && banReason.length() > 1) { try { - if (conf.getConfigurationSection("ban").contains("timeout")) { - banTimeout = Long.parseLong(conf.getConfigurationSection("ban").getString("timeout")); + if (conf.hasProperty("ban.timeout")) { + banTimeout = Long.parseLong(conf.getString("ban.timeout", null)); } else { banTimeout = 0L; } @@ -772,5 +819,6 @@ public class EssentialsUpgrade { warnMetrics(); repairUserMap(); convertIgnoreList(); + convertStupidCamelCaseUserdataKeys(); } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/ISettings.java b/Essentials/src/main/java/com/earth2me/essentials/ISettings.java index 54f2a4cc6..13cfeff48 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/ISettings.java +++ b/Essentials/src/main/java/com/earth2me/essentials/ISettings.java @@ -4,8 +4,8 @@ import com.earth2me.essentials.commands.IEssentialsCommand; import com.earth2me.essentials.signs.EssentialsSign; import com.earth2me.essentials.textreader.IText; import org.bukkit.Material; -import org.bukkit.configuration.ConfigurationSection; import org.bukkit.event.EventPriority; +import org.spongepowered.configurate.CommentedConfigurationNode; import java.math.BigDecimal; import java.text.NumberFormat; @@ -65,26 +65,8 @@ public interface ISettings extends IConf { Set getMuteCommands(); - /** - * @Deprecated in favor of {@link Kits#getKits()} - */ @Deprecated - ConfigurationSection getKits(); - - /** - * @Deprecated in favor of {@link Kits#getKit(String)} - */ - @Deprecated - Map getKit(String kit); - - /** - * @Deprecated in favor of {@link Kits#addKit(String, List, long)}} - */ - @Deprecated - void addKit(String name, List lines, long delay); - - @Deprecated - ConfigurationSection getKitSection(); + CommentedConfigurationNode getKitSection(); boolean isSkippingUsedOneTimeKitsFromKitList(); diff --git a/Essentials/src/main/java/com/earth2me/essentials/IUser.java b/Essentials/src/main/java/com/earth2me/essentials/IUser.java index 0cf40706f..42040f93d 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/IUser.java +++ b/Essentials/src/main/java/com/earth2me/essentials/IUser.java @@ -2,6 +2,7 @@ package com.earth2me.essentials; import com.earth2me.essentials.api.IAsyncTeleport; import com.earth2me.essentials.commands.IEssentialsCommand; +import com.earth2me.essentials.config.entities.CommandCooldown; import net.ess3.api.ITeleport; import net.ess3.api.MaxMoneyException; import net.ess3.api.events.AfkStatusChangeEvent; @@ -160,6 +161,7 @@ public interface IUser { void setIgnoreMsg(boolean ignoreMsg); + @Deprecated void setConfigProperty(String node, Object object); Set getConfigKeys(); @@ -168,8 +170,11 @@ public interface IUser { Map getConfigMap(String node); + @Deprecated Map getCommandCooldowns(); + List getCooldownsList(); + Date getCommandCooldownExpiry(String label); void addCommandCooldown(Pattern pattern, Date expiresAt, boolean save); diff --git a/Essentials/src/main/java/com/earth2me/essentials/Jails.java b/Essentials/src/main/java/com/earth2me/essentials/Jails.java index b78ff0345..f91f24ed5 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Jails.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Jails.java @@ -1,10 +1,12 @@ package com.earth2me.essentials; -import com.earth2me.essentials.storage.AsyncStorageObjectHolder; +import com.earth2me.essentials.config.ConfigurateUtil; +import com.earth2me.essentials.config.EssentialsConfiguration; import net.ess3.api.IEssentials; import net.ess3.api.IUser; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -23,28 +25,58 @@ import org.bukkit.event.player.PlayerRespawnEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.plugin.PluginManager; +import org.spongepowered.configurate.CommentedConfigurationNode; import java.io.File; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.Locale; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.logging.Level; import java.util.logging.Logger; import static com.earth2me.essentials.I18n.tl; -public class Jails extends AsyncStorageObjectHolder implements net.ess3.api.IJails { - private static final transient Logger LOGGER = Bukkit.getLogger(); +public class Jails implements net.ess3.api.IJails { + private static final transient Logger LOGGER = Logger.getLogger("Essentials"); private static transient boolean enabled = false; + private final IEssentials ess; + private final EssentialsConfiguration config; + private final Map jails = new HashMap<>(); public Jails(final IEssentials ess) { - super(ess, com.earth2me.essentials.settings.Jails.class); + this.ess = ess; + this.config = new EssentialsConfiguration(new File(ess.getDataFolder(), "jail.yml")); reloadConfig(); } + @Override + public void reloadConfig() { + synchronized (jails) { + config.load(); + jails.clear(); + final CommentedConfigurationNode jailsNode = config.getSection("jails"); + for (final Map.Entry entry : ConfigurateUtil.getMap(jailsNode).entrySet()) { + final CommentedConfigurationNode jailNode = entry.getValue(); + final String worldName = jailNode.node("world").getString(); + if (worldName == null || worldName.isEmpty()) { + continue; + } + + final World world = Bukkit.getWorld(worldName); + if (world == null) { + LOGGER.log(Level.WARNING, "Invalid world name, " + worldName + ", for jail name " + entry.getKey()); + continue; + } + jails.put(entry.getKey().toLowerCase(Locale.ENGLISH), new Location(world, jailNode.node("x").getDouble(), jailNode.node("y").getDouble(), + jailNode.node("z").getDouble(), jailNode.node("yaw").getFloat(), jailNode.node("pitch").getFloat())); + } + checkRegister(); + } + } + private void registerListeners() { enabled = true; final PluginManager pluginManager = ess.getServer().getPluginManager(); @@ -55,21 +87,6 @@ public class Jails extends AsyncStorageObjectHolder getList() throws Exception { - acquireReadLock(); - try { - if (getData().getJails() == null) { - return Collections.emptyList(); - } - return new ArrayList<>(getData().getJails().keySet()); - } finally { - unlock(); + synchronized (jails) { + return new ArrayList<>(jails.keySet()); } } @Override - public void removeJail(final String jail) throws Exception { - acquireWriteLock(); - try { - if (getData().getJails() == null) { - return; + public void removeJail(String jail) throws Exception { + if (jail == null) { + return; + } + + jail = jail.toLowerCase(Locale.ENGLISH); + synchronized (jails) { + if (jails.remove(jail) != null) { + config.getSection("jails").node(jail).set(null); + config.save(); } - getData().getJails().remove(jail.toLowerCase(Locale.ENGLISH)); - } finally { - unlock(); } } /** * @deprecated This method does not use asynchronous teleportation. Use {@link Jails#sendToJail(IUser, String, CompletableFuture)} */ + @SuppressWarnings("deprecation") @Override @Deprecated - public void sendToJail(final IUser user, final String jail) throws Exception { - acquireReadLock(); - try { - if (user.getBase().isOnline()) { - final Location loc = getJail(jail); - user.getTeleport().now(loc, false, TeleportCause.COMMAND); + public void sendToJail(final IUser user, String jail) throws Exception { + if (jail == null || jail.isEmpty()) { + return; + } + + jail = jail.toLowerCase(Locale.ENGLISH); + synchronized (jails) { + if (jails.containsKey(jail)) { + if (user.getBase().isOnline()) { + user.getTeleport().now(jails.get(jail), false, TeleportCause.COMMAND); + } + user.setJail(jail); } - user.setJail(jail); - } finally { - unlock(); } } @Override - public void sendToJail(final IUser user, final String jail, final CompletableFuture future) throws Exception { - acquireReadLock(); - try { - if (user.getBase().isOnline()) { - final Location loc = getJail(jail); - user.getAsyncTeleport().now(loc, false, TeleportCause.COMMAND, future); - future.thenAccept(success -> user.setJail(jail)); - return; + public void sendToJail(final IUser user, final String jailName, final CompletableFuture future) throws Exception { + if (jailName == null || jailName.isEmpty()) { + return; + } + + final String jail = jailName.toLowerCase(Locale.ENGLISH); + synchronized (jails) { + if (jails.containsKey(jail)) { + if (user.getBase().isOnline()) { + user.getAsyncTeleport().now(jails.get(jail), false, TeleportCause.COMMAND, future); + future.thenAccept(success -> user.setJail(jail)); + return; + } + user.setJail(jail); } - user.setJail(jail); - } finally { - unlock(); } } @Override - public void setJail(final String jailName, final Location loc) throws Exception { - acquireWriteLock(); - try { - if (getData().getJails() == null) { - getData().setJails(new HashMap<>()); - } - getData().getJails().put(jailName.toLowerCase(Locale.ENGLISH), loc); - } finally { - unlock(); + public void setJail(String jailName, final Location loc) throws Exception { + jailName = jailName.toLowerCase(Locale.ENGLISH); + synchronized (jails) { + jails.put(jailName, loc); + config.setProperty("jails." + jailName, loc); + config.save(); } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/Kits.java b/Essentials/src/main/java/com/earth2me/essentials/Kits.java index 19c0c7b95..5cb419bab 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Kits.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Kits.java @@ -1,8 +1,10 @@ package com.earth2me.essentials; +import com.earth2me.essentials.config.ConfigurateUtil; +import com.earth2me.essentials.config.EssentialsConfiguration; import com.earth2me.essentials.utils.NumberUtil; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.MemoryConfiguration; +import org.spongepowered.configurate.CommentedConfigurationNode; +import org.spongepowered.configurate.serialize.SerializationException; import java.io.File; import java.math.BigDecimal; @@ -14,13 +16,11 @@ import static com.earth2me.essentials.I18n.capitalCase; import static com.earth2me.essentials.I18n.tl; public class Kits implements IConf { - - private final EssentialsConf config; - private ConfigurationSection kits; + private final EssentialsConfiguration config; + private CommentedConfigurationNode kits; public Kits(final IEssentials essentials) { - config = new EssentialsConf(new File(essentials.getDataFolder(), "kits.yml")); - config.setTemplateName("/kits.yml"); + config = new EssentialsConfiguration(new File(essentials.getDataFolder(), "kits.yml"), "/kits.yml"); reloadConfig(); } @@ -31,13 +31,18 @@ public class Kits implements IConf { kits = _getKits(); } - private ConfigurationSection _getKits() { - if (config.isConfigurationSection("kits")) { - final ConfigurationSection section = config.getConfigurationSection("kits"); - final ConfigurationSection newSection = new MemoryConfiguration(); - for (final String kitItem : section.getKeys(false)) { - if (section.isConfigurationSection(kitItem)) { - newSection.set(kitItem.toLowerCase(Locale.ENGLISH), section.getConfigurationSection(kitItem)); + private CommentedConfigurationNode _getKits() { + final CommentedConfigurationNode section = config.getSection("kits"); + if (section != null) { + final CommentedConfigurationNode newSection = config.newSection(); + for (final String kitItem : ConfigurateUtil.getKeys(section)) { + final CommentedConfigurationNode kitSection = section.node(kitItem); + if (kitSection.isMap()) { + try { + newSection.node(kitItem.toLowerCase(Locale.ENGLISH)).set(kitSection); + } catch (SerializationException e) { + e.printStackTrace(); + } } } return newSection; @@ -45,25 +50,23 @@ public class Kits implements IConf { return null; } - public EssentialsConf getConfig() { + public EssentialsConfiguration getConfig() { return config; } - public ConfigurationSection getKits() { + public CommentedConfigurationNode getKits() { return kits; } public Map getKit(String name) { name = name.replace('.', '_').replace('/', '_'); if (getKits() != null) { - final ConfigurationSection kits = getKits(); - // For some reason, YAML doesn't sees keys as always lowercase even if they aren't defined like that. - // Workaround is to toLowercase when getting from the config, but showing normally elsewhere. - // ODDLY ENOUGH when you get the configuration section for ALL kits, it will return the proper - // case of each kit. But when you check for each kit's configuration section, it won't return the kit - // you just found if you don't toLowercase it. - if (kits.isConfigurationSection(name.toLowerCase())) { - return kits.getConfigurationSection(name.toLowerCase()).getValues(true); + final CommentedConfigurationNode kits = getKits(); + // Other parts of the codebase/3rd party plugins expect us to lowercase kit names here. + // This isn't strictly needed for the future of Essentials, but for compatibility it's here. + final CommentedConfigurationNode kitSection = kits.node(name.toLowerCase()); + if (!kitSection.virtual() && kitSection.isMap()) { + return ConfigurateUtil.getRawMap(kitSection); } } @@ -72,13 +75,11 @@ public class Kits implements IConf { // Tries to find an existing kit name that matches the given name, ignoring case. Returns null if no match. public String matchKit(final String name) { - if (config.isConfigurationSection("kits")) { - final ConfigurationSection section = config.getConfigurationSection("kits"); - if (section != null) { - for (final String kitName : section.getKeys(false)) { - if (kitName.equalsIgnoreCase(name)) { - return kitName; - } + final CommentedConfigurationNode section = config.getSection("kits"); + if (section != null) { + for (final String kitName : ConfigurateUtil.getKeys(section)) { + if (kitName.equalsIgnoreCase(name)) { + return kitName; } } } @@ -87,23 +88,23 @@ public class Kits implements IConf { public void addKit(final String name, final List lines, final long delay) { // Will overwrite but w/e - config.set("kits." + name + ".delay", delay); - config.set("kits." + name + ".items", lines); + config.setProperty("kits." + name + ".delay", delay); + config.setProperty("kits." + name + ".items", lines); kits = _getKits(); config.save(); } public void removeKit(final String name) { - config.set("kits." + name, null); + config.removeProperty("kits." + name); kits = _getKits(); config.save(); } public String listKits(final net.ess3.api.IEssentials ess, final User user) throws Exception { try { - final ConfigurationSection kits = config.getConfigurationSection("kits"); + final CommentedConfigurationNode kits = config.getSection("kits"); final StringBuilder list = new StringBuilder(); - for (final String kitItem : kits.getKeys(false)) { + for (final String kitItem : ConfigurateUtil.getKeys(kits)) { if (user == null) { list.append(" ").append(capitalCase(kitItem)); } else if (user.isAuthorized("essentials.kits." + kitItem.toLowerCase(Locale.ENGLISH))) { diff --git a/Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java b/Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java index d9e928858..d830a1bf2 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java +++ b/Essentials/src/main/java/com/earth2me/essentials/RandomTeleport.java @@ -1,5 +1,6 @@ package com.earth2me.essentials; +import com.earth2me.essentials.config.EssentialsConfiguration; import com.earth2me.essentials.utils.LocationUtil; import com.earth2me.essentials.utils.VersionUtil; import io.papermc.lib.PaperLib; @@ -21,15 +22,13 @@ public class RandomTeleport implements IConf { private static final Random RANDOM = new Random(); private static final int HIGHEST_BLOCK_Y_OFFSET = VersionUtil.getServerBukkitVersion().isHigherThanOrEqualTo(VersionUtil.v1_15_R01) ? 1 : 0; private final IEssentials essentials; - private final EssentialsConf config; + private final EssentialsConfiguration config; private final ConcurrentLinkedQueue cachedLocations = new ConcurrentLinkedQueue<>(); public RandomTeleport(final IEssentials essentials) { this.essentials = essentials; - final File file = new File(essentials.getDataFolder(), "tpr.yml"); - config = new EssentialsConf(file); - config.setTemplateName("/tpr.yml"); - config.options().copyHeader(true); + config = new EssentialsConfiguration(new File(essentials.getDataFolder(), "tpr.yml"), "/tpr.yml", + "Configuration for the random teleport command.\nSome settings may be defaulted, and can be changed via the /settpr command in-game."); reloadConfig(); } @@ -41,7 +40,7 @@ public class RandomTeleport implements IConf { public Location getCenter() { try { - final Location center = config.getLocation("center", essentials.getServer()); + final Location center = config.getLocation("center"); if (center != null) { return center; } @@ -77,7 +76,7 @@ public class RandomTeleport implements IConf { } public Set getExcludedBiomes() { - final List biomeNames = config.getStringList("excluded-biomes"); + final List biomeNames = config.getList("excluded-biomes", String.class); final Set excludedBiomes = new HashSet<>(); for (final String biomeName : biomeNames) { try { diff --git a/Essentials/src/main/java/com/earth2me/essentials/Settings.java b/Essentials/src/main/java/com/earth2me/essentials/Settings.java index 57a4db231..4efe62276 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Settings.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Settings.java @@ -2,6 +2,8 @@ package com.earth2me.essentials; import com.earth2me.essentials.api.IItemDb; import com.earth2me.essentials.commands.IEssentialsCommand; +import com.earth2me.essentials.config.ConfigurateUtil; +import com.earth2me.essentials.config.EssentialsConfiguration; import com.earth2me.essentials.signs.EssentialsSign; import com.earth2me.essentials.signs.Signs; import com.earth2me.essentials.textreader.IText; @@ -14,10 +16,9 @@ import net.ess3.api.IEssentials; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.command.Command; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.MemoryConfiguration; import org.bukkit.event.EventPriority; import org.bukkit.inventory.ItemStack; +import org.spongepowered.configurate.CommentedConfigurationNode; import java.io.File; import java.math.BigDecimal; @@ -49,7 +50,7 @@ public class Settings implements net.ess3.api.ISettings { private static final Logger logger = Logger.getLogger("Essentials"); private static final BigDecimal MAXMONEY = new BigDecimal("10000000000000"); private static final BigDecimal MINMONEY = new BigDecimal("-10000000000000"); - private final transient EssentialsConf config; + private final transient EssentialsConfiguration config; private final transient IEssentials ess; private final transient AtomicInteger reloadCount = new AtomicInteger(0); private final Map chatFormats = Collections.synchronizedMap(new HashMap<>()); @@ -62,7 +63,7 @@ public class Settings implements net.ess3.api.ISettings { private boolean forceDisableTeleportSafety; private Set disabledCommands = new HashSet<>(); private final transient Map disabledBukkitCommands = new HashMap<>(); - private ConfigurationSection commandCosts; + private Map commandCosts; private Set socialSpyCommands = new HashSet<>(); private Set muteCommands = new HashSet<>(); private String nicknamePrefix = "~"; @@ -125,7 +126,6 @@ public class Settings implements net.ess3.api.ISettings { private boolean isCompassTowardsHomePerm; private boolean isAllowWorldInBroadcastworld; private String itemDbType; // #EasterEgg - admins can manually switch items provider if they want - private boolean forceEnableRecipe; // https://github.com/EssentialsX/Essentials/issues/1397 private boolean allowOldIdSigns; private boolean isWaterSafe; private boolean isSafeUsermap; @@ -137,8 +137,7 @@ public class Settings implements net.ess3.api.ISettings { public Settings(final IEssentials ess) { this.ess = ess; - config = new EssentialsConf(new File(ess.getDataFolder(), "config.yml")); - config.setTemplateName("/config.yml"); + config = new EssentialsConfiguration(new File(ess.getDataFolder(), "config.yml"), "/config.yml"); reloadConfig(); } @@ -159,8 +158,8 @@ public class Settings implements net.ess3.api.ISettings { @Override public Set getMultipleHomes() { - final ConfigurationSection section = config.getConfigurationSection("sethome-multiple"); - return section == null ? null : section.getKeys(false); + final CommentedConfigurationNode section = config.getSection("sethome-multiple"); + return section == null ? null : ConfigurateUtil.getKeys(section); } @Override @@ -305,10 +304,10 @@ public class Settings implements net.ess3.api.ISettings { private Set _getDisabledCommands() { final Set disCommands = new HashSet<>(); - for (final String c : config.getStringList("disabled-commands")) { + for (final String c : config.getList("disabled-commands", String.class)) { disCommands.add(c.toLowerCase(Locale.ENGLISH)); } - for (final String c : config.getKeys(false)) { + for (final String c : config.getKeys()) { if (c.startsWith("disable-")) { disCommands.add(c.substring(8).toLowerCase(Locale.ENGLISH)); } @@ -318,7 +317,7 @@ public class Settings implements net.ess3.api.ISettings { @Override public boolean isPlayerCommand(final String label) { - for (final String c : config.getStringList("player-commands")) { + for (final String c : config.getList("player-commands", String.class)) { if (!c.equalsIgnoreCase(label)) { continue; } @@ -329,7 +328,7 @@ public class Settings implements net.ess3.api.ISettings { @Override public boolean isCommandOverridden(final String name) { - for (final String c : config.getStringList("overridden-commands")) { + for (final String c : config.getList("overridden-commands", String.class)) { if (!c.equalsIgnoreCase(name)) { continue; } @@ -343,32 +342,34 @@ public class Settings implements net.ess3.api.ISettings { return getCommandCost(cmd.getName()); } - private ConfigurationSection _getCommandCosts() { - if (config.isConfigurationSection("command-costs")) { - final ConfigurationSection section = config.getConfigurationSection("command-costs"); - final ConfigurationSection newSection = new MemoryConfiguration(); - for (final String command : section.getKeys(false)) { + private Map _getCommandCosts() { + final Map section = ConfigurateUtil.getMap(config.getSection("command-costs")); + if (!section.isEmpty()) { + final Map newMap = new HashMap<>(); + for (Map.Entry entry : section.entrySet()) { + final String command = entry.getKey(); + final CommentedConfigurationNode node = entry.getValue(); if (command.charAt(0) == '/') { ess.getLogger().warning("Invalid command cost. '" + command + "' should not start with '/'."); } - if (section.isDouble(command)) { - newSection.set(command.toLowerCase(Locale.ENGLISH), section.getDouble(command)); - } else if (section.isInt(command)) { - newSection.set(command.toLowerCase(Locale.ENGLISH), (double) section.getInt(command)); - } else if (section.isString(command)) { - final String costString = section.getString(command); - try { + try { + if (ConfigurateUtil.isDouble(node)) { + newMap.put(command.toLowerCase(Locale.ENGLISH), BigDecimal.valueOf(node.getDouble())); + } else if (ConfigurateUtil.isInt(node)) { + newMap.put(command.toLowerCase(Locale.ENGLISH), BigDecimal.valueOf(node.getInt())); + } else if (ConfigurateUtil.isString(node)) { + final String costString = node.getString(); + //noinspection ConstantConditions final double cost = Double.parseDouble(costString.trim().replace("$", "").replace(getCurrencySymbol(), "").replaceAll("\\W", "")); - newSection.set(command.toLowerCase(Locale.ENGLISH), cost); - } catch (final NumberFormatException ex) { - ess.getLogger().warning("Invalid command cost for: " + command + " (" + costString + ")"); + newMap.put(command.toLowerCase(Locale.ENGLISH), BigDecimal.valueOf(cost)); + } else { + ess.getLogger().warning("Invalid command cost for: " + command); } - - } else { + } catch (final Exception ex) { ess.getLogger().warning("Invalid command cost for: " + command); } } - return newSection; + return newMap; } return null; } @@ -376,8 +377,8 @@ public class Settings implements net.ess3.api.ISettings { @Override public BigDecimal getCommandCost(String name) { name = name.replace('.', '_').replace('/', '_'); - if (commandCosts != null) { - return EssentialsConf.toBigDecimal(commandCosts.getString(name), BigDecimal.ZERO); + if (commandCosts != null && commandCosts.containsKey(name)) { + return commandCosts.get(name); } return BigDecimal.ZERO; } @@ -386,7 +387,7 @@ public class Settings implements net.ess3.api.ISettings { final Set socialspyCommands = new HashSet<>(); if (config.isList("socialspy-commands")) { - for (final String c : config.getStringList("socialspy-commands")) { + for (final String c : config.getList("socialspy-commands", String.class)) { socialspyCommands.add(c.toLowerCase(Locale.ENGLISH)); } } else { @@ -414,7 +415,7 @@ public class Settings implements net.ess3.api.ISettings { private Set _getMuteCommands() { final Set muteCommands = new HashSet<>(); if (config.isList("mute-commands")) { - for (final String s : config.getStringList("mute-commands")) { + for (final String s : config.getList("mute-commands", String.class)) { muteCommands.add(s.toLowerCase(Locale.ENGLISH)); } } @@ -447,23 +448,8 @@ public class Settings implements net.ess3.api.ISettings { } @Override - public ConfigurationSection getKits() { - return ess.getKits().getKits(); - } - - @Override - public Map getKit(final String name) { - return ess.getKits().getKit(name); - } - - @Override - public void addKit(final String name, final List lines, final long delay) { - ess.getKits().addKit(name, lines, delay); - } - - @Override - public ConfigurationSection getKitSection() { - return config.getConfigurationSection("kits"); + public CommentedConfigurationNode getKitSection() { + return config.getSection("kits"); } @Override @@ -577,13 +563,13 @@ public class Settings implements net.ess3.api.ISettings { private Map _getWorldAliases() { final Map map = new HashMap<>(); - final ConfigurationSection section = config.getConfigurationSection("chat.world-aliases"); + final CommentedConfigurationNode section = config.getSection("chat.world-aliases"); if (section == null) { return map; } - for (String world : section.getKeys(false)) { - map.put(world.toLowerCase(), FormatUtil.replaceFormat(section.getString(world))); + for (Map.Entry entry : ConfigurateUtil.getMap(section).entrySet()) { + map.put(entry.getKey().toLowerCase(), FormatUtil.replaceFormat(entry.getValue().getString())); } return map; } @@ -615,8 +601,9 @@ public class Settings implements net.ess3.api.ISettings { @Override public Map getListGroupConfig() { - if (config.isConfigurationSection("list")) { - final Map values = config.getConfigurationSection("list").getValues(false); + final CommentedConfigurationNode node = config.getSection("list"); + if (node.isMap()) { + final Map values = ConfigurateUtil.getRawMap(node); if (!values.isEmpty()) { return values; } @@ -633,7 +620,7 @@ public class Settings implements net.ess3.api.ISettings { @Override public void reloadConfig() { config.load(); - noGodWorlds = new HashSet<>(config.getStringList("no-god-in-worlds")); + noGodWorlds = new HashSet<>(config.getList("no-god-in-worlds", String.class)); enabledSigns = _getEnabledSigns(); teleportSafety = _isTeleportSafetyEnabled(); forceDisableTeleportSafety = _isForceDisableTeleportSafety(); @@ -767,6 +754,7 @@ public class Settings implements net.ess3.api.ISettings { private List _getItemSpawnBlacklist() { final List epItemSpwn = new ArrayList<>(); + //noinspection deprecation final IItemDb itemDb = ess.getItemDb(); if (itemDb == null || !itemDb.isReady()) { logger.log(Level.FINE, "Skipping item spawn blacklist read; item DB not yet loaded."); @@ -797,7 +785,7 @@ public class Settings implements net.ess3.api.ISettings { final List newSigns = new ArrayList<>(); - for (String signName : config.getStringList("enabledSigns")) { + for (String signName : config.getList("enabledSigns", String.class)) { signName = signName.trim().toUpperCase(Locale.ENGLISH); if (signName.isEmpty()) { continue; @@ -1463,12 +1451,12 @@ public class Settings implements net.ess3.api.ISettings { public List _getSpawnOnJoinGroups() { final List def = Collections.emptyList(); - if (config.isSet("spawn-on-join")) { + if (config.hasProperty("spawn-on-join")) { if (config.isList("spawn-on-join")) { - return new ArrayList<>(config.getStringList("spawn-on-join")); + return new ArrayList<>(config.getList("spawn-on-join", String.class)); } else if (config.isBoolean("spawn-on-join")) { // List of [*] to make all groups go to spawn on join. // This also maintains backwards compatibility with initial impl of single boolean value. - return config.getBoolean("spawn-on-join") ? Collections.singletonList("*") : def; + return config.getBoolean("spawn-on-join", true) ? Collections.singletonList("*") : def; } // Take whatever the value is, convert to string and add it to a list as a single value. final String val = config.get("spawn-on-join").toString(); @@ -1484,7 +1472,7 @@ public class Settings implements net.ess3.api.ISettings { } @Override - public boolean isUserInSpawnOnJoinGroup(final IUser user) { + public boolean isUserInSpawnOnJoinGroup(@SuppressWarnings("deprecation") final IUser user) { for (final String group : this.spawnOnJoinGroups) { if (group.equals("*") || user.inGroup(group)) { return true; @@ -1499,12 +1487,14 @@ public class Settings implements net.ess3.api.ISettings { } private Map _getCommandCooldowns() { - if (!config.isConfigurationSection("command-cooldowns")) { + final CommentedConfigurationNode section = config.getSection("command-cooldowns"); + if (section == null) { return null; } - final ConfigurationSection section = config.getConfigurationSection("command-cooldowns"); final Map result = new LinkedHashMap<>(); - for (String cmdEntry : section.getKeys(false)) { + for (Map.Entry entry : ConfigurateUtil.getRawMap(section).entrySet()) { + String cmdEntry = entry.getKey(); + Object value = entry.getValue(); Pattern pattern = null; /* ================================ @@ -1522,14 +1512,13 @@ public class Settings implements net.ess3.api.ISettings { cmdEntry = cmdEntry.substring(1); } final String cmd = cmdEntry - .replaceAll("\\*", ".*"); // Wildcards are accepted as asterisk * as known universally. + .replaceAll("\\*", ".*"); // Wildcards are accepted as asterisk * as known universally. pattern = Pattern.compile(cmd + "( .*)?"); // This matches arguments, if present, to "ignore" them from the feature. } /* ================================ * >> Process cooldown value * ================================ */ - Object value = section.get(cmdEntry); if (value instanceof String) { try { value = Double.parseDouble(value.toString()); @@ -1597,7 +1586,7 @@ public class Settings implements net.ess3.api.ISettings { private NumberFormat _getCurrencyFormat() { final String currencyFormatString = config.getString("currency-format", "#,##0.00"); - final String symbolLocaleString = config.getString("currency-symbol-format-locale"); + final String symbolLocaleString = config.getString("currency-symbol-format-locale", null); final DecimalFormatSymbols decimalFormatSymbols; if (symbolLocaleString != null) { decimalFormatSymbols = DecimalFormatSymbols.getInstance(Locale.forLanguageTag(symbolLocaleString)); @@ -1627,7 +1616,7 @@ public class Settings implements net.ess3.api.ISettings { private List _getUnprotectedSign() { final List newSigns = new ArrayList<>(); - for (String signName : config.getStringList("unprotected-sign-names")) { + for (String signName : config.getList("unprotected-sign-names", String.class)) { signName = signName.trim().toUpperCase(Locale.ENGLISH); if (signName.isEmpty()) { continue; @@ -1697,7 +1686,7 @@ public class Settings implements net.ess3.api.ISettings { } private List _getDefaultEnabledConfirmCommands() { - final List commands = config.getStringList("default-enabled-confirm-commands"); + final List commands = config.getList("default-enabled-confirm-commands", String.class); for (int i = 0; i < commands.size(); i++) { commands.set(i, commands.get(i).toLowerCase()); } @@ -1797,7 +1786,7 @@ public class Settings implements net.ess3.api.ISettings { private Set> _getNickBlacklist() { final Set> blacklist = new HashSet<>(); - config.getStringList("nick-blacklist").forEach(entry -> { + config.getList("nick-blacklist", String.class).forEach(entry -> { try { blacklist.add(Pattern.compile(entry).asPredicate()); } catch (final PatternSyntaxException e) { diff --git a/Essentials/src/main/java/com/earth2me/essentials/UserData.java b/Essentials/src/main/java/com/earth2me/essentials/UserData.java index d7d035b6d..4db5bfc25 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/UserData.java +++ b/Essentials/src/main/java/com/earth2me/essentials/UserData.java @@ -1,77 +1,40 @@ package com.earth2me.essentials; +import com.earth2me.essentials.config.ConfigurateUtil; +import com.earth2me.essentials.config.EssentialsUserConfiguration; +import com.earth2me.essentials.config.entities.CommandCooldown; +import com.earth2me.essentials.config.holders.UserConfigHolder; import com.earth2me.essentials.utils.NumberUtil; import com.earth2me.essentials.utils.StringUtil; import com.google.common.base.Charsets; -import com.google.common.collect.ImmutableMap; import net.ess3.api.IEssentials; -import net.ess3.api.InvalidWorldException; import net.ess3.api.MaxMoneyException; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.spongepowered.configurate.serialize.SerializationException; import java.io.File; import java.math.BigDecimal; import java.util.ArrayList; -import java.util.Collections; import java.util.Date; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.UUID; +import java.util.logging.Level; import java.util.regex.Pattern; -import java.util.stream.Collectors; import static com.earth2me.essentials.I18n.tl; public abstract class UserData extends PlayerExtension implements IConf { protected final transient IEssentials ess; - private final EssentialsUserConf config; + private final EssentialsUserConfiguration config; + private UserConfigHolder holder; private BigDecimal money; - private Map homes; - private String nickname; - private Set unlimited; - private Map powertools; - private Location lastLocation; - private Location logoutLocation; - private long lastTeleportTimestamp; - private long lastHealTimestamp; - private String jail; - private List mails; - private boolean teleportEnabled; - private boolean autoTeleportEnabled; - private List ignoredPlayers; - private boolean godmode; - private boolean muted; - private String muteReason; - private long muteTimeout; - private boolean jailed; - private long jailTimeout; - private long lastLogin; - private long lastLogout; - private String lastLoginAddress; - private boolean afk; - private boolean newplayer; - private String geolocation; - private boolean isSocialSpyEnabled; - private boolean isNPC; - private String lastAccountName = null; - private boolean arePowerToolsEnabled; - private Map kitTimestamps; - // Pattern, Date. Pattern for less pattern creations - private Map commandCooldowns; - private boolean acceptingPay = true; // players accept pay by default - private Boolean confirmPay; - private Boolean confirmClear; - private boolean lastMessageReplyRecipient; - private boolean baltopExemptCache; protected UserData(final Player base, final IEssentials ess) { super(base); @@ -89,69 +52,48 @@ public abstract class UserData extends PlayerExtension implements IConf { filename = base.getName(); } - config = new EssentialsUserConf(base.getName(), base.getUniqueId(), new File(folder, filename + ".yml")); + config = new EssentialsUserConfiguration(base.getName(), base.getUniqueId(), new File(folder, filename + ".yml")); reloadConfig(); - if (config.username == null) { + if (config.getUsername() == null) { config.setUsername(getLastAccountName()); } } public final void reset() { - config.forceSave(); + config.blockingSave(); config.getFile().delete(); - if (config.username != null) { - ess.getUserMap().removeUser(config.username); + if (config.getUsername() != null) { + ess.getUserMap().removeUser(config.getUsername()); if (isNPC()) { - final String uuid = UUID.nameUUIDFromBytes(("NPC:" + config.username).getBytes(Charsets.UTF_8)).toString(); + final String uuid = UUID.nameUUIDFromBytes(("NPC:" + config.getUsername()).getBytes(Charsets.UTF_8)).toString(); ess.getUserMap().removeUserUUID(uuid); } } } public final void cleanup() { - config.cleanup(); + config.blockingSave(); } @Override public final void reloadConfig() { config.load(); + try { + holder = config.getRootNode().get(UserConfigHolder.class); + } catch (SerializationException e) { + ess.getLogger().log(Level.SEVERE, "Error while reading user config: " + e.getMessage(), e); + throw new RuntimeException(e); + } + config.setSaveHook(() -> { + try { + config.getRootNode().set(UserConfigHolder.class, holder); + } catch (SerializationException e) { + ess.getLogger().log(Level.SEVERE, "Error while saving user config: " + e.getMessage(), e); + throw new RuntimeException(e); + } + }); money = _getMoney(); - unlimited = _getUnlimited(); - powertools = _getPowertools(); - homes = _getHomes(); - lastLocation = _getLastLocation(); - lastTeleportTimestamp = _getLastTeleportTimestamp(); - lastHealTimestamp = _getLastHealTimestamp(); - jail = _getJail(); - mails = _getMails(); - teleportEnabled = _getTeleportEnabled(); - godmode = _getGodModeEnabled(); - muted = _getMuted(); - muteTimeout = _getMuteTimeout(); - muteReason = _getMuteReason(); - jailed = _getJailed(); - jailTimeout = _getJailTimeout(); - onlineJailed = _getOnlineJailedTime(); - lastLogin = _getLastLogin(); - lastLogout = _getLastLogout(); - lastLoginAddress = _getLastLoginAddress(); - afk = _getAfk(); - geolocation = _getGeoLocation(); - isSocialSpyEnabled = _isSocialSpyEnabled(); - isNPC = _isNPC(); - arePowerToolsEnabled = _arePowerToolsEnabled(); - kitTimestamps = _getKitTimestamps(); - nickname = _getNickname(); - ignoredPlayers = _getIgnoredPlayers(); - logoutLocation = _getLogoutLocation(); - lastAccountName = _getLastAccountName(); - commandCooldowns = _getCommandCooldowns(); - acceptingPay = _getAcceptingPay(); - confirmPay = _getConfirmPay(); - confirmClear = _getConfirmClear(); - lastMessageReplyRecipient = _getLastMessageReplyRecipient(); - baltopExemptCache = _getBaltopExcludeCache(); } private BigDecimal _getMoney() { @@ -164,8 +106,8 @@ public abstract class UserData extends PlayerExtension implements IConf { result = BigDecimal.ZERO; } - if (config.hasProperty("money")) { - result = config.getBigDecimal("money", result); + if (holder.money() != null) { + result = holder.money(); } if (result.compareTo(maxMoney) > 0) { result = maxMoney; @@ -173,7 +115,9 @@ public abstract class UserData extends PlayerExtension implements IConf { if (result.compareTo(minMoney) < 0) { result = minMoney; } - return result; + holder.money(result); + + return holder.money(); } public BigDecimal getMoney() { @@ -194,17 +138,10 @@ public abstract class UserData extends PlayerExtension implements IConf { if (money.compareTo(minMoney) < 0) { money = minMoney; } - config.setProperty("money", money); + holder.money(money); stopTransaction(); } - private Map _getHomes() { - if (config.isConfigurationSection("homes")) { - return config.getConfigurationSection("homes").getValues(false); - } - return new HashMap<>(); - } - private String getHomeName(String search) { if (NumberUtil.isInt(search)) { try { @@ -217,49 +154,43 @@ public abstract class UserData extends PlayerExtension implements IConf { public Location getHome(final String name) throws Exception { final String search = getHomeName(name); - return config.getLocation("homes." + search, this.getBase().getServer()); + return holder.homes().get(search); } public Location getHome(final Location world) { - try { - if (getHomes().isEmpty()) { - return null; - } - Location loc; - for (final String home : getHomes()) { - loc = config.getLocation("homes." + home, this.getBase().getServer()); - if (world.getWorld() == loc.getWorld()) { - return loc; - } - - } - loc = config.getLocation("homes." + getHomes().get(0), this.getBase().getServer()); - return loc; - } catch (final InvalidWorldException ex) { + if (getHomes().isEmpty()) { return null; } + Location loc; + for (final String home : getHomes()) { + loc = holder.homes().get(home); + if (world.getWorld() == loc.getWorld()) { + return loc; + } + + } + loc = holder.homes().get(getHomes().get(0)); + return loc; } public List getHomes() { - return new ArrayList<>(homes.keySet()); + return new ArrayList<>(holder.homes().keySet()); } public void setHome(String name, final Location loc) { //Invalid names will corrupt the yaml name = StringUtil.safeString(name); - homes.put(name, loc); - config.setProperty("homes." + name, loc); + holder.homes().put(name, loc); config.save(); } public void delHome(final String name) throws Exception { String search = getHomeName(name); - if (!homes.containsKey(search)) { + if (!holder.homes().containsKey(search)) { search = StringUtil.safeString(search); } - if (homes.containsKey(search)) { - homes.remove(search); - config.removeProperty("homes." + search); + if (holder.homes().containsKey(search)) { + holder.homes().remove(search); config.save(); } else { throw new Exception(tl("invalidHome", search)); @@ -267,255 +198,152 @@ public abstract class UserData extends PlayerExtension implements IConf { } public boolean hasHome() { - return config.hasProperty("home"); + return !holder.homes().isEmpty(); } public boolean hasHome(final String name) { - return config.hasProperty("homes." + name); - } - - public String _getNickname() { - return config.getString("nickname"); + return holder.homes().containsKey(name); } public String getNickname() { - return nickname; + return holder.nickname(); } public void setNickname(final String nick) { - nickname = nick; - config.setProperty("nickname", nick); + holder.nickname(nick); config.save(); } - private Set _getUnlimited() { - final Set retlist = new HashSet<>(); - final List configList = config.getStringList("unlimited"); - for (final String s : configList) { - final Material mat = Material.matchMaterial(s); - if (mat != null) { - retlist.add(mat); - } - } - - return retlist; - } - public Set getUnlimited() { - return unlimited; + return holder.unlimited(); } public boolean hasUnlimited(final ItemStack stack) { - return unlimited.contains(stack.getType()); + return holder.unlimited().contains(stack.getType()); } public void setUnlimited(final ItemStack stack, final boolean state) { final boolean wasUpdated; if (state) { - wasUpdated = unlimited.add(stack.getType()); + wasUpdated = holder.unlimited().add(stack.getType()); } else { - wasUpdated = unlimited.remove(stack.getType()); + wasUpdated = holder.unlimited().remove(stack.getType()); } if (wasUpdated) { - applyUnlimited(); + config.save(); } } - private void applyUnlimited() { - config.setProperty("unlimited", unlimited.stream().map(Enum::name).collect(Collectors.toList())); - config.save(); - } - - private Map _getPowertools() { - if (config.isConfigurationSection("powertools")) { - return config.getConfigurationSection("powertools").getValues(false); - } - return new HashMap<>(); - } - public void clearAllPowertools() { - powertools.clear(); - config.setProperty("powertools", powertools); + holder.powertools().clear(); config.save(); } - @SuppressWarnings("unchecked") public List getPowertool(final ItemStack stack) { - return (List) powertools.get(stack.getType().name().toLowerCase(Locale.ENGLISH)); + return getPowertool(stack.getType()); } - @SuppressWarnings("unchecked") public List getPowertool(final Material material) { - return (List) powertools.get(material.name().toLowerCase(Locale.ENGLISH)); + return holder.powertools().get(material.name().toLowerCase(Locale.ENGLISH)); } public void setPowertool(final ItemStack stack, final List commandList) { if (commandList == null || commandList.isEmpty()) { - powertools.remove(stack.getType().name().toLowerCase(Locale.ENGLISH)); + holder.powertools().remove(stack.getType().name().toLowerCase(Locale.ENGLISH)); } else { - powertools.put(stack.getType().name().toLowerCase(Locale.ENGLISH), commandList); + holder.powertools().put(stack.getType().name().toLowerCase(Locale.ENGLISH), commandList); } - config.setProperty("powertools", powertools); config.save(); } public boolean hasPowerTools() { - return !powertools.isEmpty(); - } - - private Location _getLastLocation() { - try { - return config.getLocation("lastlocation", this.getBase().getServer()); - } catch (final InvalidWorldException e) { - return null; - } + return !holder.powertools().isEmpty(); } public Location getLastLocation() { - return lastLocation; + return holder.lastLocation(); } public void setLastLocation(final Location loc) { if (loc == null || loc.getWorld() == null) { return; } - lastLocation = loc; - config.setProperty("lastlocation", loc); + holder.lastLocation(loc); config.save(); } - private Location _getLogoutLocation() { - try { - return config.getLocation("logoutlocation", this.getBase().getServer()); - } catch (final InvalidWorldException e) { - return null; - } - } - public Location getLogoutLocation() { - return logoutLocation; + return holder.logoutLocation(); } public void setLogoutLocation(final Location loc) { if (loc == null || loc.getWorld() == null) { return; } - logoutLocation = loc; - config.setProperty("logoutlocation", loc); + holder.logoutLocation(loc); config.save(); } - private long _getLastTeleportTimestamp() { - return config.getLong("timestamps.lastteleport", 0); - } - public long getLastTeleportTimestamp() { - return lastTeleportTimestamp; + return holder.timestamps().lastTeleport(); } public void setLastTeleportTimestamp(final long time) { - lastTeleportTimestamp = time; - config.setProperty("timestamps.lastteleport", time); + holder.timestamps().lastTeleport(time); config.save(); } - private long _getLastHealTimestamp() { - return config.getLong("timestamps.lastheal", 0); - } - public long getLastHealTimestamp() { - return lastHealTimestamp; + return holder.timestamps().lastHeal(); } public void setLastHealTimestamp(final long time) { - lastHealTimestamp = time; - config.setProperty("timestamps.lastheal", time); + holder.timestamps().lastHeal(time); config.save(); } - private String _getJail() { - return config.getString("jail"); - } - public String getJail() { - return jail; + return holder.jail(); } public void setJail(final String jail) { - if (jail == null || jail.isEmpty()) { - this.jail = null; - config.removeProperty("jail"); - } else { - this.jail = jail; - config.setProperty("jail", jail); - } + holder.jail(jail); config.save(); } - private List _getMails() { - return config.getStringList("mail"); - } - public List getMails() { - return mails; + return holder.mails(); } public void setMails(List mails) { - if (mails == null) { - config.removeProperty("mail"); - mails = _getMails(); - } else { - config.setProperty("mail", mails); - } - this.mails = mails; + holder.mails(mails); config.save(); } public void addMail(final String mail) { - mails.add(mail); - setMails(mails); - } - - private boolean _getTeleportEnabled() { - return config.getBoolean("teleportenabled", true); + holder.mails().add(mail); + config.save(); } public boolean isTeleportEnabled() { - return teleportEnabled; + return holder.teleportEnabled(); } public void setTeleportEnabled(final boolean set) { - teleportEnabled = set; - config.setProperty("teleportenabled", set); + holder.teleportEnabled(set); config.save(); } - private boolean _getAutoTeleportEnabled() { - return config.getBoolean("teleportauto", false); - } - public boolean isAutoTeleportEnabled() { - return autoTeleportEnabled; + return holder.teleportAuto(); } public void setAutoTeleportEnabled(final boolean set) { - autoTeleportEnabled = set; - config.setProperty("teleportauto", set); + holder.teleportAuto(set); config.save(); } - public List _getIgnoredPlayers() { - final List players = new ArrayList<>(); - for (final String uuid : config.getStringList("ignore")) { - try { - players.add(UUID.fromString(uuid)); - } catch (final IllegalArgumentException ignored) { - } - } - return Collections.synchronizedList(players); - } - @Deprecated public void setIgnoredPlayers(final List players) { final List uuids = new ArrayList<>(); @@ -530,17 +358,7 @@ public abstract class UserData extends PlayerExtension implements IConf { } public void setIgnoredPlayerUUIDs(final List players) { - if (players == null || players.isEmpty()) { - ignoredPlayers = Collections.synchronizedList(new ArrayList<>()); - config.removeProperty("ignore"); - } else { - ignoredPlayers = players; - final List uuids = new ArrayList<>(); - for (final UUID uuid : players) { - uuids.add(uuid.toString()); - } - config.setProperty("ignore", uuids); - } + holder.ignore(players); config.save(); } @@ -554,101 +372,75 @@ public abstract class UserData extends PlayerExtension implements IConf { } public boolean isIgnoredPlayer(final IUser user) { - return ignoredPlayers.contains(user.getBase().getUniqueId()) && !user.isIgnoreExempt(); + return holder.ignore().contains(user.getBase().getUniqueId()) && !user.isIgnoreExempt(); + } + + public List _getIgnoredPlayers() { + return holder.ignore(); } public void setIgnoredPlayer(final IUser user, final boolean set) { final UUID uuid = user.getBase().getUniqueId(); if (set) { - if (!ignoredPlayers.contains(uuid)) { - ignoredPlayers.add(uuid); + if (!holder.ignore().contains(uuid)) { + holder.ignore().add(uuid); } } else { - ignoredPlayers.remove(uuid); + holder.ignore().remove(uuid); } - setIgnoredPlayerUUIDs(ignoredPlayers); - } - - private boolean _getGodModeEnabled() { - return config.getBoolean("godmode", false); + config.save(); } public boolean isGodModeEnabled() { - return godmode; + return holder.godMode(); } public void setGodModeEnabled(final boolean set) { - godmode = set; - config.setProperty("godmode", set); + holder.godMode(set); config.save(); } - public boolean _getMuted() { - return config.getBoolean("muted", false); - } - public boolean getMuted() { - return muted; + return holder.muted(); } public boolean isMuted() { - return muted; + return getMuted(); } public void setMuted(final boolean set) { - muted = set; - config.setProperty("muted", set); + holder.muted(set); config.save(); } - public String _getMuteReason() { - return config.getString("muteReason"); - } - public String getMuteReason() { - return muteReason; + return holder.muteReason(); } public void setMuteReason(final String reason) { - if (reason == null) { - config.removeProperty("muteReason"); - muteReason = null; - } else { - muteReason = reason; - config.setProperty("muteReason", reason); - } + holder.muteReason(reason); config.save(); } public boolean hasMuteReason() { - return muteReason != null; - } - - private long _getMuteTimeout() { - return config.getLong("timestamps.mute", 0); + return holder.muteReason() != null; } public long getMuteTimeout() { - return muteTimeout; + return holder.timestamps().mute(); } public void setMuteTimeout(final long time) { - muteTimeout = time; - config.setProperty("timestamps.mute", time); + holder.timestamps().mute(time); config.save(); } - private boolean _getJailed() { - return config.getBoolean("jailed", false); - } - public boolean isJailed() { - return jailed; + return holder.jailed(); } public void setJailed(final boolean set) { - jailed = set; - config.setProperty("jailed", set); + holder.jailed(set); config.save(); } @@ -658,167 +450,101 @@ public abstract class UserData extends PlayerExtension implements IConf { return ret; } - private long _getJailTimeout() { - return config.getLong("timestamps.jail", 0); - } - public long getJailTimeout() { - return jailTimeout; + return holder.timestamps().jail(); } public void setJailTimeout(final long time) { - jailTimeout = time; - config.setProperty("timestamps.jail", time); + holder.timestamps().jail(time); config.save(); } - private long onlineJailed; - - private long _getOnlineJailedTime() { - return config.getLong("timestamps.onlinejail", 0); - } - public long getOnlineJailedTime() { - return onlineJailed; + return holder.timestamps().onlineJail(); } public void setOnlineJailedTime(long onlineJailed) { - this.onlineJailed = onlineJailed; - config.setProperty("timestamps.onlinejail", onlineJailed); + holder.timestamps().onlineJail(onlineJailed); config.save(); } - private long _getLastLogin() { - return config.getLong("timestamps.login", 0); - } - public long getLastLogin() { - return lastLogin; + return holder.timestamps().login(); } public void setLastLogin(final long time) { - _setLastLogin(time); + holder.timestamps().login(time); if (base.getAddress() != null && base.getAddress().getAddress() != null) { - _setLastLoginAddress(base.getAddress().getAddress().getHostAddress()); + holder.ipAddress(base.getAddress().getAddress().getHostAddress()); } config.save(); } - private void _setLastLogin(final long time) { - lastLogin = time; - config.setProperty("timestamps.login", time); - } - - private long _getLastLogout() { - return config.getLong("timestamps.logout", 0); - } - public long getLastLogout() { - return lastLogout; + return holder.timestamps().logout(); } public void setLastLogout(final long time) { - lastLogout = time; - config.setProperty("timestamps.logout", time); + holder.timestamps().logout(time); config.save(); } - private String _getLastLoginAddress() { - return config.getString("ipAddress", ""); - } - public String getLastLoginAddress() { - return lastLoginAddress; - } - - private void _setLastLoginAddress(final String address) { - lastLoginAddress = address; - config.setProperty("ipAddress", address); - } - - private boolean _getAfk() { - return config.getBoolean("afk", false); + return holder.ipAddress(); } public boolean isAfk() { - return afk; + return holder.afk(); } public void _setAfk(final boolean set) { - afk = set; - config.setProperty("afk", set); + holder.afk(set); config.save(); } - private String _getGeoLocation() { - return config.getString("geolocation"); - } - public String getGeoLocation() { - return geolocation; + return holder.geolocation(); } public void setGeoLocation(final String geolocation) { - if (geolocation == null || geolocation.isEmpty()) { - this.geolocation = null; - config.removeProperty("geolocation"); - } else { - this.geolocation = geolocation; - config.setProperty("geolocation", geolocation); - } + holder.geolocation(geolocation); config.save(); } - private boolean _isSocialSpyEnabled() { - return config.getBoolean("socialspy", false); - } - public boolean isSocialSpyEnabled() { - return isSocialSpyEnabled; + return holder.socialSpy(); } public void setSocialSpyEnabled(final boolean status) { - isSocialSpyEnabled = status; - config.setProperty("socialspy", status); + holder.socialSpy(status); config.save(); } - private boolean _isNPC() { - return config.getBoolean("npc", false); - } - public boolean isNPC() { - return isNPC; + return holder.npc(); } public void setNPC(final boolean set) { - isNPC = set; - config.setProperty("npc", set); + holder.npc(set); config.save(); } public String getLastAccountName() { - return lastAccountName; + return holder.lastAccountName(); } public void setLastAccountName(final String lastAccountName) { - this.lastAccountName = lastAccountName; - config.setProperty("lastAccountName", lastAccountName); + holder.lastAccountName(lastAccountName); config.save(); ess.getUserMap().trackUUID(getConfigUUID(), lastAccountName, true); } - public String _getLastAccountName() { - return config.getString("lastAccountName", null); - } - public boolean arePowerToolsEnabled() { - return arePowerToolsEnabled; + return holder.powerToolsEnabled(); } public void setPowerToolsEnabled(final boolean set) { - arePowerToolsEnabled = set; - config.setProperty("powertoolsenabled", set); + holder.powerToolsEnabled(set); config.save(); } @@ -828,232 +554,110 @@ public abstract class UserData extends PlayerExtension implements IConf { return ret; } - private boolean _arePowerToolsEnabled() { - return config.getBoolean("powertoolsenabled", true); - } - - private Map _getKitTimestamps() { - - if (config.isConfigurationSection("timestamps.kits")) { - final ConfigurationSection section = config.getConfigurationSection("timestamps.kits"); - final Map timestamps = new HashMap<>(); - for (final String command : section.getKeys(false)) { - if (section.isLong(command)) { - timestamps.put(command.toLowerCase(Locale.ENGLISH), section.getLong(command)); - } else if (section.isInt(command)) { - timestamps.put(command.toLowerCase(Locale.ENGLISH), (long) section.getInt(command)); - } - } - return timestamps; - } - return new HashMap<>(); - } - public long getKitTimestamp(String name) { name = name.replace('.', '_').replace('/', '_').toLowerCase(Locale.ENGLISH); - if (kitTimestamps != null && kitTimestamps.containsKey(name)) { - return kitTimestamps.get(name); + if (holder.timestamps().kits() != null && holder.timestamps().kits().containsKey(name)) { + return holder.timestamps().kits().get(name); } return 0L; } public void setKitTimestamp(String name, final long time) { name = name.replace('.', '_').replace('/', '_').toLowerCase(Locale.ENGLISH); - kitTimestamps.put(name, time); - config.setProperty("timestamps.kits", kitTimestamps); + holder.timestamps().kits().put(name, time); config.save(); } - public void setConfigProperty(String node, final Object object) { - final String prefix = "info."; - node = prefix + node; - if (object instanceof Map) { - config.setProperty(node, (Map) object); - } else if (object instanceof List) { - config.setProperty(node, (List) object); - } else if (object instanceof Location) { - config.setProperty(node, (Location) object); - } else if (object instanceof ItemStack) { - config.setProperty(node, (ItemStack) object); - } else { - config.setProperty(node, object); - } - config.save(); - } - - public Set getConfigKeys() { - if (config.isConfigurationSection("info")) { - return config.getConfigurationSection("info").getKeys(true); - } - return new HashSet<>(); - } - - public Map getConfigMap() { - if (config.isConfigurationSection("info")) { - return config.getConfigurationSection("info").getValues(true); - } - return new HashMap<>(); - } - - public Map getConfigMap(final String node) { - if (config.isConfigurationSection("info." + node)) { - return config.getConfigurationSection("info." + node).getValues(true); - } - return new HashMap<>(); - } - - private Map _getCommandCooldowns() { - if (!config.contains("timestamps.command-cooldowns")) { - return null; - } - - // See saveCommandCooldowns() for deserialization explanation - final List> section = config.getMapList("timestamps.command-cooldowns"); - final HashMap result = new HashMap<>(); - for (final Map map : section) { - final Pattern pattern = Pattern.compile(map.get("pattern").toString()); - final long expiry = ((Number) map.get("expiry")).longValue(); - result.put(pattern, expiry); - } - return result; + public List getCooldownsList() { + return holder.timestamps().commandCooldowns(); } public Map getCommandCooldowns() { - if (this.commandCooldowns == null) { - return Collections.emptyMap(); + final Map map = new HashMap<>(); + for (final CommandCooldown c : getCooldownsList()) { + map.put(c.pattern(), c.value()); } - return Collections.unmodifiableMap(this.commandCooldowns); + return map; } public Date getCommandCooldownExpiry(final String label) { - if (commandCooldowns != null) { - for (final Entry entry : this.commandCooldowns.entrySet()) { - if (entry.getKey().matcher(label).matches()) { - return new Date(entry.getValue()); - } + for (CommandCooldown cooldown : getCooldownsList()) { + if (cooldown.pattern().matcher(label).matches()) { + return new Date(cooldown.value()); } } return null; } public void addCommandCooldown(final Pattern pattern, final Date expiresAt, final boolean save) { - if (this.commandCooldowns == null) { - this.commandCooldowns = new HashMap<>(); - } - this.commandCooldowns.put(pattern, expiresAt.getTime()); + final CommandCooldown cooldown = new CommandCooldown(); + cooldown.pattern(pattern); + cooldown.value(expiresAt.getTime()); + holder.timestamps().commandCooldowns().add(cooldown); if (save) { - saveCommandCooldowns(); + save(); } } public boolean clearCommandCooldown(final Pattern pattern) { - if (this.commandCooldowns == null) { + if (holder.timestamps().commandCooldowns().isEmpty()) { return false; // false for no modification } - if (this.commandCooldowns.remove(pattern) != null) { - saveCommandCooldowns(); + if (getCooldownsList().removeIf(cooldown -> cooldown.pattern().equals(pattern))) { + save(); return true; } return false; } - private void saveCommandCooldowns() { - // Serialization explanation: - // - // Serialization is done as a map list instead of a config section due to limitations. - // When serializing patterns (which commonly include full stops .) Bukkit/Essentials config framework - // interprets it as a path separator, thus it breaks up the regex into sub nodes causing invalid syntax. - // Thus each command cooldown is instead stored as a Map of {pattern: .., expiry: ..} to work around this. - final List serialized = new ArrayList<>(); - for (final Entry entry : this.commandCooldowns.entrySet()) { - // Don't save expired cooldowns - if (entry.getValue() < System.currentTimeMillis()) { - continue; - } - - final Map map = ImmutableMap.builder() - .put("pattern", entry.getKey().pattern()) - .put("expiry", entry.getValue()) - .build(); - serialized.add(map); - } - config.setProperty("timestamps.command-cooldowns", serialized); - save(); - } - - public boolean _getAcceptingPay() { - return config.getBoolean("acceptingPay", true); - } - public boolean isAcceptingPay() { - return acceptingPay; + return holder.acceptingPay(); } public void setAcceptingPay(final boolean acceptingPay) { - this.acceptingPay = acceptingPay; - config.setProperty("acceptingPay", acceptingPay); + holder.acceptingPay(acceptingPay); save(); } - private Boolean _getConfirmPay() { - return (Boolean) config.get("confirm-pay"); - } - public boolean isPromptingPayConfirm() { - return confirmPay != null ? confirmPay : ess.getSettings().isConfirmCommandEnabledByDefault("pay"); + return holder.confirmPay() != null ? holder.confirmPay() : ess.getSettings().isConfirmCommandEnabledByDefault("pay"); } public void setPromptingPayConfirm(final boolean prompt) { - this.confirmPay = prompt; - config.setProperty("confirm-pay", prompt); + holder.confirmPay(prompt); save(); } - private Boolean _getConfirmClear() { - return (Boolean) config.get("confirm-clear"); - } - public boolean isPromptingClearConfirm() { - return confirmClear != null ? confirmClear : ess.getSettings().isConfirmCommandEnabledByDefault("clearinventory"); + return holder.confirmClear() != null ? holder.confirmClear() : ess.getSettings().isConfirmCommandEnabledByDefault("clearinventory"); } public void setPromptingClearConfirm(final boolean prompt) { - this.confirmClear = prompt; - config.setProperty("confirm-clear", prompt); + holder.confirmClear(prompt); save(); } - private boolean _getLastMessageReplyRecipient() { - return config.getBoolean("last-message-reply-recipient", ess.getSettings().isLastMessageReplyRecipient()); - } - public boolean isLastMessageReplyRecipient() { - return this.lastMessageReplyRecipient; + return holder.lastMessageReplyRecipient() != null ? holder.lastMessageReplyRecipient() : ess.getSettings().isLastMessageReplyRecipient(); } public void setLastMessageReplyRecipient(final boolean enabled) { - this.lastMessageReplyRecipient = enabled; - config.setProperty("last-message-reply-recipient", enabled); + holder.lastMessageReplyRecipient(enabled); save(); } - public boolean _getBaltopExcludeCache() { - return config.getBoolean("baltop-exempt", false); - } - public boolean isBaltopExcludeCache() { - return baltopExemptCache; + return holder.baltopExempt(); } public void setBaltopExemptCache(boolean baltopExempt) { - this.baltopExemptCache = baltopExempt; - config.setProperty("baltop-exempt", baltopExempt); + holder.baltopExempt(baltopExempt); config.save(); } public UUID getConfigUUID() { - return config.uuid; + return config.getUuid(); } public void save() { @@ -1067,4 +671,25 @@ public abstract class UserData extends PlayerExtension implements IConf { public void stopTransaction() { config.stopTransaction(); } + + public void setConfigProperty(String node, Object object) { + setConfigPropertyRaw("info." + node, object); + } + + public void setConfigPropertyRaw(String node, Object object) { + config.setRaw(node, object); + config.save(); + } + + public Set getConfigKeys() { + return ConfigurateUtil.getKeys(config.getSection("info")); + } + + public Map getConfigMap() { + return ConfigurateUtil.getRawMap(config.getSection("info")); + } + + public Map getConfigMap(final String node) { + return ConfigurateUtil.getRawMap(config.getSection("info." + node)); + } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/Warps.java b/Essentials/src/main/java/com/earth2me/essentials/Warps.java index 828c3cfaa..f1f671fc0 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Warps.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Warps.java @@ -1,14 +1,13 @@ package com.earth2me.essentials; import com.earth2me.essentials.commands.WarpNotFoundException; +import com.earth2me.essentials.config.EssentialsConfiguration; import com.earth2me.essentials.utils.StringUtil; import net.ess3.api.InvalidNameException; import net.ess3.api.InvalidWorldException; import org.bukkit.Location; -import org.bukkit.Server; import java.io.File; -import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -23,12 +22,10 @@ import static com.earth2me.essentials.I18n.tl; public class Warps implements IConf, net.ess3.api.IWarps { private static final Logger logger = Logger.getLogger("Essentials"); - private final Map warpPoints = new HashMap<>(); + private final Map warpPoints = new HashMap<>(); private final File warpsFolder; - private final Server server; - public Warps(final Server server, final File dataFolder) { - this.server = server; + public Warps(final File dataFolder) { warpsFolder = new File(dataFolder, "warps"); if (!warpsFolder.exists()) { warpsFolder.mkdirs(); @@ -53,11 +50,11 @@ public class Warps implements IConf, net.ess3.api.IWarps { @Override public Location getWarp(final String warp) throws WarpNotFoundException, InvalidWorldException { - final EssentialsConf conf = warpPoints.get(new StringIgnoreCase(warp)); + final EssentialsConfiguration conf = warpPoints.get(new StringIgnoreCase(warp)); if (conf == null) { throw new WarpNotFoundException(); } - return conf.getLocation(null, server); + return conf.getLocation(null); } @Override @@ -68,34 +65,33 @@ public class Warps implements IConf, net.ess3.api.IWarps { @Override public void setWarp(final IUser user, final String name, final Location loc) throws Exception { final String filename = StringUtil.sanitizeFileName(name); - EssentialsConf conf = warpPoints.get(new StringIgnoreCase(name)); + EssentialsConfiguration conf = warpPoints.get(new StringIgnoreCase(name)); if (conf == null) { final File confFile = new File(warpsFolder, filename + ".yml"); if (confFile.exists()) { throw new Exception(tl("similarWarpExist")); } - conf = new EssentialsConf(confFile); + conf = new EssentialsConfiguration(confFile); + conf.load(); warpPoints.put(new StringIgnoreCase(name), conf); } conf.setProperty(null, loc); conf.setProperty("name", name); - if (user != null) conf.setProperty("lastowner", user.getBase().getUniqueId().toString()); - try { - conf.saveWithError(); - } catch (final IOException ex) { - throw new IOException(tl("invalidWarpName")); + if (user != null) { + conf.setProperty("lastowner", user.getBase().getUniqueId().toString()); } + conf.save(); } @Override public UUID getLastOwner(final String warp) throws WarpNotFoundException { - final EssentialsConf conf = warpPoints.get(new StringIgnoreCase(warp)); + final EssentialsConfiguration conf = warpPoints.get(new StringIgnoreCase(warp)); if (conf == null) { throw new WarpNotFoundException(); } UUID uuid = null; try { - uuid = UUID.fromString(conf.getString("lastowner")); + uuid = UUID.fromString(conf.getString("lastowner", null)); } catch (final Exception ignored) { } return uuid; @@ -103,7 +99,7 @@ public class Warps implements IConf, net.ess3.api.IWarps { @Override public void removeWarp(final String name) throws Exception { - final EssentialsConf conf = warpPoints.get(new StringIgnoreCase(name)); + final EssentialsConfiguration conf = warpPoints.get(new StringIgnoreCase(name)); if (conf == null) { throw new Exception(tl("warpNotExist")); } @@ -122,9 +118,9 @@ public class Warps implements IConf, net.ess3.api.IWarps { final String filename = listOfFile.getName(); if (listOfFile.isFile() && filename.endsWith(".yml")) { try { - final EssentialsConf conf = new EssentialsConf(listOfFile); + final EssentialsConfiguration conf = new EssentialsConfiguration(listOfFile); conf.load(); - final String name = conf.getString("name"); + final String name = conf.getString("name", null); if (name != null) { warpPoints.put(new StringIgnoreCase(name), conf); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/Worth.java b/Essentials/src/main/java/com/earth2me/essentials/Worth.java index 9beea1918..dc9e64058 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/Worth.java +++ b/Essentials/src/main/java/com/earth2me/essentials/Worth.java @@ -1,10 +1,12 @@ package com.earth2me.essentials; import com.earth2me.essentials.commands.NotEnoughArgumentsException; +import com.earth2me.essentials.config.ConfigurateUtil; +import com.earth2me.essentials.config.EssentialsConfiguration; import com.earth2me.essentials.utils.VersionUtil; import org.bukkit.Material; -import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; +import org.spongepowered.configurate.CommentedConfigurationNode; import java.io.File; import java.math.BigDecimal; @@ -13,11 +15,10 @@ import java.util.Locale; import static com.earth2me.essentials.I18n.tl; public class Worth implements IConf { - private final EssentialsConf config; + private final EssentialsConfiguration config; public Worth(final File dataFolder) { - config = new EssentialsConf(new File(dataFolder, "worth.yml")); - config.setTemplateName("/worth.yml"); + config = new EssentialsConfiguration(new File(dataFolder, "worth.yml"), "/worth.yml"); config.load(); } @@ -39,8 +40,8 @@ public class Worth implements IConf { // Check for matches with data value 0 if (result.signum() < 0) { - final ConfigurationSection itemNameMatch = config.getConfigurationSection("worth." + itemname); - if (itemNameMatch != null && itemNameMatch.getKeys(false).size() == 1) { + final CommentedConfigurationNode itemNameMatch = config.getSection("worth." + itemname); + if (itemNameMatch != null && ConfigurateUtil.getKeys(itemNameMatch).size() == 1) { result = config.getBigDecimal("worth." + itemname + ".0", BigDecimal.ONE.negate()); } } diff --git a/Essentials/src/main/java/com/earth2me/essentials/api/Economy.java b/Essentials/src/main/java/com/earth2me/essentials/api/Economy.java index 69dc7a361..d0a12b77a 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/api/Economy.java +++ b/Essentials/src/main/java/com/earth2me/essentials/api/Economy.java @@ -1,8 +1,8 @@ package com.earth2me.essentials.api; -import com.earth2me.essentials.EssentialsUserConf; import com.earth2me.essentials.Trade; import com.earth2me.essentials.User; +import com.earth2me.essentials.config.EssentialsUserConfiguration; import com.earth2me.essentials.utils.NumberUtil; import com.earth2me.essentials.utils.StringUtil; import com.google.common.base.Charsets; @@ -57,12 +57,12 @@ public class Economy { LOGGER.log(Level.SEVERE, MessageFormat.format(WARN_NPC_RECREATE_1, name, npcUUID.toString()), new RuntimeException()); LOGGER.log(Level.SEVERE, WARN_NPC_RECREATE_2); } - final EssentialsUserConf npcConfig = new EssentialsUserConf(name, npcUUID, npcFile); + final EssentialsUserConfiguration npcConfig = new EssentialsUserConfiguration(name, npcUUID, npcFile); npcConfig.load(); npcConfig.setProperty("npc", true); npcConfig.setProperty("lastAccountName", name); npcConfig.setProperty("money", ess.getSettings().getStartingBalance()); - npcConfig.forceSave(); + npcConfig.blockingSave(); ess.getUserMap().trackUUID(npcUUID, name, false); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/api/IJails.java b/Essentials/src/main/java/com/earth2me/essentials/api/IJails.java index 9a779e980..94947c9c2 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/api/IJails.java +++ b/Essentials/src/main/java/com/earth2me/essentials/api/IJails.java @@ -1,5 +1,6 @@ package com.earth2me.essentials.api; +import com.earth2me.essentials.IConf; import net.ess3.api.IUser; import org.bukkit.Location; @@ -12,7 +13,7 @@ import java.util.concurrent.CompletableFuture; * @deprecated External plugins should use {@link net.ess3.api.IJails} instead of this interface in case future APIs are added. */ @Deprecated -public interface IJails extends IReload { +public interface IJails extends IConf { /** * Gets the location of the jail with the given name * @@ -74,4 +75,14 @@ public interface IJails extends IReload { * @throws Exception */ void setJail(String jailName, Location loc) throws Exception; + + /** + * Begins a transaction + */ + void startTransaction(); + + /** + * Ends the current transaction and saves the state + */ + void stopTransaction(boolean blocking); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/api/IReload.java b/Essentials/src/main/java/com/earth2me/essentials/api/IReload.java deleted file mode 100644 index 1cacf8f79..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/api/IReload.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.earth2me.essentials.api; - -/** - * Represents a storage object that is reloadable. - * - * @deprecated This is a remnant of the abandoned 3.x storage system. Neither future 2.x code nor external plugins - * should use this interface. - */ -@Deprecated -public interface IReload { - /** - * Reloads the given storage object. - */ - void onReload(); -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandcreatekit.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandcreatekit.java index 5147be0d2..590d28779 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandcreatekit.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandcreatekit.java @@ -10,18 +10,15 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import org.bukkit.Material; import org.bukkit.Server; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.MemoryConfiguration; -import org.bukkit.configuration.file.YamlConstructor; -import org.bukkit.configuration.file.YamlRepresenter; import org.bukkit.inventory.ItemStack; -import org.yaml.snakeyaml.DumperOptions; -import org.yaml.snakeyaml.DumperOptions.FlowStyle; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.representer.Representer; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.yaml.NodeStyle; +import org.spongepowered.configurate.yaml.YamlConfigurationLoader; +import java.io.BufferedWriter; import java.io.InputStreamReader; import java.io.OutputStream; +import java.io.StringWriter; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; @@ -32,20 +29,14 @@ import java.util.concurrent.Executors; import static com.earth2me.essentials.I18n.tl; public class Commandcreatekit extends EssentialsCommand { - private static final String PASTE_URL = "https://paste.gg/"; private static final String PASTE_UPLOAD_URL = "https://api.paste.gg/v1/pastes"; private static final Gson GSON = new Gson(); private final ExecutorService executorService = Executors.newSingleThreadExecutor(); - private final DumperOptions yamlOptions = new DumperOptions(); - private final Representer yamlRepresenter = new YamlRepresenter(); - private final YamlConstructor yamlConstructor = new YamlConstructor(); public Commandcreatekit() { super("createkit"); - yamlOptions.setDefaultFlowStyle(FlowStyle.BLOCK); - yamlRepresenter.setDefaultFlowStyle(FlowStyle.BLOCK); } // /createkit @@ -71,21 +62,25 @@ public class Commandcreatekit extends EssentialsCommand { ess.getKits().addKit(kitname, list, delay); user.sendMessage(tl("createdKit", kitname, list.size(), delay)); } else { - final ConfigurationSection config = new MemoryConfiguration(); - config.set("kits." + kitname + ".delay", delay); - config.set("kits." + kitname + ".items", list); - - final Yaml yaml = new Yaml(yamlConstructor, yamlRepresenter, yamlOptions); - String fileContents = "# Copy the kit code below into the kits section in your config.yml file\n"; - fileContents += yaml.dump(config.getValues(false)); - - uploadPaste(user.getSource(), kitname, delay, fileContents); + uploadPaste(user.getSource(), kitname, delay, list); } } - private void uploadPaste(final CommandSource sender, final String kitName, final long delay, final String contents) { + private void uploadPaste(final CommandSource sender, final String kitName, final long delay, final List list) { executorService.submit(() -> { try { + final StringWriter sw = new StringWriter(); + final YamlConfigurationLoader loader = YamlConfigurationLoader.builder().sink(() -> new BufferedWriter(sw)).indent(2).nodeStyle(NodeStyle.BLOCK).build(); + + final ConfigurationNode config = loader.createNode(); + config.node("kits", kitName, "delay").set(delay); + config.node("kits", kitName, "items").set(list); + + sw.append("# Copy the kit code below into the kits section in your config.yml file\n"); + loader.save(config); + + final String fileContents = sw.toString(); + final HttpURLConnection connection = (HttpURLConnection) new URL(PASTE_UPLOAD_URL).openConnection(); connection.setRequestMethod("POST"); connection.setDoInput(true); @@ -97,7 +92,7 @@ public class Commandcreatekit extends EssentialsCommand { final JsonObject file = new JsonObject(); final JsonObject content = new JsonObject(); content.addProperty("format", "text"); - content.addProperty("value", contents); + content.addProperty("value", fileContents); file.add("content", content); files.add(file); body.add("files", files); diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commanddelkit.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commanddelkit.java index d14280e87..777fd29b2 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commanddelkit.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commanddelkit.java @@ -2,6 +2,7 @@ package com.earth2me.essentials.commands; import com.earth2me.essentials.CommandSource; import com.earth2me.essentials.Kit; +import com.earth2me.essentials.config.ConfigurateUtil; import com.google.common.collect.Lists; import org.bukkit.Server; @@ -37,7 +38,7 @@ public class Commanddelkit extends EssentialsCommand { @Override protected List getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) { if (args.length == 1) { - return Lists.newArrayList(ess.getKits().getKits().getKeys(false)); + return Lists.newArrayList(ConfigurateUtil.getKeys(ess.getKits().getKits())); } return Collections.emptyList(); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandkit.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandkit.java index 445e4064d..10f2eacb0 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandkit.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandkit.java @@ -3,6 +3,7 @@ package com.earth2me.essentials.commands; import com.earth2me.essentials.CommandSource; import com.earth2me.essentials.Kit; import com.earth2me.essentials.User; +import com.earth2me.essentials.config.ConfigurateUtil; import com.earth2me.essentials.utils.StringUtil; import org.bukkit.Server; @@ -100,7 +101,7 @@ public class Commandkit extends EssentialsCommand { if (args.length == 1) { final List options = new ArrayList<>(); // TODO: Move all of this to its own method - for (final String kitName : ess.getKits().getKits().getKeys(false)) { + for (final String kitName : ConfigurateUtil.getKeys(ess.getKits().getKits())) { if (!user.isAuthorized("essentials.kits." + kitName)) { // Only check perm, not time or money continue; } @@ -117,7 +118,7 @@ public class Commandkit extends EssentialsCommand { @Override protected List getTabCompleteOptions(final Server server, final CommandSource sender, final String commandLabel, final String[] args) { if (args.length == 1) { - return new ArrayList<>(ess.getKits().getKits().getKeys(false)); // TODO: Move this to its own method + return new ArrayList<>(ConfigurateUtil.getKeys(ess.getKits().getKits())); // TODO: Move this to its own method } else if (args.length == 2) { return getPlayers(server, sender); } else { diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandkitreset.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandkitreset.java index 2129c347c..82dc54921 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandkitreset.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandkitreset.java @@ -2,6 +2,7 @@ package com.earth2me.essentials.commands; import com.earth2me.essentials.CommandSource; import com.earth2me.essentials.User; +import com.earth2me.essentials.config.ConfigurateUtil; import org.bukkit.Server; import java.util.ArrayList; @@ -58,7 +59,7 @@ public class Commandkitreset extends EssentialsCommand { @Override protected List getTabCompleteOptions(Server server, CommandSource sender, String commandLabel, String[] args) { if (args.length == 1) { - return new ArrayList<>(ess.getKits().getKits().getKeys(false)); + return new ArrayList<>(ConfigurateUtil.getKeys(ess.getKits().getKits())); } else if (args.length == 2 && sender.isAuthorized("essentials.kitreset.others", ess)) { return getPlayers(server, sender); } else { diff --git a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandshowkit.java b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandshowkit.java index 142b2ec90..1da50851a 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/commands/Commandshowkit.java +++ b/Essentials/src/main/java/com/earth2me/essentials/commands/Commandshowkit.java @@ -2,6 +2,7 @@ package com.earth2me.essentials.commands; import com.earth2me.essentials.Kit; import com.earth2me.essentials.User; +import com.earth2me.essentials.config.ConfigurateUtil; import org.bukkit.Server; import java.util.ArrayList; @@ -33,7 +34,7 @@ public class Commandshowkit extends EssentialsCommand { @Override protected List getTabCompleteOptions(final Server server, final User user, final String commandLabel, final String[] args) { if (args.length == 1) { - return new ArrayList<>(ess.getKits().getKits().getKeys(false)); // TODO: Move this to its own method + return new ArrayList<>(ConfigurateUtil.getKeys(ess.getKits().getKits())); // TODO: Move this to its own method } else { return Collections.emptyList(); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/ConfigurateUtil.java b/Essentials/src/main/java/com/earth2me/essentials/config/ConfigurateUtil.java new file mode 100644 index 000000000..fccaf0ffb --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/config/ConfigurateUtil.java @@ -0,0 +1,103 @@ +package com.earth2me.essentials.config; + +import org.spongepowered.configurate.CommentedConfigurationNode; +import org.spongepowered.configurate.serialize.SerializationException; + +import java.math.BigDecimal; +import java.math.MathContext; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public final class ConfigurateUtil { + private ConfigurateUtil() { + } + + public static Set getRootNodeKeys(final EssentialsConfiguration config) { + return getKeys(config.getRootNode()); + } + + public static Set getKeys(final CommentedConfigurationNode node) { + if (node == null || !node.isMap()) { + return Collections.emptySet(); + } + + final Set keys = new LinkedHashSet<>(); + for (Object obj : node.childrenMap().keySet()) { + keys.add(String.valueOf(obj)); + } + return keys; + } + + public static Map getMap(final CommentedConfigurationNode node) { + if (node == null || !node.isMap()) { + return Collections.emptyMap(); + } + + final Map map = new LinkedHashMap<>(); + for (Map.Entry entry : node.childrenMap().entrySet()) { + map.put(String.valueOf(entry.getKey()), entry.getValue()); + } + return map; + } + + public static Map getRawMap(final CommentedConfigurationNode node) { + if (node == null || !node.isMap()) { + return Collections.emptyMap(); + } + + final Map map = new LinkedHashMap<>(); + for (Map.Entry entry : node.childrenMap().entrySet()) { + map.put(String.valueOf(entry.getKey()), entry.getValue().raw()); + } + return map; + } + + public static List> getMapList(final CommentedConfigurationNode node) { + List list = null; + try { + list = node.getList(Object.class); + } catch (SerializationException ignored) { + } + final List> result = new ArrayList<>(); + + if (list == null) { + return result; + } + + for (Object object : list) { + if (object instanceof Map) { + result.add((Map) object); + } + } + return result; + } + + public static BigDecimal toBigDecimal(final String input, final BigDecimal def) { + if (input == null || input.isEmpty()) { + return def; + } + + try { + return new BigDecimal(input, MathContext.DECIMAL128); + } catch (final NumberFormatException | ArithmeticException e) { + return def; + } + } + + public static boolean isDouble(final CommentedConfigurationNode node) { + return node != null && node.raw() instanceof Double; + } + + public static boolean isInt(final CommentedConfigurationNode node) { + return node != null && node.raw() instanceof Integer; + } + + public static boolean isString(final CommentedConfigurationNode node) { + return node != null && node.raw() instanceof String; + } +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/ConfigurationSaveTask.java b/Essentials/src/main/java/com/earth2me/essentials/config/ConfigurationSaveTask.java new file mode 100644 index 000000000..6c9ebc51c --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/config/ConfigurationSaveTask.java @@ -0,0 +1,41 @@ +package com.earth2me.essentials.config; + +import org.spongepowered.configurate.CommentedConfigurationNode; +import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.yaml.YamlConfigurationLoader; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; + +import static com.earth2me.essentials.config.EssentialsConfiguration.LOGGER; + +public class ConfigurationSaveTask implements Runnable { + private final YamlConfigurationLoader loader; + private final CommentedConfigurationNode node; + private final AtomicInteger pendingWrites; + + public ConfigurationSaveTask(final YamlConfigurationLoader loader, final CommentedConfigurationNode node, final AtomicInteger pendingWrites) { + this.loader = loader; + this.node = node; + this.pendingWrites = pendingWrites; + } + + @Override + public void run() { + synchronized (loader) { + // Check if there are more writes in queue. + // If that's the case, we shouldn't bother writing data which is already out-of-date. + if (pendingWrites.get() > 1) { + pendingWrites.decrementAndGet(); + } + + try { + loader.save(node); + } catch (ConfigurateException e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + } finally { + pendingWrites.decrementAndGet(); + } + } + } +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsConfiguration.java b/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsConfiguration.java new file mode 100644 index 000000000..90b66f4e4 --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsConfiguration.java @@ -0,0 +1,432 @@ +package com.earth2me.essentials.config; + +import com.earth2me.essentials.config.annotations.DeleteOnEmpty; +import com.earth2me.essentials.config.processors.DeleteOnEmptyProcessor; +import com.earth2me.essentials.config.serializers.BigDecimalTypeSerializer; +import com.earth2me.essentials.config.serializers.LocationTypeSerializer; +import com.earth2me.essentials.config.serializers.MaterialTypeSerializer; +import net.ess3.api.InvalidWorldException; +import org.bukkit.Location; +import org.bukkit.Material; +import org.spongepowered.configurate.CommentedConfigurationNode; +import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.loader.HeaderMode; +import org.spongepowered.configurate.loader.ParsingException; +import org.spongepowered.configurate.objectmapping.ObjectMapper; +import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.TypeSerializerCollection; +import org.spongepowered.configurate.yaml.NodeStyle; +import org.spongepowered.configurate.yaml.YamlConfigurationLoader; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; + +import static com.earth2me.essentials.I18n.tl; + +public class EssentialsConfiguration { + protected static final Logger LOGGER = Logger.getLogger("Essentials"); + private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); + private static final ObjectMapper.Factory MAPPER_FACTORY = ObjectMapper.factoryBuilder() + .addProcessor(DeleteOnEmpty.class, (data, value) -> new DeleteOnEmptyProcessor()) + .build(); + private static final TypeSerializerCollection SERIALIZERS = TypeSerializerCollection.defaults().childBuilder() + .registerAnnotatedObjects(MAPPER_FACTORY) + .register(BigDecimal.class, new BigDecimalTypeSerializer()) + .register(Location.class, new LocationTypeSerializer()) + .register(Material.class, new MaterialTypeSerializer()) + .build(); + + private final AtomicInteger pendingWrites = new AtomicInteger(0); + private final AtomicBoolean transaction = new AtomicBoolean(false); + private Class resourceClass = EssentialsConfiguration.class; + protected final File configFile; + private final YamlConfigurationLoader loader; + private final String templateName; + private CommentedConfigurationNode configurationNode; + private Runnable saveHook; + + public EssentialsConfiguration(final File configFile) { + this(configFile, null); + } + + public EssentialsConfiguration(final File configFile, final String templateName) { + this(configFile, templateName, (String) null); + } + + public EssentialsConfiguration(final File configFile, final String templateName, final Class resourceClass) { + this(configFile, templateName, (String) null); + this.resourceClass = resourceClass; + } + + public EssentialsConfiguration(final File configFile, final String templateName, final String header) { + this.configFile = configFile; + this.loader = YamlConfigurationLoader.builder() + .defaultOptions(opts -> opts + .header(header) + .serializers(SERIALIZERS)) + .headerMode(HeaderMode.PRESET) + .nodeStyle(NodeStyle.BLOCK) + .indent(2) + .file(configFile) + .build(); + this.templateName = templateName; + } + + public CommentedConfigurationNode getRootNode() { + return configurationNode; + } + + public File getFile() { + return configFile; + } + + public void setProperty(String path, final Location location) { + path = path == null ? "" : path; + setInternal(path, location); + } + + public Location getLocation(final String path) throws InvalidWorldException { + final CommentedConfigurationNode node = path == null ? getRootNode() : getSection(path); + if (node == null) { + return null; + } + + try { + return node.get(Location.class); + } catch (SerializationException e) { + return null; + } + } + + public Map getLocationSectionMap(final String path) { + final CommentedConfigurationNode node = getSection(path); + final Map result = new HashMap<>(); + for (final Map.Entry entry : ConfigurateUtil.getMap(node).entrySet()) { + final CommentedConfigurationNode jailNode = entry.getValue(); + try { + result.put(entry.getKey().toLowerCase(Locale.ENGLISH), jailNode.get(Location.class)); + } catch (SerializationException e) { + LOGGER.log(Level.WARNING, "Error serializing key " + entry.getKey(), e); + } + } + return result; + } + + public void setProperty(final String path, final List list) { + setInternal(path, list); + } + + public List getList(final String path, Class type) { + final CommentedConfigurationNode node = getInternal(path); + if (node == null) { + return new ArrayList<>(); + } + try { + final List list = node.getList(type); + if (list == null) { + return new ArrayList<>(); + } + return list; + } catch (SerializationException e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + return new ArrayList<>(); + } + } + + public boolean isList(String path) { + final CommentedConfigurationNode node = getInternal(path); + return node != null && node.isList(); + } + + public void setProperty(final String path, final String value) { + setInternal(path, value); + } + + public String getString(final String path, final String def) { + final CommentedConfigurationNode node = getInternal(path); + if (node == null) { + return def; + } + return node.getString(); + } + + public void setProperty(final String path, final boolean value) { + setInternal(path, value); + } + + public boolean getBoolean(final String path, final boolean def) { + final CommentedConfigurationNode node = getInternal(path); + if (node == null) { + return def; + } + return node.getBoolean(); + } + + public boolean isBoolean(final String path) { + final CommentedConfigurationNode node = getInternal(path); + return node != null && node.raw() instanceof Boolean; + } + + public void setProperty(final String path, final long value) { + setInternal(path, value); + } + + public long getLong(final String path, final long def) { + final CommentedConfigurationNode node = getInternal(path); + if (node == null) { + return def; + } + return node.getLong(); + } + + public void setProperty(final String path, final int value) { + setInternal(path, value); + } + + public int getInt(final String path, final int def) { + final CommentedConfigurationNode node = getInternal(path); + if (node == null) { + return def; + } + return node.getInt(); + } + + public void setProperty(final String path, final double value) { + setInternal(path, value); + } + + public double getDouble(final String path, final double def) { + final CommentedConfigurationNode node = getInternal(path); + if (node == null) { + return def; + } + return node.getDouble(); + } + + public void setProperty(final String path, final float value) { + setInternal(path, value); + } + + public float getFloat(final String path, final float def) { + final CommentedConfigurationNode node = getInternal(path); + if (node == null) { + return def; + } + return node.getFloat(); + } + + public void setProperty(final String path, final BigDecimal value) { + setInternal(path, value); + } + + public BigDecimal getBigDecimal(final String path, final BigDecimal def) { + final CommentedConfigurationNode node = getInternal(path); + if (node == null) { + return def; + } + try { + return node.get(BigDecimal.class); + } catch (SerializationException e) { + return null; + } + } + + public void setRaw(final String path, final Object value) { + setInternal(path, value); + } + + public Object get(final String path) { + final CommentedConfigurationNode node = getInternal(path); + return node == null ? null : node.raw(); + } + + public CommentedConfigurationNode getSection(final String path) { + final CommentedConfigurationNode node = configurationNode.node(toSplitRoot(path)); + if (node.virtual()) { + return null; + } + return node; + } + + public CommentedConfigurationNode newSection() { + return loader.createNode(); + } + + public Set getKeys() { + return ConfigurateUtil.getKeys(configurationNode); + } + + public Map getMap() { + return ConfigurateUtil.getMap(configurationNode); + } + + public void removeProperty(String path) { + final CommentedConfigurationNode node = getInternal(path); + if (node != null) { + try { + node.set(null); + } catch (SerializationException e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + } + } + } + + private void setInternal(final String path, final Object value) { + try { + configurationNode.node(toSplitRoot(path)).set(value); + } catch (SerializationException e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + } + } + + private CommentedConfigurationNode getInternal(final String path) { + final CommentedConfigurationNode node = configurationNode.node(toSplitRoot(path)); + if (node.virtual()) { + return null; + } + return node; + } + + public boolean hasProperty(final String path) { + return !configurationNode.node(toSplitRoot(path)).isNull(); + } + + public Object[] toSplitRoot(String node) { + node = node.startsWith(".") ? node.substring(1) : node; + return node.contains(".") ? node.split("\\.") : new Object[]{node}; + } + + public synchronized void load() { + if (pendingWrites.get() != 0) { + LOGGER.log(Level.INFO, "Parsing config file {0} has been aborted due to {1} current pending write(s).", new Object[]{configFile, pendingWrites.get()}); + return; + } + + if (configFile.getParentFile() != null && !configFile.getParentFile().exists()) { + if (!configFile.getParentFile().mkdirs()) { + LOGGER.log(Level.SEVERE, tl("failedToCreateConfig", configFile.toString())); + return; + } + } + + if (!configFile.exists()) { + if (legacyFileExists()) { + convertLegacyFile(); + } else if (altFileExists()) { + convertAltFile(); + } else if (templateName != null) { + try (final InputStream is = resourceClass.getResourceAsStream(templateName)) { + LOGGER.log(Level.INFO, tl("creatingConfigFromTemplate", configFile.toString())); + Files.copy(is, configFile.toPath()); + } catch (IOException e) { + LOGGER.log(Level.SEVERE, tl("failedToWriteConfig", configFile.toString()), e); + } + } + } + + try { + configurationNode = loader.load(); + } catch (final ParsingException e) { + final File broken = new File(configFile.getAbsolutePath() + ".broken." + System.currentTimeMillis()); + if (configFile.renameTo(broken)) { + LOGGER.log(Level.SEVERE, "The file " + configFile.toString() + " is broken, it has been renamed to " + broken.toString(), e.getCause()); + return; + } + LOGGER.log(Level.SEVERE, "The file " + configFile.toString() + " is broken. A backup file has failed to be created", e.getCause()); + } catch (final ConfigurateException e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + } finally { + // Something is wrong! We need a node! I hope the backup worked! + if (configurationNode == null) { + configurationNode = loader.createNode(); + } + } + } + + public boolean legacyFileExists() { + return false; + } + + public void convertLegacyFile() { + + } + + public boolean altFileExists() { + return false; + } + + public void convertAltFile() { + + } + + /** + * Begins a transaction. + *

+ * A transaction informs Essentials to pause the saving of data. This is should be used when + * bulk operations are being done and data shouldn't be saved until after the transaction has + * been completed. + */ + public void startTransaction() { + transaction.set(true); + } + + public void stopTransaction() { + stopTransaction(false); + } + + public void stopTransaction(final boolean blocking) { + transaction.set(false); + if (blocking) { + blockingSave(); + } else { + save(); + } + } + + public void setSaveHook(Runnable saveHook) { + this.saveHook = saveHook; + } + + public synchronized void save() { + if (!transaction.get()) { + delaySave(); + } + } + + public synchronized void blockingSave() { + try { + delaySave().get(); + } catch (final InterruptedException | ExecutionException e) { + LOGGER.log(Level.SEVERE, e.getMessage(), e); + } + } + + private Future delaySave() { + if (saveHook != null) { + saveHook.run(); + } + + final CommentedConfigurationNode node = configurationNode.copy(); + + pendingWrites.incrementAndGet(); + + return EXECUTOR_SERVICE.submit(new ConfigurationSaveTask(loader, node, pendingWrites)); + } +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsUserConfiguration.java b/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsUserConfiguration.java new file mode 100644 index 000000000..2eb9ab2cb --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/config/EssentialsUserConfiguration.java @@ -0,0 +1,74 @@ +package com.earth2me.essentials.config; + +import com.google.common.base.Charsets; +import com.google.common.io.Files; + +import java.io.File; +import java.io.IOException; +import java.util.Locale; +import java.util.UUID; +import java.util.logging.Level; + +public class EssentialsUserConfiguration extends EssentialsConfiguration { + private String username; + private final UUID uuid; + + public EssentialsUserConfiguration(final String username, final UUID uuid, final File configFile) { + super(configFile); + this.username = username; + this.uuid = uuid; + } + + public String getUsername() { + return username; + } + + public UUID getUuid() { + return uuid; + } + + public void setUsername(final String username) { + this.username = username; + } + + @Override + public boolean legacyFileExists() { + return new File(configFile.getParentFile(), username + ".yml").exists(); + } + + @Override + public void convertLegacyFile() { + final File file = new File(configFile.getParentFile(), username + ".yml"); + try { + //noinspection UnstableApiUsage + Files.move(file, new File(configFile.getParentFile(), uuid + ".yml")); + } catch (final IOException ex) { + LOGGER.log(Level.WARNING, "Failed to migrate user: " + username, ex); + } + + setProperty("lastAccountName", username); + } + + private File getAltFile() { + final UUID fn = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username.toLowerCase(Locale.ENGLISH)).getBytes(Charsets.UTF_8)); + return new File(configFile.getParentFile(), fn.toString() + ".yml"); + } + + @Override + public boolean altFileExists() { + if (username.equals(username.toLowerCase())) { + return false; + } + return getAltFile().exists(); + } + + @Override + public void convertAltFile() { + try { + //noinspection UnstableApiUsage + Files.move(getAltFile(), new File(configFile.getParentFile(), uuid + ".yml")); + } catch (final IOException ex) { + LOGGER.log(Level.WARNING, "Failed to migrate user: " + username, ex); + } + } +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/annotations/DeleteOnEmpty.java b/Essentials/src/main/java/com/earth2me/essentials/config/annotations/DeleteOnEmpty.java new file mode 100644 index 000000000..364ed3177 --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/config/annotations/DeleteOnEmpty.java @@ -0,0 +1,15 @@ +package com.earth2me.essentials.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used to indicate to Configurate that the annotated field should be + * treated as null if it is a Collection, Map, or String that is empty. + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +public @interface DeleteOnEmpty { +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/entities/CommandCooldown.java b/Essentials/src/main/java/com/earth2me/essentials/config/entities/CommandCooldown.java new file mode 100644 index 000000000..56bac7ae1 --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/config/entities/CommandCooldown.java @@ -0,0 +1,28 @@ +package com.earth2me.essentials.config.entities; + +import org.spongepowered.configurate.objectmapping.ConfigSerializable; + +import java.util.regex.Pattern; + +@ConfigSerializable +public class CommandCooldown { + private Pattern pattern; + + public Pattern pattern() { + return this.pattern; + } + + public void pattern(final Pattern value) { + this.pattern = value; + } + + private Long value; + + public Long value() { + return this.value; + } + + public void value(final Long value) { + this.value = value; + } +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/holders/UserConfigHolder.java b/Essentials/src/main/java/com/earth2me/essentials/config/holders/UserConfigHolder.java new file mode 100644 index 000000000..5e8889569 --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/config/holders/UserConfigHolder.java @@ -0,0 +1,428 @@ +package com.earth2me.essentials.config.holders; + +import com.earth2me.essentials.config.annotations.DeleteOnEmpty; +import com.earth2me.essentials.config.entities.CommandCooldown; +import org.bukkit.Location; +import org.bukkit.Material; +import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.configurate.objectmapping.ConfigSerializable; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +@ConfigSerializable +public class UserConfigHolder { + private @MonotonicNonNull BigDecimal money; + + public BigDecimal money() { + return money; + } + + public void money(final BigDecimal value) { + this.money = value; + } + + @DeleteOnEmpty + private @MonotonicNonNull Map homes; + + public Map homes() { + if (this.homes == null) { + this.homes = new HashMap<>(); + } + return this.homes; + } + + public void homes(final Map value) { + this.homes = value; + } + + private @Nullable String nickname; + + public String nickname() { + return nickname; + } + + public void nickname(final String value) { + this.nickname = value; + } + + @DeleteOnEmpty + private @MonotonicNonNull Set unlimited; + + public Set unlimited() { + if (this.unlimited == null) { + this.unlimited = new HashSet<>(); + } + return this.unlimited; + } + + @DeleteOnEmpty + private @MonotonicNonNull Map> powertools; + + public Map> powertools() { + if (this.powertools == null) { + this.powertools = new HashMap<>(); + } + return this.powertools; + } + + private @MonotonicNonNull Location lastlocation; + + public Location lastLocation() { + return this.lastlocation; + } + + public void lastLocation(final Location value) { + if (value == null || value.getWorld() == null) { + return; + } + this.lastlocation = value; + } + + private @MonotonicNonNull Location logoutlocation; + + public Location logoutLocation() { + return this.logoutlocation; + } + + public void logoutLocation(final Location value) { + if (value == null || value.getWorld() == null) { + return; + } + this.logoutlocation = value; + } + + private @Nullable String jail; + + public String jail() { + return this.jail; + } + + public void jail(final String value) { + this.jail = value; + } + + @DeleteOnEmpty + private @MonotonicNonNull List mails; + + public List mails() { + if (this.mails == null) { + this.mails = new ArrayList<>(); + } + return this.mails; + } + + public void mails(final List value) { + this.mails = value; + } + + private boolean teleportenabled = true; + + public boolean teleportEnabled() { + return this.teleportenabled; + } + + public void teleportEnabled(final boolean value) { + this.teleportenabled = value; + } + + private boolean teleportauto = false; + + public boolean teleportAuto() { + return this.teleportauto; + } + + public void teleportAuto(final boolean value) { + this.teleportauto = value; + } + + @DeleteOnEmpty + private @MonotonicNonNull List ignore; + + public List ignore() { + if (this.ignore == null) { + this.ignore = new ArrayList<>(); + } + return this.ignore; + } + + public void ignore(final List value) { + this.ignore = value; + } + + private boolean godmode = false; + + public boolean godMode() { + return this.godmode; + } + + public void godMode(final boolean value) { + this.godmode = value; + } + + private boolean muted = false; + + public boolean muted() { + return this.muted; + } + + public void muted(final boolean value) { + this.muted = value; + } + + private @Nullable String muteReason; + + public String muteReason() { + return this.muteReason; + } + + public void muteReason(final String value) { + this.muteReason = value; + } + + private boolean jailed = false; + + public boolean jailed() { + return this.jailed; + } + + public void jailed(final boolean value) { + this.jailed = value; + } + + private @NonNull String ipAddress = ""; + + public String ipAddress() { + return this.ipAddress; + } + + public void ipAddress(final String value) { + this.ipAddress = value; + } + + private boolean afk = false; + + public boolean afk() { + return this.afk; + } + + public void afk(final boolean value) { + this.afk = value; + } + + @DeleteOnEmpty + private @Nullable String geolocation; + + public String geolocation() { + return this.geolocation; + } + + public void geolocation(final String value) { + this.geolocation = value; + } + + private boolean socialspy = false; + + public boolean socialSpy() { + return this.socialspy; + } + + public void socialSpy(final boolean value) { + this.socialspy = value; + } + + private boolean npc = false; + + public boolean npc() { + return this.npc; + } + + public void npc(final boolean value) { + this.npc = value; + } + + private @MonotonicNonNull String lastAccountName; + + public String lastAccountName() { + return this.lastAccountName; + } + + public void lastAccountName(final String value) { + this.lastAccountName = value; + } + + private boolean powertoolsenabled = true; + + public boolean powerToolsEnabled() { + return this.powertoolsenabled; + } + + public void powerToolsEnabled(final boolean value) { + this.powertoolsenabled = value; + } + + private boolean acceptingPay = true; + + public boolean acceptingPay() { + return this.acceptingPay; + } + + public void acceptingPay(final boolean value) { + this.acceptingPay = value; + } + + private @Nullable Boolean confirmPay; + + public Boolean confirmPay() { + return this.confirmPay; + } + + public void confirmPay(final Boolean value) { + this.confirmPay = value; + } + + private @Nullable Boolean confirmClear; + + public Boolean confirmClear() { + return this.confirmClear; + } + + public void confirmClear(final Boolean value) { + this.confirmClear = value; + } + + private @Nullable Boolean lastMessageReplyRecipient; + + public Boolean lastMessageReplyRecipient() { + return this.lastMessageReplyRecipient; + } + + public void lastMessageReplyRecipient(final Boolean value) { + this.lastMessageReplyRecipient = value; + } + + private boolean baltopExempt = false; + + public boolean baltopExempt() { + return this.baltopExempt; + } + + public void baltopExempt(final boolean value) { + this.baltopExempt = value; + } + + private @NonNull Timestamps timestamps = new Timestamps(); + + public Timestamps timestamps() { + return this.timestamps; + } + + @ConfigSerializable + public static class Timestamps { + private long lastteleport = 0L; + + public long lastTeleport() { + return this.lastteleport; + } + + public void lastTeleport(final long value) { + this.lastteleport = value; + } + + private long lastheal = 0L; + + public long lastHeal() { + return this.lastheal; + } + + public void lastHeal(final long value) { + this.lastheal = value; + } + + private long mute = 0L; + + public long mute() { + return this.mute; + } + + public void mute(final long value) { + this.mute = value; + } + + private long jail = 0L; + + public long jail() { + return this.jail; + } + + public void jail(final long value) { + this.jail = value; + } + + private long onlinejail = 0L; + + public long onlineJail() { + return this.onlinejail; + } + + public void onlineJail(final long value) { + this.onlinejail = value; + } + + private long logout = 0L; + + public long logout() { + return this.logout; + } + + public void logout(final long value) { + this.logout = value; + } + + private long login = 0L; + + public long login() { + return this.login; + } + + public void login(final long value) { + this.login = value; + } + + @DeleteOnEmpty + private @MonotonicNonNull Map kits; + + public Map kits() { + if (this.kits == null) { + this.kits = new HashMap<>(); + } + return this.kits; + } + + public void kits(final Map value) { + this.kits = value; + } + + @DeleteOnEmpty + private @MonotonicNonNull List commandCooldowns; + + public List commandCooldowns() { + if (this.commandCooldowns == null) { + this.commandCooldowns = new ArrayList<>(); + } + return this.commandCooldowns; + } + + public void commandCooldowns(final List value) { + this.commandCooldowns = value; + } + } +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/processors/DeleteOnEmptyProcessor.java b/Essentials/src/main/java/com/earth2me/essentials/config/processors/DeleteOnEmptyProcessor.java new file mode 100644 index 000000000..2f84f0ed0 --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/config/processors/DeleteOnEmptyProcessor.java @@ -0,0 +1,28 @@ +package com.earth2me.essentials.config.processors; + +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.objectmapping.meta.Processor; +import org.spongepowered.configurate.serialize.SerializationException; + +import java.util.Collection; +import java.util.Map; + +public class DeleteOnEmptyProcessor implements Processor { + @Override + public void process(final Object value, final ConfigurationNode destination) { + if (value == null) { + return; + } + try { + if (value instanceof Map && ((Map) value).isEmpty()) { + destination.set(null); + } else if (value instanceof Collection && ((Collection) value).isEmpty()) { + destination.set(null); + } else if (value instanceof CharSequence && ((CharSequence) value).length() == 0) { + destination.set(null); + } + } catch (SerializationException e) { + e.printStackTrace(); + } + } +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/serializers/BigDecimalTypeSerializer.java b/Essentials/src/main/java/com/earth2me/essentials/config/serializers/BigDecimalTypeSerializer.java new file mode 100644 index 000000000..6e147eba6 --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/config/serializers/BigDecimalTypeSerializer.java @@ -0,0 +1,61 @@ +package com.earth2me.essentials.config.serializers; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.configurate.ConfigurationOptions; +import org.spongepowered.configurate.serialize.ScalarSerializer; +import org.spongepowered.configurate.serialize.SerializationException; + +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.util.function.Predicate; + +/** + * A Configurate type serializer for {@link BigDecimal}s. + */ +public class BigDecimalTypeSerializer extends ScalarSerializer { + + public BigDecimalTypeSerializer() { + super(BigDecimal.class); + } + + @Override + public BigDecimal deserialize(Type type, Object obj) throws SerializationException { + if (obj instanceof Double) { + return BigDecimal.valueOf((double) obj); + } + + if (obj instanceof Integer) { + return BigDecimal.valueOf((int) obj); + } + + if (obj instanceof Long) { + return BigDecimal.valueOf((long) obj); + } + + if (obj instanceof BigInteger) { + return new BigDecimal((BigInteger) obj); + } + + if (obj instanceof String) { + try { + return new BigDecimal((String) obj, MathContext.DECIMAL128); + } catch (final NumberFormatException | ArithmeticException e) { + throw new SerializationException(type, "Failed to coerce input value of type " + obj.getClass() + " to BigDecimal", e); + } + } + + throw new SerializationException(type, "Failed to coerce input value of type " + obj.getClass() + " to BigDecimal"); + } + + @Override + protected Object serialize(BigDecimal item, Predicate> typeSupported) { + return item.toString(); + } + + @Override + public @Nullable BigDecimal emptyValue(Type specificType, ConfigurationOptions options) { + return BigDecimal.ZERO; + } +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/serializers/LocationTypeSerializer.java b/Essentials/src/main/java/com/earth2me/essentials/config/serializers/LocationTypeSerializer.java new file mode 100644 index 000000000..0c7a07b0f --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/config/serializers/LocationTypeSerializer.java @@ -0,0 +1,66 @@ +package com.earth2me.essentials.config.serializers; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.spongepowered.configurate.ConfigurationNode; +import org.spongepowered.configurate.serialize.SerializationException; +import org.spongepowered.configurate.serialize.TypeSerializer; + +import java.lang.reflect.Type; +import java.util.UUID; + +/** + * A Configurate type serializer for {@link Location}s. + * + * Locations with a null or empty world will be considered invalid. + */ +public class LocationTypeSerializer implements TypeSerializer { + @Override + public Location deserialize(Type type, ConfigurationNode node) throws SerializationException { + final String worldValue = node.node("world").getString(); + if (worldValue == null || worldValue.isEmpty()) { + throw new SerializationException("No world value present!"); + } + + World world = null; + + try { + final UUID worldId = UUID.fromString(worldValue); + world = Bukkit.getWorld(worldId); + } catch (IllegalArgumentException ignored) { + } + + if (world == null) { + world = Bukkit.getWorld(worldValue); + } + + if (world == null) { + throw new SerializationException("No world value present!"); + } + + return new Location( + world, + node.node("x").getDouble(), + node.node("y").getDouble(), + node.node("z").getDouble(), + node.node("yaw").getFloat(), + node.node("pitch").getFloat()); + } + + @Override + public void serialize(Type type, @Nullable Location value, ConfigurationNode node) throws SerializationException { + if (value == null || value.getWorld() == null) { + node.raw(null); + return; + } + + node.node("world").set(String.class, value.getWorld().getName()); + node.node("x").set(Double.class, value.getX()); + node.node("y").set(Double.class, value.getY()); + node.node("z").set(Double.class, value.getZ()); + node.node("yaw").set(Float.class, value.getYaw()); + node.node("pitch").set(Float.class, value.getPitch()); + } +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/config/serializers/MaterialTypeSerializer.java b/Essentials/src/main/java/com/earth2me/essentials/config/serializers/MaterialTypeSerializer.java new file mode 100644 index 000000000..ca940a3b5 --- /dev/null +++ b/Essentials/src/main/java/com/earth2me/essentials/config/serializers/MaterialTypeSerializer.java @@ -0,0 +1,27 @@ +package com.earth2me.essentials.config.serializers; + +import org.bukkit.Material; +import org.spongepowered.configurate.serialize.ScalarSerializer; +import org.spongepowered.configurate.serialize.SerializationException; + +import java.lang.reflect.Type; +import java.util.function.Predicate; + +public class MaterialTypeSerializer extends ScalarSerializer { + public MaterialTypeSerializer() { + super(Material.class); + } + + @Override + public Material deserialize(Type type, Object obj) throws SerializationException { + if (obj instanceof String) { + return Material.matchMaterial((String) obj); + } + return null; + } + + @Override + protected Object serialize(Material item, Predicate> typeSupported) { + return item.name(); + } +} diff --git a/Essentials/src/main/java/com/earth2me/essentials/economy/vault/VaultEconomyProvider.java b/Essentials/src/main/java/com/earth2me/essentials/economy/vault/VaultEconomyProvider.java index b07c4b0ce..054c95462 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/economy/vault/VaultEconomyProvider.java +++ b/Essentials/src/main/java/com/earth2me/essentials/economy/vault/VaultEconomyProvider.java @@ -1,9 +1,9 @@ package com.earth2me.essentials.economy.vault; import com.earth2me.essentials.Essentials; -import com.earth2me.essentials.EssentialsUserConf; import com.earth2me.essentials.api.NoLoanPermittedException; import com.earth2me.essentials.api.UserDoesNotExistException; +import com.earth2me.essentials.config.EssentialsUserConfiguration; import com.earth2me.essentials.utils.NumberUtil; import com.google.common.base.Charsets; import net.ess3.api.MaxMoneyException; @@ -303,12 +303,12 @@ public class VaultEconomyProvider implements Economy { LOGGER.log(Level.SEVERE, MessageFormat.format(WARN_NPC_RECREATE_1, player.getName(), player.getUniqueId().toString()), new RuntimeException()); LOGGER.log(Level.SEVERE, WARN_NPC_RECREATE_2); } - final EssentialsUserConf npcConfig = new EssentialsUserConf(player.getName(), player.getUniqueId(), npcFile); + final EssentialsUserConfiguration npcConfig = new EssentialsUserConfiguration(player.getName(), player.getUniqueId(), npcFile); npcConfig.load(); npcConfig.setProperty("npc", true); npcConfig.setProperty("lastAccountName", player.getName()); npcConfig.setProperty("money", ess.getSettings().getStartingBalance()); - npcConfig.forceSave(); + npcConfig.blockingSave(); ess.getUserMap().trackUUID(player.getUniqueId(), player.getName(), false); return true; } diff --git a/Essentials/src/main/java/com/earth2me/essentials/items/CustomItemResolver.java b/Essentials/src/main/java/com/earth2me/essentials/items/CustomItemResolver.java index 18fbdfb05..6e49feb19 100644 --- a/Essentials/src/main/java/com/earth2me/essentials/items/CustomItemResolver.java +++ b/Essentials/src/main/java/com/earth2me/essentials/items/CustomItemResolver.java @@ -1,10 +1,10 @@ package com.earth2me.essentials.items; import com.earth2me.essentials.Essentials; -import com.earth2me.essentials.EssentialsConf; import com.earth2me.essentials.IConf; +import com.earth2me.essentials.config.ConfigurateUtil; +import com.earth2me.essentials.config.EssentialsConfiguration; import net.ess3.api.IItemDb; -import org.bukkit.configuration.ConfigurationSection; import org.bukkit.inventory.ItemStack; import java.io.File; @@ -15,14 +15,13 @@ import java.util.List; import java.util.Map; public class CustomItemResolver implements IItemDb.ItemResolver, IConf { - private final EssentialsConf config; + private final EssentialsConfiguration config; private final Essentials ess; private final HashMap map = new HashMap<>(); public CustomItemResolver(final Essentials ess) { - config = new EssentialsConf(new File(ess.getDataFolder(), "custom_items.yml")); + config = new EssentialsConfiguration(new File(ess.getDataFolder(), "custom_items.yml"), "/custom_items.yml"); this.ess = ess; - config.setTemplateName("/custom_items.yml"); } @Override @@ -57,18 +56,20 @@ public class CustomItemResolver implements IItemDb.ItemResolver, IConf { map.clear(); config.load(); - final ConfigurationSection section = config.getConfigurationSection("aliases"); - if (section == null || section.getKeys(false).isEmpty()) { + final Map section = ConfigurateUtil.getRawMap(config.getSection("aliases")); + if (section.isEmpty()) { ess.getLogger().warning("No aliases found in custom_items.yml."); return; } - for (final String alias : section.getKeys(false)) { - if (!section.isString(alias)) continue; - final String target = section.getString(alias); + for (final Map.Entry alias : section.entrySet()) { + if (!(alias.getValue() instanceof String)) { + continue; + } + final String target = (String) alias.getValue(); - if (target != null && !section.contains(target) && existsInItemDb(target)) { - map.put(alias, target); + if (existsInItemDb(target)) { + map.put(alias.getKey(), target); } } } @@ -89,7 +90,7 @@ public class CustomItemResolver implements IItemDb.ItemResolver, IConf { } private void save() { - config.setProperty("aliases", map); + config.setRaw("aliases", map); config.save(); } diff --git a/Essentials/src/main/java/com/earth2me/essentials/settings/Jails.java b/Essentials/src/main/java/com/earth2me/essentials/settings/Jails.java deleted file mode 100644 index 1c867cfa8..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/settings/Jails.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.earth2me.essentials.settings; - -import com.earth2me.essentials.storage.MapValueType; -import com.earth2me.essentials.storage.StorageObject; -import org.bukkit.Location; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -public class Jails implements StorageObject { - @MapValueType(Location.class) - private Map jails = new HashMap<>(); - - public Map getJails() { - return jails; - } - - public void setJails(final Map jails) { - this.jails = jails; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final Jails jails1 = (Jails) o; - return Objects.equals(jails, jails1.jails); - } - - @Override - public int hashCode() { - return Objects.hash(jails); - } -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/settings/Spawns.java b/Essentials/src/main/java/com/earth2me/essentials/settings/Spawns.java deleted file mode 100644 index 5f0c3b5e0..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/settings/Spawns.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.earth2me.essentials.settings; - -import com.earth2me.essentials.storage.MapValueType; -import com.earth2me.essentials.storage.StorageObject; -import org.bukkit.Location; - -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; - -public class Spawns implements StorageObject { - @MapValueType(Location.class) - private Map spawns = new HashMap<>(); - - public Map getSpawns() { - return spawns; - } - - public void setSpawns(final Map spawns) { - this.spawns = spawns; - } - - @Override - public boolean equals(final Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - final Spawns spawns1 = (Spawns) o; - return Objects.equals(spawns, spawns1.spawns); - } - - @Override - public int hashCode() { - return Objects.hash(spawns); - } -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/AbstractDelayedYamlFileReader.java b/Essentials/src/main/java/com/earth2me/essentials/storage/AbstractDelayedYamlFileReader.java deleted file mode 100644 index 1903a20f6..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/AbstractDelayedYamlFileReader.java +++ /dev/null @@ -1,56 +0,0 @@ -package com.earth2me.essentials.storage; - -import net.ess3.api.IEssentials; -import org.bukkit.Bukkit; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.util.logging.Level; - -public abstract class AbstractDelayedYamlFileReader implements Runnable { - protected final transient IEssentials plugin; - private final transient File file; - private final transient Class clazz; - - public AbstractDelayedYamlFileReader(final IEssentials ess, final File file, final Class clazz) { - this.file = file; - this.clazz = clazz; - this.plugin = ess; - ess.runTaskAsynchronously(this); - } - - public abstract void onStart(); - - @Override - public void run() { - onStart(); - try { - final FileReader reader = new FileReader(file); - try { - final T object = new YamlStorageReader(reader, plugin).load(clazz); - onSuccess(object); - } finally { - try { - reader.close(); - } catch (final IOException ex) { - Bukkit.getLogger().log(Level.SEVERE, "File can't be closed: " + file.toString(), ex); - } - } - - } catch (final FileNotFoundException ex) { - onException(); - if (plugin.getSettings() == null || plugin.getSettings().isDebug()) { - Bukkit.getLogger().log(Level.INFO, "File not found: " + file.toString()); - } - } catch (final ObjectLoadException ex) { - onException(); - Bukkit.getLogger().log(Level.SEVERE, "File broken: " + file.toString(), ex.getCause()); - } - } - - public abstract void onSuccess(T object); - - public abstract void onException(); -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/AbstractDelayedYamlFileWriter.java b/Essentials/src/main/java/com/earth2me/essentials/storage/AbstractDelayedYamlFileWriter.java deleted file mode 100644 index 0b75a53dd..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/AbstractDelayedYamlFileWriter.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.earth2me.essentials.storage; - -import net.ess3.api.IEssentials; -import org.bukkit.Bukkit; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintWriter; -import java.util.logging.Level; - -public abstract class AbstractDelayedYamlFileWriter implements Runnable { - private final transient File file; - - public AbstractDelayedYamlFileWriter(final IEssentials ess, final File file) { - this.file = file; - ess.runTaskAsynchronously(this); - } - - public abstract StorageObject getObject(); - - @Override - public void run() { - PrintWriter pw = null; - try { - final StorageObject object = getObject(); - final File folder = file.getParentFile(); - if (!folder.exists()) { - folder.mkdirs(); - } - pw = new PrintWriter(file); - new YamlStorageWriter(pw).save(object); - } catch (final FileNotFoundException ex) { - Bukkit.getLogger().log(Level.SEVERE, file.toString(), ex); - } finally { - onFinish(); - if (pw != null) { - pw.close(); - } - } - - } - - public abstract void onFinish(); -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/AsyncStorageObjectHolder.java b/Essentials/src/main/java/com/earth2me/essentials/storage/AsyncStorageObjectHolder.java deleted file mode 100644 index 6788bd4af..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/AsyncStorageObjectHolder.java +++ /dev/null @@ -1,128 +0,0 @@ -package com.earth2me.essentials.storage; - -import com.earth2me.essentials.IConf; -import net.ess3.api.IEssentials; -import net.ess3.api.IReload; -import org.bukkit.Bukkit; - -import java.io.File; -import java.util.concurrent.locks.ReentrantReadWriteLock; -import java.util.logging.Level; - -public abstract class AsyncStorageObjectHolder implements IConf, IStorageObjectHolder, IReload { - protected final transient IEssentials ess; - private final transient ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); - private final transient Class clazz; - private transient T data; - - public AsyncStorageObjectHolder(final IEssentials ess, final Class clazz) { - this.ess = ess; - this.clazz = clazz; - try { - this.data = clazz.newInstance(); - } catch (final IllegalAccessException | InstantiationException ex) { - Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); - } - } - - @Override - public T getData() { - return data; - } - - @Override - public void acquireReadLock() { - rwl.readLock().lock(); - } - - @Override - public void acquireWriteLock() { - while (rwl.getReadHoldCount() > 0) { - rwl.readLock().unlock(); - } - rwl.writeLock().lock(); - rwl.readLock().lock(); - } - - @Override - public void close() { - unlock(); - } - - @Override - public void unlock() { - if (rwl.isWriteLockedByCurrentThread()) { - rwl.writeLock().unlock(); - new StorageObjectDataWriter(); - } - while (rwl.getReadHoldCount() > 0) { - rwl.readLock().unlock(); - } - } - - @Override - public void reloadConfig() { - new StorageObjectDataReader(); - } - - @Override - public void onReload() { - new StorageObjectDataReader(); - } - - public abstract void finishRead(); - - public abstract void finishWrite(); - - public abstract File getStorageFile(); - - private class StorageObjectDataWriter extends AbstractDelayedYamlFileWriter { - StorageObjectDataWriter() { - super(ess, getStorageFile()); - } - - @Override - public StorageObject getObject() { - acquireReadLock(); - return getData(); - } - - @Override - public void onFinish() { - unlock(); - finishWrite(); - } - } - - private class StorageObjectDataReader extends AbstractDelayedYamlFileReader { - StorageObjectDataReader() { - super(ess, getStorageFile(), clazz); - } - - @Override - public void onStart() { - rwl.writeLock().lock(); - } - - @Override - public void onSuccess(final T object) { - if (object != null) { - data = object; - } - rwl.writeLock().unlock(); - finishRead(); - } - - @Override - public void onException() { - if (data == null) { - try { - data = clazz.newInstance(); - } catch (final IllegalAccessException | InstantiationException ex) { - Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); - } - } - rwl.writeLock().unlock(); - } - } -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/BukkitConstructor.java b/Essentials/src/main/java/com/earth2me/essentials/storage/BukkitConstructor.java deleted file mode 100644 index d4aa1d3b4..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/BukkitConstructor.java +++ /dev/null @@ -1,214 +0,0 @@ -package com.earth2me.essentials.storage; - -import com.earth2me.essentials.Enchantments; -import com.earth2me.essentials.utils.NumberUtil; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.inventory.ItemStack; -import org.bukkit.material.MaterialData; -import org.bukkit.plugin.Plugin; -import org.yaml.snakeyaml.constructor.BaseConstructor; -import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor; -import org.yaml.snakeyaml.introspector.PropertyUtils; -import org.yaml.snakeyaml.nodes.MappingNode; -import org.yaml.snakeyaml.nodes.Node; -import org.yaml.snakeyaml.nodes.NodeId; -import org.yaml.snakeyaml.nodes.NodeTuple; -import org.yaml.snakeyaml.nodes.ScalarNode; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class BukkitConstructor extends CustomClassLoaderConstructor { - private Method constructScalarMethod = null; - - public BukkitConstructor(final Class clazz, final Plugin plugin) { - super(clazz, plugin.getClass().getClassLoader()); - yamlClassConstructors.put(NodeId.scalar, new ConstructBukkitScalar()); - yamlClassConstructors.put(NodeId.mapping, new ConstructBukkitMapping()); - - final PropertyUtils propertyUtils = getPropertyUtils(); - propertyUtils.setSkipMissingProperties(true); - setPropertyUtils(propertyUtils); - } - - protected String constructScalarRefl(final ScalarNode scalarNode) { - try { - if (constructScalarMethod == null) { - constructScalarMethod = BaseConstructor.class.getDeclaredMethod("constructScalar", ScalarNode.class); - } - return (String) constructScalarMethod.invoke(this, scalarNode); - } catch (final NoSuchMethodException - | SecurityException - | IllegalAccessException - | IllegalArgumentException - | InvocationTargetException e) { - e.printStackTrace(); - } - - return null; - } - - private class ConstructBukkitScalar extends ConstructScalar { - - @Override - public Object construct(final Node node) { - if (node.getType().equals(Material.class)) { - final String val = constructScalarRefl((ScalarNode) node); - return Material.matchMaterial(val); - } - - if (node.getType().equals(MaterialData.class)) { - final String val = constructScalarRefl((ScalarNode) node); - if (val.isEmpty()) { - return null; - } - final String[] split = val.split("[:+',;.]", 2); - if (split.length == 0) { - return null; - } - - final Material mat = Material.matchMaterial(split[0]); - - if (mat == null) { - return null; - } - byte data = 0; - if (split.length == 2 && NumberUtil.isInt(split[1])) { - data = Byte.parseByte(split[1]); - } - return new MaterialData(mat, data); - } - if (node.getType().equals(ItemStack.class)) { - final String val = constructScalarRefl((ScalarNode) node); - if (val.isEmpty()) { - return null; - } - final String[] split1 = val.split("\\W"); - if (split1.length == 0) { - return null; - } - final String[] split2 = split1[0].split("[:+',;.]", 2); - if (split2.length == 0) { - return null; - } - - final Material mat = Material.matchMaterial(split2[0]); - - if (mat == null) { - return null; - } - short data = 0; - if (split2.length == 2 && NumberUtil.isInt(split2[1])) { - data = Short.parseShort(split2[1]); - } - int size = mat.getMaxStackSize(); - if (split1.length > 1 && NumberUtil.isInt(split1[1])) { - size = Integer.parseInt(split1[1]); - } - final ItemStack stack = new ItemStack(mat, size, data); - if (split1.length > 2) { - for (int i = 2; i < split1.length; i++) { - final String[] split3 = split1[0].split("[:+',;.]", 2); - if (split3.length < 1) { - continue; - } - final Enchantment enchantment = Enchantments.getByName(split3[0]); - if (enchantment == null) { - continue; - } - int level = enchantment.getStartLevel(); - if (split3.length == 2 && NumberUtil.isInt(split3[1])) { - level = Integer.parseInt(split3[1]); - } - if (level < enchantment.getStartLevel()) { - level = enchantment.getStartLevel(); - } - if (level > enchantment.getMaxLevel()) { - level = enchantment.getMaxLevel(); - } - stack.addUnsafeEnchantment(enchantment, level); - } - } - return stack; - } - if (node.getType().equals(EnchantmentLevel.class)) { - final String val = constructScalarRefl((ScalarNode) node); - if (val.isEmpty()) { - return null; - } - final String[] split = val.split("[:+',;.]", 2); - if (split.length == 0) { - return null; - } - final Enchantment enchant = Enchantments.getByName(split[0]); - if (enchant == null) { - return null; - } - int level = enchant.getStartLevel(); - if (split.length == 2 && NumberUtil.isInt(split[1])) { - level = Integer.parseInt(split[1]); - } - if (level < enchant.getStartLevel()) { - level = enchant.getStartLevel(); - } - if (level > enchant.getMaxLevel()) { - level = enchant.getMaxLevel(); - } - return new EnchantmentLevel(enchant, level); - } - return super.construct(node); - } - } - - private class ConstructBukkitMapping extends ConstructMapping { - - @Override - public Object construct(final Node node) { - if (node.getType().equals(Location.class)) { - //TODO: NPE checks - final MappingNode mnode = (MappingNode) node; - String worldName = ""; - double x = 0, y = 0, z = 0; - float yaw = 0, pitch = 0; - if (mnode.getValue().size() < 4) { - return null; - } - for (final NodeTuple nodeTuple : mnode.getValue()) { - final String key = constructScalarRefl((ScalarNode) nodeTuple.getKeyNode()); - final ScalarNode snode = (ScalarNode) nodeTuple.getValueNode(); - if (key.equalsIgnoreCase("world")) { - worldName = constructScalarRefl(snode); - } - if (key.equalsIgnoreCase("x")) { - x = Double.parseDouble(constructScalarRefl(snode)); - } - if (key.equalsIgnoreCase("y")) { - y = Double.parseDouble(constructScalarRefl(snode)); - } - if (key.equalsIgnoreCase("z")) { - z = Double.parseDouble(constructScalarRefl(snode)); - } - if (key.equalsIgnoreCase("yaw")) { - yaw = Float.parseFloat(constructScalarRefl(snode)); - } - if (key.equalsIgnoreCase("pitch")) { - pitch = Float.parseFloat(constructScalarRefl(snode)); - } - } - if (worldName == null || worldName.isEmpty()) { - return null; - } - final World world = Bukkit.getWorld(worldName); - if (world == null) { - return null; - } - return new Location(world, x, y, z, yaw, pitch); - } - return super.construct(node); - } - } -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/Comment.java b/Essentials/src/main/java/com/earth2me/essentials/storage/Comment.java deleted file mode 100644 index 0a4514a67..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/Comment.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.earth2me.essentials.storage; - -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; - -@Target(ElementType.FIELD) -@Documented -@Retention(RetentionPolicy.RUNTIME) -public @interface Comment { - String[] value() default ""; -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/EnchantmentLevel.java b/Essentials/src/main/java/com/earth2me/essentials/storage/EnchantmentLevel.java deleted file mode 100644 index b9290a761..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/EnchantmentLevel.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.earth2me.essentials.storage; - -import org.bukkit.enchantments.Enchantment; - -import java.util.Map.Entry; - -public class EnchantmentLevel implements Entry { - private Enchantment enchantment; - private int level; - - public EnchantmentLevel(final Enchantment enchantment, final int level) { - this.enchantment = enchantment; - this.level = level; - } - - public Enchantment getEnchantment() { - return enchantment; - } - - public void setEnchantment(final Enchantment enchantment) { - this.enchantment = enchantment; - } - - public int getLevel() { - return level; - } - - public void setLevel(final int level) { - this.level = level; - } - - @Override - public Enchantment getKey() { - return enchantment; - } - - @Override - public Integer getValue() { - return level; - } - - @Override - public Integer setValue(final Integer v) { - final int t = level; - level = v; - return t; - } - - @Override - public int hashCode() { - return enchantment.hashCode() ^ level; - } - - @Override - public boolean equals(final Object obj) { - if (obj instanceof Entry) { - final Entry entry = (Entry) obj; - if (entry.getKey() instanceof Enchantment && entry.getValue() instanceof Integer) { - final Enchantment enchant = (Enchantment) entry.getKey(); - final Integer lvl = (Integer) entry.getValue(); - return this.enchantment.equals(enchant) && this.level == lvl; - } - } - return false; - } -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/IStorageObjectHolder.java b/Essentials/src/main/java/com/earth2me/essentials/storage/IStorageObjectHolder.java deleted file mode 100644 index b7ef42d7e..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/IStorageObjectHolder.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.earth2me.essentials.storage; - -public interface IStorageObjectHolder { - T getData(); - - void acquireReadLock(); - - void acquireWriteLock(); - - void close(); - - void unlock(); -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/IStorageReader.java b/Essentials/src/main/java/com/earth2me/essentials/storage/IStorageReader.java deleted file mode 100644 index b21d9aa31..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/IStorageReader.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.earth2me.essentials.storage; - -public interface IStorageReader { - T load(final Class clazz) throws ObjectLoadException; -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/IStorageWriter.java b/Essentials/src/main/java/com/earth2me/essentials/storage/IStorageWriter.java deleted file mode 100644 index 698ee9ec1..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/IStorageWriter.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.earth2me.essentials.storage; - -public interface IStorageWriter { - void save(final StorageObject object); -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/ListType.java b/Essentials/src/main/java/com/earth2me/essentials/storage/ListType.java deleted file mode 100644 index d58af7930..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/ListType.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.earth2me.essentials.storage; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface ListType { - Class value() default String.class; -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/MapKeyType.java b/Essentials/src/main/java/com/earth2me/essentials/storage/MapKeyType.java deleted file mode 100644 index 2a2374d55..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/MapKeyType.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.earth2me.essentials.storage; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface MapKeyType { - Class value() default String.class; -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/MapValueType.java b/Essentials/src/main/java/com/earth2me/essentials/storage/MapValueType.java deleted file mode 100644 index ef6d72e7b..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/MapValueType.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.earth2me.essentials.storage; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target(ElementType.FIELD) -@Retention(RetentionPolicy.RUNTIME) -public @interface MapValueType { - Class value() default String.class; -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/ObjectLoadException.java b/Essentials/src/main/java/com/earth2me/essentials/storage/ObjectLoadException.java deleted file mode 100644 index 97a1de67d..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/ObjectLoadException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.earth2me.essentials.storage; - -public class ObjectLoadException extends Exception { - public ObjectLoadException(final Throwable thrwbl) { - super(thrwbl); - } -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/StorageObject.java b/Essentials/src/main/java/com/earth2me/essentials/storage/StorageObject.java deleted file mode 100644 index 7e01ce463..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/StorageObject.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.earth2me.essentials.storage; - -public interface StorageObject { -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/YamlStorageReader.java b/Essentials/src/main/java/com/earth2me/essentials/storage/YamlStorageReader.java deleted file mode 100644 index f3038fb6a..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/YamlStorageReader.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.earth2me.essentials.storage; - -import org.bukkit.plugin.Plugin; -import org.yaml.snakeyaml.TypeDescription; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.Constructor; - -import java.io.Reader; -import java.lang.reflect.Field; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.locks.ReentrantLock; - -public class YamlStorageReader implements IStorageReader { - private transient static final Map PREPARED_YAMLS = Collections.synchronizedMap(new HashMap<>()); - private transient static final Map LOCKS = new HashMap<>(); - private transient final Reader reader; - private transient final Plugin plugin; - - public YamlStorageReader(final Reader reader, final Plugin plugin) { - this.reader = reader; - this.plugin = plugin; - } - - @Override - public T load(final Class clazz) throws ObjectLoadException { - Yaml yaml = PREPARED_YAMLS.get(clazz); - if (yaml == null) { - yaml = new Yaml(prepareConstructor(clazz)); - PREPARED_YAMLS.put(clazz, yaml); - } - ReentrantLock lock; - synchronized (LOCKS) { - lock = LOCKS.get(clazz); - if (lock == null) { - lock = new ReentrantLock(); - } - } - lock.lock(); - try { - T object = yaml.load(reader); - if (object == null) { - object = clazz.newInstance(); - } - return object; - } catch (final IllegalAccessException | InstantiationException ex) { - throw new ObjectLoadException(ex); - } finally { - lock.unlock(); - } - } - - private Constructor prepareConstructor(final Class clazz) { - final Constructor constructor = new BukkitConstructor(clazz, plugin); - final Set classes = new HashSet<>(); - - prepareConstructor(constructor, classes, clazz); - return constructor; - } - - private void prepareConstructor(final Constructor constructor, final Set classes, final Class clazz) { - classes.add(clazz); - final TypeDescription description = new TypeDescription(clazz); - for (final Field field : clazz.getDeclaredFields()) { - prepareList(field, description, classes, constructor); - prepareMap(field, description, classes, constructor); - if (StorageObject.class.isAssignableFrom(field.getType()) && !classes.contains(field.getType())) { - prepareConstructor(constructor, classes, field.getType()); - } - } - constructor.addTypeDescription(description); - } - - private void prepareList(final Field field, final TypeDescription description, final Set classes, final Constructor constructor) { - final ListType listType = field.getAnnotation(ListType.class); - if (listType != null) { - description.putListPropertyType(field.getName(), listType.value()); - if (StorageObject.class.isAssignableFrom(listType.value()) && !classes.contains(listType.value())) { - prepareConstructor(constructor, classes, listType.value()); - } - } - } - - private void prepareMap(final Field field, final TypeDescription description, final Set classes, final Constructor constructor) { - final MapValueType mapType = field.getAnnotation(MapValueType.class); - if (mapType != null) { - final MapKeyType mapKeyType = field.getAnnotation(MapKeyType.class); - description.putMapPropertyType(field.getName(), mapKeyType == null ? String.class : mapKeyType.value(), mapType.value()); - if (StorageObject.class.isAssignableFrom(mapType.value()) && !classes.contains(mapType.value())) { - prepareConstructor(constructor, classes, mapType.value()); - } - } - } -} diff --git a/Essentials/src/main/java/com/earth2me/essentials/storage/YamlStorageWriter.java b/Essentials/src/main/java/com/earth2me/essentials/storage/YamlStorageWriter.java deleted file mode 100644 index c6a8a3532..000000000 --- a/Essentials/src/main/java/com/earth2me/essentials/storage/YamlStorageWriter.java +++ /dev/null @@ -1,254 +0,0 @@ -package com.earth2me.essentials.storage; - -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.inventory.ItemStack; -import org.bukkit.material.MaterialData; -import org.yaml.snakeyaml.Yaml; - -import java.io.PrintWriter; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.Collection; -import java.util.Collections; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Pattern; - -public class YamlStorageWriter implements IStorageWriter { - private transient static final Pattern NON_WORD_PATTERN = Pattern.compile("\\W"); - private transient static final Yaml YAML = new Yaml(); - private transient final PrintWriter writer; - - public YamlStorageWriter(final PrintWriter writer) { - this.writer = writer; - } - - @Override - public void save(final StorageObject object) { - try { - writeToFile(object, 0, object.getClass()); - } catch (final IllegalArgumentException | IllegalAccessException ex) { - Logger.getLogger(YamlStorageWriter.class.getName()).log(Level.SEVERE, null, ex); - } - } - - private void writeToFile(final Object object, final int depth, final Class clazz) throws IllegalAccessException { - for (final Field field : clazz.getDeclaredFields()) { - final int modifier = field.getModifiers(); - if (Modifier.isPrivate(modifier) && !Modifier.isTransient(modifier) && !Modifier.isStatic(modifier)) { - field.setAccessible(true); - - final Object data = field.get(object); - if (writeKey(field, depth, data)) { - continue; - } - if (data instanceof StorageObject) { - writer.println(); - writeToFile(data, depth + 1, data.getClass()); - } else if (data instanceof Map) { - writeMap((Map) data, depth + 1); - } else if (data instanceof Collection) { - writeCollection((Collection) data, depth + 1); - } else if (data instanceof Location) { - writeLocation((Location) data, depth + 1); - } else { - writeScalar(data); - writer.println(); - } - } - } - } - - private boolean writeKey(final Field field, final int depth, final Object data) { - final boolean commentPresent = writeComment(field, depth); - if (data == null && !commentPresent) { - return true; - } - writeIndention(depth); - if (data == null && commentPresent) { - writer.print('#'); - } - final String name = field.getName(); - writer.print(name); - writer.print(": "); - if (data == null && commentPresent) { - writer.println(); - writer.println(); - return true; - } - return false; - } - - private boolean writeComment(final Field field, final int depth) { - final boolean commentPresent = field.isAnnotationPresent(Comment.class); - if (commentPresent) { - final Comment comments = field.getAnnotation(Comment.class); - for (final String comment : comments.value()) { - final String trimmed = comment.trim(); - if (trimmed.isEmpty()) { - continue; - } - writeIndention(depth); - writer.print("# "); - writer.print(trimmed); - writer.println(); - } - } - return commentPresent; - } - - private void writeCollection(final Collection data, final int depth) throws IllegalAccessException { - writer.println(); - if (data.isEmpty()) { - writer.println(); - } - for (final Object entry : data) { - if (entry != null) { - writeIndention(depth); - writer.print("- "); - if (entry instanceof StorageObject) { - writer.println(); - writeToFile(entry, depth + 1, entry.getClass()); - } else if (entry instanceof Location) { - writeLocation((Location) entry, depth + 1); - } else { - writeScalar(entry); - } - } - } - writer.println(); - } - - private void writeMap(final Map data, final int depth) throws IllegalArgumentException, IllegalAccessException { - writer.println(); - if (data.isEmpty()) { - writer.println(); - } - for (final Entry entry : data.entrySet()) { - final Object value = entry.getValue(); - if (value != null) { - writeIndention(depth); - writeKey(entry.getKey()); - writer.print(": "); - if (value instanceof StorageObject) { - writer.println(); - writeToFile(value, depth + 1, value.getClass()); - } else if (value instanceof Collection) { - writeCollection((Collection) value, depth + 1); - } else if (value instanceof Location) { - writeLocation((Location) value, depth + 1); - } else { - writeScalar(value); - writer.println(); - } - } - } - } - - private void writeIndention(final int depth) { - for (int i = 0; i < depth; i++) { - writer.print(" "); - } - } - - private void writeScalar(final Object data) { - if (data instanceof String || data instanceof Boolean || data instanceof Number) { - synchronized (YAML) { - YAML.dumpAll(Collections.singletonList(data).iterator(), writer); - } - } else if (data instanceof Material) { - writeMaterial(data); - writer.println(); - } else if (data instanceof MaterialData) { - writeMaterialData(data); - writer.println(); - } else if (data instanceof ItemStack) { - writeItemStack(data); - writer.println(); - } else if (data instanceof EnchantmentLevel) { - writeEnchantmentLevel(data); - writer.println(); - } else { - throw new UnsupportedOperationException(); - } - } - - private void writeKey(final Object data) { - if (data instanceof String || data instanceof Boolean || data instanceof Number) { - final String output = data.toString(); - if (NON_WORD_PATTERN.matcher(output).find()) { - writer.print('"'); - writer.print(output.replace("\"", "\\\"")); - writer.print('"'); - } else { - writer.print(output); - } - } else if (data instanceof Material) { - writeMaterial(data); - } else if (data instanceof MaterialData) { - writeMaterialData(data); - } else if (data instanceof EnchantmentLevel) { - writeEnchantmentLevel(data); - } else { - throw new UnsupportedOperationException(); - } - } - - private void writeMaterial(final Object data) { - writer.print(data.toString().toLowerCase(Locale.ENGLISH)); - } - - private void writeMaterialData(final Object data) { - final MaterialData matData = (MaterialData) data; - writeMaterial(matData.getItemType()); - if (matData.getData() > 0) { - writer.print(':'); - writer.print(matData.getData()); - } - } - - private void writeItemStack(final Object data) { - final ItemStack itemStack = (ItemStack) data; - writeMaterialData(itemStack.getData()); - writer.print(' '); - writer.print(itemStack.getAmount()); - for (final Entry entry : itemStack.getEnchantments().entrySet()) { - writer.print(' '); - writeEnchantmentLevel(entry); - } - } - - private void writeEnchantmentLevel(final Object data) { - final Entry enchLevel = (Entry) data; - writer.print(enchLevel.getKey().getName().toLowerCase(Locale.ENGLISH)); - writer.print(':'); - writer.print(enchLevel.getValue()); - } - - private void writeLocation(final Location entry, final int depth) { - writer.println(); - writeIndention(depth); - writer.print("world: "); - writeScalar(entry.getWorld().getName()); - writeIndention(depth); - writer.print("x: "); - writeScalar(entry.getX()); - writeIndention(depth); - writer.print("y: "); - writeScalar(entry.getY()); - writeIndention(depth); - writer.print("z: "); - writeScalar(entry.getZ()); - writeIndention(depth); - writer.print("yaw: "); - writeScalar(entry.getYaw()); - writeIndention(depth); - writer.print("pitch: "); - writeScalar(entry.getPitch()); - } -} diff --git a/Essentials/src/main/java/net/ess3/api/IReload.java b/Essentials/src/main/java/net/ess3/api/IReload.java deleted file mode 100644 index 734708930..000000000 --- a/Essentials/src/main/java/net/ess3/api/IReload.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.ess3.api; - -/** - * Represents a storage object that is reloadable. - * - * @deprecated This is a remnant of the abandoned 3.x storage system. Neither future 2.x code nor external plugins - * should use this interface. - */ -@Deprecated -public interface IReload extends com.earth2me.essentials.api.IReload { - -} diff --git a/EssentialsGeoIP/src/main/java/com/earth2me/essentials/geoip/EssentialsGeoIPPlayerListener.java b/EssentialsGeoIP/src/main/java/com/earth2me/essentials/geoip/EssentialsGeoIPPlayerListener.java index 806b138d5..9bdbc30bd 100644 --- a/EssentialsGeoIP/src/main/java/com/earth2me/essentials/geoip/EssentialsGeoIPPlayerListener.java +++ b/EssentialsGeoIP/src/main/java/com/earth2me/essentials/geoip/EssentialsGeoIPPlayerListener.java @@ -1,8 +1,8 @@ package com.earth2me.essentials.geoip; -import com.earth2me.essentials.EssentialsConf; import com.earth2me.essentials.IConf; import com.earth2me.essentials.User; +import com.earth2me.essentials.config.EssentialsConfiguration; import com.ice.tar.TarEntry; import com.ice.tar.TarInputStream; import com.maxmind.geoip2.DatabaseReader; @@ -39,7 +39,7 @@ import static com.earth2me.essentials.I18n.tl; public class EssentialsGeoIPPlayerListener implements Listener, IConf { private static final Logger logger = Logger.getLogger("EssentialsGeoIP"); private final File dataFolder; - private final EssentialsConf config; + private final EssentialsConfiguration config; private final transient IEssentials ess; private DatabaseReader mmreader = null; // initialize maxmind geoip2 reader private File databaseFile; @@ -47,8 +47,7 @@ public class EssentialsGeoIPPlayerListener implements Listener, IConf { EssentialsGeoIPPlayerListener(final File dataFolder, final IEssentials ess) { this.ess = ess; this.dataFolder = dataFolder; - this.config = new EssentialsConf(new File(dataFolder, "config.yml")); - config.setTemplateName("/config.yml", EssentialsGeoIP.class); + this.config = new EssentialsConfiguration(new File(dataFolder, "config.yml"), "/config.yml", EssentialsGeoIP.class); reloadConfig(); } @@ -130,13 +129,13 @@ public class EssentialsGeoIPPlayerListener implements Listener, IConf { config.load(); // detect and update the old config.yml. migrate from legacy GeoIP to GeoIP2. - if (!config.isSet("enable-locale")) { - config.set("database.download-url", "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key={LICENSEKEY}&suffix=tar.gz"); - config.set("database.download-url-city", "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key={LICENSEKEY}&suffix=tar.gz"); - config.set("database.license-key", ""); - config.set("database.update.enable", true); - config.set("database.update.by-every-x-days", 30); - config.set("enable-locale", true); + if (!config.hasProperty("enable-locale")) { + config.setProperty("database.download-url", "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key={LICENSEKEY}&suffix=tar.gz"); + config.setProperty("database.download-url-city", "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-City&license_key={LICENSEKEY}&suffix=tar.gz"); + config.setProperty("database.license-key", ""); + config.setProperty("database.update.enable", true); + config.setProperty("database.update.by-every-x-days", 30); + config.setProperty("enable-locale", true); config.save(); // delete old GeoIP.dat fiiles final File oldDatFile = new File(dataFolder, "GeoIP.dat"); @@ -166,7 +165,7 @@ public class EssentialsGeoIPPlayerListener implements Listener, IConf { } try { // locale setting - if (config.getBoolean("enable-locale")) { + if (config.getBoolean("enable-locale", false)) { // Get geolocation based on Essentials' locale. If the locale is not avaliable, use "en". String locale = ess.getI18n().getCurrentLocale().toString().replace('_', '-'); // This fixes an inconsistency where Essentials uses "zh" but MaxMind expects "zh-CN". @@ -186,9 +185,9 @@ public class EssentialsGeoIPPlayerListener implements Listener, IConf { try { String url; if (config.getBoolean("database.show-cities", false)) { - url = config.getString("database.download-url-city"); + url = config.getString("database.download-url-city", null); } else { - url = config.getString("database.download-url"); + url = config.getString("database.download-url", null); } if (url == null || url.isEmpty()) { logger.log(Level.SEVERE, tl("geoIpUrlEmpty")); diff --git a/EssentialsSpawn/src/main/java/com/earth2me/essentials/spawn/SpawnStorage.java b/EssentialsSpawn/src/main/java/com/earth2me/essentials/spawn/SpawnStorage.java index adab926ae..1f7bc14a2 100644 --- a/EssentialsSpawn/src/main/java/com/earth2me/essentials/spawn/SpawnStorage.java +++ b/EssentialsSpawn/src/main/java/com/earth2me/essentials/spawn/SpawnStorage.java @@ -1,8 +1,8 @@ package com.earth2me.essentials.spawn; +import com.earth2me.essentials.IConf; import com.earth2me.essentials.IEssentialsModule; -import com.earth2me.essentials.settings.Spawns; -import com.earth2me.essentials.storage.AsyncStorageObjectHolder; +import com.earth2me.essentials.config.EssentialsConfiguration; import net.ess3.api.IEssentials; import org.bukkit.Location; import org.bukkit.World; @@ -12,58 +12,47 @@ import java.util.HashMap; import java.util.Locale; import java.util.Map; -public class SpawnStorage extends AsyncStorageObjectHolder implements IEssentialsModule { +public class SpawnStorage implements IEssentialsModule, IConf { + private final IEssentials ess; + private final EssentialsConfiguration config; + private final Map spawns = new HashMap<>(); + SpawnStorage(final IEssentials ess) { - super(ess, Spawns.class); + this.ess = ess; + this.config = new EssentialsConfiguration(new File(ess.getDataFolder(), "spawn.yml")); reloadConfig(); } @Override - public File getStorageFile() { - return new File(ess.getDataFolder(), "spawn.yml"); - } - - @Override - public void finishRead() { - } - - @Override - public void finishWrite() { - } - - void setSpawn(final Location loc, final String group) { - acquireWriteLock(); - try { - if (getData().getSpawns() == null) { - getData().setSpawns(new HashMap<>()); - } - getData().getSpawns().put(group.toLowerCase(Locale.ENGLISH), loc); - } finally { - unlock(); - } - - if ("default".equalsIgnoreCase(group)) { - loc.getWorld().setSpawnLocation(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + public void reloadConfig() { + synchronized (spawns) { + config.load(); + spawns.clear(); + // need to outsource this because transitive relocations :) + spawns.putAll(config.getLocationSectionMap("spawns")); } } - Location getSpawn(final String group) { - acquireReadLock(); - try { - if (getData().getSpawns() == null || group == null) { + void setSpawn(final Location loc, String group) { + group = group.toLowerCase(Locale.ENGLISH); + synchronized (spawns) { + spawns.put(group, loc); + config.setProperty("spawns." + group, loc); + config.save(); + } + } + + Location getSpawn(String group) { + if (group == null) { + return getWorldSpawn(); + } + + group = group.toLowerCase(Locale.ENGLISH); + synchronized (spawns) { + if (!spawns.containsKey(group)) { return getWorldSpawn(); } - final Map spawnMap = getData().getSpawns(); - String groupName = group.toLowerCase(Locale.ENGLISH); - if (!spawnMap.containsKey(groupName)) { - groupName = "default"; - } - if (!spawnMap.containsKey(groupName)) { - return getWorldSpawn(); - } - return spawnMap.get(groupName); - } finally { - unlock(); + return spawns.get(group); } } diff --git a/EssentialsXMPP/src/main/java/com/earth2me/essentials/xmpp/UserManager.java b/EssentialsXMPP/src/main/java/com/earth2me/essentials/xmpp/UserManager.java index 64d5541db..d559b4aa8 100644 --- a/EssentialsXMPP/src/main/java/com/earth2me/essentials/xmpp/UserManager.java +++ b/EssentialsXMPP/src/main/java/com/earth2me/essentials/xmpp/UserManager.java @@ -1,7 +1,8 @@ package com.earth2me.essentials.xmpp; -import com.earth2me.essentials.EssentialsConf; import com.earth2me.essentials.IConf; +import com.earth2me.essentials.config.ConfigurateUtil; +import com.earth2me.essentials.config.EssentialsConfiguration; import java.io.File; import java.util.ArrayList; @@ -15,11 +16,11 @@ import java.util.Set; public class UserManager implements IConf { private static final String ADDRESS = "address"; private static final String SPY = "spy"; - private final transient EssentialsConf users; + private final transient EssentialsConfiguration users; private final transient List spyusers = Collections.synchronizedList(new ArrayList<>()); UserManager(final File folder) { - users = new EssentialsConf(new File(folder, "users.yml")); + users = new EssentialsConfiguration(new File(folder, "users.yml")); reloadConfig(); } @@ -36,7 +37,7 @@ public class UserManager implements IConf { } final String getUserByAddress(final String search) { - final Set usernames = users.getKeys(false); + final Set usernames = ConfigurateUtil.getRootNodeKeys(users); for (final String username : usernames) { final String address = users.getString(username + "." + ADDRESS, null); if (search.equalsIgnoreCase(address)) { @@ -58,7 +59,7 @@ public class UserManager implements IConf { final Map userdata = new HashMap<>(); userdata.put(ADDRESS, address); userdata.put(SPY, spy); - users.setProperty(username, userdata); + users.setRaw(username, userdata); users.save(); reloadConfig(); } @@ -67,7 +68,7 @@ public class UserManager implements IConf { public final void reloadConfig() { users.load(); spyusers.clear(); - final Set keys = users.getKeys(false); + final Set keys = ConfigurateUtil.getRootNodeKeys(users); for (final String key : keys) { if (isSpy(key)) { final String address = getAddress(key); diff --git a/EssentialsXMPP/src/main/java/com/earth2me/essentials/xmpp/XMPPManager.java b/EssentialsXMPP/src/main/java/com/earth2me/essentials/xmpp/XMPPManager.java index ae1cb4d16..d8dc4c035 100644 --- a/EssentialsXMPP/src/main/java/com/earth2me/essentials/xmpp/XMPPManager.java +++ b/EssentialsXMPP/src/main/java/com/earth2me/essentials/xmpp/XMPPManager.java @@ -1,8 +1,8 @@ package com.earth2me.essentials.xmpp; import com.earth2me.essentials.Console; -import com.earth2me.essentials.EssentialsConf; import com.earth2me.essentials.IConf; +import com.earth2me.essentials.config.EssentialsConfiguration; import com.earth2me.essentials.utils.FormatUtil; import net.ess3.api.IUser; import org.bukkit.entity.Player; @@ -37,7 +37,7 @@ import static com.earth2me.essentials.I18n.tl; public class XMPPManager extends Handler implements MessageListener, ChatManagerListener, IConf { private static final Logger logger = Logger.getLogger("EssentialsXMPP"); private static final SimpleFormatter formatter = new SimpleFormatter(); - private final transient EssentialsConf config; + private final transient EssentialsConfiguration config; private final transient Map chats = Collections.synchronizedMap(new HashMap<>()); private final transient Set logrecords = Collections.synchronizedSet(new HashSet<>()); private final transient IEssentialsXMPP parent; @@ -52,8 +52,7 @@ public class XMPPManager extends Handler implements MessageListener, ChatManager XMPPManager(final IEssentialsXMPP parent) { super(); this.parent = parent; - config = new EssentialsConf(new File(parent.getDataFolder(), "config.yml")); - config.setTemplateName("/config.yml", EssentialsXMPP.class); + config = new EssentialsConfiguration(new File(parent.getDataFolder(), "config.yml"), "/config.yml", EssentialsXMPP.class); reloadConfig(); } @@ -102,15 +101,15 @@ public class XMPPManager extends Handler implements MessageListener, ChatManager } private boolean connect() { - final String server = config.getString("xmpp.server"); + final String server = config.getString("xmpp.server", null); if (server == null || server.equals("example.com")) { logger.log(Level.WARNING, tl("xmppNotConfigured")); return false; } final int port = config.getInt("xmpp.port", 5222); final String serviceName = config.getString("xmpp.servicename", server); - final String xmppuser = config.getString("xmpp.user"); - final String password = config.getString("xmpp.password"); + final String xmppuser = config.getString("xmpp.user", null); + final String password = config.getString("xmpp.password", null); final boolean requireTLS = config.getBoolean("xmpp.require-server-tls", false); final ConnectionConfiguration connConf = new ConnectionConfiguration(server, port, serviceName); final String stringBuilder = "Connecting to xmpp server " + server + ":" + port + " as user " + xmppuser + "."; @@ -207,7 +206,7 @@ public class XMPPManager extends Handler implements MessageListener, ChatManager } if (config.getBoolean("log-enabled", false)) { logger.addHandler(this); - logUsers = config.getStringList("log-users"); + logUsers = config.getList("log-users", String.class); final String level = config.getString("log-level", "info"); try { logLevel = Level.parse(level.toUpperCase(Locale.ENGLISH)); @@ -328,7 +327,7 @@ public class XMPPManager extends Handler implements MessageListener, ChatManager } private void sendCommand(final Chat chat, final String message) { - if (config.getStringList("op-users").contains(StringUtils.parseBareAddress(chat.getParticipant()))) { + if (config.getList("op-users", String.class).contains(StringUtils.parseBareAddress(chat.getParticipant()))) { parent.getServer().getScheduler().runTask(parent, () -> { try { parent.getServer().dispatchCommand(Console.getInstance().getCommandSender(), message.substring(1)); @@ -348,7 +347,7 @@ public class XMPPManager extends Handler implements MessageListener, ChatManager } public boolean isConfigValid() { - final String server = config.getString("xmpp.server"); + final String server = config.getString("xmpp.server", null); return server != null && !server.equals("example.com"); } } diff --git a/build-logic/src/main/kotlin/essentials.base-conventions.gradle.kts b/build-logic/src/main/kotlin/essentials.base-conventions.gradle.kts index 39bbb8b7b..0261315ee 100644 --- a/build-logic/src/main/kotlin/essentials.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/essentials.base-conventions.gradle.kts @@ -18,7 +18,9 @@ dependencies { testImplementation("org.mockito", "mockito-core", mockitoVersion) if (project.name != "1_8Provider" && project.name != "PaperProvider" && project.name != "NMSReflectionProvider") { // These providers use their own bukkit versions - api("org.spigotmc", "spigot-api", spigotVersion) + api("org.spigotmc", "spigot-api", spigotVersion) { + exclude(group = "org.yaml", module = "snakeyaml") + } } }