Optional Generators (#67)
* old generators in new api * add NewMaterialPopulator * forgot to prevent physics loop * I see... the new generator creates caves * apply getMinHeight and getMaxHeight * getMinHeight and getMaxHeight for populators too * summarize * general reformat on populators * small typos * comment sections * small reformat * warning on config * apply new API on BlockPopulator p.1 * apply new API on BlockPopulator p.2 * apply new API on BlockPopulator p.3 (final) * hasAI option
This commit is contained in:
parent
30f59d2a31
commit
7824c7bf71
|
@ -812,6 +812,15 @@ public class Settings implements WorldSettings
|
|||
return numberOfBlockGenerationTries;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the newMaterialGenerator value.
|
||||
* @return the value of newMaterialGenerator.
|
||||
*/
|
||||
public boolean isNewMaterialGenerator()
|
||||
{
|
||||
return newMaterialGenerator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
|
@ -1647,6 +1656,17 @@ public class Settings implements WorldSettings
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method sets the newMaterialGenerator value.
|
||||
* @param newMaterialGenerator the numberOfBlockGenerationTries new value.
|
||||
*
|
||||
*/
|
||||
public void setNewMaterialGenerator(boolean newMaterialGenerator)
|
||||
{
|
||||
this.newMaterialGenerator = newMaterialGenerator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the debug
|
||||
*/
|
||||
|
@ -2198,6 +2218,12 @@ public class Settings implements WorldSettings
|
|||
@ConfigEntry(path = "world.generation-tries", needsReset = true)
|
||||
private int numberOfBlockGenerationTries = 1;
|
||||
|
||||
@ConfigComment("Should we use the new material generator ?")
|
||||
@ConfigComment("This will generate ores and blocks similar to how vanilla does,")
|
||||
@ConfigComment("but it will override the blocks settings of each world.")
|
||||
@ConfigEntry(path = "world.use-new-material-generator", needsReset = true)
|
||||
private boolean newMaterialGenerator = false;
|
||||
|
||||
@ConfigComment("")
|
||||
@ConfigComment("Make over world roof of bedrock, if false, it will be made from stone")
|
||||
@ConfigEntry(path = "world.normal.roof", needsReset = true)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package world.bentobox.caveblock;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
public class Utils {
|
||||
|
||||
/**
|
||||
* Convert chunk location to world location
|
||||
*
|
||||
* @param x the x coordinate of the chunk location
|
||||
* @param y the y coordinate
|
||||
* @param z the z coordinate of the chunk location
|
||||
* @param chunkX the x coordinate of the chunk
|
||||
* @param chunkZ the z coordinate of the chunk
|
||||
* @return the world location
|
||||
*/
|
||||
public static Location getLocationFromChunkLocation(int x, int y, int z, int chunkX, int chunkZ) {
|
||||
return new Location(null, x + (chunkX * 16D), y, z + (chunkZ * 16D));
|
||||
}
|
||||
}
|
|
@ -1,23 +1,21 @@
|
|||
package world.bentobox.caveblock.generators;
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.generator.BiomeProvider;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.generator.WorldInfo;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.caveblock.CaveBlock;
|
||||
import world.bentobox.caveblock.Settings;
|
||||
import world.bentobox.caveblock.generators.populators.EntitiesPopulator;
|
||||
import world.bentobox.caveblock.generators.populators.FlatBiomeProvider;
|
||||
import world.bentobox.caveblock.generators.populators.MaterialPopulator;
|
||||
import world.bentobox.caveblock.generators.populators.NewMaterialPopulator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* Class ChunkGeneratorWorld ...
|
||||
|
@ -25,155 +23,81 @@ import world.bentobox.caveblock.Settings;
|
|||
* @author BONNe
|
||||
* Created on 27.01.2019
|
||||
*/
|
||||
public class ChunkGeneratorWorld extends ChunkGenerator
|
||||
{
|
||||
private CaveBlock addon;
|
||||
private Settings settings;
|
||||
private Map<Environment, ChunkData> map = new EnumMap<>(Environment.class);
|
||||
private final Random r = new Random();
|
||||
private Map<Environment, List<Ore>> ores = new EnumMap<>(Environment.class);
|
||||
public class ChunkGeneratorWorld extends ChunkGenerator {
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private final CaveBlock addon;
|
||||
private final Settings settings;
|
||||
private final List<BlockPopulator> blockPopulators;
|
||||
private BiomeProvider biomeProvider;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Constructor
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* @param addon - CaveBlock object
|
||||
*/
|
||||
public ChunkGeneratorWorld(CaveBlock addon)
|
||||
{
|
||||
super();
|
||||
public ChunkGeneratorWorld(CaveBlock addon) {
|
||||
this.addon = addon;
|
||||
this.settings = addon.getSettings();
|
||||
// Source https://minecraft.fandom.com/wiki/Blob
|
||||
List<Ore> worldOres = new ArrayList<>();
|
||||
worldOres.add(new Ore(-64, 16, Material.DIAMOND_ORE, 1, 10, true));
|
||||
worldOres.add(new Ore(-64, 64, Material.LAPIS_ORE, 1, 7, true));
|
||||
worldOres.add(new Ore(-64, 30, Material.GOLD_ORE, 2, 9, true));
|
||||
worldOres.add(new Ore(0, 16, Material.TUFF, 2, 33, false));
|
||||
worldOres.add(new Ore(-64, 16, Material.REDSTONE_ORE, 8, 8, true));
|
||||
worldOres.add(new Ore(0, 16, Material.GRAVEL, 8 , 33, false));
|
||||
worldOres.add(new Ore(0, 79, Material.GRANITE, 5, 33, false));
|
||||
worldOres.add(new Ore(0, 79, Material.ANDESITE,5, 33, false));
|
||||
worldOres.add(new Ore(0, 79, Material.DIORITE,5, 33, false));
|
||||
worldOres.add(new Ore(32, 320, Material.EMERALD_ORE, 11, 1, true));
|
||||
worldOres.add(new Ore(95, 136, Material.COAL_ORE, 20, 17, false));
|
||||
worldOres.add(new Ore(0, 96, Material.COPPER_ORE, 20, 9, true));
|
||||
worldOres.add(new Ore(-64, 320, Material.IRON_ORE, 20, 9, true));
|
||||
worldOres.add(new Ore(-64, 320, Material.CAVE_AIR, 8 , 33, false));
|
||||
ores.put(Environment.NORMAL, worldOres);
|
||||
List<Ore> netherOres = new ArrayList<>();
|
||||
netherOres.add(new Ore(1, 22, Material.ANCIENT_DEBRIS, 1, 5, true));
|
||||
netherOres.add(new Ore(-64, 30, Material.NETHER_GOLD_ORE, 2, 9, true));
|
||||
netherOres.add(new Ore(0, 16, Material.GRAVEL, 8 , 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.BASALT, 8 , 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.BLACKSTONE, 8 , 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.FIRE, 8 , 33, false));
|
||||
netherOres.add(new Ore(200, 320, Material.GLOWSTONE, 8 , 33, false));
|
||||
netherOres.add(new Ore(-64, 320, Material.CAVE_AIR, 8 , 33, false));
|
||||
netherOres.add(new Ore(-64, 320, Material.LAVA, 8 , 33, false));
|
||||
netherOres.add(new Ore(0, 16, Material.MAGMA_BLOCK, 8 , 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.CRIMSON_FUNGUS, 8 , 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.WARPED_FUNGUS, 8 , 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.CRIMSON_NYLIUM, 8 , 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.WARPED_NYLIUM, 8 , 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.SHROOMLIGHT, 8 , 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.CRIMSON_STEM, 8 , 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.WARPED_STEM, 8 , 33, false));
|
||||
netherOres.add(new Ore(-64, 34, Material.SOUL_SOIL, 20, 17, false));
|
||||
netherOres.add(new Ore(0, 96, Material.NETHER_QUARTZ_ORE, 20, 9, true));
|
||||
netherOres.add(new Ore(-64, 320, Material.BONE_BLOCK, 20, 9, true));
|
||||
ores.put(Environment.NETHER, netherOres);
|
||||
List<Ore> endOres = new ArrayList<>();
|
||||
endOres.add(new Ore(32, 320, Material.PURPUR_BLOCK, 11, 1, true));
|
||||
endOres.add(new Ore(95, 136, Material.OBSIDIAN, 20, 17, false));
|
||||
endOres.add(new Ore(-64, 320, Material.CAVE_AIR, 8 , 33, false));
|
||||
ores.put(Environment.THE_END, endOres);
|
||||
this.blockPopulators = new ArrayList<>(2);
|
||||
|
||||
reload();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Methods
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public void generateNoise(WorldInfo worldInfo, Random random, int x, int z, ChunkData chunkData) {
|
||||
switch(worldInfo.getEnvironment()) {
|
||||
default:
|
||||
chunkData.setRegion(0, worldInfo.getMinHeight(), 0, 16, worldInfo.getMaxHeight(), 16, Material.STONE);
|
||||
chunkData.setRegion(0, worldInfo.getMinHeight(), 0, 16, 7, 16, Material.DEEPSLATE);
|
||||
chunkData.setRegion(0, worldInfo.getMaxHeight() - 1, 0, 16, worldInfo.getMaxHeight(), 16, Material.BEDROCK);
|
||||
break;
|
||||
case NETHER:
|
||||
chunkData.setRegion(0, worldInfo.getMinHeight(), 0, 16, worldInfo.getMaxHeight(), 16, Material.NETHERRACK);
|
||||
chunkData.setRegion(0, worldInfo.getMinHeight(), 0, 16, 34, 16, Material.SOUL_SAND);
|
||||
chunkData.setRegion(0, worldInfo.getMaxHeight() - 1, 0, 16, worldInfo.getMaxHeight(), 16, Material.BEDROCK);
|
||||
break;
|
||||
case THE_END:
|
||||
chunkData.setRegion(0, worldInfo.getMinHeight(), 0, 16, worldInfo.getMaxHeight(), 16, Material.END_STONE);
|
||||
chunkData.setRegion(0, worldInfo.getMaxHeight() - 1, 0, 16, worldInfo.getMaxHeight(), 16, Material.BEDROCK);
|
||||
break;
|
||||
}
|
||||
|
||||
// Generate ores
|
||||
for (int y = worldInfo.getMinHeight(); y < worldInfo.getMaxHeight(); y++) {
|
||||
for (Ore o: ores.get(worldInfo.getEnvironment())) {
|
||||
if (y > o.minY() && y < o.maxY() && r.nextInt(100) <= o.chance()) {
|
||||
pasteBlob(chunkData, y, o);
|
||||
if (o.cont()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private Material getGroundCeilMaterial(World.Environment environment) {
|
||||
return switch (environment) {
|
||||
case NETHER -> this.settings.isNetherRoof() ? Material.BEDROCK : this.settings.getNetherMainBlock();
|
||||
case THE_END -> this.settings.isEndFloor() ? Material.BEDROCK : this.settings.getEndMainBlock();
|
||||
default -> this.settings.isNormalFloor() ? Material.BEDROCK : this.settings.getNormalMainBlock();
|
||||
};
|
||||
}
|
||||
|
||||
private void pasteBlob(ChunkData chunkData, int y, Ore o) {
|
||||
//int blobSize = (int) (((double)r.nextInt(o.blob()) / 3) + 1);
|
||||
int blobSize = 1;
|
||||
int offset = r.nextInt(16);
|
||||
for (int x = Math.max(0, offset - blobSize); x < Math.min(16, offset + blobSize); x++) {
|
||||
for (int z = Math.max(0, offset - blobSize); z < Math.min(16, offset + blobSize); z++) {
|
||||
for (int yy = Math.max(chunkData.getMinHeight(), y - blobSize); yy < Math.min(chunkData.getMaxHeight(),y + blobSize); yy++) {
|
||||
BlockData bd = chunkData.getBlockData(x, yy, z);
|
||||
if (bd.getMaterial().isSolid() && r.nextBoolean()) {
|
||||
chunkData.setBlock(x, yy, z, o.material());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@Override
|
||||
public void generateSurface(WorldInfo worldInfo, Random random, int x, int z, ChunkData chunkData) {
|
||||
//BentoBox.getInstance().logDebug("generateSurface " + x + " " + z + " " + chunkData);
|
||||
private Material getBaseMaterial(World.Environment environment) {
|
||||
return switch (environment) {
|
||||
case NETHER -> this.settings.getNetherMainBlock();
|
||||
case THE_END -> this.settings.getEndMainBlock();
|
||||
default -> this.settings.getNormalMainBlock();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateBedrock(WorldInfo worldInfo, Random random, int x, int z, ChunkData chunkData) {
|
||||
//BentoBox.getInstance().logDebug("generateBedrock " + x + " " + z + " " + chunkData);
|
||||
}
|
||||
@Override
|
||||
public void generateCaves(WorldInfo worldInfo, Random random, int x, int z, ChunkData chunkData) {
|
||||
//BentoBox.getInstance().logDebug("generateCaves " + x + " " + z + " " + chunkData);
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* This method sets if given coordinates can be set as spawn location
|
||||
*/
|
||||
@Override
|
||||
public boolean canSpawn(World world, int x, int z)
|
||||
{
|
||||
return true;
|
||||
public void generateBedrock(WorldInfo worldInfo, Random random, int chunkX, int chunkZ, ChunkData chunkData) {
|
||||
final int minHeight = worldInfo.getMinHeight();
|
||||
Material material = getGroundCeilMaterial(worldInfo.getEnvironment());
|
||||
chunkData.setRegion(0, minHeight, 0, 16, minHeight + 1, 16, material);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldGenerateNoise() {
|
||||
return false;
|
||||
public void generateSurface(WorldInfo worldInfo, Random random, int chunkX, int chunkZ, ChunkData chunkData) {
|
||||
final int worldHeight = Math.min(worldInfo.getMaxHeight(), this.settings.getWorldDepth());
|
||||
Material material = getGroundCeilMaterial(worldInfo.getEnvironment());
|
||||
chunkData.setRegion(0, worldHeight - 1, 0, 16, worldHeight, 16, material);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateNoise(WorldInfo worldInfo, Random random, int chunkX, int chunkZ, ChunkData chunkData) {
|
||||
final int minHeight = worldInfo.getMinHeight();
|
||||
final int worldHeight = Math.min(worldInfo.getMaxHeight(), this.settings.getWorldDepth());
|
||||
Material material = getBaseMaterial(worldInfo.getEnvironment());
|
||||
chunkData.setRegion(0, minHeight + 1, 0, 16, worldHeight - 1, 16, material);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPopulator> getDefaultPopulators(final World world) {
|
||||
return this.blockPopulators;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeProvider getDefaultBiomeProvider(WorldInfo worldInfo) {
|
||||
return biomeProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -188,9 +112,22 @@ public class ChunkGeneratorWorld extends ChunkGenerator
|
|||
|
||||
@Override
|
||||
public boolean shouldGenerateCaves() {
|
||||
return true;
|
||||
return this.settings.isNewMaterialGenerator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when config is reloaded
|
||||
*/
|
||||
public void reload() {
|
||||
this.blockPopulators.clear();
|
||||
|
||||
if (this.settings.isNewMaterialGenerator()) {
|
||||
this.blockPopulators.add(new NewMaterialPopulator());
|
||||
} else {
|
||||
this.blockPopulators.add(new MaterialPopulator(this.addon));
|
||||
}
|
||||
this.blockPopulators.add(new EntitiesPopulator(this.addon));
|
||||
|
||||
this.biomeProvider = new FlatBiomeProvider(this.addon);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,14 +3,14 @@ package world.bentobox.caveblock.generators;
|
|||
import org.bukkit.Material;
|
||||
|
||||
/**
|
||||
* @author tastybento
|
||||
* @param minY minimum Y level this ore should appear
|
||||
* @param minY maximum Y level this ore should appear
|
||||
* @param minY minimum Y level this ore should appear
|
||||
* @param minY maximum Y level this ore should appear
|
||||
* @param material Material
|
||||
* @param chance chance
|
||||
* @param blob maximum size of blob to generate
|
||||
* @param cont whether the generator should continue to try to make other ores at this level after making this one
|
||||
* @param chance chance
|
||||
* @param blob maximum size of blob to generate
|
||||
* @param cont whether the generator should continue to try to make other ores at this level after making this one
|
||||
* @author tastybento
|
||||
*/
|
||||
public record Ore (int minY, int maxY, Material material, int chance, int blob, boolean cont){
|
||||
public record Ore(int minY, int maxY, Material material, int chance, int blob, boolean cont) {
|
||||
|
||||
}
|
||||
|
|
|
@ -1,52 +1,80 @@
|
|||
package world.bentobox.caveblock.generators.populators;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
import org.bukkit.generator.LimitedRegion;
|
||||
import org.bukkit.generator.WorldInfo;
|
||||
import org.bukkit.util.BoundingBox;
|
||||
|
||||
import world.bentobox.bentobox.util.Pair;
|
||||
import world.bentobox.caveblock.CaveBlock;
|
||||
import world.bentobox.caveblock.Utils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* This class populates generated chunk with entites by random chance.
|
||||
* This class populates generated chunk with entities by random chance.
|
||||
*/
|
||||
public class EntitiesPopulator extends BlockPopulator
|
||||
{
|
||||
public class EntitiesPopulator extends BlockPopulator {
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Water entities
|
||||
*/
|
||||
private static final List<EntityType> WATER_ENTITIES = Arrays.asList(EntityType.GUARDIAN,
|
||||
EntityType.SQUID,
|
||||
EntityType.COD,
|
||||
EntityType.SALMON,
|
||||
EntityType.PUFFERFISH,
|
||||
EntityType.TROPICAL_FISH,
|
||||
EntityType.DROWNED,
|
||||
EntityType.DOLPHIN);
|
||||
/**
|
||||
* CaveBlock addon.
|
||||
*/
|
||||
private final CaveBlock addon;
|
||||
/**
|
||||
* Map that contains chances for spawning per environment.
|
||||
*/
|
||||
private Map<Environment, Chances> chances;
|
||||
/**
|
||||
* World height
|
||||
*/
|
||||
private int worldHeight;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Constructor
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This is default constructor
|
||||
*
|
||||
* @param addon CaveBlock addon.
|
||||
*/
|
||||
public EntitiesPopulator(CaveBlock addon)
|
||||
{
|
||||
public EntitiesPopulator(CaveBlock addon) {
|
||||
this.addon = addon;
|
||||
this.loadSettings();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Methods
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This method load chances per environment.
|
||||
*/
|
||||
private void loadSettings() {
|
||||
// Set up chances
|
||||
chances = new HashMap<>();
|
||||
chances = new EnumMap<>(Environment.class);
|
||||
// Normal
|
||||
chances.put(Environment.NORMAL, new Chances(this.getEntityMap(addon.getSettings().getNormalBlocks()), addon.getSettings().getNormalMainBlock()));
|
||||
// Nether
|
||||
|
@ -54,43 +82,49 @@ public class EntitiesPopulator extends BlockPopulator
|
|||
// End
|
||||
chances.put(Environment.THE_END, new Chances(this.getEntityMap(addon.getSettings().getEndBlocks()), addon.getSettings().getEndMainBlock()));
|
||||
// Other settings
|
||||
worldHeight = addon.getSettings().getWorldDepth() - 1;
|
||||
worldHeight = addon.getSettings().getWorldDepth();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method populates chunk with entities.
|
||||
* @param world World where population must be.
|
||||
* @param random Randomness
|
||||
* @param chunk Chunk were populator operates.
|
||||
*
|
||||
* @param worldInfo World where population must be.
|
||||
* @param random Randomness
|
||||
* @param chunkX X coordinate of chunk
|
||||
* @param chunkZ Z coordinate of chunk
|
||||
* @param limitedRegion Region where population operates.
|
||||
*/
|
||||
@Override
|
||||
public void populate(World world, Random random, Chunk chunk)
|
||||
{
|
||||
for (Map.Entry<EntityType, Pair<Double, Integer>> entry : chances.get(world.getEnvironment()).entityChanceMap.entrySet())
|
||||
{
|
||||
for (int subY = 0; subY < worldHeight; subY += 16)
|
||||
{
|
||||
public void populate(WorldInfo worldInfo, Random random, int chunkX, int chunkZ, LimitedRegion limitedRegion) {
|
||||
int minHeight = worldInfo.getMinHeight();
|
||||
int height = Math.min(worldInfo.getMaxHeight(), worldHeight) - 1;
|
||||
|
||||
for (Map.Entry<EntityType, Pair<Pair<Double, Integer>, Boolean>> entry : chances.get(worldInfo.getEnvironment()).entityChanceMap.entrySet()) {
|
||||
Pair<Double, Integer> value = entry.getValue().x;
|
||||
boolean hasAI = entry.getValue().z;
|
||||
for (int subY = minHeight; subY < height; subY += 16) {
|
||||
// Use double so chance can be < 1
|
||||
if (random.nextDouble() * 100 < entry.getValue().x)
|
||||
{
|
||||
int y = Math.min(worldHeight - 2, subY + random.nextInt(15));
|
||||
if (random.nextDouble() * 100 < value.x) {
|
||||
int y = Math.min(height - 2, subY + random.nextInt(15));
|
||||
// Spawn only in middle of chunk because bounding box will grow out from here
|
||||
this.tryToPlaceEntity(world, chunk.getBlock(7, y, 7), entry.getKey(), chances.get(world.getEnvironment()).mainMaterial);
|
||||
this.tryToPlaceEntity(
|
||||
worldInfo, Utils.getLocationFromChunkLocation(7, y, 7, chunkX, chunkZ), limitedRegion,
|
||||
entry.getKey(), hasAI,
|
||||
chances.get(worldInfo.getEnvironment()).mainMaterial
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method returns Entity frequently and pack size map.
|
||||
*
|
||||
* @param objectList List with objects that contains data.
|
||||
* @return Map that contains entity, its rarity and pack size.
|
||||
*/
|
||||
private Map<EntityType, Pair<Double, Integer>> getEntityMap(List<String> objectList)
|
||||
{
|
||||
Map<EntityType, Pair<Double, Integer>> entityMap = new HashMap<>(objectList.size());
|
||||
private Map<EntityType, Pair<Pair<Double, Integer>, Boolean>> getEntityMap(List<String> objectList) {
|
||||
Map<EntityType, Pair<Pair<Double, Integer>, Boolean>> entityMap = new EnumMap<>(EntityType.class);
|
||||
|
||||
Map<String, EntityType> entityTypeMap = Arrays.stream(EntityType.values()).
|
||||
collect(Collectors.toMap(Enum::name,
|
||||
|
@ -100,128 +134,86 @@ public class EntitiesPopulator extends BlockPopulator
|
|||
|
||||
// wrong material object.
|
||||
objectList.stream().
|
||||
filter(object -> object.startsWith("ENTITY")).
|
||||
map(object -> object.split(":")).
|
||||
filter(splitString -> splitString.length == 4).
|
||||
forEach(splitString -> {
|
||||
EntityType entity = entityTypeMap.getOrDefault(splitString[1], null);
|
||||
filter(object -> object.startsWith("ENTITY")).
|
||||
map(object -> object.split(":")).
|
||||
filter(splitString -> splitString.length >= 4).
|
||||
forEach(splitString -> {
|
||||
EntityType entity = entityTypeMap.getOrDefault(splitString[1], null);
|
||||
boolean hasAI = splitString.length <= 4 || Boolean.parseBoolean(splitString[4]);
|
||||
|
||||
if (entity != null)
|
||||
{
|
||||
entityMap.put(entity,
|
||||
new Pair<>(Double.parseDouble(splitString[2]), Integer.parseInt(splitString[3])));
|
||||
}
|
||||
});
|
||||
if (entity != null) {
|
||||
entityMap.put(entity,
|
||||
new Pair<>(
|
||||
new Pair<>(Double.parseDouble(splitString[2]), Integer.parseInt(splitString[3])),
|
||||
hasAI
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return entityMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Places entities if there is room for them.
|
||||
* @param world - World were mob must be spawned.
|
||||
* @param block - Block that was chosen by random.
|
||||
* @param entity - Entity that must be spawned.
|
||||
*
|
||||
* @param worldInfo - World were mob must be spawned.
|
||||
* @param location - Location that was chosen by random.
|
||||
* @param limitedRegion - Region where entity must be spawned.
|
||||
* @param entityType - Entity that must be spawned.
|
||||
* @param hasAI - If entity has AI.
|
||||
* @param originalMaterial - replacement material.
|
||||
*/
|
||||
private void tryToPlaceEntity(World world, Block block, EntityType entity, Material originalMaterial)
|
||||
{
|
||||
if (block.getType().equals(originalMaterial)) {
|
||||
// Spawn entity
|
||||
Entity e = world.spawnEntity(block.getLocation().add(0.5, 0, 0.5), entity);
|
||||
if (e instanceof LivingEntity) {
|
||||
// Do not despawn
|
||||
((LivingEntity)e).setRemoveWhenFarAway(false);
|
||||
}
|
||||
// Make space for entity based on the entity's size
|
||||
BoundingBox bb = e.getBoundingBox();
|
||||
private void tryToPlaceEntity(WorldInfo worldInfo, Location location, LimitedRegion limitedRegion, EntityType entityType, boolean hasAI, Material originalMaterial) {
|
||||
if (!limitedRegion.isInRegion(location)) return;
|
||||
if (!limitedRegion.getType(location).equals(originalMaterial)) return;
|
||||
|
||||
for (int x = (int) Math.floor(bb.getMinX()); x < bb.getMaxX(); x++) {
|
||||
for (int z = (int) Math.floor(bb.getMinZ()); z < bb.getMaxZ(); z++) {
|
||||
int y = (int) Math.floor(bb.getMinY());
|
||||
Block b = world.getBlockAt(x, y, z);
|
||||
for (; y < bb.getMaxY(); y++) {
|
||||
if (addon.getSettings().isDebug()) {
|
||||
addon.log("DEBUG: Entity spawn: " + world.getName() + " " + x + " " + y + " " + z + " " + e.getType());
|
||||
}
|
||||
b = world.getBlockAt(x, y, z);
|
||||
if (!b.getType().equals(originalMaterial)) {
|
||||
// Cannot place entity
|
||||
e.remove();
|
||||
return;
|
||||
}
|
||||
b.setType(WATER_ENTITIES.contains(entity) ? Material.WATER : Material.AIR);
|
||||
Entity entity = limitedRegion.spawnEntity(location, entityType);
|
||||
if (entity instanceof LivingEntity livingEntity) {
|
||||
livingEntity.setAI(hasAI);
|
||||
livingEntity.setRemoveWhenFarAway(false);
|
||||
}
|
||||
|
||||
BoundingBox bb = entity.getBoundingBox();
|
||||
for (int x = (int) Math.floor(bb.getMinX()); x < bb.getMaxX(); x++) {
|
||||
for (int z = (int) Math.floor(bb.getMinZ()); z < bb.getMaxZ(); z++) {
|
||||
int y = (int) Math.floor(bb.getMinY());
|
||||
if (!limitedRegion.isInRegion(x, y, z)) {
|
||||
entity.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
for (; y <= bb.getMaxY(); y++) {
|
||||
if (addon.getSettings().isDebug()) {
|
||||
addon.log("DEBUG: Entity spawn: " + worldInfo.getName() + " " + x + " " + y + " " + z + " " + entity.getType());
|
||||
}
|
||||
// Add air block on top for all water entities (required for dolphin, okay for others)
|
||||
if (WATER_ENTITIES.contains(entity) && b.getRelative(BlockFace.UP).getType().equals(originalMaterial)) {
|
||||
b.getRelative(BlockFace.UP).setType(Material.CAVE_AIR);
|
||||
|
||||
if (!limitedRegion.isInRegion(x, y, z) || !limitedRegion.getType(x, y, z).equals(originalMaterial)) {
|
||||
// Cannot place entity
|
||||
entity.remove();
|
||||
return;
|
||||
}
|
||||
limitedRegion.setType(x, y, z, WATER_ENTITIES.contains(entityType) ? Material.WATER : Material.AIR);
|
||||
}
|
||||
// Add air block on top for all water entities (required for dolphin, okay for others)
|
||||
if (WATER_ENTITIES.contains(entityType) && limitedRegion.isInRegion(x, y, z) && limitedRegion.getType(x, y, z).equals(originalMaterial)) {
|
||||
limitedRegion.setType(x, y, z, Material.CAVE_AIR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Private Classes
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Chances class to store chances for environments and main material
|
||||
*
|
||||
* @param entityChanceMap - contains chances for each entity, and the boolean indicates that entity should have AI.
|
||||
* @param mainMaterial - material on which entity can replace.
|
||||
*/
|
||||
private class Chances
|
||||
{
|
||||
/**
|
||||
* @param entityChanceMap - contains chances for each entity.
|
||||
* @param mainMaterial - material on which entity can replace.
|
||||
*/
|
||||
Chances(Map<EntityType, Pair<Double, Integer>> entityChanceMap, Material mainMaterial)
|
||||
{
|
||||
this.entityChanceMap = entityChanceMap;
|
||||
this.mainMaterial = mainMaterial;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Map that contains chances for entity to spawn.
|
||||
*/
|
||||
final Map<EntityType, Pair<Double, Integer>> entityChanceMap;
|
||||
|
||||
/**
|
||||
* Main material that can be replaced.
|
||||
*/
|
||||
final Material mainMaterial;
|
||||
private record Chances(Map<EntityType, Pair<Pair<Double, Integer>, Boolean>> entityChanceMap,
|
||||
Material mainMaterial) {
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* CaveBlock addon.
|
||||
*/
|
||||
private CaveBlock addon;
|
||||
|
||||
/**
|
||||
* Map that contains chances for spawning per environment.
|
||||
*/
|
||||
private Map<Environment, Chances> chances;
|
||||
|
||||
/**
|
||||
* World height
|
||||
*/
|
||||
private int worldHeight;
|
||||
|
||||
/**
|
||||
* Water entities
|
||||
*/
|
||||
private final static List<EntityType> WATER_ENTITIES = Arrays.asList(EntityType.GUARDIAN,
|
||||
EntityType.SQUID,
|
||||
EntityType.COD,
|
||||
EntityType.SALMON,
|
||||
EntityType.PUFFERFISH,
|
||||
EntityType.TROPICAL_FISH,
|
||||
EntityType.DROWNED,
|
||||
EntityType.DOLPHIN);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package world.bentobox.caveblock.generators.populators;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.generator.BiomeProvider;
|
||||
import org.bukkit.generator.WorldInfo;
|
||||
import world.bentobox.caveblock.CaveBlock;
|
||||
import world.bentobox.caveblock.Settings;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class FlatBiomeProvider extends BiomeProvider {
|
||||
private final Settings settings;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Constructor
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @param addon - CaveBlock object
|
||||
*/
|
||||
public FlatBiomeProvider(CaveBlock addon) {
|
||||
this.settings = addon.getSettings();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Methods
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private Biome getBiome(World.Environment environment) {
|
||||
return switch (environment) {
|
||||
case NETHER -> this.settings.getDefaultNetherBiome();
|
||||
case THE_END -> this.settings.getDefaultTheEndBiome();
|
||||
default -> this.settings.getDefaultBiome();
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(WorldInfo worldInfo, int x, int y, int z) {
|
||||
return getBiome(worldInfo.getEnvironment());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Biome> getBiomes(WorldInfo worldInfo) {
|
||||
return Collections.singletonList(getBiome(worldInfo.getEnvironment()));
|
||||
}
|
||||
}
|
|
@ -1,47 +1,67 @@
|
|||
|
||||
package world.bentobox.caveblock.generators.populators;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
import org.bukkit.generator.LimitedRegion;
|
||||
import org.bukkit.generator.WorldInfo;
|
||||
import world.bentobox.bentobox.util.Pair;
|
||||
import world.bentobox.caveblock.CaveBlock;
|
||||
import world.bentobox.caveblock.Utils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
|
||||
import world.bentobox.bentobox.util.Pair;
|
||||
import world.bentobox.caveblock.CaveBlock;
|
||||
|
||||
|
||||
/**
|
||||
* This class allows to fill given chunk with necessary blocks.
|
||||
* This class allows filling given chunk with necessary blocks.
|
||||
*/
|
||||
public class MaterialPopulator extends BlockPopulator
|
||||
{
|
||||
public class MaterialPopulator extends BlockPopulator {
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* CaveBlock addon.
|
||||
*/
|
||||
private final CaveBlock addon;
|
||||
/**
|
||||
* Map that contains chances for spawning per environment.
|
||||
*/
|
||||
private Map<Environment, Chances> chances;
|
||||
/**
|
||||
* World height
|
||||
*/
|
||||
private int worldHeight;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Constructor
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This is default constructor
|
||||
*
|
||||
* @param addon CaveBlock addon.
|
||||
*/
|
||||
public MaterialPopulator(CaveBlock addon)
|
||||
{
|
||||
public MaterialPopulator(CaveBlock addon) {
|
||||
this.addon = addon;
|
||||
// Load settings
|
||||
this.loadSettings();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Methods
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Loads chances for Material Populator
|
||||
*/
|
||||
private void loadSettings() {
|
||||
// Set up chances
|
||||
chances = new HashMap<>();
|
||||
chances = new EnumMap<>(Environment.class);
|
||||
// Normal
|
||||
chances.put(Environment.NORMAL, new Chances(this.getMaterialMap(addon.getSettings().getNormalBlocks()), addon.getSettings().getNormalMainBlock()));
|
||||
// Nether
|
||||
|
@ -49,84 +69,71 @@ public class MaterialPopulator extends BlockPopulator
|
|||
// End
|
||||
chances.put(Environment.THE_END, new Chances(this.getMaterialMap(addon.getSettings().getEndBlocks()), addon.getSettings().getEndMainBlock()));
|
||||
// Other settings
|
||||
worldHeight = addon.getSettings().getWorldDepth() - 1;
|
||||
worldHeight = addon.getSettings().getWorldDepth();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method populates chunk with blocks.
|
||||
* @param world World where population must be.
|
||||
* @param random Randomness
|
||||
* @param chunk Chunk were populator operates.
|
||||
*
|
||||
* @param worldInfo World where population must be.
|
||||
* @param random Randomness
|
||||
* @param chunkX X coordinate of chunk
|
||||
* @param chunkZ Z coordinate of chunk
|
||||
* @param limitedRegion Region were populator operates.
|
||||
*/
|
||||
@Override
|
||||
public void populate(World world, Random random, Chunk chunk)
|
||||
{
|
||||
Chances chances = this.chances.get(world.getEnvironment());
|
||||
public void populate(WorldInfo worldInfo, Random random, int chunkX, int chunkZ, LimitedRegion limitedRegion) {
|
||||
int minHeight = worldInfo.getMinHeight();
|
||||
int height = Math.min(worldInfo.getMaxHeight(), worldHeight) - 1;
|
||||
Chances envChances = this.chances.get(worldInfo.getEnvironment());
|
||||
for (Map.Entry<Material, Pair<Double, Integer>> entry : envChances.materialChanceMap.entrySet()) {
|
||||
for (int subY = minHeight + 1; subY < height; subY += 16) {
|
||||
if (random.nextDouble() * 100 >= entry.getValue().x) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Map.Entry<Material, Pair<Double, Integer>> entry : chances.materialChanceMap.entrySet())
|
||||
{
|
||||
for (int subY = 1; subY < worldHeight; subY += 16)
|
||||
{
|
||||
if (random.nextDouble() * 100 < entry.getValue().x)
|
||||
{
|
||||
// Blocks must be 1 away from edge to avoid adjacent chunk loading
|
||||
Location location = Utils.getLocationFromChunkLocation(
|
||||
random.nextInt(13) + 1,
|
||||
Math.min(height - 2, subY + random.nextInt(15)),
|
||||
random.nextInt(13) + 1,
|
||||
chunkX, chunkZ);
|
||||
|
||||
// Blocks must be 1 away from edge to avoid adjacent chunk loading
|
||||
int x = random.nextInt(13) + 1;
|
||||
int z = random.nextInt(13) + 1;
|
||||
int y = Math.min(worldHeight - 2, subY + random.nextInt(15));
|
||||
/*
|
||||
* TODO: remove
|
||||
if (addon.getSettings().isDebug()) {
|
||||
addon.log("DEBUG: Material: " + world.getName() + " " + x + " " + y + " " + z + " " + entry.getKey());
|
||||
if (!limitedRegion.isInRegion(location)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Material material = limitedRegion.getType(location);
|
||||
if (!material.equals(envChances.mainMaterial)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int packSize = random.nextInt(entry.getValue().z);
|
||||
boolean continuePlacing = true;
|
||||
while (continuePlacing) {
|
||||
if (!material.equals(entry.getKey())) {
|
||||
limitedRegion.setType(location, entry.getKey());
|
||||
packSize--;
|
||||
}
|
||||
*/
|
||||
Block block = chunk.getBlock(x, y, z);
|
||||
|
||||
if (block.getType().equals(chances.mainMaterial))
|
||||
{
|
||||
int packSize = random.nextInt(entry.getValue().z);
|
||||
|
||||
boolean continuePlacing = true;
|
||||
|
||||
while (continuePlacing)
|
||||
{
|
||||
if (!block.getType().equals(entry.getKey()))
|
||||
{
|
||||
// Set type without physics is required otherwise server goes into an infinite loop
|
||||
block.setType(entry.getKey(), false);
|
||||
packSize--;
|
||||
}
|
||||
|
||||
// The direction chooser
|
||||
switch (random.nextInt(5))
|
||||
{
|
||||
case 0:
|
||||
x = Math.min(15, x + 1);
|
||||
break;
|
||||
case 1:
|
||||
y = Math.min(worldHeight - 2, y + 1);
|
||||
break;
|
||||
case 2:
|
||||
z = Math.min(15, z + 1);
|
||||
break;
|
||||
case 3:
|
||||
x = Math.max(0, x - 1);
|
||||
break;
|
||||
case 4:
|
||||
y = Math.max(1, y - 1);
|
||||
break;
|
||||
case 5:
|
||||
z = Math.max(0, z - 1);
|
||||
break;
|
||||
}
|
||||
|
||||
block = chunk.getBlock(x, y, z);
|
||||
|
||||
continuePlacing = packSize > 0 && (block.getType().equals(chances.mainMaterial) ||
|
||||
block.getType().equals(entry.getKey()));
|
||||
switch (random.nextInt(6)) {
|
||||
case 0 -> location.setX(location.getX() + 1);
|
||||
case 1 -> location.setY(location.getY() + 1);
|
||||
case 2 -> location.setZ(location.getZ() + 1);
|
||||
case 3 -> location.setX(location.getX() - 1);
|
||||
case 4 -> location.setY(location.getY() - 1);
|
||||
case 5 -> location.setZ(location.getZ() - 1);
|
||||
default -> {
|
||||
continuePlacing = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
continuePlacing = packSize > 0 && limitedRegion.isInRegion(location) && location.getY() > minHeight;
|
||||
if (continuePlacing) {
|
||||
material = limitedRegion.getType(location);
|
||||
continuePlacing = material.equals(envChances.mainMaterial) || material.equals(entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -134,84 +141,42 @@ public class MaterialPopulator extends BlockPopulator
|
|||
|
||||
/**
|
||||
* This method returns material frequently and pack size map.
|
||||
*
|
||||
* @param objectList List with objects that contains data.
|
||||
* @return Map that contains material, its rarity and pack size.
|
||||
*/
|
||||
private Map<Material, Pair<Double, Integer>> getMaterialMap(List<String> objectList)
|
||||
{
|
||||
Map<Material, Pair<Double, Integer>> materialMap = new HashMap<>(objectList.size());
|
||||
private Map<Material, Pair<Double, Integer>> getMaterialMap(List<String> objectList) {
|
||||
Map<Material, Pair<Double, Integer>> materialMap = new EnumMap<>(Material.class);
|
||||
|
||||
// wrong material object.
|
||||
objectList.stream().
|
||||
filter(object -> object.startsWith("MATERIAL")).
|
||||
map(object -> object.split(":")).
|
||||
filter(splitString -> splitString.length == 4).
|
||||
forEach(splitString -> {
|
||||
Material material = Material.getMaterial(splitString[1]);
|
||||
// Material must be a block otherwise the chunk cannot be populated
|
||||
if (material != null && material.isBlock())
|
||||
{
|
||||
materialMap.put(material,
|
||||
new Pair<>(Double.parseDouble(splitString[2]), Integer.parseInt(splitString[3])));
|
||||
} else {
|
||||
addon.logError("Could not parse MATERIAL in config.yml: " + splitString[1] + " is not a valid block.");
|
||||
}
|
||||
});
|
||||
filter(object -> object.startsWith("MATERIAL")).
|
||||
map(object -> object.split(":")).
|
||||
filter(splitString -> splitString.length == 4).
|
||||
forEach(splitString -> {
|
||||
Material material = Material.getMaterial(splitString[1]);
|
||||
// Material must be a block otherwise the chunk cannot be populated
|
||||
if (material != null && material.isBlock()) {
|
||||
materialMap.put(material,
|
||||
new Pair<>(Double.parseDouble(splitString[2]), Integer.parseInt(splitString[3])));
|
||||
} else {
|
||||
addon.logError("Could not parse MATERIAL in config.yml: " + splitString[1] + " is not a valid block.");
|
||||
}
|
||||
});
|
||||
|
||||
return materialMap;
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Private Classes
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Chances class to store chances for environments and main material
|
||||
*
|
||||
* @param materialChanceMap - contains chances for each material.
|
||||
* @param mainMaterial - material on which material can replace.
|
||||
*/
|
||||
private class Chances
|
||||
{
|
||||
/**
|
||||
* @param materialChanceMap - contains chances for each material.
|
||||
* @param mainMaterial - material on which material can replace.
|
||||
*/
|
||||
Chances(Map<Material, Pair<Double, Integer>> materialChanceMap, Material mainMaterial)
|
||||
{
|
||||
this.materialChanceMap = materialChanceMap;
|
||||
this.mainMaterial = mainMaterial;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Map that contains chances for entity to spawn.
|
||||
*/
|
||||
final Map<Material, Pair<Double, Integer>> materialChanceMap;
|
||||
|
||||
/**
|
||||
* Main material that can be replaced.
|
||||
*/
|
||||
final Material mainMaterial;
|
||||
private record Chances(Map<Material, Pair<Double, Integer>> materialChanceMap, Material mainMaterial) {
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* CaveBlock addon.
|
||||
*/
|
||||
private CaveBlock addon;
|
||||
|
||||
/**
|
||||
* Map that contains chances for spawning per environment.
|
||||
*/
|
||||
private Map<Environment, Chances> chances;
|
||||
|
||||
/**
|
||||
* World height
|
||||
*/
|
||||
private int worldHeight;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
package world.bentobox.caveblock.generators.populators;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
import org.bukkit.generator.LimitedRegion;
|
||||
import org.bukkit.generator.WorldInfo;
|
||||
import world.bentobox.caveblock.Utils;
|
||||
import world.bentobox.caveblock.generators.Ore;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class NewMaterialPopulator extends BlockPopulator {
|
||||
private final Map<World.Environment, List<Ore>> ores = new EnumMap<>(World.Environment.class);
|
||||
|
||||
public NewMaterialPopulator() {
|
||||
// Source https://minecraft.fandom.com/wiki/Blob
|
||||
List<Ore> worldOres = new ArrayList<>();
|
||||
worldOres.add(new Ore(-64, 16, Material.DIAMOND_ORE, 1, 10, true));
|
||||
worldOres.add(new Ore(-64, 64, Material.LAPIS_ORE, 1, 7, true));
|
||||
worldOres.add(new Ore(-64, 30, Material.GOLD_ORE, 2, 9, true));
|
||||
worldOres.add(new Ore(0, 16, Material.TUFF, 2, 33, false));
|
||||
worldOres.add(new Ore(-64, 16, Material.REDSTONE_ORE, 8, 8, true));
|
||||
worldOres.add(new Ore(0, 16, Material.GRAVEL, 8, 33, false));
|
||||
worldOres.add(new Ore(0, 79, Material.GRANITE, 5, 33, false));
|
||||
worldOres.add(new Ore(0, 79, Material.ANDESITE, 5, 33, false));
|
||||
worldOres.add(new Ore(0, 79, Material.DIORITE, 5, 33, false));
|
||||
worldOres.add(new Ore(32, 320, Material.EMERALD_ORE, 11, 1, true));
|
||||
worldOres.add(new Ore(95, 136, Material.COAL_ORE, 20, 17, false));
|
||||
worldOres.add(new Ore(0, 96, Material.COPPER_ORE, 20, 9, true));
|
||||
worldOres.add(new Ore(-64, 320, Material.IRON_ORE, 20, 9, true));
|
||||
worldOres.add(new Ore(-64, 320, Material.CAVE_AIR, 8, 33, false));
|
||||
ores.put(World.Environment.NORMAL, worldOres);
|
||||
List<Ore> netherOres = new ArrayList<>();
|
||||
netherOres.add(new Ore(1, 22, Material.ANCIENT_DEBRIS, 1, 5, true));
|
||||
netherOres.add(new Ore(-64, 30, Material.NETHER_GOLD_ORE, 2, 9, true));
|
||||
netherOres.add(new Ore(0, 16, Material.GRAVEL, 8, 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.BASALT, 8, 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.BLACKSTONE, 8, 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.FIRE, 8, 33, false));
|
||||
netherOres.add(new Ore(200, 320, Material.GLOWSTONE, 8, 33, false));
|
||||
netherOres.add(new Ore(-64, 320, Material.CAVE_AIR, 8, 33, false));
|
||||
netherOres.add(new Ore(-64, 320, Material.LAVA, 8, 33, false));
|
||||
netherOres.add(new Ore(0, 16, Material.MAGMA_BLOCK, 8, 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.CRIMSON_FUNGUS, 8, 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.WARPED_FUNGUS, 8, 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.CRIMSON_NYLIUM, 8, 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.WARPED_NYLIUM, 8, 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.SHROOMLIGHT, 8, 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.CRIMSON_STEM, 8, 33, false));
|
||||
netherOres.add(new Ore(0, 320, Material.WARPED_STEM, 8, 33, false));
|
||||
netherOres.add(new Ore(-64, 34, Material.SOUL_SOIL, 20, 17, false));
|
||||
netherOres.add(new Ore(0, 96, Material.NETHER_QUARTZ_ORE, 20, 9, true));
|
||||
netherOres.add(new Ore(-64, 320, Material.BONE_BLOCK, 20, 9, true));
|
||||
ores.put(World.Environment.NETHER, netherOres);
|
||||
List<Ore> endOres = new ArrayList<>();
|
||||
endOres.add(new Ore(32, 320, Material.PURPUR_BLOCK, 11, 1, true));
|
||||
endOres.add(new Ore(95, 136, Material.OBSIDIAN, 20, 17, false));
|
||||
endOres.add(new Ore(-64, 320, Material.CAVE_AIR, 8, 33, false));
|
||||
ores.put(World.Environment.THE_END, endOres);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populate(WorldInfo worldInfo, Random random, int chunkX, int chunkZ, LimitedRegion limitedRegion) {
|
||||
for (int y = worldInfo.getMinHeight(); y < worldInfo.getMaxHeight(); y++) {
|
||||
for (Ore o : ores.get(worldInfo.getEnvironment())) {
|
||||
if (y > o.minY() && y < o.maxY() && random.nextInt(100) <= o.chance()) {
|
||||
pasteBlob(worldInfo, random, chunkX, chunkZ, limitedRegion, y, o);
|
||||
if (o.cont()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void pasteBlob(WorldInfo worldInfo, Random random, int chunkX, int chunkZ, LimitedRegion limitedRegion, int y, Ore o) {
|
||||
//int blobSize = (int) (((double)random.nextInt(o.blob()) / 3) + 1);
|
||||
int blobSize = 1;
|
||||
int offset = random.nextInt(16);
|
||||
for (int x = Math.max(0, offset - blobSize); x < Math.min(16, offset + blobSize); x++) {
|
||||
for (int z = Math.max(0, offset - blobSize); z < Math.min(16, offset + blobSize); z++) {
|
||||
for (int yy = Math.max(worldInfo.getMinHeight(), y - blobSize); yy < Math.min(worldInfo.getMaxHeight(), y + blobSize); yy++) {
|
||||
Location location = Utils.getLocationFromChunkLocation(x, yy, z, chunkX, chunkZ);
|
||||
if (!limitedRegion.isInRegion(location)) {
|
||||
continue;
|
||||
}
|
||||
if (limitedRegion.getType(location).isSolid() && random.nextBoolean()) {
|
||||
limitedRegion.setType(location, o.material());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -93,6 +93,11 @@ world:
|
|||
# This indicate how many times block should be tried to generate.
|
||||
# /!\ BentoBox currently does not support changing this value mid-game. If you do need to change it, do a full reset of your databases and worlds.
|
||||
generation-tries: 2
|
||||
# Should we use the new material generator ?
|
||||
# This will generate ores and blocks similar to how vanilla does,
|
||||
# but it will override the blocks settings of each world.
|
||||
# /!\ BentoBox currently does not support changing this value mid-game. If you do need to change it, do a full reset of your databases and worlds.
|
||||
use-new-material-generator: false
|
||||
normal:
|
||||
#
|
||||
# Make over world roof of bedrock, if false, it will be made from stone
|
||||
|
|
Loading…
Reference in New Issue