diff --git a/src/main/java/world/bentobox/greenhouses/greenhouse/BiomeRecipe.java b/src/main/java/world/bentobox/greenhouses/greenhouse/BiomeRecipe.java index 9baaa42..40a2f03 100644 --- a/src/main/java/world/bentobox/greenhouses/greenhouse/BiomeRecipe.java +++ b/src/main/java/world/bentobox/greenhouses/greenhouse/BiomeRecipe.java @@ -5,12 +5,12 @@ import java.util.EnumMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Optional; import java.util.Random; import java.util.Set; import java.util.TreeMap; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; import org.bukkit.Bukkit; @@ -107,7 +107,7 @@ public class BiomeRecipe implements Comparable { /** * @param mobType - entity type - * @param mobProbability - reltive probability + * @param mobProbability - relative probability * @param mobSpawnOn - material to spawn on * @return true if add is successful */ @@ -236,22 +236,30 @@ public class BiomeRecipe implements Comparable { /** * Check if block should be converted - * @param gh - greenhouse * @param b - block to check */ - public void convertBlock(Greenhouse gh, Block b) { - conversionBlocks.get(b.getType()).stream().filter(Objects::nonNull) - .filter(bc -> random.nextDouble() < bc.getProbability()) - .forEach(bc -> { - // Check if the block is in the right area, up, down, n,s,e,w - if (ADJ_BLOCKS.stream().map(b::getRelative) - .filter(r -> gh.contains(r.getLocation())) - .map(Block::getType) - .anyMatch(m -> bc.getLocalMaterial() == null || m == bc.getLocalMaterial())) { - // Convert! - b.setType(bc.getNewMaterial()); + public void convertBlock(Block b) { + Material bType = b.getType(); + // Check if there is a block conversion for this block, as while the rest of the method wont do anything if .get() returns nothing anyway it still seems to be quite expensive + if(conversionBlocks.keySet().contains(bType)) { + for(GreenhouseBlockConversions conversion_option : conversionBlocks.get(bType)) { + + // Roll the dice before bothering with checking the surrounding block as I think it's more common for greenhouses to be filled with convertable blocks and thus this dice roll wont be "wasted" + if(ThreadLocalRandom.current().nextDouble() < conversion_option.getProbability()) { + // Check if any of the adjacent blocks matches the required LocalMaterial, if there are any required LocalMaterials + if(conversion_option.getLocalMaterial() != null) { + for(BlockFace adjacent_block : ADJ_BLOCKS) { + if(b.getRelative(adjacent_block).getType() == conversion_option.getLocalMaterial()) { + b.setType(conversion_option.getNewMaterial()); + break; + } + } + } else { + b.setType(conversion_option.getNewMaterial()); + } + } } - }); + } } /** diff --git a/src/main/java/world/bentobox/greenhouses/managers/EcoSystemManager.java b/src/main/java/world/bentobox/greenhouses/managers/EcoSystemManager.java index c3a2e95..1cd1728 100644 --- a/src/main/java/world/bentobox/greenhouses/managers/EcoSystemManager.java +++ b/src/main/java/world/bentobox/greenhouses/managers/EcoSystemManager.java @@ -1,14 +1,7 @@ package world.bentobox.greenhouses.managers; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; -import java.util.Objects; -import java.util.Random; - import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Hopper; @@ -18,6 +11,15 @@ import org.bukkit.util.NumberConversions; import world.bentobox.greenhouses.Greenhouses; import world.bentobox.greenhouses.data.Greenhouse; +import world.bentobox.greenhouses.greenhouse.BiomeRecipe; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Objects; +import java.util.Random; /** * Runs the ecosystem for a greenhouse @@ -54,7 +56,7 @@ public class EcoSystemManager { } // Kick block conversion growing - long blockTick = addon.getSettings().getBlockTick() * 60 * 20l; // In minutes + long blockTick = addon.getSettings().getBlockTick() * 60 * 20L; // In minutes if (blockTick > 0) { addon.log("Kicking off block conversion scheduler every " + addon.getSettings().getBlockTick() + MINUTES); @@ -86,11 +88,24 @@ public class EcoSystemManager { if(!gh.getLocation().getWorld().isChunkLoaded(((int) gh.getBoundingBox().getMaxX()) >> 4, ((int) gh.getBoundingBox().getMaxZ()) >> 4) || !gh.getLocation().getWorld().isChunkLoaded(((int) gh.getBoundingBox().getMinX()) >> 4, ((int) gh.getBoundingBox().getMinZ()) >> 4)){ return; } - for (double x = gh.getInternalBoundingBox().getMinX(); x < gh.getInternalBoundingBox().getMaxX(); x++) { - for (double z = gh.getInternalBoundingBox().getMinZ(); z < gh.getInternalBoundingBox().getMaxZ(); z++) { - for (double y = gh.getInternalBoundingBox().getMaxY() - 1; y >= gh.getBoundingBox().getMinY() && y > 0; y--) { - Block b = gh.getWorld().getBlockAt(NumberConversions.floor(x), NumberConversions.floor(y), NumberConversions.floor(z)).getRelative(BlockFace.DOWN); - if (!b.isEmpty()) gh.getBiomeRecipe().convertBlock(gh, b); + + int gh_min_x = NumberConversions.floor(gh.getInternalBoundingBox().getMinX()); + int gh_max_x = NumberConversions.floor(gh.getInternalBoundingBox().getMaxX()); + int gh_min_y = NumberConversions.floor(gh.getInternalBoundingBox().getMinY()); + int gh_max_y = NumberConversions.floor(gh.getInternalBoundingBox().getMaxY()); + int gh_min_z = NumberConversions.floor(gh.getInternalBoundingBox().getMinZ()); + int gh_max_z = NumberConversions.floor(gh.getInternalBoundingBox().getMaxZ()); + World world = gh.getWorld(); + BiomeRecipe biomeRecipe = gh.getBiomeRecipe(); + + for (int x = gh_min_x; x < gh_max_x; x++) { + for (int z = gh_min_z; z < gh_max_z; z++) { + for (int y = gh_min_y; y < gh_max_y; y++) { + Block b = world.getBlockAt(x, y, z); + + if(!b.isEmpty()) { + biomeRecipe.convertBlock(b); + } } } } @@ -187,7 +202,7 @@ public class EcoSystemManager { * Get a list of the lowest level blocks inside the greenhouse. May be air, liquid or plants. * These blocks sit just above solid blocks * @param gh - greenhouse - * @param ignoreliquid - true if liquid blocks should be treated like air blocks + * @param ignoreLiquid - true if liquid blocks should be treated like air blocks * @return List of blocks */ public List getAvailableBlocks(Greenhouse gh, boolean ignoreLiquid) { diff --git a/src/test/java/world/bentobox/greenhouses/greenhouse/BiomeRecipeTest.java b/src/test/java/world/bentobox/greenhouses/greenhouse/BiomeRecipeTest.java index 08c8282..b58304c 100644 --- a/src/test/java/world/bentobox/greenhouses/greenhouse/BiomeRecipeTest.java +++ b/src/test/java/world/bentobox/greenhouses/greenhouse/BiomeRecipeTest.java @@ -263,7 +263,7 @@ public class BiomeRecipeTest { Block ab = mock(Block.class); when(ab.getType()).thenReturn(Material.WATER); when(b.getRelative(any())).thenReturn(ab); - br.convertBlock(gh, b); + br.convertBlock(b); verify(b).setType(Material.CLAY); } @@ -282,7 +282,7 @@ public class BiomeRecipeTest { when(b.getRelative(any())).thenReturn(ab); when(ab.getLocation()).thenReturn(location); when(gh.contains(any())).thenReturn(false); - br.convertBlock(gh, b); + br.convertBlock(b); verify(b, never()).setType(any()); } @@ -299,7 +299,7 @@ public class BiomeRecipeTest { Block ab = mock(Block.class); when(ab.getType()).thenReturn(Material.SAND); when(b.getRelative(any())).thenReturn(ab); - br.convertBlock(gh, b); + br.convertBlock(b); verify(b, never()).setType(Material.CLAY); } @@ -311,7 +311,7 @@ public class BiomeRecipeTest { // Mock Block b = mock(Block.class); when(b.getType()).thenReturn(Material.SAND); - br.convertBlock(gh, b); + br.convertBlock(b); verify(b, never()).setType(Material.CLAY); } @@ -333,7 +333,7 @@ public class BiomeRecipeTest { Block ab = mock(Block.class); when(ab.getType()).thenReturn(Material.WATER); when(b.getRelative(any())).thenReturn(ab); - br.convertBlock(gh, b); + br.convertBlock(b); verify(b, never()).setType(Material.CLAY); }