blob: e5936bd98b2c7ea6809181422fb001a7a8465349 [file] [log] [blame] [raw]
package net.glowstone.entity;
import com.flowpowered.network.Message;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import lombok.Getter;
import lombok.Setter;
import net.glowstone.PotionDataHolder;
import net.glowstone.entity.meta.MetadataIndex;
import net.glowstone.entity.meta.MetadataMap;
import net.glowstone.net.message.play.entity.EntityMetadataMessage;
import net.glowstone.net.message.play.entity.SpawnObjectMessage;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.entity.AreaEffectCloud;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.potion.PotionData;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.projectiles.ProjectileSource;
public class GlowAreaEffectCloud extends GlowEntity implements AreaEffectCloud, PotionDataHolder {
private static final int NETWORK_TYPE_ID = 3;
/**
* Used to implement the reapplication delay. Note that this isn't serialized -- all
* reapplication delays will effectively end when the chunk unloads.
*/
private final Map<LivingEntity, Long> temporaryImmunities = new WeakHashMap<>();
@Override
public void pulse() {
super.pulse();
radius += radiusPerTick;
waitTime--;
duration--;
if (duration <= 0 || radius <= 0) {
remove();
}
if (waitTime <= 0) {
long currentTick = world.getFullTime();
for (Entity entity : world.getNearbyEntities(location, radius, radius, radius)) {
if (entity instanceof LivingEntity
&& temporaryImmunities.getOrDefault(entity, Long.MIN_VALUE) <= currentTick
&& location.distanceSquared(entity.getLocation()) < radius * radius) {
((LivingEntity) entity).addPotionEffects(customEffects.values());
temporaryImmunities.put((LivingEntity) entity,
currentTick + reapplicationDelay);
}
}
}
}
private final Map<PotionEffectType, PotionEffect> customEffects = new ConcurrentHashMap<>();
@Getter
@Setter
private int duration;
@Getter
@Setter
private int waitTime;
@Getter
@Setter
private int reapplicationDelay;
@Getter
@Setter
private int durationOnUse;
@Getter
@Setter
private float radius;
@Getter
@Setter
private float radiusOnUse;
@Getter
@Setter
private float radiusPerTick;
@Getter
@Setter
private Particle particle;
@Getter
@Setter
private PotionData basePotionData;
@Getter
@Setter
private ProjectileSource source;
@Getter
@Setter
private Color color;
/**
* Creates an entity and adds it to the specified world.
*
* @param location The location of the entity.
*/
public GlowAreaEffectCloud(Location location) {
super(location);
}
@Override
public List<Message> createSpawnMessage() {
MetadataMap metadataMap = new MetadataMap(GlowAreaEffectCloud.class);
metadataMap.set(MetadataIndex.AREAEFFECTCLOUD_COLOR, color);
metadataMap.set(MetadataIndex.AREAEFFECTCLOUD_RADIUS, radius);
metadataMap.set(MetadataIndex.AREAEFFECTCLOUD_PARTICLEID, particle.ordinal());
return Arrays.asList(
new SpawnObjectMessage(entityId, getUniqueId(), NETWORK_TYPE_ID, location),
new EntityMetadataMessage(entityId, metadataMap.getEntryList()));
}
@Override
public boolean hasCustomEffects() {
return !customEffects.isEmpty();
}
@Override
public List<PotionEffect> getCustomEffects() {
return new ArrayList<>(customEffects.values());
}
@Override
public boolean addCustomEffect(PotionEffect potionEffect, boolean overwrite) {
PotionEffectType type = potionEffect.getType();
if (overwrite) {
customEffects.put(type, potionEffect);
return true;
} else {
return customEffects.putIfAbsent(type, potionEffect) == null;
}
}
@Override
public boolean removeCustomEffect(PotionEffectType potionEffectType) {
return customEffects.remove(potionEffectType) != null;
}
@Override
public boolean hasCustomEffect(PotionEffectType potionEffectType) {
return customEffects.containsKey(potionEffectType);
}
@Override
public void clearCustomEffects0() {
clearCustomEffects();
}
@Override
public void clearCustomEffects() {
customEffects.clear();
}
}