package com.dfsek.terra; import com.dfsek.tectonic.loading.TypeRegistry; import com.dfsek.terra.api.bukkit.BukkitWorldHandle; import com.dfsek.terra.api.generic.TerraPlugin; import com.dfsek.terra.api.generic.world.WorldHandle; import com.dfsek.terra.biome.grid.master.TerraBiomeGrid; import com.dfsek.terra.biome.palette.PaletteHolder; import com.dfsek.terra.biome.palette.PaletteLayer; import com.dfsek.terra.carving.CarverPalette; import com.dfsek.terra.command.TerraCommand; import com.dfsek.terra.command.structure.LocateCommand; import com.dfsek.terra.config.base.ConfigPack; import com.dfsek.terra.config.base.PluginConfig; import com.dfsek.terra.config.lang.LangUtil; import com.dfsek.terra.config.loaders.ImageLoaderLoader; import com.dfsek.terra.config.loaders.MaterialSetLoader; import com.dfsek.terra.config.loaders.ProbabilityCollectionLoader; import com.dfsek.terra.config.loaders.RangeLoader; import com.dfsek.terra.config.loaders.config.FloraLayerLoader; import com.dfsek.terra.config.loaders.config.GridSpawnLoader; import com.dfsek.terra.config.loaders.config.NoiseBuilderLoader; import com.dfsek.terra.config.loaders.config.OreConfigLoader; import com.dfsek.terra.config.loaders.config.OreHolderLoader; import com.dfsek.terra.config.loaders.config.StructureFeatureLoader; import com.dfsek.terra.config.loaders.config.TreeLayerLoader; import com.dfsek.terra.config.loaders.palette.CarverPaletteLoader; import com.dfsek.terra.config.loaders.palette.PaletteHolderLoader; import com.dfsek.terra.config.loaders.palette.PaletteLayerLoader; import com.dfsek.terra.debug.Debug; import com.dfsek.terra.generation.TerraChunkGenerator; import com.dfsek.terra.generation.config.NoiseBuilder; import com.dfsek.terra.generation.items.flora.FloraLayer; import com.dfsek.terra.generation.items.flora.TerraFlora; import com.dfsek.terra.generation.items.ores.Ore; import com.dfsek.terra.generation.items.ores.OreConfig; import com.dfsek.terra.generation.items.ores.OreHolder; import com.dfsek.terra.generation.items.tree.TreeLayer; import com.dfsek.terra.image.ImageLoader; import com.dfsek.terra.listeners.EventListener; import com.dfsek.terra.listeners.SpigotListener; import com.dfsek.terra.procgen.GridSpawn; import com.dfsek.terra.registry.ConfigRegistry; import com.dfsek.terra.structure.features.Feature; import com.dfsek.terra.util.MaterialSet; import com.dfsek.terra.util.PaperUtil; import com.dfsek.terra.util.StructureTypeEnum; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; import org.bukkit.command.PluginCommand; import org.bukkit.entity.EntityType; import org.bukkit.generator.ChunkGenerator; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.polydev.gaea.GaeaPlugin; import org.polydev.gaea.generation.GaeaChunkGenerator; import org.polydev.gaea.lang.Language; import org.polydev.gaea.math.ProbabilityCollection; import org.polydev.gaea.math.Range; import java.util.HashMap; import java.util.Map; import java.util.Objects; public class Terra extends GaeaPlugin implements TerraPlugin { private final Map generatorMap = new HashMap<>(); private final Map worldMap = new HashMap<>(); private final Map worlds = new HashMap<>(); private final ConfigRegistry registry = new ConfigRegistry(); private final PluginConfig config = new PluginConfig(); private WorldHandle handle = new BukkitWorldHandle(); public void reload() { Map newMap = new HashMap<>(); worldMap.forEach((world, tw) -> { String packID = tw.getConfig().getTemplate().getID(); newMap.put(world, new TerraWorld(world, registry.get(packID))); }); worldMap.clear(); worldMap.putAll(newMap); } public void setHandle(WorldHandle handle) { getLogger().warning("|-------------------------------------------------------|"); getLogger().warning("A third-party addon has injected a custom WorldHandle!"); getLogger().warning("If you encounter issues, try *without* the addon before"); getLogger().warning("reporting to Terra. Report issues with the addon to the"); getLogger().warning("addon's maintainers!"); getLogger().warning("|-------------------------------------------------------|"); this.handle = handle; } @Override public void onDisable() { TerraChunkGenerator.saveAll(); } @Override public void onEnable() { Debug.setLogger(getLogger()); // Set debug logger. saveDefaultConfig(); Metrics metrics = new Metrics(this, 9017); // Set up bStats. metrics.addCustomChart(new Metrics.SingleLineChart("worlds", worldMap::size)); // World number chart. config.load(this); // Load master config.yml LangUtil.load(config.getLanguage(), this); // Load language. Debug.setDebug(isDebug()); registry.loadAll(this); // Load all config packs. PluginCommand c = Objects.requireNonNull(getCommand("terra")); TerraCommand command = new TerraCommand(this); // Set up main Terra command. c.setExecutor(command); c.setTabCompleter(command); LocateCommand locate = new LocateCommand(command, false); PluginCommand locatePl = Objects.requireNonNull(getCommand("locate")); locatePl.setExecutor(locate); // Override locate command. Once Paper accepts StructureLocateEvent this will be unneeded on Paper implementations. locatePl.setTabCompleter(locate); long save = config.getDataSaveInterval(); Bukkit.getScheduler().runTaskTimerAsynchronously(this, TerraChunkGenerator::saveAll, save, save); // Schedule population data saving Bukkit.getPluginManager().registerEvents(new EventListener(this), this); // Register master event listener Bukkit.getPluginManager().registerEvents(new SpigotListener(this), this); // Register Spigot event listener, once Paper accepts StructureLocateEvent PR Spigot and Paper events will be separate. PaperUtil.checkPaper(this); } @Override public @Nullable ChunkGenerator getDefaultWorldGenerator(@NotNull String worldName, @Nullable String id) { return generatorMap.computeIfAbsent(worldName, name -> { if(!registry.contains(id)) throw new IllegalArgumentException("No such config pack \"" + id + "\""); worlds.put(worldName, registry.get(id)); return new TerraChunkGenerator(registry.get(id), this); }); } @Override public boolean isDebug() { return config.isDebug(); } @Override public Class getGeneratorClass() { return TerraChunkGenerator.class; } @Override public Language getLanguage() { return LangUtil.getLanguage(); } public void registerAllLoaders(TypeRegistry registry) { registry.registerLoader(ProbabilityCollection.class, new ProbabilityCollectionLoader()) .registerLoader(Range.class, new RangeLoader()) .registerLoader(CarverPalette.class, new CarverPaletteLoader()) .registerLoader(GridSpawn.class, new GridSpawnLoader()) .registerLoader(PaletteHolder.class, new PaletteHolderLoader()) .registerLoader(PaletteLayer.class, new PaletteLayerLoader()) .registerLoader(Biome.class, (t, o, l) -> Biome.valueOf((String) o)) .registerLoader(BlockData.class, (t, o, l) -> Bukkit.createBlockData((String) o)) .registerLoader(Material.class, (t, o, l) -> Material.matchMaterial((String) o)) .registerLoader(FloraLayer.class, new FloraLayerLoader()) .registerLoader(Ore.Type.class, (t, o, l) -> Ore.Type.valueOf((String) o)) .registerLoader(OreConfig.class, new OreConfigLoader()) .registerLoader(NoiseBuilder.class, new NoiseBuilderLoader()) .registerLoader(TreeLayer.class, new TreeLayerLoader(this)) .registerLoader(MaterialSet.class, new MaterialSetLoader()) .registerLoader(OreHolder.class, new OreHolderLoader()) .registerLoader(Feature.class, new StructureFeatureLoader()) .registerLoader(ImageLoader.class, new ImageLoaderLoader()) .registerLoader(EntityType.class, (t, o, l) -> EntityType.valueOf((String) o)) .registerLoader(TerraBiomeGrid.Type.class, (t, o, l) -> TerraBiomeGrid.Type.valueOf((String) o)) .registerLoader(StructureTypeEnum.class, (t, o, l) -> StructureTypeEnum.valueOf((String) o)) .registerLoader(ImageLoader.Channel.class, (t, o, l) -> ImageLoader.Channel.valueOf((String) o)) .registerLoader(ImageLoader.Align.class, (t, o, l) -> ImageLoader.Align.valueOf((String) o)) .registerLoader(TerraFlora.Search.class, (t, o, l) -> TerraFlora.Search.valueOf((String) o)); } public ConfigRegistry getRegistry() { return registry; } public TerraWorld getWorld(World w) { if(!(w.getGenerator() instanceof TerraChunkGenerator)) throw new IllegalArgumentException("Not a Terra world!"); if(!worlds.containsKey(w.getName())) { getLogger().warning("Unexpected world load detected: \"" + w.getName() + "\""); return new TerraWorld(w, ((TerraChunkGenerator) w.getGenerator()).getConfigPack()); } return worldMap.computeIfAbsent(w, world -> new TerraWorld(w, worlds.get(w.getName()))); } @NotNull public PluginConfig getTerraConfig() { return config; } @Override public WorldHandle getHandle() { return handle; } }