Makes chunk population more efficient

Adds locale text.
This commit is contained in:
tastybento 2019-02-01 12:29:28 -08:00
parent 4f866ea2a2
commit f6c1bc7d7f
4 changed files with 822 additions and 558 deletions

View File

@ -17,218 +17,218 @@ import world.bentobox.caveblock.generators.ChunkGeneratorWorld;
public class CaveBlock extends GameModeAddon public class CaveBlock extends GameModeAddon
{ {
/** /**
* Executes code when loading the addon. This is called before {@link #onEnable()}. This should preferably * Executes code when loading the addon. This is called before {@link #onEnable()}. This should preferably
* be used to setup configuration and worlds. * be used to setup configuration and worlds.
*/ */
@Override @Override
public void onLoad() public void onLoad()
{ {
super.onLoad(); super.onLoad();
this.saveDefaultConfig(); this.saveDefaultConfig();
this.loadSettings(); this.loadSettings();
} }
/** /**
* Executes code when enabling the addon. This is called after {@link #onLoad()}. * Executes code when enabling the addon. This is called after {@link #onLoad()}.
*/ */
@Override @Override
public void onEnable() public void onEnable()
{ {
this.playerCommand = new IslandCommand(this); this.playerCommand = new IslandCommand(this);
this.adminCommand = new AdminCommand(this); this.adminCommand = new AdminCommand(this);
} }
/** /**
* Executes code when reloading the addon. * Executes code when reloading the addon.
*/ */
@Override @Override
public void onReload() public void onReload()
{ {
super.onReload(); super.onReload();
this.loadSettings(); this.loadSettings();
} }
/** /**
* Executes code when disabling the addon. * Executes code when disabling the addon.
*/ */
@Override @Override
public void onDisable() public void onDisable()
{ {
if (this.settings != null) if (this.settings != null)
{ {
new Config<>(this, Settings.class).saveConfigObject(this.settings); new Config<>(this, Settings.class).saveConfigObject(this.settings);
} }
} }
/** /**
* This method loads CaveBlock settings * This method loads CaveBlock settings
*/ */
private void loadSettings() private void loadSettings()
{ {
this.settings = new Config<>(this, Settings.class).loadConfigObject(); this.settings = new Config<>(this, Settings.class).loadConfigObject();
if (this.settings == null) if (this.settings == null)
{ {
// Disable // Disable
this.logError("CaveBlock settings could not load! Addon disabled."); this.logError("CaveBlock settings could not load! Addon disabled.");
this.setState(State.DISABLED); this.setState(State.DISABLED);
} }
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Section: World generators // Section: World generators
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
/** /**
* Make the worlds for this GameMode in this method. BentoBox will call it after onLoad() and before * Make the worlds for this GameMode in this method. BentoBox will call it after onLoad() and before
* onEnable(). {@link #islandWorld} must be created and assigned, {@link #netherWorld} and {@link * onEnable(). {@link #islandWorld} must be created and assigned, {@link #netherWorld} and {@link
* #endWorld} are optional and may be null. * #endWorld} are optional and may be null.
*/ */
@Override @Override
public void createWorlds() public void createWorlds()
{ {
String worldName = this.settings.getWorldName(); String worldName = this.settings.getWorldName();
if (this.getServer().getWorld(worldName) == null) if (this.getServer().getWorld(worldName) == null)
{ {
this.getLogger().info("Creating CaveBlock world ..."); this.getLogger().info("Creating CaveBlock world ...");
} }
this.chunkGenerator = new ChunkGeneratorWorld(this); this.chunkGenerator = new ChunkGeneratorWorld(this);
// Create the world if it does not exist // Create the world if it does not exist
this.islandWorld = WorldCreator.name(worldName). this.islandWorld = WorldCreator.name(worldName).
type(WorldType.FLAT). type(WorldType.FLAT).
environment(World.Environment.NORMAL). environment(World.Environment.NORMAL).
generator(new ChunkGeneratorWorld(this)). generator(this.chunkGenerator).
createWorld(); createWorld();
// Make the nether if it does not exist // Make the nether if it does not exist
if (this.settings.isNetherGenerate()) if (this.settings.isNetherGenerate())
{ {
if (this.getServer().getWorld(worldName + NETHER) == null) if (this.getServer().getWorld(worldName + NETHER) == null)
{ {
this.log("Creating CaveBlock's Nether..."); this.log("Creating CaveBlock's Nether...");
} }
if (!this.settings.isNetherIslands()) if (!this.settings.isNetherIslands())
{ {
this.netherWorld = WorldCreator.name(worldName + NETHER). this.netherWorld = WorldCreator.name(worldName + NETHER).
type(WorldType.NORMAL). type(WorldType.NORMAL).
environment(World.Environment.NETHER). environment(World.Environment.NETHER).
createWorld(); createWorld();
} }
else else
{ {
this.netherWorld = WorldCreator.name(worldName + NETHER). this.netherWorld = WorldCreator.name(worldName + NETHER).
type(WorldType.FLAT). type(WorldType.FLAT).
generator(new ChunkGeneratorWorld(this)). generator(this.chunkGenerator).
environment(World.Environment.NETHER). environment(World.Environment.NETHER).
createWorld(); createWorld();
} }
} }
// Make the end if it does not exist // Make the end if it does not exist
if (this.settings.isEndGenerate()) if (this.settings.isEndGenerate())
{ {
if (this.getServer().getWorld(worldName + THE_END) == null) if (this.getServer().getWorld(worldName + THE_END) == null)
{ {
this.log("Creating CaveBlock's End World..."); this.log("Creating CaveBlock's End World...");
} }
if (!this.settings.isEndIslands()) if (!this.settings.isEndIslands())
{ {
this.endWorld = WorldCreator.name(worldName + THE_END). this.endWorld = WorldCreator.name(worldName + THE_END).
type(WorldType.NORMAL). type(WorldType.NORMAL).
environment(World.Environment.THE_END). environment(World.Environment.THE_END).
createWorld(); createWorld();
} }
else else
{ {
this.endWorld = WorldCreator.name(worldName + THE_END). this.endWorld = WorldCreator.name(worldName + THE_END).
type(WorldType.FLAT). type(WorldType.FLAT).
generator(new ChunkGeneratorWorld(this)). generator(this.chunkGenerator).
environment(World.Environment.THE_END). environment(World.Environment.THE_END).
createWorld(); createWorld();
} }
} }
} }
/** /**
* Defines the world generator for this game mode * Defines the world generator for this game mode
* *
* @param worldName - name of world that this applies to * @param worldName - name of world that this applies to
* @param id - id if any * @param id - id if any
* @return Chunk generator * @return Chunk generator
* @since 1.2.0 * @since 1.2.0
*/ */
@Override @Override
public @NonNull ChunkGenerator getDefaultWorldGenerator(String worldName, String id) public @NonNull ChunkGenerator getDefaultWorldGenerator(String worldName, String id)
{ {
return this.chunkGenerator; return this.chunkGenerator;
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Section: Getters // Section: Getters
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
/** /**
* @return WorldSettings for this GameMode * @return WorldSettings for this GameMode
*/ */
@Override @Override
public WorldSettings getWorldSettings() public WorldSettings getWorldSettings()
{ {
return this.settings; return this.settings;
} }
/** /**
* @return Settings for this GameMode * @return Settings for this GameMode
*/ */
public Settings getSettings() public Settings getSettings()
{ {
return this.settings; return this.settings;
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Section: Variables // Section: Variables
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
/** /**
* This stores CaveBlock addon settings. * This stores CaveBlock addon settings.
*/ */
private Settings settings; private Settings settings;
/** /**
* This stores CaveBlock addon WorldGenerator. * This stores CaveBlock addon WorldGenerator.
*/ */
private ChunkGeneratorWorld chunkGenerator; private ChunkGeneratorWorld chunkGenerator;
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Section: Constants // Section: Constants
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
/** /**
* String for nether world. * String for nether world.
*/ */
private static final String NETHER = "_nether"; private static final String NETHER = "_nether";
/** /**
* String for the end world. * String for the end world.
*/ */
private static final String THE_END = "_the_end"; private static final String THE_END = "_the_end";
} }

View File

@ -1,14 +1,20 @@
package world.bentobox.caveblock.generators.populators; 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.Chunk;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.BlockPopulator;
import java.util.*;
import java.util.stream.Collectors;
import world.bentobox.bentobox.util.Pair; import world.bentobox.bentobox.util.Pair;
import world.bentobox.caveblock.CaveBlock; import world.bentobox.caveblock.CaveBlock;
@ -20,250 +26,267 @@ import world.bentobox.caveblock.Settings;
*/ */
public class EntitiesPopulator extends BlockPopulator public class EntitiesPopulator extends BlockPopulator
{ {
/**
* This is default constructor private Map<Environment, Chances> chances;
* @param addon CaveBlock addon.
*/ private final int generationTry;
public EntitiesPopulator(CaveBlock addon)
{ private int worldHeight;
this.addon = addon;
this.settings = addon.getSettings();
}
/** /**
* This method populates chunk with entities. * This is default constructor
* @param world World where population must be. * @param addon CaveBlock addon.
* @param random Randomness */
* @param chunk Chunk were populator operates. public EntitiesPopulator(CaveBlock addon)
*/ {
@Override this.addon = addon;
public void populate(World world, Random random, Chunk chunk) this.settings = addon.getSettings();
{ // Set up chances
Map<EntityType, Pair<Integer, Integer>> entityChanceMap; chances = new HashMap<>();
Material mainMaterial; // Normal
chances.put(Environment.NORMAL, new Chances(this.getEntityMap(this.settings.getNormalBlocks()), this.settings.getNormalMainBlock()));
if (world.getEnvironment().equals(World.Environment.NETHER)) // Nether
{ chances.put(Environment.NETHER, new Chances(this.getEntityMap(this.settings.getNetherBlocks()), this.settings.getNetherMainBlock()));
entityChanceMap = this.getEntityMap(this.settings.getNetherBlocks()); // End
mainMaterial = this.settings.getNetherMainBlock(); chances.put(Environment.THE_END, new Chances(this.getEntityMap(this.settings.getEndBlocks()), this.settings.getEndMainBlock()));
} // Other settings
else if (world.getEnvironment().equals(World.Environment.THE_END)) generationTry = this.settings.getNumberOfBlockGenerationTries();
{ worldHeight = this.settings.getWorldDepth() - 1;
entityChanceMap = this.getEntityMap(this.settings.getEndBlocks()); }
mainMaterial = this.settings.getEndMainBlock();
}
else
{
entityChanceMap = this.getEntityMap(this.settings.getNormalBlocks());
mainMaterial = this.settings.getNormalMainBlock();
}
final int generationTry = this.settings.getNumberOfBlockGenerationTries();
final int worldHeight = this.settings.getWorldDepth() - 1;
for (Map.Entry<EntityType, Pair<Integer, Integer>> entry : entityChanceMap.entrySet())
{
for (int subY = 0; subY < worldHeight; subY += 16)
{
for (int tries = 0; tries < generationTry; tries++)
{
if (random.nextInt(100) < entry.getValue().x)
{
int x = random.nextInt(15);
int z = random.nextInt(15);
int y = Math.min(worldHeight - 2, subY + random.nextInt(15));
this.tryToPlaceEntity(world, chunk.getBlock(x, y, z), entry.getKey(), x, z, mainMaterial);
}
}
}
}
}
/** /**
* This method returns Entity frequently and pack size map. * This method populates chunk with entities.
* @param objectList List with objects that contains data. * @param world World where population must be.
* @return Map that contains entity, its rarity and pack size. * @param random Randomness
*/ * @param chunk Chunk were populator operates.
private Map<EntityType, Pair<Integer, Integer>> getEntityMap(List<String> objectList) */
{ @Override
Map<EntityType, Pair<Integer, Integer>> entityMap = new HashMap<>(objectList.size()); public void populate(World world, Random random, Chunk chunk)
{
for (Map.Entry<EntityType, Pair<Integer, Integer>> entry : chances.get(world.getEnvironment()).entityChanceMap.entrySet())
{
for (int subY = 0; subY < worldHeight; subY += 16)
{
for (int tries = 0; tries < generationTry; tries++)
{
if (random.nextInt(100) < entry.getValue().x)
{
int x = random.nextInt(15);
int z = random.nextInt(15);
int y = Math.min(worldHeight - 2, subY + random.nextInt(15));
Map<String, EntityType> entityTypeMap = Arrays.stream(EntityType.values()). this.tryToPlaceEntity(world, chunk.getBlock(x, y, z), entry.getKey(), x, z, chances.get(world.getEnvironment()).mainMaterial);
collect(Collectors.toMap(Enum::name, }
entityType -> entityType, }
(a, b) -> b, }
() -> new HashMap<>(EntityType.values().length))); }
}
// 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);
if (entity != null)
{
entityMap.put(entity,
new Pair<>(Integer.parseInt(splitString[2]), Integer.parseInt(splitString[3])));
}
});
return entityMap;
}
/** /**
* This method checks if all chunks around given block is generated. * This method returns Entity frequently and pack size map.
* @param world World in which block is located * @param objectList List with objects that contains data.
* @param block Block that must be checked. * @return Map that contains entity, its rarity and pack size.
* @param x Block x-index in chunk */
* @param z Block z-index in chunk private Map<EntityType, Pair<Integer, Integer>> getEntityMap(List<String> objectList)
* @return true, if all chunks around given block are generated. {
*/ Map<EntityType, Pair<Integer, Integer>> entityMap = new HashMap<>(objectList.size());
private boolean isValidBlock(World world, Block block, int x, int z)
{ Map<String, EntityType> entityTypeMap = Arrays.stream(EntityType.values()).
return x > 0 && x < 15 && z > 0 && z < 15 || collect(Collectors.toMap(Enum::name,
world.isChunkGenerated(block.getX() + 1, block.getZ()) && entityType -> entityType,
world.isChunkGenerated(block.getX() - 1, block.getZ()) && (a, b) -> b,
world.isChunkGenerated(block.getX(), block.getZ() - 1) && () -> new HashMap<>(EntityType.values().length)));
world.isChunkGenerated(block.getX(), block.getZ() + 1);
} // 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);
if (entity != null)
{
entityMap.put(entity,
new Pair<>(Integer.parseInt(splitString[2]), Integer.parseInt(splitString[3])));
}
});
return entityMap;
}
/** /**
* This method is not completed. It must reserve space for entities to spawn, but * This method checks if all chunks around given block is generated.
* current implementation just allows to spawn 2 high mobs that can be in single * @param world World in which block is located
* place. * @param block Block that must be checked.
* @param world - World were mob must be spawned. * @param x Block x-index in chunk
* @param block - Block that was choosed by random. * @param z Block z-index in chunk
* @param entity - Entity that must be spawned. * @return true, if all chunks around given block are generated.
* @param x - ChunkX coordinate. */
* @param z - ChunkY coordinate. private boolean isValidBlock(World world, Block block, int x, int z)
* @param originalMaterial - replacement manterial. {
*/ return x > 0 && x < 15 && z > 0 && z < 15 ||
private void tryToPlaceEntity(World world, Block block, EntityType entity, int x, int z, Material originalMaterial) world.isChunkGenerated(block.getX() + 1, block.getZ()) &&
{ world.isChunkGenerated(block.getX() - 1, block.getZ()) &&
if (this.isValidBlock(world, block, x, z) && block.getType().equals(originalMaterial)) world.isChunkGenerated(block.getX(), block.getZ() - 1) &&
{ world.isChunkGenerated(block.getX(), block.getZ() + 1);
if (entity.isAlive()) }
{
int height = 0;
int width = 0;
int length = 0;
boolean water = false;
switch (entity)
{
case SPIDER:
width = 1;
length = 1;
break;
case SLIME:
case ELDER_GUARDIAN:
case GHAST:
case MAGMA_CUBE:
case WITHER:
height = 2;
width = 2;
length = 2;
break;
case ENDERMAN:
case IRON_GOLEM:
height = 2;
break;
case WITHER_SKELETON:
case STRAY:
case HUSK:
case ZOMBIE_VILLAGER:
case EVOKER:
case VINDICATOR:
case ILLUSIONER:
case CREEPER:
case SKELETON:
case ZOMBIE:
case BLAZE:
case SNOWMAN:
case VILLAGER:
case PIG_ZOMBIE:
case WITCH:
case SHULKER:
case SHEEP:
case COW:
case MUSHROOM_COW:
height = 12;
break;
case SKELETON_HORSE:
case ZOMBIE_HORSE:
case DONKEY:
case MULE:
case HORSE:
case POLAR_BEAR:
case LLAMA:
height = 1;
width = 1;
break;
case GUARDIAN:
case SQUID:
case COD:
case SALMON:
case PUFFERFISH:
case TROPICAL_FISH:
water = true;
break;
case DROWNED:
case DOLPHIN:
water = true;
height = 1;
break;
}
Block otherBlock = world.getBlockAt(block.getX(), block.getY() + 1, block.getZ()); /**
* This method is not completed. It must reserve space for entities to spawn, but
* current implementation just allows to spawn 2 high mobs that can be in single
* place.
* @param world - World were mob must be spawned.
* @param block - Block that was choosed by random.
* @param entity - Entity that must be spawned.
* @param x - ChunkX coordinate.
* @param z - ChunkY coordinate.
* @param originalMaterial - replacement manterial.
*/
private void tryToPlaceEntity(World world, Block block, EntityType entity, int x, int z, Material originalMaterial)
{
if (this.isValidBlock(world, block, x, z) && block.getType().equals(originalMaterial))
{
if (entity.isAlive())
{
int height = 0;
int width = 0;
int length = 0;
boolean water = false;
if (!otherBlock.getType().equals(originalMaterial)) switch (entity)
{ {
otherBlock = world.getBlockAt(block.getX(), block.getY() - 1, block.getZ()); case SPIDER:
} width = 1;
length = 1;
break;
case SLIME:
case ELDER_GUARDIAN:
case GHAST:
case MAGMA_CUBE:
case WITHER:
height = 2;
width = 2;
length = 2;
break;
case ENDERMAN:
case IRON_GOLEM:
height = 2;
break;
case WITHER_SKELETON:
case STRAY:
case HUSK:
case ZOMBIE_VILLAGER:
case EVOKER:
case VINDICATOR:
case ILLUSIONER:
case CREEPER:
case SKELETON:
case ZOMBIE:
case BLAZE:
case SNOWMAN:
case VILLAGER:
case PIG_ZOMBIE:
case WITCH:
case SHULKER:
case SHEEP:
case COW:
case MUSHROOM_COW:
height = 12;
break;
case SKELETON_HORSE:
case ZOMBIE_HORSE:
case DONKEY:
case MULE:
case HORSE:
case POLAR_BEAR:
case LLAMA:
height = 1;
width = 1;
break;
case GUARDIAN:
case SQUID:
case COD:
case SALMON:
case PUFFERFISH:
case TROPICAL_FISH:
water = true;
break;
case DROWNED:
case DOLPHIN:
water = true;
height = 1;
break;
default:
break;
}
if (otherBlock.getType().equals(originalMaterial)) Block otherBlock = world.getBlockAt(block.getX(), block.getY() + 1, block.getZ());
{
block.setType(Material.CAVE_AIR);
otherBlock.setType(Material.CAVE_AIR);
if (otherBlock.getY() < block.getY()) if (!otherBlock.getType().equals(originalMaterial))
{ {
world.spawnEntity(otherBlock.getLocation(), entity); otherBlock = world.getBlockAt(block.getX(), block.getY() - 1, block.getZ());
} }
else
{ if (otherBlock.getType().equals(originalMaterial))
world.spawnEntity(block.getLocation(), entity); {
} block.setType(Material.CAVE_AIR);
} otherBlock.setType(Material.CAVE_AIR);
}
else if (otherBlock.getY() < block.getY())
{ {
block.setType(Material.CAVE_AIR); world.spawnEntity(otherBlock.getLocation(), entity);
world.spawnEntity(block.getLocation(), entity); }
} else
} {
} world.spawnEntity(block.getLocation(), entity);
}
}
}
else
{
block.setType(Material.CAVE_AIR);
world.spawnEntity(block.getLocation(), entity);
}
}
}
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Section: Variables // Section: Variables
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
/** /**
* CaveBlock addon. * CaveBlock addon.
*/ */
private CaveBlock addon; private CaveBlock addon;
/** /**
* CaveBlock settings. * CaveBlock settings.
*/ */
private Settings settings; private Settings settings;
/**
* Chances class to store chances for environments and main material
*
*/
private class Chances {
final Map<EntityType, Pair<Integer, Integer>> entityChanceMap;
final Material mainMaterial;
/**
* @param materialChanceMap
* @param mainMaterial
*/
public Chances(Map<EntityType, Pair<Integer, Integer>> entityChanceMap, Material mainMaterial) {
this.entityChanceMap = entityChanceMap;
this.mainMaterial = mainMaterial;
}
}
} }

View File

@ -2,16 +2,18 @@
package world.bentobox.caveblock.generators.populators; package world.bentobox.caveblock.generators.populators;
import org.bukkit.Chunk;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.generator.BlockPopulator;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random; 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.bentobox.util.Pair;
import world.bentobox.caveblock.CaveBlock; import world.bentobox.caveblock.CaveBlock;
import world.bentobox.caveblock.Settings; import world.bentobox.caveblock.Settings;
@ -22,173 +24,188 @@ import world.bentobox.caveblock.Settings;
*/ */
public class MaterialPopulator extends BlockPopulator public class MaterialPopulator extends BlockPopulator
{ {
/** private Map<Environment, Chances> chances;
* This is default constructor
* @param addon CaveBlock addon. private final int generationTry;
*/
public MaterialPopulator(CaveBlock addon) private int worldHeight;
{
this.addon = addon; /**
this.settings = addon.getSettings(); * This is default constructor
} * @param addon CaveBlock addon.
*/
public MaterialPopulator(CaveBlock addon)
{
this.addon = addon;
this.settings = addon.getSettings();
// Set up chances
chances = new HashMap<>();
// Normal
chances.put(Environment.NORMAL, new Chances(this.getMaterialMap(this.settings.getNormalBlocks()), this.settings.getNormalMainBlock()));
// Nether
chances.put(Environment.NETHER, new Chances(this.getMaterialMap(this.settings.getNetherBlocks()), this.settings.getNetherMainBlock()));
// End
chances.put(Environment.THE_END, new Chances(this.getMaterialMap(this.settings.getEndBlocks()), this.settings.getEndMainBlock()));
// Other settings
generationTry = this.settings.getNumberOfBlockGenerationTries();
worldHeight = this.settings.getWorldDepth() - 1;
}
/** /**
* This method populates chunk with blocks. * This method populates chunk with blocks.
* @param world World where population must be. * @param world World where population must be.
* @param random Randomness * @param random Randomness
* @param chunk Chunk were populator operates. * @param chunk Chunk were populator operates.
*/ */
@Override @Override
public void populate(World world, Random random, Chunk chunk) public void populate(World world, Random random, Chunk chunk)
{ {
Map<Material, Pair<Integer, Integer>> materialChanceMap; for (Map.Entry<Material, Pair<Integer, Integer>> entry : chances.get(world.getEnvironment()).materialChanceMap.entrySet())
Material mainMaterial; {
for (int subY = 0; subY < worldHeight; subY += 16)
{
for (int tries = 0; tries < generationTry; tries++)
{
if (random.nextInt(100) < entry.getValue().x)
{
int x = random.nextInt(15);
int z = random.nextInt(15);
int y = Math.min(worldHeight - 2, subY + random.nextInt(15));
if (world.getEnvironment().equals(World.Environment.NETHER)) Block block = chunk.getBlock(x, y, z);
{
materialChanceMap = this.getMaterialMap(this.settings.getNetherBlocks());
mainMaterial = this.settings.getNetherMainBlock();
}
else if (world.getEnvironment().equals(World.Environment.THE_END))
{
materialChanceMap = this.getMaterialMap(this.settings.getEndBlocks());
mainMaterial = this.settings.getEndMainBlock();
}
else
{
materialChanceMap = this.getMaterialMap(this.settings.getNormalBlocks());
mainMaterial = this.settings.getNormalMainBlock();
}
final int generationTry = this.settings.getNumberOfBlockGenerationTries(); if (block.getType().equals(chances.get(world.getEnvironment()).mainMaterial) &&
final int worldHeight = this.settings.getWorldDepth() - 1; this.isValidBlock(world, block, x, z))
{
int packSize = random.nextInt(entry.getValue().z);
for (Map.Entry<Material, Pair<Integer, Integer>> entry : materialChanceMap.entrySet()) boolean continuePlacing = true;
{
for (int subY = 0; subY < worldHeight; subY += 16)
{
for (int tries = 0; tries < generationTry; tries++)
{
if (random.nextInt(100) < entry.getValue().x)
{
int x = random.nextInt(15);
int z = random.nextInt(15);
int y = Math.min(worldHeight - 2, subY + random.nextInt(15));
Block block = chunk.getBlock(x, y, z); while (continuePlacing)
{
if (!block.getType().equals(entry.getKey()))
{
block.setType(entry.getKey());
packSize--;
}
if (block.getType().equals(mainMaterial) && // The direction chooser
this.isValidBlock(world, block, x, z)) switch (random.nextInt(5))
{ {
int packSize = random.nextInt(entry.getValue().z); 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;
}
boolean continuePlacing = true; block = chunk.getBlock(x, y, z);
while (continuePlacing) continuePlacing = this.isValidBlock(world, block, x, z) &&
{ packSize > 0 &&
if (!block.getType().equals(entry.getKey())) (block.getType().equals(chances.get(world.getEnvironment()).mainMaterial) ||
{ block.getType().equals(entry.getKey()));
block.setType(entry.getKey()); }
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 = this.isValidBlock(world, block, x, z) &&
packSize > 0 &&
(block.getType().equals(mainMaterial) ||
block.getType().equals(entry.getKey()));
}
}
}
}
}
}
}
/** /**
* This method checks if all chunks around given block is generated. * This method checks if all chunks around given block is generated.
* @param world World in which block is located * @param world World in which block is located
* @param block Block that must be checked. * @param block Block that must be checked.
* @param x Block x-index in chunk * @param x Block x-index in chunk
* @param z Block z-index in chunk * @param z Block z-index in chunk
* @return true, if all chunks around given block are generated. * @return true, if all chunks around given block are generated.
*/ */
private boolean isValidBlock(World world, Block block, int x, int z) private boolean isValidBlock(World world, Block block, int x, int z)
{ {
return x > 0 && x < 15 && z > 0 && z < 15 || return x > 0 && x < 15 && z > 0 && z < 15 ||
world.isChunkGenerated(block.getX() + 1, block.getZ()) && world.isChunkGenerated(block.getX() + 1, block.getZ()) &&
world.isChunkGenerated(block.getX() - 1, block.getZ()) && world.isChunkGenerated(block.getX() - 1, block.getZ()) &&
world.isChunkGenerated(block.getX(), block.getZ() - 1) && world.isChunkGenerated(block.getX(), block.getZ() - 1) &&
world.isChunkGenerated(block.getX(), block.getZ() + 1); world.isChunkGenerated(block.getX(), block.getZ() + 1);
} }
/** /**
* This method returns material frequently and pack size map. * This method returns material frequently and pack size map.
* @param objectList List with objects that contains data. * @param objectList List with objects that contains data.
* @return Map that contains material, its rarity and pack size. * @return Map that contains material, its rarity and pack size.
*/ */
private Map<Material, Pair<Integer, Integer>> getMaterialMap(List<String> objectList) private Map<Material, Pair<Integer, Integer>> getMaterialMap(List<String> objectList)
{ {
Map<Material, Pair<Integer, Integer>> materialMap = new HashMap<>(objectList.size()); Map<Material, Pair<Integer, Integer>> materialMap = new HashMap<>(objectList.size());
// wrong material object. // wrong material object.
objectList.stream(). objectList.stream().
filter(object -> object.startsWith("MATERIAL")). filter(object -> object.startsWith("MATERIAL")).
map(object -> object.split(":")). map(object -> object.split(":")).
filter(splitString -> splitString.length == 4). filter(splitString -> splitString.length == 4).
forEach(splitString -> { forEach(splitString -> {
Material material = Material.getMaterial(splitString[1]); Material material = Material.getMaterial(splitString[1]);
if (material != null) if (material != null)
{ {
materialMap.put(material, materialMap.put(material,
new Pair<>(Integer.parseInt(splitString[2]), Integer.parseInt(splitString[3]))); new Pair<>(Integer.parseInt(splitString[2]), Integer.parseInt(splitString[3])));
} }
}); });
return materialMap; return materialMap;
} }
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
// Section: Variables // Section: Variables
// --------------------------------------------------------------------- // ---------------------------------------------------------------------
/** /**
* CaveBlock addon. * CaveBlock addon.
*/ */
private CaveBlock addon; private CaveBlock addon;
/** /**
* CaveBlock settings. * CaveBlock settings.
*/ */
private Settings settings; private Settings settings;
/**
* Chances class to store chances for environments and main material
*
*/
private class Chances {
final Map<Material, Pair<Integer, Integer>> materialChanceMap;
final Material mainMaterial;
/**
* @param materialChanceMap
* @param mainMaterial
*/
public Chances(Map<Material, Pair<Integer, Integer>> materialChanceMap, Material mainMaterial) {
this.materialChanceMap = materialChanceMap;
this.mainMaterial = mainMaterial;
}
}
} }

View File

@ -9,4 +9,228 @@ caveblock:
line1: "Welcome!" line1: "Welcome!"
line2: "[name]" line2: "[name]"
line3: "Start digging! &c<3" line3: "Start digging! &c<3"
# Override BentoBox default command strings
# General strings
general:
errors:
no-island: "&cYou do not have a cave!"
player-has-island: "&cPlayer already has a cave!"
player-has-no-island: "&cThat player has no cave!"
already-have-island: "&cYou already have a cave!"
no-safe-location: "&cNo safe location found!"
not-owner: "&cYou are not the owner of your team!"
commands:
# Override BentoBox default island command strings
island:
info:
description: "display info about your cave or the player's cave"
go:
description: "teleport you to your cave"
teleport: "&aTeleporting you to your cave."
create:
description: "create a cave, using optional schem (requires permission)"
too-many-islands: "&cThere are too many caves in this world: there isn't enough room for yours to be created."
unable-create-island: "&cYour cave could not be generated, please contact an administrator."
creating-island: "&aCreating your cave, please wait a moment..."
reset:
description: "restart your cave from scratch"
parameters: ""
must-remove-members: "&cYou must remove all team players before you can restart (/[label] team kick <player>)."
sethome:
must-be-on-your-island: "&cYou must be in your cave to set home!"
home-set: "&6Your home has been set to your current location."
setname:
description: "set a name for your cave"
resetname:
description: "reset your cave name"
team:
coop:
description: "make a player coop rank"
uncoop:
you-are-no-longer-a-coop-member: "&cYou are no longer a coop member of [name]'s cave"
all-members-logged-off: "&cAll team members logged off so you are no longer a coop member of [name]'s cave"
trust:
description: "give a player trusted rank"
invite:
description: "invite a player to join your team"
name-has-invited-you: "&a[name] has invited you to join their team."
to-accept-or-reject: "&aDo /[label] team accept to accept, or /[label] team reject to reject"
you-will-lose-your-island: "&cWARNING! You will lose your our cave if you accept!"
errors:
island-is-full: "&cYour team is full, you can't invite anyone else."
accept:
you-joined-island: "&aYou joined a team! Use /[label] team info to see the other members."
name-joined-your-island: "&a[name] joined your team!"
confirmation: |-
&cAre you sure you want to accept this invite?
&c&lThis will &nDESTORY &r&c&lyour current cave!
reject:
you-rejected-invite: "&aYou rejected the invitation to join a team."
name-rejected-your-invite: "&c[name] rejected your invite!"
cancel:
description: "cancel the pending invite to join your team"
leave:
description: "leave your team"
left-your-island: "&c[name] &cleft your team"
kick:
description: "remove a team member"
owner-kicked: "&cThe owner kicked you from the team!"
demote:
description: "demote a player one rank"
promote:
description: "promote a player one rank"
setowner:
description: "transfer team ownership to a member"
errors:
target-is-not-member: "&cThat player is not part of your team!"
name-is-the-owner: "&a[name] is now the cave owner!"
you-are-the-owner: "&aYou are now the cave owner!"
ban:
description: "ban a player from your cave"
cannot-ban-more-players: "&cYou reached the ban limit, you cannot ban any more players."
owner-banned-you: "&b[name]&c banned you from their cave!"
you-are-banned: "&bYou are banned from this cave!"
unban:
description: "unban a player from your cave"
you-are-unbanned: "&b[name]&a unbanned you from their cave!"
banlist:
noone: "&aNo one is banned on this cave"
settings:
description: "display cave settings"
# Admin commands
admin:
team:
add:
name-has-island: "&c[name] has a cave. Unregister or delete them first!"
setowner:
description: "transfers cave ownership to the player"
already-owner: "&cPlayer is already the owner of this cave!"
range:
description: "Admin cave range command"
display:
description: "Show/hide cave range indicators"
hint: |-
&cRed Barrier icons &fshow the current protected range limit.
&7Gray Particles &fshow the max limit.
&aGreen Particles &fshow the default protected range if the protection range differs from it.
set:
description: "Sets the cave protected range"
reset:
description: "Resets the protected range to the world default"
register:
parameters: "<player>"
description: "register player to unowned cave you are in"
registered-island: "&aRegistered player to cave at [xyz]."
already-owned: "&ccave is already owned by another player!"
no-island-here: "&cThere is no player cave here. Confirm to make one."
in-deletion: "&cThis space is currently being regenerated. Try later."
unregister:
description: "unregister owner from a cave, but keep cave blocks as-is"
unregistered-island: "&aUnregistered player from cave at [xyz]."
info:
parameters: "<player>"
description: "get info on where you are or on player"
no-island: "&cYou are not in a registered cave right now..."
title: "========== Cave Info ============"
owner: "Owner: [owner] ([uuid])"
last-login: "Last login: [date]"
deaths: "Deaths: [number]"
resets-left: "Resets: [number] (Max: [total])"
team-members-title: "Team members:"
team-owner-format: "&a[name] [rank]"
team-member-format: "&b[name] [rank]"
island-location: "Cave location: [xyz]"
island-coords: "Cave coordinates: [xz1] to [xz2]"
protection-range: "Protection range: [range]"
max-protection-range: "Largest historical protection range: [range]"
protection-coords: "Protection coordinates: [xz1] to [xz2]"
is-spawn: "Cave is a spawn cave"
banned-players: "Banned players:"
banned-format: "&c[name]"
unowned: "&cUnowned"
setrange:
description: "set the range of player's cave"
range-updated: "Cave range updated to [number]"
tp:
parameters: "<player>"
description: "teleport to a player's cave"
getrank:
description: "get a player's rank in their cave"
rank-is: "&aRank is [rank] in their cave."
setrank:
description: "set a player's rank in their cave"
setspawn:
description: "set a cave as spawn for this world"
already-spawn: "&cThis cave is already a spawn!"
no-island-here: "&cThere is no registered cave here."
confirmation: "&cAre you sure you want to set this cave as the spawn for this world?"
delete:
parameters: ""
description: "deletes a player and regenerates their cave"
cannot-delete-owner: "&cAll team members must be kicked before deleting."
deleted-island: "&aCave at &e[xyz] &ahas been successfully regenerated."
protection:
flags:
ELYTRA:
description: "Toggle use"
ENDERMAN_GRIEFING:
description: |-
&aEndermen can remove
&ablocks
ENTER_EXIT_MESSAGES:
description: "Display entry and exit messages"
island: "[name]'s protected cave"
name: "Enter/Exit messages"
now-entering: "&bNow entering [name]"
now-leaving: "&bNow leaving [name]"
GEO_LIMIT_MOBS:
description: |-
&aRemove mobs that go
&aoutside protected
&aplayer space
name: "&eLimit mobs to player cave"
ISLAND_RESPAWN:
description: |-
&aPlayers respawn
&ain their cave
name: "Cave respawn"
LOCK:
name: "Lock player cave"
OFFLINE_REDSTONE:
description: |-
&aWhen disabled, redstone
&awill not operate in caves
&awhere all members are offline.
&aMay help reduce lag.
PISTON_PUSH:
description: |-
&aAllow pistons to push
&ablocks outside a player's cave
PVP_OVERWORLD:
description: |-
&cEnable/Disable PVP
&cin protected cave.
REMOVE_MOBS:
description: |-
&aRemove monsters when
&ateleporting to a cave
PREVENT_TELEPORT_WHEN_FALLING:
description: |-
&aPrevent players from teleporting
&aif they are falling.
hint: "&cYou cannot teleport while you are falling!"
locked: "&cThis cave is locked!"
protected: "&ccave protected: [description]"
panel:
PROTECTION:
title: "&6Protection"
description: |-
&aProtection settings
&afor this cave
SETTING:
description: |-
&aGeneral settings
&afor this cave