package com.nicewuerfel.blockown; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.ref.WeakReference; import java.util.Collection; import java.util.UUID; import javax.annotation.Nonnull; import javax.annotation.Nullable; public class OwnedEntity implements Ownable { private static final long serialVersionUID = -5197934920645104143L; @Nonnull private transient WeakReference<Entity> entityRef = new WeakReference<>(null); @Nullable private transient Material material = null; @Nonnull private final UUID id; @Nonnull private final String worldName; /** * Creates a new OwnedEntity instance holding a WeakReference to the given block. * * @param entity the entity * @return the new OwnedEntity instance */ @Nonnull public static OwnedEntity newInstance(Entity entity) { if (entity == null) { throw new NullPointerException("Entity can't be null"); } return new OwnedEntity(entity.getUniqueId(), entity.getWorld().getName(), new Material(entity.getType()), entity); } /** * Creates a new OwnedEntity instance. The corresponding Entity will be looked up when getEntity() * is called. * * @param id the UUID * @param worldName the worldName * @param material the material * @return the new OwnedEntity instance */ @Nonnull public static OwnedEntity newInstance(UUID id, String worldName, Material material) { if (id == null) { throw new NullPointerException("UUID can't be null"); } if (worldName == null) { throw new NullPointerException("world name can't be null"); } // it's okay if material is null return new OwnedEntity(id, worldName, material, null); } /** * Creates a new OwnedEntity instance. The corresponding Entity and its Material will be looked up * when needed. * * @param id the UUID * @param worldName the worldName * @return the new OwnedEntity instance */ @Nonnull public static OwnedEntity newInstance(UUID id, String worldName) { return newInstance(id, worldName, null); } private OwnedEntity(UUID id, String worldName, Material material, Entity entity) { this.id = id; this.worldName = worldName; this.material = material; this.entityRef = new WeakReference<>(entity); } /** * Gets the entity corresponding to this OwnedEntity. Keep in mind that this can be a very * expensive operation. * * @return the entity * @throws InvalidWorldNameException if the world name is invalid * @throws InvalidUUIDException if the entity can't be found in the specified world */ @Nonnull public Entity getEntity() throws InvalidWorldNameException, InvalidUUIDException { Entity result = entityRef.get(); if (result == null) { Class<? extends Entity> materialClass = getMaterial().getEntityType().getEntityClass(); Collection<? extends Entity> entities; if (materialClass == null) { entities = getWorld().getEntities(); } else { entities = getWorld().getEntitiesByClass(materialClass); } for (Entity entity : entities) { if (entity.getUniqueId().equals(id)) { entityRef = new WeakReference<>(entity); return entity; } } throw new InvalidUUIDException( "No entity with UUID " + id + " could be found in world " + worldName); } else { return result; } } @Nonnull public UUID getUniqueId() { return id; } /** * Returns the world this entity lives in. * * @throws InvalidWorldNameException if the world name is invalid */ @Override @Nonnull public World getWorld() throws InvalidWorldNameException { World world = Bukkit.getServer().getWorld(worldName); if (world == null) { throw new InvalidWorldNameException("There is no world called " + worldName); } return world; } @Override @Nonnull public String getWorldName() { return worldName; } @Override @Nonnull public Material getMaterial() throws InvalidWorldNameException { if (material == null) { material = new Material(getEntity().getType()); } return material; } /** * Checks if the entity is living. This can be a very expensive operation if it needs to look up * the entity. * * @return true, if it is a LivingEntity * @throws InvalidWorldNameException if the world name is invalid * @throws InvalidUUIDException if the entity can't be found in the specified world */ @Nonnull public boolean isLiving() throws InvalidWorldNameException, InvalidUUIDException { EntityType type = getMaterial().getEntityType(); return type.isAlive(); } private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); entityRef = new WeakReference<>(null); } @Override public int hashCode() { return id.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!(obj instanceof OwnedEntity)) { return false; } OwnedEntity other = (OwnedEntity) obj; if (!id.equals(other.id)) { return false; } return true; } @Override public String toString() { return "OwnedEntity [id=" + id + ", worldName=" + worldName + ", material=" + material + "]"; } }