From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: dfsek Date: Sat, 19 Jun 2021 20:15:29 -0700 Subject: [PATCH] Add more LimitedRegion API diff --git a/src/main/java/io/papermc/paper/world/generation/ProtoWorld.java b/src/main/java/io/papermc/paper/world/generation/ProtoWorld.java new file mode 100644 index 0000000000000000000000000000000000000000..edf8d0ae398f123ab25cb7954df07f6020454dd4 --- /dev/null +++ b/src/main/java/io/papermc/paper/world/generation/ProtoWorld.java @@ -0,0 +1,319 @@ +package io.papermc.paper.world.generation; + +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.BlockData; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.bukkit.generator.LimitedRegion; +import org.bukkit.generator.WorldInfo; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Random; +import java.util.function.Consumer; + +/** + * Represents a small grid of chunks in a {@link World} + * with rudimentary block and entity access, for use during world generation. + *

+ * A ProtoWorld is guaranteed read/write access to a 3x3 grid of chunks, + * but may have access to a grid as large as 17x17. It is safest to assume + * that there is only read/write access to 3x3 chunks. Some chunks outside + * of the 3x3 area may be readable but not writable. + *

+ * ProtoWorlds should not be stored! After they are used during + * chunk generation they should be disposed of. + * + * @see org.bukkit.generator.BlockPopulator#populate(WorldInfo, Random, int, int, LimitedRegion) + * @deprecated see {@link org.bukkit.RegionAccessor} and {@link org.bukkit.generator.LimitedRegion} + */ +@Deprecated(forRemoval = true) +public interface ProtoWorld { + /** + * Sets the block at (x, y, z) to the provided {@link BlockData}. + * + * @param x X coordinate in this ProtoWorld + * @param y Y coordinate in this ProtoWorld + * @param z Z coordinate in this ProtoWorld + * @param data {@link BlockData} to set the block at the provided coordinates to. + */ + void setBlockData(int x, int y, int z, @NotNull BlockData data); + + /** + * Sets the block at a vector location to the provided {@link BlockData}. + * + * @param vector {@link Vector} representing the position of the block to set. + * @param data {@link BlockData} to set the block at the provided coordinates to. + */ + default void setBlockData(@NotNull Vector vector, @NotNull BlockData data) { + setBlockData(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ(), data); + } + + /** + * Sets the {@link BlockState} at a location. + * + * @param x X coordinate. + * @param y Y coordinate. + * @param z Z coordinate. + * @param state The block state. + */ + void setBlockState(int x, int y, int z, @NotNull BlockState state); + + /** + * Sets the {@link BlockState} at a location. + * + * @param location Location to set block state. + * @param state The block state. + */ + default void setBlockState(@NotNull Vector location, @NotNull BlockState state) { + setBlockState(location.getBlockX(), location.getBlockY(), location.getBlockZ(), state); + } + + /** + * Gets the {@link BlockState} at a location. + * + * @param x X coordinate. + * @param y Y coordinate. + * @param z Z coordinate. + * @return The block state. + */ + @NotNull + BlockState getBlockState(int x, int y, int z); + + /** + * Gets the {@link BlockState} at a location. + * + * @param location Location to get block state from. + * @return The block state. + */ + @NotNull + default BlockState getBlockState(@NotNull Vector location) { + return getBlockState(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + /** + * Schedule a block update at (x, y, z). + * + * @param x X coordinate in this ProtoWorld + * @param y Y coordinate in this ProtoWorld + * @param z Z coordinate in this ProtoWorld + */ + void scheduleBlockUpdate(int x, int y, int z); + + /** + * Schedule a block update at a vector location + * + * @param location {@link Vector} representing the position of the block to update. + */ + default void scheduleBlockUpdate(@NotNull Vector location) { + scheduleBlockUpdate(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + /** + * Schedule a fluid update at (x, y, z). + * + * @param x X coordinate in this ProtoWorld + * @param y Y coordinate in this ProtoWorld + * @param z Z coordinate in this ProtoWorld + */ + void scheduleFluidUpdate(int x, int y, int z); + + /** + * Schedule a fluid update at a vector location + * + * @param location {@link Vector} representing the position of the block to update. + */ + default void scheduleFluidUpdate(@NotNull Vector location) { + scheduleFluidUpdate(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + /** + * Get the {@link World} object this ProtoWorld represents. + *

+ * Do not attempt to read from/write to this world! Doing so during generation will cause a deadlock! + * + * @return The {@link World} object that this ProtoWorld represents. + */ + @NotNull + World getWorld(); + + + /** + * Get the {@link BlockData} of the block at the provided coordinates. + * + * @param x X coordinate in this ProtoWorld + * @param y Y coordinate in this ProtoWorld + * @param z Z coordinate in this ProtoWorld + * @return {@link BlockData} at the coordinates + */ + @NotNull + BlockData getBlockData(int x, int y, int z); + + /** + * Get the {@link BlockData} of the block at the provided coordinates. + * + * @param vector {@link Vector} representing the position of the block to get. + * @return {@link BlockData} at the coordinates + */ + @NotNull + default BlockData getBlockData(@NotNull Vector vector) { + return getBlockData(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); + } + + /** + * Get the X-coordinate of the chunk in the center of this ProtoWorld + * + * @return The center chunk's X coordinate. + */ + int getCenterChunkX(); + + /** + * Get the X-coordinate of the block in the center of this {@link ProtoWorld} + * + * @return The center chunk's X coordinate. + */ + default int getCenterBlockX() { + return getCenterChunkX() << 4; + } + + /** + * Get the Z-coordinate of the chunk in the center of this {@link ProtoWorld} + * + * @return The center chunk's Z coordinate. + */ + int getCenterChunkZ(); + + /** + * Get the Z-coordinate of the block in the center of this {@link ProtoWorld} + * + * @return The center chunk's Z coordinate. + */ + default int getCenterBlockZ() { + return getCenterChunkZ() << 4; + } + + /** + * Creates an entity at the location represented by the given {@link Vector} + * + * @param loc The {@link Vector} representing the location to spawn the entity + * @param type The entity to spawn + * @return Resulting Entity of this method + */ + @NotNull + default Entity spawnEntity(@NotNull Vector loc, @NotNull EntityType type) { + return spawn(loc, type.getEntityClass(), CreatureSpawnEvent.SpawnReason.DEFAULT); + } + + /** + * Spawn an entity of a specific class at location represented by the given {@link Vector} + * + * @param location The {@link Vector} representing the location to spawn the entity at + * @param clazz The class of the {@link Entity} to spawn + * @param The class of the {@link Entity} to spawn + * @return An instance of the spawned {@link Entity} + * @throws IllegalArgumentException if either parameter is null or the + * {@link Entity} requested cannot be spawned + */ + @NotNull + default T spawn(@NotNull Vector location, @NotNull Class clazz) throws IllegalArgumentException { + return spawn(location, clazz, CreatureSpawnEvent.SpawnReason.DEFAULT, null); + } + + /** + * Spawn an entity of a specific class at location represented by the given {@link Vector} + * + * @param location The {@link Vector} representing the location to spawn the entity at + * @param clazz The class of the {@link Entity} to spawn + * @param The class of the {@link Entity} to spawn + * @param reason The reason for the entity's spawn. + * @return An instance of the spawned {@link Entity} + * @throws IllegalArgumentException if either parameter is null or the + * {@link Entity} requested cannot be spawned + */ + @NotNull + default T spawn(@NotNull Vector location, @NotNull Class clazz, @NotNull CreatureSpawnEvent.SpawnReason reason) throws IllegalArgumentException { + return spawn(location, clazz, reason, null); + } + + /** + * Spawn an entity of a specific class at the location represented by the given {@link Vector}, with + * the supplied function run before the entity is added to the world. + *
+ * 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 Vector} representing the 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 The class of the {@link Entity} to spawn + * @return An instance of the spawned {@link Entity} + * @throws IllegalArgumentException if either parameter is null or the + * {@link Entity} requested cannot be spawned + */ + @NotNull + default T spawn(@NotNull Vector location, @NotNull Class clazz, @Nullable Consumer function) throws IllegalArgumentException { + return spawn(location, clazz, CreatureSpawnEvent.SpawnReason.CUSTOM, function); + } + + /** + * Spawn an entity of a specific class at the location represented by the given {@link Vector}, with + * the supplied function run before the entity is added to the world. + *
+ * 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 Vector} representing the location to spawn the entity at + * @param clazz The class of the {@link Entity} to spawn + * @param reason The reason for the entity's spawn. + * @param function The function to be run before the entity is spawned. + * @param The class of the {@link Entity} to spawn + * @return An instance of the spawned {@link Entity} + * @throws IllegalArgumentException if either parameter is null or the + * {@link Entity} requested cannot be spawned + */ + @NotNull + default T spawn(@NotNull Vector location, @NotNull Class clazz, @NotNull CreatureSpawnEvent.SpawnReason reason, @Nullable Consumer function) throws IllegalArgumentException { + return spawn(location, clazz, function, reason); + } + + /** + * Creates an entity at the location represented by the given {@link Vector} + * + * @param loc The {@link Vector} representing the location to spawn the entity + * @param type The entity to spawn + * @param reason The reason for the entity's spawn. + * @return Resulting Entity of this method + */ + @SuppressWarnings("unchecked") + @NotNull + default Entity spawnEntity(@NotNull Vector loc, @NotNull EntityType type, @NotNull CreatureSpawnEvent.SpawnReason reason) { + return spawn(loc, (Class) type.getEntityClass(), reason, null); + } + + /** + * Creates an entity at the location represented by the given {@link Vector}, with + * the supplied function run before the entity is added to the world. + *
+ * 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 loc The {@link Vector} representing the location to spawn the entity + * @param type The entity to spawn + * @param reason The reason for the entity's spawn. + * @param function The function to be run before the entity is spawned. + * @return Resulting Entity of this method + */ + @SuppressWarnings("unchecked") + @NotNull + default Entity spawnEntity(@NotNull Vector loc, @NotNull EntityType type, @NotNull CreatureSpawnEvent.SpawnReason reason, @Nullable Consumer function) { + return spawn(loc, (Class) type.getEntityClass(), reason, function); + } + + @NotNull T spawn(@NotNull Vector location, @NotNull Class clazz, @Nullable Consumer function, @NotNull CreatureSpawnEvent.SpawnReason reason) throws IllegalArgumentException; +} diff --git a/src/main/java/org/bukkit/generator/ChunkGenerator.java b/src/main/java/org/bukkit/generator/ChunkGenerator.java index 0667315e2bd10254aef59c2a6bcceee9d927b6d5..e96d8877f73de12a56a2b36e32381a0b48bce297 100644 --- a/src/main/java/org/bukkit/generator/ChunkGenerator.java +++ b/src/main/java/org/bukkit/generator/ChunkGenerator.java @@ -343,6 +343,20 @@ public abstract class ChunkGenerator { return new ArrayList(); } + + // Paper start + /** + * Generate decorations in a chunk, with quick access to its neighbors. + * + * @param world ProtoWorld to generate decorations with. + * @deprecated use and override {@link BlockPopulator#populate(WorldInfo, Random, int, int, LimitedRegion)} + */ + @Deprecated(forRemoval = true) + public void generateDecorations(@NotNull io.papermc.paper.world.generation.ProtoWorld world) { + // Do nothing by default to maintain compatibility with existing generators. + } + // Paper end + /** * Gets a fixed spawn location to use for a given world. *

diff --git a/src/main/java/org/bukkit/generator/LimitedRegion.java b/src/main/java/org/bukkit/generator/LimitedRegion.java index 85faeeeef908243aa5f172284784e7e67995ebfb..e0b249d328f7671894cea94bc00d54ab54aacd36 100644 --- a/src/main/java/org/bukkit/generator/LimitedRegion.java +++ b/src/main/java/org/bukkit/generator/LimitedRegion.java @@ -4,6 +4,12 @@ import java.util.List; import org.bukkit.Location; import org.bukkit.RegionAccessor; import org.bukkit.block.BlockState; +// Paper start +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.BlockData; +import org.bukkit.util.Vector; +// Paper end import org.jetbrains.annotations.NotNull; /** @@ -53,4 +59,137 @@ public interface LimitedRegion extends RegionAccessor { */ @NotNull List getTileEntities(); + + + // Paper start + /** + * Sets the block at a vector location to the provided {@link BlockData}. + * + * @param vector {@link Vector} representing the position of the block to set. + * @param data {@link BlockData} to set the block at the provided coordinates to. + */ + default void setBlockData(@NotNull Vector vector, @NotNull BlockData data) { + setBlockData(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ(), data); + } + + /** + * Sets the {@link BlockState} at a location. + * + * @param x X coordinate. + * @param y Y coordinate. + * @param z Z coordinate. + * @param state The block state. + */ + void setBlockState(int x, int y, int z, @NotNull BlockState state); + + /** + * Sets the {@link BlockState} at a location. + * + * @param location Location to set block state. + * @param state The block state. + */ + default void setBlockState(@NotNull Vector location, @NotNull BlockState state) { + setBlockState(location.getBlockX(), location.getBlockY(), location.getBlockZ(), state); + } + + /** + * Gets the {@link BlockState} at a location. + * + * @param location Location to get block state from. + * @return The block state. + */ + @NotNull + default BlockState getBlockState(@NotNull Vector location) { + return getBlockState(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + /** + * Schedules a block update at (x, y, z). + * + * @param x X coordinate + * @param y Y coordinate + * @param z Z coordinate + */ + void scheduleBlockUpdate(int x, int y, int z); + + /** + * Schedules a block update at a vector location. + * + * @param location {@link Vector} representing the position of the block to update. + */ + default void scheduleBlockUpdate(@NotNull Vector location) { + scheduleBlockUpdate(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + /** + * Schedules a fluid update at (x, y, z). + * + * @param x X coordinate + * @param y Y coordinate + * @param z Z coordinate + */ + void scheduleFluidUpdate(int x, int y, int z); + + /** + * Schedules a fluid update at a vector location. + * + * @param location {@link Vector} representing the position of the block to update. + */ + default void scheduleFluidUpdate(@NotNull Vector location) { + scheduleFluidUpdate(location.getBlockX(), location.getBlockY(), location.getBlockZ()); + } + + /** + * Gets the {@link World} object this region represents. + *

+ * Do not attempt to read from/write to this world! Doing so during generation will cause a deadlock! + * + * @return The {@link World} object that this region represents. + */ + @NotNull + World getWorld(); + + /** + * Gets the {@link BlockData} of the block at the provided coordinates. + * + * @param vector {@link Vector} representing the position of the block to get. + * @return {@link BlockData} at the coordinates + */ + @NotNull + default BlockData getBlockData(@NotNull Vector vector) { + return getBlockData(vector.getBlockX(), vector.getBlockY(), vector.getBlockZ()); + } + + /** + * Gets the X-coordinate of the chunk in the center of the region. + * + * @return The center chunk's X coordinate. + */ + int getCenterChunkX(); + + /** + * Gets the X-coordinate of the block in the center of the region. + * + * @return The center chunk's X coordinate. + */ + default int getCenterBlockX() { + return getCenterChunkX() << 4; + } + + /** + * Gets the Z-coordinate of the chunk in the center of the region. + * + * @return The center chunk's Z coordinate. + */ + int getCenterChunkZ(); + + /** + * Gets the Z-coordinate of the block in the center of the region. + * + * @return The center chunk's Z coordinate. + */ + default int getCenterBlockZ() { + return getCenterChunkZ() << 4; + } + // Paper end }