summaryrefslogtreecommitdiffstats
path: root/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/fight/FightCheckListener.java
diff options
context:
space:
mode:
Diffstat (limited to 'EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/fight/FightCheckListener.java')
-rw-r--r--EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/fight/FightCheckListener.java291
1 files changed, 291 insertions, 0 deletions
diff --git a/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/fight/FightCheckListener.java b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/fight/FightCheckListener.java
new file mode 100644
index 000000000..fc1ea160c
--- /dev/null
+++ b/EssentialsAntiCheat/src/com/earth2me/essentials/anticheat/checks/fight/FightCheckListener.java
@@ -0,0 +1,291 @@
+package com.earth2me.essentials.anticheat.checks.fight;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import org.bukkit.craftbukkit.entity.CraftEntity;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.event.entity.EntityDamageEvent;
+import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
+import org.bukkit.event.entity.EntityDeathEvent;
+import org.bukkit.event.entity.EntityRegainHealthEvent;
+import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason;
+import org.bukkit.event.player.PlayerAnimationEvent;
+import com.earth2me.essentials.anticheat.EventManager;
+import com.earth2me.essentials.anticheat.NoCheat;
+import com.earth2me.essentials.anticheat.NoCheatPlayer;
+import com.earth2me.essentials.anticheat.config.ConfigurationCacheStore;
+
+
+/**
+ * Central location to listen to events that are relevant for the fight checks
+ *
+ */
+public class FightCheckListener implements Listener, EventManager
+{
+ private final List<FightCheck> checks;
+ private final GodmodeCheck godmodeCheck;
+ private final InstanthealCheck instanthealCheck;
+ private final NoCheat plugin;
+
+ public FightCheckListener(NoCheat plugin)
+ {
+
+ this.checks = new ArrayList<FightCheck>(4);
+
+ // Keep these in a list, because they can be executed in a bundle
+ this.checks.add(new SpeedCheck(plugin));
+ this.checks.add(new NoswingCheck(plugin));
+ this.checks.add(new DirectionCheck(plugin));
+ this.checks.add(new ReachCheck(plugin));
+
+ this.godmodeCheck = new GodmodeCheck(plugin);
+ this.instanthealCheck = new InstanthealCheck(plugin);
+
+ this.plugin = plugin;
+ }
+
+ /**
+ * We listen to EntityDamage events for obvious reasons
+ *
+ * @param event The EntityDamage Event
+ */
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void entityDamage(final EntityDamageEvent event)
+ {
+
+ // Filter some unwanted events right now
+ if (event.isCancelled() || !(event instanceof EntityDamageByEntityEvent))
+ {
+ return;
+ }
+
+ final EntityDamageByEntityEvent e = (EntityDamageByEntityEvent)event;
+ if (!(e.getDamager() instanceof Player))
+ {
+ return;
+ }
+
+ if (e.getCause() == DamageCause.ENTITY_ATTACK)
+ {
+ normalDamage(e);
+ }
+ else if (e.getCause() == DamageCause.CUSTOM)
+ {
+ customDamage(e);
+ }
+ }
+
+ /**
+ * We listen to EntityDamage events (again) for obvious reasons
+ *
+ * @param event The EntityDamage Event
+ */
+ @EventHandler(priority = EventPriority.LOW)
+ public void entityDamageForGodmodeCheck(final EntityDamageEvent event)
+ {
+
+ if (event.isCancelled())
+ {
+ return;
+ }
+
+ // Filter unwanted events right here
+ final Entity entity = event.getEntity();
+ if (!(entity instanceof Player) || entity.isDead())
+ {
+ return;
+ }
+
+ NoCheatPlayer player = plugin.getPlayer((Player)entity);
+ FightConfig cc = FightCheck.getConfig(player);
+
+ if (!godmodeCheck.isEnabled(cc) || player.hasPermission(godmodeCheck.permission))
+ {
+ return;
+ }
+
+ FightData data = FightCheck.getData(player);
+
+ // Run the godmode check on the attacked player
+ boolean cancelled = godmodeCheck.check(plugin.getPlayer((Player)entity), data, cc);
+
+ // It requested to "cancel" the players invulnerability, so set his
+ // noDamageTicks to 0
+ if (cancelled)
+ {
+ // Remove the invulnerability from the player
+ player.getPlayer().setNoDamageTicks(0);
+ }
+ }
+
+ /**
+ * We listen to EntityRegainHealth events of type "Satiated" for instantheal check
+ *
+ * @param event The EntityRegainHealth Event
+ */
+ @EventHandler(priority = EventPriority.LOWEST)
+ public void satiatedRegen(final EntityRegainHealthEvent event)
+ {
+
+ if (!(event.getEntity() instanceof Player) || event.isCancelled() || event.getRegainReason() != RegainReason.SATIATED)
+ {
+ return;
+ }
+
+ boolean cancelled = false;
+
+ NoCheatPlayer player = plugin.getPlayer((Player)event.getEntity());
+ FightConfig config = FightCheck.getConfig(player);
+
+ if (!instanthealCheck.isEnabled(config) || player.hasPermission(instanthealCheck.permission))
+ {
+ return;
+ }
+
+ FightData data = FightCheck.getData(player);
+
+ cancelled = instanthealCheck.check(player, data, config);
+
+ if (cancelled)
+ {
+ event.setCancelled(true);
+ }
+ }
+
+ /**
+ * A player attacked something with DamageCause ENTITY_ATTACK. That's most likely what we want to really check.
+ *
+ * @param event The EntityDamageByEntityEvent
+ */
+ private void normalDamage(final EntityDamageByEntityEvent event)
+ {
+
+ final Player damager = (Player)event.getDamager();
+
+ final NoCheatPlayer player = plugin.getPlayer(damager);
+ final FightConfig cc = FightCheck.getConfig(player);
+ final FightData data = FightCheck.getData(player);
+
+ // For some reason we decided to skip this event anyway
+ if (data.skipNext)
+ {
+ data.skipNext = false;
+ return;
+ }
+
+ boolean cancelled = false;
+
+ // Get the attacked entity and remember it
+ data.damagee = ((CraftEntity)event.getEntity()).getHandle();
+
+ // Run through the four main checks
+ for (FightCheck check : checks)
+ {
+ // If it should be executed, do it
+ if (!cancelled && check.isEnabled(cc) && !player.hasPermission(check.permission))
+ {
+ cancelled = check.check(player, data, cc);
+ }
+ }
+
+ // Forget the attacked entity (to allow garbage collecting etc.
+ data.damagee = null;
+
+ // One of the checks requested the event to be cancelled, so do it
+ if (cancelled)
+ {
+ event.setCancelled(cancelled);
+ }
+ }
+
+ /**
+ * There is an unofficial agreement that if a plugin wants an attack to not get checked by NoCheat, it either has to
+ * use a Damage type different from ENTITY_ATTACK or fire an event with damage type CUSTOM and damage 0 directly
+ * before the to-be-ignored event.
+ *
+ * @param event The EntityDamageByEntityEvent
+ */
+ private void customDamage(final EntityDamageByEntityEvent event)
+ {
+
+ final Player damager = (Player)event.getDamager();
+ final NoCheatPlayer player = plugin.getPlayer(damager);
+
+ final FightData data = FightCheck.getData(player);
+
+ // Skip the next damage event, because it is with high probability
+ // something from the Heroes plugin
+ data.skipNext = true;
+
+ return;
+ }
+
+ /**
+ * We listen to death events to prevent a very specific method of doing godmode.
+ *
+ * @param event The EntityDeathEvent
+ */
+ @EventHandler(priority = EventPriority.MONITOR)
+ protected void death(final EntityDeathEvent event)
+ {
+ // Only interested in dying players
+ if (!(event.getEntity() instanceof CraftPlayer))
+ {
+ return;
+ }
+
+ godmodeCheck.death((CraftPlayer)event.getEntity());
+ }
+
+ /**
+ * We listen to PlayerAnimationEvent because it is used for arm swinging
+ *
+ * @param event The PlayerAnimationEvent
+ */
+ @EventHandler(priority = EventPriority.MONITOR)
+ protected void armSwing(final PlayerAnimationEvent event)
+ {
+ // Set a flag telling us that the arm has been swung
+ FightCheck.getData(plugin.getPlayer(event.getPlayer())).armswung = true;
+ }
+
+ public List<String> getActiveChecks(ConfigurationCacheStore cc)
+ {
+ LinkedList<String> s = new LinkedList<String>();
+
+ FightConfig f = FightCheck.getConfig(cc);
+
+ if (f.directionCheck)
+ {
+ s.add("fight.direction");
+ }
+ if (f.noswingCheck)
+ {
+ s.add("fight.noswing");
+ }
+ if (f.reachCheck)
+ {
+ s.add("fight.reach");
+ }
+ if (f.speedCheck)
+ {
+ s.add("fight.speed");
+ }
+ if (f.godmodeCheck)
+ {
+ s.add("fight.godmode");
+ }
+ if (f.instanthealCheck)
+ {
+ s.add("fight.instantHeal");
+ }
+ return s;
+ }
+}