13
0
geforkt von Mirrors/Paper

#915: Add support for virtual entities

By: Jishuna <joshl5324@gmail.com>
Dieser Commit ist enthalten in:
Bukkit/Spigot 2023-11-19 19:03:25 +13:00
Ursprung 1f322369a0
Commit 90df6eb97a
9 geänderte Dateien mit 525 neuen und 3 gelöschten Zeilen

Datei anzeigen

@ -279,6 +279,24 @@ public interface RegionAccessor {
@NotNull
Collection<Entity> getEntitiesByClasses(@NotNull Class<?>... classes);
/**
* Creates an entity of a specific class at the given {@link Location} but
* does not spawn it in the world.
* <p>
* <b>Note:</b> The created entity keeps a reference to the world it was
* created in, care should be taken that the entity does not outlive the
* world instance as this will lead to memory leaks.
*
* @param <T> the class of the {@link Entity} to create
* @param location the {@link Location} to create the entity at
* @param clazz the class of the {@link Entity} to spawn
* @return an instance of the created {@link Entity}
* @see #addEntity(Entity)
* @see Entity#createSnapshot()
*/
@NotNull
<T extends Entity> T createEntity(@NotNull Location location, @NotNull Class<T> clazz);
/**
* Spawn an entity of a specific class at the given {@link Location}
*
@ -393,4 +411,15 @@ public interface RegionAccessor {
* {@link HeightMap}
*/
public int getHighestBlockYAt(@NotNull Location location, @NotNull HeightMap heightMap);
/**
* Spawns a previously created entity in the world. <br>
* The provided entity must not have already been spawned in a world.
*
* @param <T> the generic type of the entity that is being added.
* @param entity the entity to add
* @return the entity now in the world
*/
@NotNull
public <T extends Entity> T addEntity(@NotNull T entity);
}

Datei anzeigen

@ -1,6 +1,12 @@
package org.bukkit.block;
import java.util.Collection;
import java.util.List;
import org.bukkit.block.spawner.SpawnRule;
import org.bukkit.block.spawner.SpawnerEntry;
import org.bukkit.entity.EntitySnapshot;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
@ -17,7 +23,8 @@ public interface CreatureSpawner extends TileState {
public EntityType getSpawnedType();
/**
* Set the spawner's creature type.
* Set the spawner's creature type. <br>
* This will override any entities that have been added with {@link #addPotentialSpawn}
*
* @param creatureType The creature type or null to clear.
*/
@ -199,4 +206,75 @@ public interface CreatureSpawner extends TileState {
* @see #getSpawnRange()
*/
public void setSpawnRange(int spawnRange);
/**
* Gets the {@link EntitySnapshot} that will be spawned by this spawner or null
* if no entities have been assigned to this spawner. <br>
* <p>
* All applicable data from the spawner will be copied, such as custom name,
* health, and velocity. <br>
*
* @return the entity snapshot or null if no entities have been assigned to this
* spawner.
*/
@Nullable
public EntitySnapshot getSpawnedEntity();
/**
* Sets the entity that will be spawned by this spawner. <br>
* This will override any previous entries that have been added with
* {@link #addPotentialSpawn}
* <p>
* All applicable data from the snapshot will be copied, such as custom name,
* health, and velocity. <br>
*
* @param snapshot the entity snapshot
*/
public void setSpawnedEntity(@NotNull EntitySnapshot snapshot);
/**
* Adds a new {@link EntitySnapshot} to the list of entities this spawner can
* spawn.
* <p>
* The weight will determine how often this entry is chosen to spawn, higher
* weighted entries will spawn more often than lower weighted ones. <br>
* The {@link SpawnRule} will determine under what conditions this entry can
* spawn, passing null will use the default conditions for the given entity.
*
* @param snapshot the snapshot that will be spawned
* @param weight the weight
* @param spawnRule the spawn rule for this entity, or null
*/
public void addPotentialSpawn(@NotNull EntitySnapshot snapshot, int weight, @Nullable SpawnRule spawnRule);
/**
* Adds a new {@link SpawnerEntry} to the list of entities this spawner can
* spawn. <br>
*
* @param spawnerEntry the spawner entry to use
* @see #addPotentialSpawn(EntitySnapshot, int, SpawnRule)
*/
public void addPotentialSpawn(@NotNull final SpawnerEntry spawnerEntry);
/**
* Sets the list of {@link SpawnerEntry} this spawner can spawn. <br>
* This will override any previous entries added with
* {@link #addPotentialSpawn}
*
* @param entries the list of entries
*/
public void setPotentialSpawns(@NotNull final Collection<SpawnerEntry> entries);
/**
* Gets a list of potential spawns from this spawner or an empty list if no
* entities have been assigned to this spawner. <br>
* Changes made to the returned list will not be reflected in the spawner unless
* applied with {@link #setPotentialSpawns}
*
* @return a list of potential spawns from this spawner, or an empty list if no
* entities have been assigned to this spawner
* @see #getSpawnedType()
*/
@NotNull
public List<SpawnerEntry> getPotentialSpawns();
}

Datei anzeigen

@ -0,0 +1,219 @@
package org.bukkit.block.spawner;
import com.google.common.base.Preconditions;
import java.util.LinkedHashMap;
import java.util.Map;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.SerializableAs;
import org.jetbrains.annotations.NotNull;
/**
* Represents a spawn rule that controls what conditions an entity from a
* monster spawner can spawn.
*/
@SerializableAs("SpawnRule")
public class SpawnRule implements Cloneable, ConfigurationSerializable {
private int minBlockLight;
private int maxBlockLight;
private int minSkyLight;
private int maxSkyLight;
/**
* Constructs a new SpawnRule.
*
* @param minBlockLight The minimum (inclusive) block light required for
* spawning to succeed.
* @param maxBlockLight The maximum (inclusive) block light required for
* spawning to succeed.
* @param minSkyLight The minimum (inclusive) sky light required for
* spawning to succeed.
* @param maxSkyLight The maximum (inclusive) sky light required for
* spawning to succeed.
*/
public SpawnRule(int minBlockLight, int maxBlockLight, int minSkyLight, int maxSkyLight) {
Preconditions.checkArgument(minBlockLight <= maxBlockLight, "minBlockLight must be <= maxBlockLight (%s <= %s)", minBlockLight, maxBlockLight);
Preconditions.checkArgument(minSkyLight <= maxSkyLight, "minSkyLight must be <= maxSkyLight (%s <= %s)", minSkyLight, maxSkyLight);
Preconditions.checkArgument(minBlockLight >= 0, "minBlockLight must be >= 0 (given %s)", minBlockLight);
Preconditions.checkArgument(maxBlockLight >= 0, "maxBlockLight must be >= 0 (given %s)", maxBlockLight);
Preconditions.checkArgument(minSkyLight >= 0, "minSkyLight must be >= 0 (given %s)", minSkyLight);
Preconditions.checkArgument(maxSkyLight >= 0, "maxSkyLight must be >= 0 (given %s)", maxSkyLight);
this.minBlockLight = minBlockLight;
this.maxBlockLight = maxBlockLight;
this.minSkyLight = minSkyLight;
this.maxSkyLight = maxSkyLight;
}
/**
* Gets the minimum (inclusive) block light required for spawning to
* succeed.
*
* @return minimum block light
*/
public int getMinBlockLight() {
return minBlockLight;
}
/**
* Sets the minimum (inclusive) block light required for spawning to
* succeed.
*
* @param minBlockLight minimum block light
*/
public void setMinBlockLight(int minBlockLight) {
Preconditions.checkArgument(minBlockLight >= 0, "minBlockLight must be >= 0 (given %s)", minBlockLight);
Preconditions.checkArgument(minBlockLight <= maxBlockLight, "minBlockLight must be <= maxBlockLight (%s <= %s)", minBlockLight, maxBlockLight);
this.minBlockLight = minBlockLight;
}
/**
* Gets the maximum (inclusive) block light required for spawning to
* succeed.
*
* @return maximum block light
*/
public int getMaxBlockLight() {
return maxBlockLight;
}
/**
* Sets the maximum (inclusive) block light required for spawning to
* succeed.
*
* @param maxBlockLight maximum block light
*/
public void setMaxBlockLight(int maxBlockLight) {
Preconditions.checkArgument(maxBlockLight >= 0, "maxBlockLight must be >= 0 (given %s)", maxBlockLight);
this.maxBlockLight = maxBlockLight;
}
/**
* Gets the minimum (inclusive) sky light required for spawning to succeed.
*
* @return minimum sky light
*/
public int getMinSkyLight() {
return minSkyLight;
}
/**
* Sets the minimum (inclusive) sky light required for spawning to succeed.
*
* @param minSkyLight minimum sky light
*/
public void setMinSkyLight(int minSkyLight) {
Preconditions.checkArgument(minSkyLight >= 0, "minSkyLight must be >= 0 (given %s)", minSkyLight);
Preconditions.checkArgument(minSkyLight <= maxSkyLight, "minSkyLight must be <= maxSkyLight (%s <= %s)", minSkyLight, maxSkyLight);
this.minSkyLight = minSkyLight;
}
/**
* Gets the maximum (inclusive) sky light required for spawning to succeed.
*
* @return maximum sky light
*/
public int getMaxSkyLight() {
return maxSkyLight;
}
/**
* Sets the maximum (inclusive) sky light required for spawning to succeed.
*
* @param maxSkyLight maximum sky light
*/
public void setMaxSkyLight(int maxSkyLight) {
Preconditions.checkArgument(maxSkyLight >= 0, "maxSkyLight must be >= 0 (given %s)", maxSkyLight);
this.maxSkyLight = maxSkyLight;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof SpawnRule)) {
return false;
}
SpawnRule other = (SpawnRule) obj;
return minBlockLight == other.minBlockLight && maxBlockLight == other.maxBlockLight && minSkyLight == other.minSkyLight && maxSkyLight == other.maxSkyLight;
}
@Override
public int hashCode() {
int hash = minBlockLight;
hash = (hash << 4) + maxBlockLight;
hash = (hash << 4) + minSkyLight;
hash = (hash << 4) + maxSkyLight;
return hash;
}
@NotNull
@Override
public SpawnRule clone() {
try {
return (SpawnRule) super.clone();
} catch (CloneNotSupportedException e) {
throw new Error(e);
}
}
@Override
@NotNull
public Map<String, Object> serialize() {
Map<String, Object> result = new LinkedHashMap<>();
Map<String, Object> block = new LinkedHashMap<>();
Map<String, Object> sky = new LinkedHashMap<>();
block.put("min", getMinBlockLight());
block.put("max", getMaxBlockLight());
sky.put("min", getMinSkyLight());
sky.put("max", getMaxSkyLight());
result.put("block-light", block);
result.put("sky-light", sky);
return result;
}
@NotNull
public static SpawnRule deserialize(@NotNull Map<String, Object> args) {
int minBlock = 0;
int maxBlock = 0;
int minSky = 0;
int maxSky = 0;
Object block = args.get("block-light");
Object sky = args.get("sky-light");
if (block instanceof Map<?, ?>) {
Map<?, ?> blockMap = (Map<?, ?>) block;
if (blockMap.containsKey("min")) {
minBlock = (int) blockMap.get("min");
}
if (blockMap.containsKey("max")) {
maxBlock = (int) blockMap.get("max");
}
}
if (sky instanceof Map<?, ?>) {
Map<?, ?> skyMap = (Map<?, ?>) sky;
if (skyMap.containsKey("min")) {
minSky = (int) skyMap.get("min");
}
if (skyMap.containsKey("max")) {
maxSky = (int) skyMap.get("max");
}
}
return new SpawnRule(minBlock, maxBlock, minSky, maxSky);
}
}

Datei anzeigen

@ -0,0 +1,85 @@
package org.bukkit.block.spawner;
import com.google.common.base.Preconditions;
import org.bukkit.entity.EntitySnapshot;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a weighted spawn potential that can be added to a monster spawner.
*/
public class SpawnerEntry {
private EntitySnapshot snapshot;
private int spawnWeight;
private SpawnRule spawnRule;
public SpawnerEntry(@NotNull EntitySnapshot snapshot, int spawnWeight, @Nullable SpawnRule spawnRule) {
Preconditions.checkArgument(snapshot != null, "Snapshot cannot be null");
this.snapshot = snapshot;
this.spawnWeight = spawnWeight;
this.spawnRule = spawnRule;
}
/**
* Gets the {@link EntitySnapshot} for this SpawnerEntry.
*
* @return the snapshot
*/
@NotNull
public EntitySnapshot getSnapshot() {
return snapshot;
}
/**
* Sets the {@link EntitySnapshot} for this SpawnerEntry.
*
* @param snapshot the snapshot
*/
public void setSnapshot(@NotNull EntitySnapshot snapshot) {
Preconditions.checkArgument(snapshot != null, "Snapshot cannot be null");
this.snapshot = snapshot;
}
/**
* Gets the weight for this SpawnerEntry, when added to a spawner entries
* with higher weight will spawn more often.
*
* @return the weight
*/
public int getSpawnWeight() {
return spawnWeight;
}
/**
* Sets the weight for this SpawnerEntry, when added to a spawner entries
* with higher weight will spawn more often.
*
* @param spawnWeight the new spawn weight
*/
public void setSpawnWeight(int spawnWeight) {
this.spawnWeight = spawnWeight;
}
/**
* Gets a copy of the {@link SpawnRule} for this SpawnerEntry, or null if
* none has been set.
*
* @return a copy of the spawn rule or null
*/
@Nullable
public SpawnRule getSpawnRule() {
return spawnRule == null ? null : spawnRule.clone();
}
/**
* Sets the {@link SpawnRule} for this SpawnerEntry, null may be used to
* clear the current spawn rule.
*
* @param spawnRule the new spawn rule to use or null
*/
public void setSpawnRule(@Nullable SpawnRule spawnRule) {
this.spawnRule = spawnRule;
}
}

Datei anzeigen

@ -0,0 +1,4 @@
/**
* Classes relevant to mob spawners.
*/
package org.bukkit.block.spawner;

Datei anzeigen

@ -14,6 +14,7 @@ import org.bukkit.FireworkEffect;
import org.bukkit.Location;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.block.banner.Pattern;
import org.bukkit.block.spawner.SpawnRule;
import org.bukkit.configuration.Configuration;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
@ -42,6 +43,7 @@ public class ConfigurationSerialization {
registerClass(Location.class);
registerClass(AttributeModifier.class);
registerClass(BoundingBox.class);
registerClass(SpawnRule.class);
}
protected ConfigurationSerialization(@NotNull Class<? extends ConfigurationSerializable> clazz) {

Datei anzeigen

@ -26,6 +26,9 @@ import org.jetbrains.annotations.Nullable;
/**
* Represents a base entity in the world
* <p>
* Not all methods are guaranteed to work/may have side effects when
* {@link #isInWorld()} is false.
*/
public interface Entity extends Metadatable, CommandSender, Nameable, PersistentDataHolder {
@ -265,8 +268,8 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent
public boolean isDead();
/**
* Returns false if the entity has died or been despawned for some other
* reason.
* Returns false if the entity has died, been despawned for some other
* reason, or has not been added to the world.
*
* @return True if valid.
*/
@ -714,4 +717,43 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent
*/
@NotNull
SpawnCategory getSpawnCategory();
/**
* Checks if this entity has been spawned in a world. <br>
* Entities not spawned in a world will not tick, be sent to players, or be
* saved to the server files.
*
* @return whether the entity has been spawned in a world
*/
boolean isInWorld();
/**
* Crates an {@link EntitySnapshot} representing the current state of this entity.
*
* @return a snapshot representing this entity or null if one cannot be made
*/
@Nullable
@ApiStatus.Experimental
EntitySnapshot createSnapshot();
/**
* Creates a copy of this entity and all its data. Does not spawn the copy in
* the world. <br>
* <b>Note:</b> Players cannot be copied.
*
* @return a copy of this entity.
*/
@NotNull
@ApiStatus.Experimental
Entity copy();
/**
* Creates a copy of this entity and all its data. Spawns the copy at the given location. <br>
* <b>Note:</b> Players cannot be copied.
* @param to the location to copy to
* @return a copy of this entity.
*/
@NotNull
@ApiStatus.Experimental
Entity copy(@NotNull Location to);
}

Datei anzeigen

@ -0,0 +1,39 @@
package org.bukkit.entity;
import org.bukkit.Location;
import org.bukkit.World;
import org.jetbrains.annotations.NotNull;
/**
* Represents an immutable copy of an entity's state. Can be used at any time to
* create an instance of the stored entity.
*/
public interface EntitySnapshot {
/**
* Creates an entity using this template. Does not spawn the copy in the world.
* <br>
*
* @param world the world to create the entity in
* @return a copy of this entity.
*/
@NotNull
Entity createEntity(@NotNull World world);
/**
* Creates an entity using this template and spawns it at the provided location.
*
* @param to the location to copy to
* @return the new entity.
*/
@NotNull
Entity createEntity(@NotNull Location to);
/**
* Gets the type of entity this template holds.
*
* @return the type
*/
@NotNull
EntityType getEntityType();
}

Datei anzeigen

@ -1,8 +1,10 @@
package org.bukkit.inventory.meta;
import org.bukkit.entity.EntitySnapshot;
import org.bukkit.entity.EntityType;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Represents a spawn egg and it's spawned type.
@ -30,6 +32,28 @@ public interface SpawnEggMeta extends ItemMeta {
@Contract("_ -> fail")
void setSpawnedType(EntityType type);
/**
* Gets the {@link EntitySnapshot} that will be spawned by this spawn egg or null if no entity
* has been set. <br>
* <p>
* All applicable data from the egg will be copied, such as custom name, health,
* and velocity. <br>
*
* @return the entity snapshot or null if no entity has been set
*/
@Nullable
EntitySnapshot getSpawnedEntity();
/**
* Sets the {@link EntitySnapshot} that will be spawned by this spawn egg. <br>
* <p>
* All applicable data from the entity will be copied, such as custom name,
* health, and velocity. <br>
*
* @param snapshot the snapshot
*/
void setSpawnedEntity(@NotNull EntitySnapshot snapshot);
@NotNull
@Override
SpawnEggMeta clone();