mirror of
https://github.com/PaperMC/Paper.git
synced 2025-08-13 03:05:52 -07:00
SPIGOT-7283, SPIGOT-7318: Add AsyncStructureGenerateEvent and BlockState cloning
By: Lauriichan <laura.endress@playuniverse.org>
This commit is contained in:
@@ -7,6 +7,7 @@ import org.bukkit.World;
|
|||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
import org.bukkit.material.MaterialData;
|
import org.bukkit.material.MaterialData;
|
||||||
import org.bukkit.metadata.Metadatable;
|
import org.bukkit.metadata.Metadatable;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
@@ -47,6 +48,15 @@ public interface BlockState extends Metadatable {
|
|||||||
@NotNull
|
@NotNull
|
||||||
BlockData getBlockData();
|
BlockData getBlockData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a copy of this BlockState as an unplaced BlockState.
|
||||||
|
*
|
||||||
|
* @return a copy of the block state
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
BlockState copy();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the type of this block state.
|
* Gets the type of this block state.
|
||||||
*
|
*
|
||||||
|
@@ -0,0 +1,229 @@
|
|||||||
|
package org.bukkit.event.world;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.bukkit.NamespacedKey;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.bukkit.generator.structure.Structure;
|
||||||
|
import org.bukkit.util.BlockTransformer;
|
||||||
|
import org.bukkit.util.BoundingBox;
|
||||||
|
import org.bukkit.util.EntityTransformer;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This event will sometimes fire synchronously, depending on how it was
|
||||||
|
* triggered.
|
||||||
|
* <p>
|
||||||
|
* The constructor provides a boolean to indicate if the event was fired
|
||||||
|
* synchronously or asynchronously. When asynchronous, this event can be called
|
||||||
|
* from any thread, sans the main thread, and has limited access to the API.
|
||||||
|
* <p>
|
||||||
|
* If a {@link Structure} is naturally placed in a chunk of the world, this
|
||||||
|
* event will be asynchronous. If a player executes the '/place structure'
|
||||||
|
* command, this event will be synchronous.
|
||||||
|
*
|
||||||
|
* Allows to register transformers that can modify the blocks placed and
|
||||||
|
* entities spawned by the structure.
|
||||||
|
* <p>
|
||||||
|
* Care should be taken to check {@link #isAsynchronous()} and treat the event
|
||||||
|
* appropriately.
|
||||||
|
* <p>
|
||||||
|
*/
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
public class AsyncStructureGenerateEvent extends WorldEvent {
|
||||||
|
|
||||||
|
public static enum Cause {
|
||||||
|
COMMAND,
|
||||||
|
WORLD_GENERATION,
|
||||||
|
CUSTOM;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
|
||||||
|
private final Cause cause;
|
||||||
|
|
||||||
|
private final Structure structure;
|
||||||
|
private final BoundingBox boundingBox;
|
||||||
|
|
||||||
|
private final int chunkX, chunkZ;
|
||||||
|
|
||||||
|
private final Map<NamespacedKey, BlockTransformer> blockTransformers = new LinkedHashMap<>();
|
||||||
|
private final Map<NamespacedKey, EntityTransformer> entityTransformers = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
public AsyncStructureGenerateEvent(@NotNull World world, boolean async, @NotNull Cause cause, @NotNull Structure structure, @NotNull BoundingBox boundingBox, int chunkX, int chunkZ) {
|
||||||
|
super(world, async);
|
||||||
|
this.structure = structure;
|
||||||
|
this.boundingBox = boundingBox;
|
||||||
|
this.chunkX = chunkX;
|
||||||
|
this.chunkZ = chunkZ;
|
||||||
|
this.cause = cause;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the event cause.
|
||||||
|
*
|
||||||
|
* @return the event cause
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public Cause getCause() {
|
||||||
|
return cause;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a block transformer by key.
|
||||||
|
*
|
||||||
|
* @param key the key of the block transformer
|
||||||
|
*
|
||||||
|
* @return the block transformer or null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public BlockTransformer getBlockTransformer(@NotNull NamespacedKey key) {
|
||||||
|
Preconditions.checkNotNull(key, "NamespacedKey cannot be null");
|
||||||
|
return blockTransformers.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a block transformer to a key.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param transformer the block transformer
|
||||||
|
*/
|
||||||
|
public void setBlockTransformer(@NotNull NamespacedKey key, @NotNull BlockTransformer transformer) {
|
||||||
|
Preconditions.checkNotNull(key, "NamespacedKey cannot be null");
|
||||||
|
Preconditions.checkNotNull(transformer, "BlockTransformer cannot be null");
|
||||||
|
blockTransformers.put(key, transformer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a block transformer.
|
||||||
|
*
|
||||||
|
* @param key the key of the block transformer
|
||||||
|
*/
|
||||||
|
public void removeBlockTransformer(@NotNull NamespacedKey key) {
|
||||||
|
Preconditions.checkNotNull(key, "NamespacedKey cannot be null");
|
||||||
|
blockTransformers.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all block transformers.
|
||||||
|
*/
|
||||||
|
public void clearBlockTransformers() {
|
||||||
|
blockTransformers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all block transformers in a unmodifiable map.
|
||||||
|
*
|
||||||
|
* @return the block transformers in a map
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public Map<NamespacedKey, BlockTransformer> getBlockTransformers() {
|
||||||
|
return Collections.unmodifiableMap(blockTransformers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a entity transformer by key.
|
||||||
|
*
|
||||||
|
* @param key the key of the entity transformer
|
||||||
|
*
|
||||||
|
* @return the entity transformer or null
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public EntityTransformer getEntityTransformer(@NotNull NamespacedKey key) {
|
||||||
|
Preconditions.checkNotNull(key, "NamespacedKey cannot be null");
|
||||||
|
return entityTransformers.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a entity transformer to a key.
|
||||||
|
*
|
||||||
|
* @param key the key
|
||||||
|
* @param transformer the entity transformer
|
||||||
|
*/
|
||||||
|
public void setEntityTransformer(@NotNull NamespacedKey key, @NotNull EntityTransformer transformer) {
|
||||||
|
Preconditions.checkNotNull(key, "NamespacedKey cannot be null");
|
||||||
|
Preconditions.checkNotNull(transformer, "EntityTransformer cannot be null");
|
||||||
|
entityTransformers.put(key, transformer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a entity transformer.
|
||||||
|
*
|
||||||
|
* @param key the key of the entity transformer
|
||||||
|
*/
|
||||||
|
public void removeEntityTransformer(@NotNull NamespacedKey key) {
|
||||||
|
Preconditions.checkNotNull(key, "NamespacedKey cannot be null");
|
||||||
|
entityTransformers.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all entity transformers.
|
||||||
|
*/
|
||||||
|
public void clearEntityTransformers() {
|
||||||
|
entityTransformers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all entity transformers in a unmodifiable map.
|
||||||
|
*
|
||||||
|
* @return the entity transformers in a map
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public Map<NamespacedKey, EntityTransformer> getEntityTransformers() {
|
||||||
|
return Collections.unmodifiableMap(entityTransformers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the structure reference that is generated.
|
||||||
|
*
|
||||||
|
* @return the structure
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public Structure getStructure() {
|
||||||
|
return structure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the bounding box of the structure.
|
||||||
|
*
|
||||||
|
* @return the bounding box
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public BoundingBox getBoundingBox() {
|
||||||
|
return boundingBox.clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the x coordinate of the origin chunk of the structure.
|
||||||
|
*
|
||||||
|
* @return the chunk x coordinate
|
||||||
|
*/
|
||||||
|
public int getChunkX() {
|
||||||
|
return chunkX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the z coordinate of the origin chunk of the structure.
|
||||||
|
*
|
||||||
|
* @return the chunk z coordinate
|
||||||
|
*/
|
||||||
|
public int getChunkZ() {
|
||||||
|
return chunkZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,62 @@
|
|||||||
|
package org.bukkit.util;
|
||||||
|
|
||||||
|
import org.bukkit.block.BlockState;
|
||||||
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.generator.LimitedRegion;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A BlockTransformer is used to modify blocks that are placed by structure.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
public interface BlockTransformer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The TransformationState allows access to the original block state and the
|
||||||
|
* block state of the block that was at the location of the transformation
|
||||||
|
* in the world before the transformation started.
|
||||||
|
*/
|
||||||
|
public static interface TransformationState {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a clone of the original block state that a structure wanted
|
||||||
|
* to place and caches it for the current transformer.
|
||||||
|
*
|
||||||
|
* @return a clone of the original block state.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
BlockState getOriginal();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a clone of the block state that was at the location of the
|
||||||
|
* currently modified block at the start of the transformation process
|
||||||
|
* and caches it for the current transformer.
|
||||||
|
*
|
||||||
|
* @return a clone of the world block state.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
BlockState getWorld();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms a block in a structure.
|
||||||
|
*
|
||||||
|
* NOTE: The usage of {@link BlockData#createBlockState()} can provide even
|
||||||
|
* more flexibility to return the exact block state you might want to
|
||||||
|
* return.
|
||||||
|
*
|
||||||
|
* @param region the accessible region
|
||||||
|
* @param x the x position of the block
|
||||||
|
* @param y the y position of the block
|
||||||
|
* @param z the z position of the block
|
||||||
|
* @param current the state of the block that should be placed
|
||||||
|
* @param state the state of this transformation.
|
||||||
|
*
|
||||||
|
* @return the new block state
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
BlockState transform(@NotNull LimitedRegion region, int x, int y, int z, @NotNull BlockState current, @NotNull TransformationState state);
|
||||||
|
}
|
@@ -0,0 +1,29 @@
|
|||||||
|
package org.bukkit.util;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.generator.LimitedRegion;
|
||||||
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A EntityTransformer is used to modify entities that are spawned by structure.
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
@ApiStatus.Experimental
|
||||||
|
public interface EntityTransformer {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms a entity in a structure.
|
||||||
|
*
|
||||||
|
* @param region the accessible region
|
||||||
|
* @param x the x position of the entity
|
||||||
|
* @param y the y position of the entity
|
||||||
|
* @param z the z position of the entity
|
||||||
|
* @param entity the entity
|
||||||
|
* @param allowedToSpawn if the entity is allowed to spawn
|
||||||
|
*
|
||||||
|
* @return {@code true} if the entity should be spawned otherwise
|
||||||
|
* {@code false}
|
||||||
|
*/
|
||||||
|
boolean transform(@NotNull LimitedRegion region, int x, int y, int z, @NotNull Entity entity, boolean allowedToSpawn);
|
||||||
|
}
|
Reference in New Issue
Block a user