diff --git a/paper-api/src/main/java/org/bukkit/RegionAccessor.java b/paper-api/src/main/java/org/bukkit/RegionAccessor.java new file mode 100644 index 0000000000..a5539309e0 --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/RegionAccessor.java @@ -0,0 +1,266 @@ +package org.bukkit; + +import java.util.Collection; +import java.util.List; +import java.util.Random; +import org.bukkit.block.Biome; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.util.Consumer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * A RegionAccessor gives access to getting, modifying and spawning {@link Biome}, {@link BlockState} and {@link Entity}, + * as well as generating some basic structures. + */ +public interface RegionAccessor { + + /** + * Gets the {@link Biome} at the given {@link Location}. + * + * @param location the location of the biome + * @return Biome at the given location + */ + @NotNull + Biome getBiome(@NotNull Location location); + + /** + * Gets the {@link Biome} at the given coordinates. + * + * @param x X-coordinate of the block + * @param y Y-coordinate of the block + * @param z Z-coordinate of the block + * @return Biome at the given coordinates + */ + @NotNull + Biome getBiome(int x, int y, int z); + + /** + * Sets the {@link Biome} at the given {@link Location}. + * + * @param location the location of the biome + * @param biome New Biome type for this block + */ + void setBiome(@NotNull Location location, @NotNull Biome biome); + + /** + * Sets the {@link Biome} for the given block coordinates + * + * @param x X-coordinate of the block + * @param y Y-coordinate of the block + * @param z Z-coordinate of the block + * @param biome New Biome type for this block + */ + void setBiome(int x, int y, int z, @NotNull Biome biome); + + /** + * Gets the {@link BlockState} at the given {@link Location}. + * + * @param location The location of the block state + * @return Block state at the given location + */ + @NotNull + BlockState getBlockState(@NotNull Location location); + + /** + * Gets the {@link BlockState} at the given coordinates. + * + * @param x X-coordinate of the block state + * @param y Y-coordinate of the block state + * @param z Z-coordinate of the block state + * @return Block state at the given coordinates + */ + @NotNull + BlockState getBlockState(int x, int y, int z); + + /** + * Gets the {@link BlockData} at the given {@link Location}. + * + * @param location The location of the block data + * @return Block data at the given location + */ + @NotNull + BlockData getBlockData(@NotNull Location location); + + /** + * Gets the {@link BlockData} at the given coordinates. + * + * @param x X-coordinate of the block data + * @param y Y-coordinate of the block data + * @param z Z-coordinate of the block data + * @return Block data at the given coordinates + */ + @NotNull + BlockData getBlockData(int x, int y, int z); + + /** + * Gets the type of the block at the given {@link Location}. + * + * @param location The location of the block + * @return Material at the given coordinates + */ + @NotNull + Material getType(@NotNull Location location); + + /** + * Gets the type of the block at the given coordinates. + * + * @param x X-coordinate of the block + * @param y Y-coordinate of the block + * @param z Z-coordinate of the block + * @return Material at the given coordinates + */ + @NotNull + Material getType(int x, int y, int z); + + /** + * Sets the {@link BlockData} at the given {@link Location}. + * + * @param location The location of the block + * @param blockData The block data to set the block to + */ + void setBlockData(@NotNull Location location, @NotNull BlockData blockData); + + /** + * Sets the {@link BlockData} at the given coordinates. + * + * @param x X-coordinate of the block + * @param y Y-coordinate of the block + * @param z Z-coordinate of the block + * @param blockData The block data to set the block to + */ + void setBlockData(int x, int y, int z, @NotNull BlockData blockData); + + /** + * Sets the {@link Material} at the given {@link Location}. + * + * @param location The location of the block + * @param material The type to set the block to + */ + void setType(@NotNull Location location, @NotNull Material material); + + /** + * Sets the {@link Material} at the given coordinates. + * + * @param x X-coordinate of the block + * @param y Y-coordinate of the block + * @param z Z-coordinate of the block + * @param material The type to set the block to + */ + void setType(int x, int y, int z, @NotNull Material material); + + /** + * Creates a tree at the given {@link Location} + * + * @param location Location to spawn the tree + * @param random Random to use to generated the tree + * @param type Type of the tree to create + * @return true if the tree was created successfully, otherwise false + */ + boolean generateTree(@NotNull Location location, @NotNull Random random, @NotNull TreeType type); + + /** + * Creates a tree at the given {@link Location} + *
+ * The provided consumer gets called for every block which gets changed + * as a result of the tree generation. When the consumer gets called no + * modifications to the world are done yet. Which means, that calling + * {@link #getBlockState(Location)} in the consumer while return the state + * of the block before the generation. + *
+ * Modifications done to the {@link BlockState} in the consumer are respected,
+ * which means that it is not necessary to call {@link BlockState#update()}
+ *
+ * @param location Location to spawn the tree
+ * @param random Random to use to generated the tree
+ * @param type Type of the tree to create
+ * @param stateConsumer The consumer which should get called for every block which gets changed
+ * @return true if the tree was created successfully, otherwise false
+ */
+ boolean generateTree(@NotNull Location location, @NotNull Random random, @NotNull TreeType type, @Nullable Consumer
@@ -1505,24 +1419,6 @@ public interface World extends PluginMessageRecipient, Metadatable {
*/
public double getHumidity(int x, int y, int z);
- /**
- * Gets the minimum height of this world.
- *
- * If the min height is 0, there are only blocks from y=0.
- *
- * @return Minimum height of the world
- */
- public int getMinHeight();
-
- /**
- * Gets the maximum height of this world.
- *
- * If the max height is 100, there are only blocks from y=0 to y=99.
- *
- * @return Maximum height of the world
- */
- public int getMaxHeight();
-
/**
* Gets the maximum height to which chorus fruits and nether portals can
* bring players within this dimension.
diff --git a/paper-api/src/main/java/org/bukkit/WorldCreator.java b/paper-api/src/main/java/org/bukkit/WorldCreator.java
index 6774c8176c..60bed20c28 100644
--- a/paper-api/src/main/java/org/bukkit/WorldCreator.java
+++ b/paper-api/src/main/java/org/bukkit/WorldCreator.java
@@ -2,6 +2,7 @@ package org.bukkit;
import java.util.Random;
import org.bukkit.command.CommandSender;
+import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
@@ -15,6 +16,7 @@ public class WorldCreator {
private long seed;
private World.Environment environment = World.Environment.NORMAL;
private ChunkGenerator generator = null;
+ private BiomeProvider biomeProvider = null;
private WorldType type = WorldType.NORMAL;
private boolean generateStructures = true;
private String generatorSettings = "";
@@ -49,6 +51,7 @@ public class WorldCreator {
seed = world.getSeed();
environment = world.getEnvironment();
generator = world.getGenerator();
+ biomeProvider = world.getBiomeProvider();
type = world.getWorldType();
generateStructures = world.canGenerateStructures();
hardcore = world.isHardcore();
@@ -71,6 +74,7 @@ public class WorldCreator {
seed = creator.seed();
environment = creator.environment();
generator = creator.generator();
+ biomeProvider = creator.biomeProvider();
type = creator.type();
generateStructures = creator.generateStructures();
generatorSettings = creator.generatorSettings();
@@ -228,6 +232,84 @@ public class WorldCreator {
return this;
}
+ /**
+ * Gets the biome provider that will be used to create or load the world.
+ *
+ * This may be null, in which case the biome provider from the {@link ChunkGenerator}
+ * will be used. If no {@link ChunkGenerator} is specific the "natural" biome provider
+ * for this environment will be used.
+ *
+ * @return Biome provider
+ */
+ @Nullable
+ public BiomeProvider biomeProvider() {
+ return biomeProvider;
+ }
+
+ /**
+ * Sets the biome provider that will be used to create or load the world.
+ *
+ * This may be null, in which case the biome provider from the
+ * {@link ChunkGenerator} will be used. If no {@link ChunkGenerator} is
+ * specific the "natural" biome provider for this environment will be used.
+ *
+ * @param biomeProvider Biome provider
+ * @return This object, for chaining
+ */
+ @NotNull
+ public WorldCreator biomeProvider(@Nullable BiomeProvider biomeProvider) {
+ this.biomeProvider = biomeProvider;
+
+ return this;
+ }
+
+ /**
+ * Sets the biome provider that will be used to create or load the world.
+ *
+ * This may be null, in which case the biome provider from the
+ * {@link ChunkGenerator} will be used. If no {@link ChunkGenerator} is
+ * specific the "natural" biome provider for this environment will be used.
+ *
+ * If the biome provider cannot be found for the given name and no
+ * {@link ChunkGenerator} is specific, the natural environment biome
+ * provider will be used instead and a warning will be printed to the
+ * specified output
+ *
+ * @param biomeProvider Name of the biome provider to use, in "plugin:id"
+ * notation
+ * @return This object, for chaining
+ */
+ @NotNull
+ public WorldCreator biomeProvider(@Nullable String biomeProvider) {
+ this.biomeProvider = getBiomeProviderForName(name, biomeProvider, Bukkit.getConsoleSender());
+
+ return this;
+ }
+
+ /**
+ * Sets the biome provider that will be used to create or load the world.
+ *
+ * This may be null, in which case the biome provider from the
+ * {@link ChunkGenerator} will be used. If no {@link ChunkGenerator} is
+ * specific the "natural" biome provider for this environment will be used.
+ *
+ * If the biome provider cannot be found for the given name and no
+ * {@link ChunkGenerator} is specific, the natural environment biome
+ * provider will be used instead and a warning will be printed to the
+ * specified output
+ *
+ * @param biomeProvider Name of the biome provider to use, in "plugin:id"
+ * notation
+ * @param output {@link CommandSender} that will receive any error messages
+ * @return This object, for chaining
+ */
+ @NotNull
+ public WorldCreator biomeProvider(@Nullable String biomeProvider, @Nullable CommandSender output) {
+ this.biomeProvider = getBiomeProviderForName(name, biomeProvider, output);
+
+ return this;
+ }
+
/**
* Sets the generator settings of the world that will be created or loaded.
*
@@ -380,4 +462,49 @@ public class WorldCreator {
return result;
}
+
+ /**
+ * Attempts to get the {@link BiomeProvider} with the given name.
+ *
+ * If the biome provider is not found, null will be returned and a message
+ * will be printed to the specified {@link CommandSender} explaining why.
+ *
+ * The name must be in the "plugin:id" notation, or optionally just
+ * "plugin", where "plugin" is the safe-name of a plugin and "id" is an
+ * optional unique identifier for the biome provider you wish to request
+ * from the plugin.
+ *
+ * @param world Name of the world this will be used for
+ * @param name Name of the biome provider to retrieve
+ * @param output Where to output if errors are present
+ * @return Resulting biome provider, or null
+ */
+ @Nullable
+ public static BiomeProvider getBiomeProviderForName(@NotNull String world, @Nullable String name, @Nullable CommandSender output) {
+ BiomeProvider result = null;
+
+ if (world == null) {
+ throw new IllegalArgumentException("World name must be specified");
+ }
+
+ if (output == null) {
+ output = Bukkit.getConsoleSender();
+ }
+
+ if (name != null) {
+ String[] split = name.split(":", 2);
+ String id = (split.length > 1) ? split[1] : null;
+ Plugin plugin = Bukkit.getPluginManager().getPlugin(split[0]);
+
+ if (plugin == null) {
+ output.sendMessage("Could not set biome provider for world '" + world + "': Plugin '" + split[0] + "' does not exist");
+ } else if (!plugin.isEnabled()) {
+ output.sendMessage("Could not set set biome provider for world '" + world + "': Plugin '" + plugin.getDescription().getFullName() + "' is not enabled");
+ } else {
+ result = plugin.getDefaultBiomeProvider(world, id);
+ }
+ }
+
+ return result;
+ }
}
diff --git a/paper-api/src/main/java/org/bukkit/generator/BiomeProvider.java b/paper-api/src/main/java/org/bukkit/generator/BiomeProvider.java
new file mode 100644
index 0000000000..9f6d75af20
--- /dev/null
+++ b/paper-api/src/main/java/org/bukkit/generator/BiomeProvider.java
@@ -0,0 +1,52 @@
+package org.bukkit.generator;
+
+import java.util.List;
+import org.bukkit.block.Biome;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Class for providing biomes.
+ */
+public abstract class BiomeProvider {
+
+ /**
+ * Return the Biome which should be present at the provided location.
+ *
+ * Notes:
+ *
+ * This method must be completely thread safe and able to handle
+ * multiple concurrent callers.
+ *
+ * This method should only return biomes which are present in the list
+ * returned by {@link #getBiomes(WorldInfo)}
+ *
+ * This method should never return {@link Biome#CUSTOM}.
+ *
+ * @param worldInfo The world info of the world the biome will be used for
+ * @param x The X-coordinate from world origin
+ * @param y The Y-coordinate from world origin
+ * @param z The Z-coordinate from world origin
+ * @return Biome for the given location
+ */
+ @NotNull
+ public abstract Biome getBiome(@NotNull WorldInfo worldInfo, int x, int y, int z);
+
+ /**
+ * Returns a list with every biome the {@link BiomeProvider} will use for
+ * the given world.
+ *
+ * Notes:
+ *
+ * This method only gets called once, when the world is loaded. Returning
+ * another list or modifying the values from the initial returned list later
+ * one, are not respected.
+ *
+ * This method should never return a list which contains
+ * {@link Biome#CUSTOM}.
+ *
+ * @param worldInfo The world info of the world the list will be used for
+ * @return A list with every biome the {@link BiomeProvider} uses
+ */
+ @NotNull
+ public abstract List
+ * Notes:
+ *
+ * This method should never attempt to get the Chunk at the passed
+ * coordinates, as doing so may cause an infinite loop
+ *
+ * This method should never modify a {@link LimitedRegion} at a later
+ * point of time.
+ *
+ * This method must be completely thread safe and able to handle
+ * multiple concurrent callers.
+ *
+ * No physics are applied, whether or not it is set to true in
+ * {@link org.bukkit.block.BlockState#update(boolean, boolean)}
+ *
+ * Only use the {@link org.bukkit.block.BlockState} returned by
+ * {@link LimitedRegion},
+ * never use methods from a {@link World} to modify the chunk.
+ *
+ * @param worldInfo The world info of the world to generate in
+ * @param random The random generator to use
+ * @param x The X-coordinate of the chunk
+ * @param z The Z-coordinate of the chunk
+ * @param limitedRegion The chunk region to populate
+ */
+ public void populate(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull LimitedRegion limitedRegion) {
+ }
}
diff --git a/paper-api/src/main/java/org/bukkit/generator/ChunkGenerator.java b/paper-api/src/main/java/org/bukkit/generator/ChunkGenerator.java
index 9d7592988a..80fcd02e9c 100644
--- a/paper-api/src/main/java/org/bukkit/generator/ChunkGenerator.java
+++ b/paper-api/src/main/java/org/bukkit/generator/ChunkGenerator.java
@@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.bukkit.Bukkit;
+import org.bukkit.HeightMap;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
@@ -19,28 +20,205 @@ import org.jetbrains.annotations.Nullable;
* chunk. For example, the nether chunk generator should shape netherrack and
* soulsand.
*
- * By default only one thread will call
- * {@link #generateChunkData(org.bukkit.World, java.util.Random, int, int, org.bukkit.generator.ChunkGenerator.BiomeGrid)}
- * at a time, although this may not necessarily be the main server thread.
+ * A chunk is generated in multiple steps, those steps are always in the same
+ * order. Between those steps however an unlimited time may pass. This means, a
+ * chunk may generated until the surface step and continue with the bedrock step
+ * after one or multiple server restarts or even after multiple Minecraft
+ * versions.
*
- * If your generator is capable of fully asynchronous generation, then
- * {@link #isParallelCapable()} should be overridden accordingly to allow
- * multiple concurrent callers.
+ * The order of generation is as follows
+ *
+ * Notes:
+ *
+ * This method should never attempt to get the Chunk at the passed
+ * coordinates, as doing so may cause an infinite loop.
+ *
+ * This method should never modify the {@link ChunkData} at a later
+ * point of time.
+ *
+ * The Y-coordinate range should never be hardcoded, to get the
+ * Y-coordinate range use the methods {@link ChunkData#getMinHeight()} and
+ * {@link ChunkData#getMaxHeight()}.
+ *
+ * If {@link #shouldGenerateNoise()} is set to true, the given
+ * {@link ChunkData} contains already the Vanilla noise generation.
+ *
+ * @param worldInfo The world info of the world this chunk will be used for
+ * @param random The random generator to use
+ * @param x The X-coordinate of the chunk
+ * @param z The Z-coordinate of the chunk
+ * @param chunkData To modify
+ */
+ public void generateNoise(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
+ }
+
+ /**
+ * Shapes the Chunk surface for the given coordinates.
+ *
+ * Notes:
+ *
+ * This method should never attempt to get the Chunk at the passed
+ * coordinates, as doing so may cause an infinite loop.
+ *
+ * This method should never modify the {@link ChunkData} at a later
+ * point of time.
+ *
+ * The Y-coordinate range should never be hardcoded, to get the
+ * Y-coordinate range use the methods {@link ChunkData#getMinHeight()} and
+ * {@link ChunkData#getMaxHeight()}.
+ *
+ * If {@link #shouldGenerateSurface()} is set to true, the given
+ * {@link ChunkData} contains already the Vanilla surface generation.
+ *
+ * @param worldInfo The world info of the world this chunk will be used for
+ * @param random The random generator to use
+ * @param x The X-coordinate of the chunk
+ * @param z The Z-coordinate of the chunk
+ * @param chunkData To modify
+ */
+ public void generateSurface(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
+ }
+
+ /**
+ * Shapes the Chunk bedrock layer for the given coordinates.
+ *
+ * Notes:
+ *
+ * This method should never attempt to get the Chunk at the passed
+ * coordinates, as doing so may cause an infinite loop.
+ *
+ * This method should never modify the {@link ChunkData} at a later
+ * point of time.
+ *
+ * The Y-coordinate range should never be hardcoded, to get the
+ * Y-coordinate range use the methods {@link ChunkData#getMinHeight()} and
+ * {@link ChunkData#getMaxHeight()}.
+ *
+ * If {@link #shouldGenerateBedrock()} is set to true, the given
+ * {@link ChunkData} contains already the Vanilla bedrock generation.
+ *
+ * @param worldInfo The world info of the world this chunk will be used for
+ * @param random The random generator to use
+ * @param x The X-coordinate of the chunk
+ * @param z The Z-coordinate of the chunk
+ * @param chunkData To modify
+ */
+ public void generateBedrock(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
+ }
+
+ /**
+ * Shapes the Chunk caves for the given coordinates.
+ *
+ * Notes:
+ *
+ * This method should never attempt to get the Chunk at the passed
+ * coordinates, as doing so may cause an infinite loop.
+ *
+ * This method should never modify the {@link ChunkData} at a later
+ * point of time.
+ *
+ * The Y-coordinate range should never be hardcoded, to get the
+ * Y-coordinate range use the methods {@link ChunkData#getMinHeight()} and
+ * {@link ChunkData#getMaxHeight()}.
+ *
+ * If {@link #shouldGenerateCaves()} is set to true, the given
+ * {@link ChunkData} contains already the Vanilla cave generation.
+ *
+ * @param worldInfo The world info of the world this chunk will be used for
+ * @param random The random generator to use
+ * @param x The X-coordinate of the chunk
+ * @param z The Z-coordinate of the chunk
+ * @param chunkData To modify
+ */
+ public void generateCaves(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull ChunkData chunkData) {
+ }
+
+ /**
+ * Gets called when no {@link BiomeProvider} is set in
+ * {@link org.bukkit.WorldCreator} or via the server configuration files. It
+ * is therefore possible that one plugin can provide the Biomes and another
+ * one the generation.
+ *
+ * Notes:
+ *
+ * If
+ * This method only gets called once when the world is loaded. Returning
+ * another {@link BiomeProvider} later one is not respected.
+ *
+ * @param worldInfo The world info of the world the biome provider will be
+ * used for
+ * @return BiomeProvider to use to fill the biomes of a chunk
+ */
+ @Nullable
+ public BiomeProvider getDefaultBiomeProvider(@NotNull WorldInfo worldInfo) {
+ return null;
+ }
+
+ /**
+ * This method is similar to
+ * {@link World#getHighestBlockAt(int, int, HeightMap)}. With the difference
+ * being, that the highest y coordinate should be the block before any
+ * surface, bedrock, caves or decoration is applied. Or in other words the
+ * highest block when only the noise is present at the chunk.
+ *
+ * Notes:
+ *
+ * When this method is not overridden, the Vanilla base height is used.
+ *
+ * This method should never attempt to get the Chunk at the passed
+ * coordinates, or use the method
+ * {@link World#getHighestBlockAt(int, int, HeightMap)}, as doing so may
+ * cause an infinite loop.
+ *
+ * @param worldInfo The world info of the world this chunk will be used for
+ * @param random The random generator to use
+ * @param x The X-coordinate from world origin
+ * @param z The Z-coordinate from world origin
+ * @param heightMap From the highest block should be get
+ * @return The y coordinate of the highest block at the given location
+ */
+ public int getBaseHeight(@NotNull WorldInfo worldInfo, @NotNull Random random, int x, int z, @NotNull HeightMap heightMap) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
/**
* Interface to biome section for chunk to be generated: initialized with
* default values for world type and seed.
*
* Custom generator is free to access and tailor values during
* generateBlockSections() or generateExtBlockSections().
+ * @deprecated Biomes are now set with {@link BiomeProvider}
*/
+ @Deprecated
public interface BiomeGrid {
/**
@@ -111,8 +289,10 @@ public abstract class ChunkGenerator {
* generator
* @return ChunkData containing the types for each block created by this
* generator
+ * @deprecated The generation is now split up
*/
@NotNull
+ @Deprecated
public ChunkData generateChunkData(@NotNull World world, @NotNull Random random, int x, int z, @NotNull BiomeGrid biome) {
throw new UnsupportedOperationException("Custom generator " + getClass().getName() + " is missing required method generateChunkData");
}
@@ -121,8 +301,10 @@ public abstract class ChunkGenerator {
* Create a ChunkData for a world.
* @param world the world the ChunkData is for
* @return a new ChunkData for world
+ * @deprecated {@link ChunkData} are now directly provided
*/
@NotNull
+ @Deprecated
protected final ChunkData createChunkData(@NotNull World world) {
return Bukkit.getServer().createChunkData(world);
}
@@ -182,14 +364,56 @@ public abstract class ChunkGenerator {
* See {@link ChunkGenerator} for more information.
*
* @return parallel capable status
+ * @deprecated the chunk generation code should be thread safe
*/
+ @Deprecated
public boolean isParallelCapable() {
return false;
}
/**
- * Gets if the server should generate Vanilla caves after this
- * ChunkGenerator.
+ * Gets if the server should generate Vanilla noise.
+ *
+ * The Vanilla noise is generated before
+ * {@link #generateNoise(WorldInfo, Random, int, int, ChunkData)} is called.
+ *
+ * @return true if the server should generate Vanilla noise
+ */
+ public boolean shouldGenerateNoise() {
+ return false;
+ }
+
+ /**
+ * Gets if the server should generate Vanilla surface.
+ *
+ * The Vanilla surface is generated before
+ * {@link #generateSurface(WorldInfo, Random, int, int, ChunkData)} is
+ * called.
+ *
+ * @return true if the server should generate Vanilla surface
+ */
+ public boolean shouldGenerateSurface() {
+ return false;
+ }
+
+ /**
+ * Gets if the server should generate Vanilla bedrock.
+ *
+ * The Vanilla bedrock is generated before
+ * {@link #generateBedrock(WorldInfo, Random, int, int, ChunkData)} is
+ * called.
+ *
+ * @return true if the server should generate Vanilla bedrock
+ */
+ public boolean shouldGenerateBedrock() {
+ return false;
+ }
+
+ /**
+ * Gets if the server should generate Vanilla caves.
+ *
+ * The Vanilla caves are generated before
+ * {@link #generateCaves(WorldInfo, Random, int, int, ChunkData)} is called.
*
* @return true if the server should generate Vanilla caves
*/
@@ -200,6 +424,9 @@ public abstract class ChunkGenerator {
/**
* Gets if the server should generate Vanilla decorations after this
* ChunkGenerator.
+ *
+ * The Vanilla decoration are generated before any
+ * {@link BlockPopulator} are called.
*
* @return true if the server should generate Vanilla decorations
*/
@@ -232,8 +459,11 @@ public abstract class ChunkGenerator {
*/
public static interface ChunkData {
/**
- * Get the minimum height for the chunk.
- *
+ * Get the minimum height for this ChunkData.
+ *
+ * It is not guaranteed that this method will return the same value as
+ * {@link World#getMinHeight()}.
+ *
* Setting blocks below this height will do nothing.
*
* @return the minimum height
@@ -241,14 +471,29 @@ public abstract class ChunkGenerator {
public int getMinHeight();
/**
- * Get the maximum height for the chunk.
- *
+ * Get the maximum height for this ChunkData.
+ *
+ * It is not guaranteed that this method will return the same value as
+ * {@link World#getMaxHeight()}.
+ *
* Setting blocks at or above this height will do nothing.
*
* @return the maximum height
*/
public int getMaxHeight();
+ /**
+ * Get the biome at x, y, z within chunk being generated
+ *
+ * @param x the x location in the chunk from 0-15 inclusive
+ * @param y the y location in the chunk from minimum (inclusive) -
+ * maxHeight (exclusive)
+ * @param z the z location in the chunk from 0-15 inclusive
+ * @return Biome value
+ */
+ @NotNull
+ public Biome getBiome(int x, int y, int z);
+
/**
* Set the block at x,y,z in the chunk data to material.
*
diff --git a/paper-api/src/main/java/org/bukkit/generator/LimitedRegion.java b/paper-api/src/main/java/org/bukkit/generator/LimitedRegion.java
new file mode 100644
index 0000000000..0428f21086
--- /dev/null
+++ b/paper-api/src/main/java/org/bukkit/generator/LimitedRegion.java
@@ -0,0 +1,45 @@
+package org.bukkit.generator;
+
+import org.bukkit.Location;
+import org.bukkit.RegionAccessor;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * A limited region is used in world generation for features which are
+ * going over a chunk. For example, trees or ores.
+ *
+ * Use {@link #getBuffer()} to know how much you can go beyond the central
+ * chunk. The buffer zone may or may not be already populated.
+ *
+ * The coordinates are absolute from the world origin.
+ */
+public interface LimitedRegion extends RegionAccessor {
+
+ /**
+ * Gets the buffer around the central chunk which is accessible.
+ * The returned value is in normal world coordinate scale.
+ *
+ * For example: If the method returns 16 you have a working area of 48x48.
+ *
+ * @return The buffer in X and Z direction
+ */
+ int getBuffer();
+
+ /**
+ * Checks if the given {@link Location} is in the region.
+ *
+ * @param location the location to check
+ * @return true if the location is in the region, otherwise false.
+ */
+ boolean isInRegion(@NotNull Location location);
+
+ /**
+ * Checks if the given coordinates are in the region.
+ *
+ * @param x X-coordinate to check
+ * @param y Y-coordinate to check
+ * @param z Z-coordinate to check
+ * @return true if the coordinates are in the region, otherwise false.
+ */
+ boolean isInRegion(int x, int y, int z);
+}
diff --git a/paper-api/src/main/java/org/bukkit/generator/WorldInfo.java b/paper-api/src/main/java/org/bukkit/generator/WorldInfo.java
new file mode 100644
index 0000000000..5bf00f46e8
--- /dev/null
+++ b/paper-api/src/main/java/org/bukkit/generator/WorldInfo.java
@@ -0,0 +1,60 @@
+package org.bukkit.generator;
+
+import java.util.UUID;
+import org.bukkit.World;
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * Holds various information of a World
+ */
+public interface WorldInfo {
+
+ /**
+ * Gets the unique name of this world
+ *
+ * @return Name of this world
+ */
+ @NotNull
+ String getName();
+
+ /**
+ * Gets the Unique ID of this world
+ *
+ * @return Unique ID of this world.
+ */
+ @NotNull
+ UUID getUID();
+
+ /**
+ * Gets the {@link World.Environment} type of this world
+ *
+ * @return This worlds Environment type
+ */
+ @NotNull
+ World.Environment getEnvironment();
+
+ /**
+ * Gets the Seed for this world.
+ *
+ * @return This worlds Seed
+ */
+ long getSeed();
+
+ /**
+ * Gets the minimum height of this world.
+ *
+ * If the min height is 0, there are only blocks from y=0.
+ *
+ * @return Minimum height of the world
+ */
+ int getMinHeight();
+
+ /**
+ * Gets the maximum height of this world.
+ *
+ * If the max height is 100, there are only blocks from y=0 to y=99.
+ *
+ * @return Maximum height of the world
+ */
+ int getMaxHeight();
+}
diff --git a/paper-api/src/main/java/org/bukkit/plugin/Plugin.java b/paper-api/src/main/java/org/bukkit/plugin/Plugin.java
index febfec6efa..03ca87a1cb 100644
--- a/paper-api/src/main/java/org/bukkit/plugin/Plugin.java
+++ b/paper-api/src/main/java/org/bukkit/plugin/Plugin.java
@@ -6,6 +6,7 @@ import java.util.logging.Logger;
import org.bukkit.Server;
import org.bukkit.command.TabExecutor;
import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -156,6 +157,18 @@ public interface Plugin extends TabExecutor {
@Nullable
public ChunkGenerator getDefaultWorldGenerator(@NotNull String worldName, @Nullable String id);
+ /**
+ * Gets a {@link BiomeProvider} for use in a default world, as specified
+ * in the server configuration
+ *
+ * @param worldName Name of the world that this will be applied to
+ * @param id Unique ID, if any, that was specified to indicate which
+ * biome provider was requested
+ * @return BiomeProvider for use in the default world generation
+ */
+ @Nullable
+ public BiomeProvider getDefaultBiomeProvider(@NotNull String worldName, @Nullable String id);
+
/**
* Returns the plugin logger associated with this server's logger. The
* returned logger automatically tags all log messages with the plugin's
diff --git a/paper-api/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/paper-api/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
index 2231900549..50a4794889 100644
--- a/paper-api/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
+++ b/paper-api/src/main/java/org/bukkit/plugin/java/JavaPlugin.java
@@ -20,6 +20,7 @@ import org.bukkit.command.CommandSender;
import org.bukkit.command.PluginCommand;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator;
import org.bukkit.plugin.PluginBase;
import org.bukkit.plugin.PluginDescriptionFile;
@@ -335,6 +336,12 @@ public abstract class JavaPlugin extends PluginBase {
return null;
}
+ @Nullable
+ @Override
+ public BiomeProvider getDefaultBiomeProvider(@NotNull String worldName, @Nullable String id) {
+ return null;
+ }
+
@Override
public final boolean isNaggable() {
return naggable;
diff --git a/paper-api/src/test/java/org/bukkit/plugin/TestPlugin.java b/paper-api/src/test/java/org/bukkit/plugin/TestPlugin.java
index 6d45089718..a8be3e23e3 100644
--- a/paper-api/src/test/java/org/bukkit/plugin/TestPlugin.java
+++ b/paper-api/src/test/java/org/bukkit/plugin/TestPlugin.java
@@ -7,6 +7,7 @@ import org.bukkit.Server;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.ChunkGenerator;
public class TestPlugin extends PluginBase {
@@ -112,6 +113,11 @@ public class TestPlugin extends PluginBase {
throw new UnsupportedOperationException("Not supported.");
}
+ @Override
+ public BiomeProvider getDefaultBiomeProvider(String worldName, String id) {
+ throw new UnsupportedOperationException("Not supported.");
+ }
+
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
throw new UnsupportedOperationException("Not supported.");
+ * Note that when the function is run, the entity will not be actually in
+ * the world. Any operation involving such as teleporting the entity is undefined
+ * until after this function returns.
+ *
+ * @param location the {@link Location} to spawn the entity at
+ * @param clazz the class of the {@link Entity} to spawn
+ * @param function the function to be run before the entity is spawned.
+ * @param
- * Note that when the function is run, the entity will not be actually in
- * the world. Any operation involving such as teleporting the entity is undefined
- * until after this function returns.
- *
- * @param location the {@link Location} to spawn the entity at
- * @param clazz the class of the {@link Entity} to spawn
- * @param function the function to be run before the entity is spawned.
- * @param
+ *
+ *
+ * Every method listed above as well as
+ * {@link #getBaseHeight(WorldInfo, Random, int, int, HeightMap)}
+ * must be completely thread safe and able to handle multiple concurrent
+ * callers.
*
* Some aspects of world generation can be delegated to the Vanilla generator.
- * The methods {@link ChunkGenerator#shouldGenerateCaves()}, {@link ChunkGenerator#shouldGenerateDecorations()},
- * {@link ChunkGenerator#shouldGenerateMobs()} and {@link ChunkGenerator#shouldGenerateStructures()} can be
- * overridden to enable this.
+ * The following methods can be overridden to enable this:
+ *
+ *
*/
public abstract class ChunkGenerator {
+ /**
+ * Shapes the Chunk noise for the given coordinates.
+ * null
is returned, than Vanilla biomes are used.
+ *