From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: dfsek Date: Sat, 19 Jun 2021 20:15:29 -0700 Subject: [PATCH] Add Feature Stage 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..63de080e945dfa0e63e6f3c63e498f20481dab27 --- /dev/null +++ b/src/main/java/io/papermc/paper/world/generation/ProtoWorld.java @@ -0,0 +1,270 @@ +package io.papermc.paper.world.generation; + +import org.bukkit.World; +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.util.Vector; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +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. + */ +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); + } + + /** + * 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 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 ProtoWorld + * + * @return The center chunk's Z coordinate. + */ + int getCenterChunkZ(); + + /** + * Get the Z-coordinate of the block in the center of this ProtoWorld + * + * @return The center chunk's Z coordinate. + */ + default int getCenterBlockZ() { + return getCenterChunkZ() << 4; + } + + /** + * Creates a 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 a 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 a 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 244a8a93c35d5a84e17672ff745051587bca384c..e547f324790ca27dfb85b030988fc03bfc6107f1 100644 --- a/src/main/java/org/bukkit/generator/ChunkGenerator.java +++ b/src/main/java/org/bukkit/generator/ChunkGenerator.java @@ -161,6 +161,19 @@ 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. + */ + @SuppressWarnings("unused") + 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. *