#1266: Add support for virtual entities

By: Jishuna <joshl5324@gmail.com>
This commit is contained in:
CraftBukkit/Spigot
2023-11-19 19:03:35 +13:00
parent 9a3c24e787
commit 95e4221adf
13 changed files with 472 additions and 61 deletions

View File

@@ -24,6 +24,7 @@ import net.minecraft.world.entity.EntityFlying;
import net.minecraft.world.entity.EntityLightning;
import net.minecraft.world.entity.EntityLiving;
import net.minecraft.world.entity.EntityTameableAnimal;
import net.minecraft.world.entity.EntityTypes;
import net.minecraft.world.entity.GlowSquid;
import net.minecraft.world.entity.Interaction;
import net.minecraft.world.entity.Marker;
@@ -164,6 +165,7 @@ import net.minecraft.world.entity.vehicle.EntityMinecartTNT;
import net.minecraft.world.phys.AxisAlignedBB;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.Registry;
import org.bukkit.Server;
import org.bukkit.Sound;
import org.bukkit.World;
@@ -177,8 +179,10 @@ import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer;
import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry;
import org.bukkit.craftbukkit.util.CraftChatMessage;
import org.bukkit.craftbukkit.util.CraftLocation;
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.craftbukkit.util.CraftSpawnCategory;
import org.bukkit.craftbukkit.util.CraftVector;
import org.bukkit.entity.EntitySnapshot;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Pose;
@@ -641,7 +645,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
@Override
public boolean isValid() {
return entity.isAlive() && entity.valid && entity.isChunkLoaded();
return entity.isAlive() && entity.valid && entity.isChunkLoaded() && isInWorld();
}
@Override
@@ -1114,6 +1118,42 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
return CraftSpawnCategory.toBukkit(getHandle().getType().getCategory());
}
@Override
public boolean isInWorld() {
return getHandle().inWorld;
}
@Override
public EntitySnapshot createSnapshot() {
return CraftEntitySnapshot.create(this);
}
@Override
public org.bukkit.entity.Entity copy() {
Entity copy = copy(getHandle().level());
Preconditions.checkArgument(copy != null, "Error creating new entity.");
return copy.getBukkitEntity();
}
@Override
public org.bukkit.entity.Entity copy(Location location) {
Preconditions.checkArgument(location.getWorld() != null, "Location has no world");
Entity copy = copy(((CraftWorld) location.getWorld()).getHandle());
Preconditions.checkArgument(copy != null, "Error creating new entity.");
copy.setPos(location.getX(), location.getY(), location.getZ());
return location.getWorld().addEntity(copy.getBukkitEntity());
}
private Entity copy(net.minecraft.world.level.World level) {
NBTTagCompound compoundTag = new NBTTagCompound();
getHandle().saveAsPassenger(compoundTag, false);
return EntityTypes.loadEntityRecursive(compoundTag, level, java.util.function.Function.identity());
}
public void storeBukkitValues(NBTTagCompound c) {
if (!this.persistentDataContainer.isEmpty()) {
c.put("BukkitValues", this.persistentDataContainer.toTagCompound());

View File

@@ -0,0 +1,83 @@
package org.bukkit.craftbukkit.entity;
import com.google.common.base.Preconditions;
import java.util.function.Function;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.world.entity.EntityTypes;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntitySnapshot;
import org.bukkit.entity.EntityType;
public class CraftEntitySnapshot implements EntitySnapshot {
private final NBTTagCompound data;
private final EntityType type;
private CraftEntitySnapshot(NBTTagCompound data, EntityType type) {
this.data = data;
this.type = type;
}
@Override
public EntityType getEntityType() {
return type;
}
@Override
public Entity createEntity(World world) {
net.minecraft.world.entity.Entity internal = createInternal(world);
return internal.getBukkitEntity();
}
@Override
public Entity createEntity(Location location) {
Preconditions.checkArgument(location.getWorld() != null, "Location has no world");
net.minecraft.world.entity.Entity internal = createInternal(location.getWorld());
internal.setPos(location.getX(), location.getY(), location.getZ());
return location.getWorld().addEntity(internal.getBukkitEntity());
}
private net.minecraft.world.entity.Entity createInternal(World world) {
net.minecraft.world.level.World nms = ((CraftWorld) world).getHandle();
net.minecraft.world.entity.Entity internal = EntityTypes.loadEntityRecursive(data, nms, Function.identity());
if (internal == null) { // Try creating by type
internal = CraftEntityType.bukkitToMinecraft(type).create(nms);
}
Preconditions.checkArgument(internal != null, "Error creating new entity."); // This should only fail if the stored NBTTagCompound is malformed.
internal.load(data);
return internal;
}
public NBTTagCompound getData() {
return data;
}
public static CraftEntitySnapshot create(CraftEntity entity) {
NBTTagCompound tag = new NBTTagCompound();
if (!entity.getHandle().saveAsPassenger(tag, false)) {
return null;
}
return new CraftEntitySnapshot(tag, entity.getType());
}
public static CraftEntitySnapshot create(NBTTagCompound tag, EntityType type) {
if (tag == null || tag.isEmpty() || type == null) {
return null;
}
return new CraftEntitySnapshot(tag, type);
}
public static CraftEntitySnapshot create(NBTTagCompound tag) {
EntityType type = EntityTypes.by(tag).map(CraftEntityType::minecraftToBukkit).orElse(null);
return create(tag, type);
}
}

View File

@@ -38,6 +38,7 @@ import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.memory.CraftMemoryMapper;
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.craftbukkit.inventory.CraftContainer;
@@ -684,4 +685,14 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
boolean success = getHandle().level().addFreshEntity(fireworks, SpawnReason.CUSTOM);
return success ? (Firework) fireworks.getBukkitEntity() : null;
}
@Override
public org.bukkit.entity.Entity copy() {
throw new UnsupportedOperationException("Cannot copy human entities");
}
@Override
public org.bukkit.entity.Entity copy(Location location) {
throw new UnsupportedOperationException("Cannot copy human entities");
}
}