/* * Copyright 2019 Aleksander Jagiełło <[email protected]> * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package pl.craftserve.radiation; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.protection.flags.BooleanFlag; import com.sk89q.worldguard.protection.flags.Flag; import com.sk89q.worldguard.protection.flags.registry.FlagRegistry; import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.sk89q.worldguard.protection.regions.RegionContainer; import org.bukkit.ChatColor; import org.bukkit.Server; import org.bukkit.World; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarFlag; import org.bukkit.boss.BarStyle; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.MemoryConfiguration; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.plugin.java.JavaPlugin; import pl.craftserve.radiation.nms.RadiationNmsBridge; import pl.craftserve.radiation.nms.V1_14ToV1_15NmsBridge; import java.util.Collections; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; public final class RadiationPlugin extends JavaPlugin { private static final char COLOR_CODE = '&'; public static String colorize(String input) { return input == null ? null : ChatColor.translateAlternateColorCodes(COLOR_CODE, input); } private static final int CURRENT_PROTOCOL_VERSION = 1; private static final Flag<Boolean> RADIATION_FLAG = new BooleanFlag("radiation"); private RadiationNmsBridge radiationNmsBridge; private Flag<Boolean> radiationFlag; private Config config; private LugolsIodineEffect effect; private LugolsIodinePotion potion; private LugolsIodineDisplay display; private Radiation radiation; private CraftserveListener craftserveListener; private MetricsHandler metricsHandler; private RadiationNmsBridge initializeNmsBridge() { String serverVersion = RadiationNmsBridge.getServerVersion(getServer()); this.getLogger().log(Level.INFO, "Detected server version: {0}", serverVersion); switch (serverVersion) { case "v1_14_R1": case "v1_15_R1": return new V1_14ToV1_15NmsBridge(this, serverVersion); default: throw new RuntimeException("Unsupported server version: " + serverVersion); } } @Override public void onLoad() { FlagRegistry flagRegistry = WorldGuard.getInstance().getFlagRegistry(); if (flagRegistry == null) { throw new IllegalStateException("Flag registry is not set! Plugin must shut down..."); } this.radiationFlag = this.getOrCreateRadiationFlag(flagRegistry); } @Override public void onEnable() { Server server = this.getServer(); Logger logger = this.getLogger(); this.saveDefaultConfig(); try { this.radiationNmsBridge = this.initializeNmsBridge(); } catch (Exception e) { logger.log(Level.SEVERE, "Failed to launch CraftserveRadiation. Plausibly your server version is unsupported.", e); this.setEnabled(false); return; } // // Configuration // FileConfiguration config = this.getConfig(); if (!this.migrate(config, config.getInt("file-protocol-version-dont-touch", -1))) { this.setEnabled(false); return; } try { this.config = new Config(config); } catch (InvalidConfigurationException e) { logger.log(Level.SEVERE, "Could not load configuration file.", e); this.setEnabled(false); return; } // // Enabling // this.effect = new LugolsIodineEffect(this); this.potion = new LugolsIodinePotion(this, this.effect, this.config.lugolsIodinePotion()); this.display = new LugolsIodineDisplay(this, this.effect, this.config.lugolsIodineDisplay()); this.radiation = new Radiation(this, new Radiation.FlagMatcher(this.radiationFlag), this.config.radiation()); RadiationCommandHandler radiationCommandHandler = new RadiationCommandHandler(this.radiationFlag, this.potion); radiationCommandHandler.register(this.getCommand("radiation")); this.craftserveListener = new CraftserveListener(this); this.metricsHandler = new MetricsHandler(this, server, logger, this.effect, this.potion); this.effect.enable(); this.potion.enable(this.radiationNmsBridge); this.display.enable(); this.radiation.enable(); this.craftserveListener.enable(); this.metricsHandler.start(); } @Override public void onDisable() { if (this.metricsHandler != null) { this.metricsHandler.stop(); } if (this.craftserveListener != null) { this.craftserveListener.disable(); } if (this.radiation != null) { this.radiation.disable(); } if (this.display != null) { this.display.disable(); } if (this.potion != null) { this.potion.disable(this.radiationNmsBridge); } if (this.effect != null) { this.effect.disable(); } } public Flag<Boolean> getRadiationFlag() { return this.radiationFlag; } public Config getPluginConfig() { return this.config; } @SuppressWarnings("unchecked") private Flag<Boolean> getOrCreateRadiationFlag(FlagRegistry flagRegistry) { Objects.requireNonNull(flagRegistry, "flagRegistry"); Flag<Boolean> flag = (Flag<Boolean>) flagRegistry.get(RADIATION_FLAG.getName()); if (flag != null) { return flag; } flag = RADIATION_FLAG; flagRegistry.register(flag); return flag; } // // Migrations // private boolean migrate(ConfigurationSection section, int protocol) { Objects.requireNonNull(section, "section"); Logger logger = this.getLogger(); if (protocol > CURRENT_PROTOCOL_VERSION) { logger.severe("Your configuration file's protocol version \"" + protocol + "\" is invalid. Are you trying to load it using a newer version of the plugin?"); return false; } if (protocol < 0) { section.set("lugols-iodine-bar.title", "Działanie Płynu Lugola"); section.set("lugols-iodine-bar.color", BarColor.GREEN.name()); section.set("lugols-iodine-bar.style", BarStyle.SEGMENTED_20.name()); section.set("lugols-iodine-bar.flags", Collections.emptyList()); section.set("lugols-iodine-potion.name", "Płyn Lugola"); section.set("lugols-iodine-potion.description", "Odporność na promieniowanie ({0})"); section.set("lugols-iodine-potion.duration", TimeUnit.MINUTES.toSeconds(section.getInt("potion-duration", 10))); section.set("lugols-iodine-potion.drink-message", "{0}" + ChatColor.RED + " wypił/a {1}."); section.set("radiation.bar.title", "Strefa radiacji"); section.set("radiation.bar.color", BarColor.RED.name()); section.set("radiation.bar.style", BarStyle.SOLID.name()); section.set("radiation.bar.flags", Collections.singletonList(BarFlag.DARKEN_SKY.name())); section.set("radiation.effects.wither.level", 5); section.set("radiation.effects.wither.ambient", false); section.set("radiation.effects.wither.has-particles", false); section.set("radiation.effects.wither.has-icon", false); section.set("radiation.effects.hunger.level", 1); section.set("radiation.effects.hunger.ambient", false); section.set("radiation.effects.hunger.has-particles", false); section.set("radiation.effects.hunger.has-icon", false); section.set("radiation.escape-message", "{0}" + ChatColor.RED + " uciekł/a do strefy radiacji."); // Migrate from the old region-ID based system. String legacyRegionId = section.getString("region-name", "km_safe_from_radiation"); AtomicBoolean logged = new AtomicBoolean(); section.getStringList("world-names").forEach(worldName -> { if (logged.compareAndSet(false, true)) { logger.warning( "Enabling in legacy region-name mode! The plugin will try to automatically migrate to the new flag-based system.\n" + "If everything went fine please completely remove your config.yml file."); } this.migrateFromRegionId(worldName, legacyRegionId); }); } if (protocol < 1) { section.set("lugols-iodine-potion.recipe.enabled", true); section.set("lugols-iodine-potion.recipe.base-potion", LugolsIodinePotion.Config.Recipe.DEFAULT_BASE_POTION.name()); section.set("lugols-iodine-potion.recipe.ingredient", LugolsIodinePotion.Config.Recipe.DEFAULT_INGREDIENT.getKey().getKey()); section.set("lugols-iodine-potion.color", null); } return true; } /** * Migrate from region-ID based method to the new flag method. * * @param worldName Name of the world. * @param regionId ID of the region. */ private void migrateFromRegionId(String worldName, String regionId) { Objects.requireNonNull(worldName, "worldName"); Objects.requireNonNull(regionId, "regionId"); String error = "Could not migrate region " + regionId + " in world " + worldName + ": "; World world = this.getServer().getWorld(worldName); if (world == null) { this.getLogger().warning(error + ": the world is unloaded."); return; } Radiation.WorldGuardMatcher matcher = (player, regionContainer) -> { throw new UnsupportedOperationException(); }; RegionContainer regionContainer = matcher.getRegionContainer(); if (regionContainer == null) { this.getLogger().warning(error + "region container is not present."); return; } RegionManager regionManager = regionContainer.get(BukkitAdapter.adapt(world)); if (regionManager == null) { this.getLogger().warning(error + "region manager for the world is not present."); return; } ProtectedRegion legacyRegion = regionManager.getRegion(regionId); if (legacyRegion == null) { this.getLogger().warning(error + "legacy region is not present."); return; } legacyRegion.setFlag(this.radiationFlag, false); // make __global__ radioactive ProtectedRegion global = regionManager.getRegion("__global__"); if (global == null) { global = new GlobalProtectedRegion("__global__"); regionManager.addRegion(global); } global.setFlag(this.radiationFlag, true); this.getLogger().info("Region " + regionId + " in world " + worldName + " has been successfully migrated to the new flag-based system."); } // // Config // public static class Config { private final BarConfig lugolsIodineDisplay; private final LugolsIodinePotion.Config lugolsIodinePotion; private final Radiation.Config radiation; public Config(BarConfig lugolsIodineDisplay, LugolsIodinePotion.Config lugolsIodinePotion, Radiation.Config radiation) { this.lugolsIodineDisplay = Objects.requireNonNull(lugolsIodineDisplay, "lugolsIodineDisplay"); this.lugolsIodinePotion = Objects.requireNonNull(lugolsIodinePotion, "lugolsIodinePotion"); this.radiation = Objects.requireNonNull(radiation, "radiation"); } public Config(ConfigurationSection section) throws InvalidConfigurationException { if (section == null) { section = new MemoryConfiguration(); } try { this.lugolsIodineDisplay = new BarConfig(section.getConfigurationSection("lugols-iodine-bar")); } catch (InvalidConfigurationException e) { throw new InvalidConfigurationException("Could not parse lugols-iodine-bar section.", e); } try { this.lugolsIodinePotion = new LugolsIodinePotion.Config(section.getConfigurationSection("lugols-iodine-potion")); } catch (InvalidConfigurationException e) { throw new InvalidConfigurationException("Could not parse lugols-iodine-potion section.", e); } try { this.radiation = new Radiation.Config(section.getConfigurationSection("radiation")); } catch (InvalidConfigurationException e) { throw new InvalidConfigurationException("Could not parse radiation section.", e); } } public BarConfig lugolsIodineDisplay() { return this.lugolsIodineDisplay; } public LugolsIodinePotion.Config lugolsIodinePotion() { return this.lugolsIodinePotion; } public Radiation.Config radiation() { return this.radiation; } } }