From 9be8d9eb184527b860e4c204c0ce2347275d2641 Mon Sep 17 00:00:00 2001 From: Roch Blonndiaux Date: Mon, 13 Mar 2023 16:41:14 +0100 Subject: [PATCH] Optimization concept --- .../mmoitems/manager/WorldGenManager.java | 179 +++++++++++------- 1 file changed, 106 insertions(+), 73 deletions(-) diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/manager/WorldGenManager.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/manager/WorldGenManager.java index 06d88b29..b369a747 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/manager/WorldGenManager.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/manager/WorldGenManager.java @@ -4,6 +4,7 @@ import net.Indyuce.mmoitems.MMOItems; import net.Indyuce.mmoitems.api.ConfigFile; import net.Indyuce.mmoitems.api.block.CustomBlock; import net.Indyuce.mmoitems.api.block.WorldGenTemplate; +import net.Indyuce.mmoitems.util.Pair; import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -13,99 +14,131 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.world.ChunkLoadEvent; +import org.bukkit.scheduler.BukkitRunnable; import java.util.HashMap; import java.util.Map; +import java.util.Queue; import java.util.Random; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.logging.Level; public class WorldGenManager implements Listener, Reloadable { - private final Map templates = new HashMap<>(); + private final Map templates = new HashMap<>(); - /* - * maps a custom block to the world generator template so that it is later - * easier to access all the blocks which must be placed when generating a - * world. - */ - private final Map assigned = new HashMap<>(); + /* + * maps a custom block to the world generator template so that it is later + * easier to access all the blocks which must be placed when generating a + * world. + */ + private final Map assigned = new HashMap<>(); + private final Queue> modificationsQueue = new ConcurrentLinkedQueue<>(); - private static final BlockFace[] faces = { BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST, BlockFace.EAST, BlockFace.DOWN, BlockFace.UP }; - private static final Random random = new Random(); + private static final BlockFace[] faces = {BlockFace.NORTH, BlockFace.SOUTH, BlockFace.WEST, BlockFace.EAST, BlockFace.DOWN, BlockFace.UP}; + private static final Random random = new Random(); - public WorldGenManager() { + public WorldGenManager() { + /* + * load the worldGenManager even if world gen is not enabled so that if + * admins temporarily disable it, there is no console error spam saying + * MI could not find corresponding gen template in config + */ + reload(); - /* - * load the worldGenManager even if world gen is not enabled so that if - * admins temporarily disable it, there is no console error spam saying - * MI could not find corresponding gen template in config - */ - reload(); + if (MMOItems.plugin.getLanguage().worldGenEnabled) + Bukkit.getPluginManager().registerEvents(this, MMOItems.plugin); + } - if (MMOItems.plugin.getLanguage().worldGenEnabled) - Bukkit.getPluginManager().registerEvents(this, MMOItems.plugin); - } + public WorldGenTemplate getOrThrow(String id) { + Validate.isTrue(templates.containsKey(id), "Could not find gen template with ID '" + id + "'"); - public WorldGenTemplate getOrThrow(String id) { - Validate.isTrue(templates.containsKey(id), "Could not find gen template with ID '" + id + "'"); + return templates.get(id); + } - return templates.get(id); - } + /* + * it is mandatory to call this function after registering the custom block + * if you want the custom block to be spawning in the worlds + */ + public void assign(CustomBlock block, WorldGenTemplate template) { + Validate.notNull(template, "Cannot assign a null template to a custom block"); - /* - * it is mandatory to call this function after registering the custom block - * if you want the custom block to be spawning in the worlds - */ - public void assign(CustomBlock block, WorldGenTemplate template) { - Validate.notNull(template, "Cannot assign a null template to a custom block"); + assigned.put(block, template); + } - assigned.put(block, template); - } + @EventHandler + public void onChunkLoad(ChunkLoadEvent e) { + if (e.isNewChunk()) + return; - @EventHandler - public void a(ChunkLoadEvent event) { - if(event.isNewChunk()) { - Bukkit.getScheduler().runTaskAsynchronously(MMOItems.plugin, () -> assigned.forEach((block, template) -> { - if(!template.canGenerateInWorld(event.getWorld())) { - return; - } - if(random.nextDouble() < template.getChunkChance()) - for(int i = 0; i < template.getVeinCount(); i++) { - int y = random.nextInt(template.getMaxDepth() - template.getMinDepth() + 1) + template.getMinDepth(); - Location generatePoint = event.getChunk().getBlock(random.nextInt(16), y, random.nextInt(16)).getLocation(); + if (e.isAsynchronous()) + generate(e); + else + Bukkit.getScheduler().runTaskAsynchronously(MMOItems.plugin, () -> generate(e)); + } - if(template.canGenerate(generatePoint)) { - Block modify = generatePoint.getWorld().getBlockAt(generatePoint); + private void generate(ChunkLoadEvent e) { + assigned.entrySet() + .stream() + .filter(entry -> entry.getValue().canGenerateInWorld(e.getWorld())) + .forEach(entry -> { + final CustomBlock block = entry.getKey(); + final WorldGenTemplate template = entry.getValue(); + if (random.nextDouble() > template.getChunkChance()) + return; - for(int j = 0; j < template.getVeinSize(); j++) { - if(template.canReplace(modify.getType())) { - final Block fModify = modify; - Bukkit.getScheduler().runTask(MMOItems.plugin, () -> { - fModify.setType(block.getState().getType(), false); - fModify.setBlockData(block.getState().getBlockData(), false); - }); - } + for (int i = 0; i < template.getVeinCount(); i++) { + int y = random.nextInt(template.getMaxDepth() - template.getMinDepth() + 1) + template.getMinDepth(); + Location generatePoint = e.getChunk().getBlock(random.nextInt(16), y, random.nextInt(16)).getLocation(); - BlockFace nextFace = faces[random.nextInt(faces.length)]; - modify = modify.getRelative(nextFace); - } - } - } - })); - } - } + if (!template.canGenerate(generatePoint) || generatePoint.getWorld() == null) + continue; + Block modify = generatePoint.getWorld().getBlockAt(generatePoint); - public void reload() { - assigned.clear(); - templates.clear(); + for (int j = 0; j < template.getVeinSize(); j++) { + if (template.canReplace(modify.getType())) + this.modificationsQueue.add(Pair.of(modify.getLocation(), block)); + BlockFace nextFace = faces[random.nextInt(faces.length)]; + modify = modify.getRelative(nextFace); + } + } + }); - FileConfiguration config = new ConfigFile("gen-templates").getConfig(); - for(String key : config.getKeys(false)) { - try { - WorldGenTemplate template = new WorldGenTemplate(config.getConfigurationSection(key)); - templates.put(template.getId(), template); - } catch (IllegalArgumentException exception) { - MMOItems.plugin.getLogger().log(Level.WARNING, "An error occurred when loading gen template '" + key + "': " + exception.getMessage()); - } - } - } + + new BukkitRunnable() { + @Override + public void run() { + if (modificationsQueue.isEmpty()) { + this.cancel(); + return; + } + Pair pair = modificationsQueue.poll(); + + if (Bukkit.isPrimaryThread()) + setBlockData(pair.getKey().getBlock(), pair.getValue()); + else + Bukkit.getScheduler().runTask(MMOItems.plugin, () -> setBlockData(pair.getKey().getBlock(), pair.getValue())); + } + }.runTaskTimer(MMOItems.plugin, 0, 5); + } + + + private void setBlockData(Block fModify, CustomBlock block) { + fModify.setType(block.getState().getType(), false); + fModify.setBlockData(block.getState().getBlockData(), false); + } + + public void reload() { + assigned.clear(); + templates.clear(); + + FileConfiguration config = new ConfigFile("gen-templates").getConfig(); + for (String key : config.getKeys(false)) { + try { + WorldGenTemplate template = new WorldGenTemplate(config.getConfigurationSection(key)); + templates.put(template.getId(), template); + } catch (IllegalArgumentException exception) { + MMOItems.plugin.getLogger().log(Level.WARNING, "An error occurred when loading gen template '" + key + "': " + exception.getMessage()); + } + } + } }