package tc.oc.pgm.tracker.trackers; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import javax.annotation.Nullable; import javax.inject.Inject; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.PlayerDeathEvent; import tc.oc.commons.core.logging.Loggers; import tc.oc.pgm.events.ListenerScope; import tc.oc.pgm.events.MatchPlayerDeathEvent; import tc.oc.pgm.match.Match; import tc.oc.pgm.match.MatchPlayer; import tc.oc.pgm.match.MatchScope; import tc.oc.pgm.tracker.EventResolver; import tc.oc.pgm.tracker.damage.DamageInfo; import tc.oc.pgm.tracker.damage.GenericDamageInfo; /** * - Resolves all damage done to players and tracks the most recent one * - Wraps {@link PlayerDeathEvent}s in a {@link MatchPlayerDeathEvent}, together with the causing info * - Displays death messages */ @ListenerScope(MatchScope.RUNNING) public class DeathTracker implements Listener { private final Logger logger; private final Match match; private final EventResolver eventResolver; private final Map<MatchPlayer, DamageInfo> lastDamageInfos = new HashMap<>(); @Inject DeathTracker(Loggers loggers, Match match, EventResolver eventResolver) { this.logger = loggers.get(getClass()); this.match = match; this.eventResolver = eventResolver; } // Trackers will do their cleanup at MONITOR level, so we listen at // HIGHEST to make sure all the info is still available. @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onPlayerDamage(EntityDamageEvent event) { MatchPlayer victim = match.getParticipant(event.getEntity()); if(victim == null) return; lastDamageInfos.put(victim, eventResolver.resolveDamage(event)); } @Nullable DamageInfo getLastDamage(MatchPlayer victim) { DamageInfo info = lastDamageInfos.get(victim); if(info != null) return info; EntityDamageEvent damageEvent = victim.getBukkit().getLastDamageCause(); if(damageEvent != null) { return eventResolver.resolveDamage(damageEvent); } return null; } /** * Must run after {@link tc.oc.pgm.spawns.SpawnMatchModule#onVanillaDeath} */ @EventHandler(priority = EventPriority.NORMAL) public void onPlayerDeath(PlayerDeathEvent event) { logger.fine("Wrapping " + event); MatchPlayer victim = match.getParticipant(event.getEntity()); if(victim == null || victim.isDead()) return; DamageInfo info = getLastDamage(victim); if(info == null) info = new GenericDamageInfo(EntityDamageEvent.DamageCause.CUSTOM); match.callEvent(new MatchPlayerDeathEvent(event, victim, info, CombatLogTracker.isCombatLog(event))); } }