package tc.oc.pgm.effect; import org.bukkit.Color; import org.bukkit.Particle; import org.bukkit.entity.Arrow; import org.bukkit.entity.Projectile; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.ProjectileHitEvent; import org.bukkit.event.entity.ProjectileLaunchEvent; import org.bukkit.metadata.FixedMetadataValue; import tc.oc.pgm.PGM; import tc.oc.pgm.events.ListenerScope; import tc.oc.pgm.match.MatchModule; import tc.oc.pgm.match.MatchScope; import tc.oc.pgm.match.Repeatable; import tc.oc.pgm.utils.EntityUtils; /** * Change the default projectile particle trails with a colored * trail that matches the player's party color. */ @ListenerScope(MatchScope.RUNNING) public class ProjectileTrailMatchModule extends MatchModule implements Listener { private static final String TRAIL_META = "projectile_trail_color"; private static final String CRITICAL_META = "arrow_is_critical"; @Repeatable(scope = MatchScope.RUNNING) public void tick() { EntityUtils.entities(match.getWorld(), Projectile.class) .filter(projectile -> projectile.hasMetadata(TRAIL_META)) .forEach(projectile -> { if(projectile.isDead() || projectile.isOnGround()) { projectile.removeMetadata(TRAIL_META, PGM.get()); } else { final Color color = (Color) projectile.getMetadata(TRAIL_META, PGM.get()).value(); // Certain particles can have a specific color if: // - Count is 0 // - Speed is 1 // - Delta vectors are RGB values from (0,1] match.getWorld().spawnParticle( Particle.REDSTONE, projectile.getLocation(), 0, rgbToParticle(color.getRed()), rgbToParticle(color.getGreen()), rgbToParticle(color.getBlue()), 1 ); } }); } private double rgbToParticle(int rgb) { return Math.max(0.001, rgb / 255.0); } @EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true) public void onProjectileLaunch(ProjectileLaunchEvent event) { match.player(event.getActor()).ifPresent(shooter -> { final Projectile projectile = event.getEntity(); projectile.setMetadata(TRAIL_META, new FixedMetadataValue(PGM.get(), shooter.getParty().getFullColor())); // Set critical metadata to false in order to remove default particle trail. // The metadata will be restored just before the arrow hits something. if(projectile instanceof Arrow) { final Arrow arrow = (Arrow) projectile; arrow.setMetadata(CRITICAL_META, new FixedMetadataValue(PGM.get(), arrow.isCritical())); arrow.setCritical(false); } }); } @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onProjectileHit(ProjectileHitEvent event) { match.player(event.getActor()).ifPresent(shooter -> { final Projectile projectile = event.getEntity(); projectile.removeMetadata(TRAIL_META, PGM.get()); // Restore critical metadata to arrows if applicable if(projectile instanceof Arrow) { final Arrow arrow = (Arrow) projectile; if(arrow.hasMetadata(CRITICAL_META)) { arrow.setCritical(arrow.getMetadata(CRITICAL_META, PGM.get()).asBoolean()); } } }); } }