Package com.massivecraft.factions.listeners

Source Code of com.massivecraft.factions.listeners.FactionsListenerMain

package com.massivecraft.factions.listeners;

import java.text.MessageFormat;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.Wither;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockBurnEvent;
import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.block.BlockIgniteEvent;
import org.bukkit.event.block.BlockPistonExtendEvent;
import org.bukkit.event.block.BlockPistonRetractEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.BlockSpreadEvent;
import org.bukkit.event.block.BlockIgniteEvent.IgniteCause;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import org.bukkit.event.entity.EntityCombustByEntityEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.entity.PotionSplashEvent;
import org.bukkit.event.hanging.HangingBreakByEntityEvent;
import org.bukkit.event.hanging.HangingBreakEvent;
import org.bukkit.event.hanging.HangingPlaceEvent;
import org.bukkit.event.hanging.HangingBreakEvent.RemoveCause;
import org.bukkit.event.player.PlayerBucketEmptyEvent;
import org.bukkit.event.player.PlayerBucketFillEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerKickEvent;
import org.bukkit.event.player.PlayerMoveEvent;

import com.massivecraft.factions.Const;
import com.massivecraft.factions.FFlag;
import com.massivecraft.factions.FPerm;
import com.massivecraft.factions.Factions;
import com.massivecraft.factions.Rel;
import com.massivecraft.factions.TerritoryAccess;
import com.massivecraft.factions.entity.BoardColls;
import com.massivecraft.factions.entity.UPlayer;
import com.massivecraft.factions.entity.Faction;
import com.massivecraft.factions.entity.MConf;
import com.massivecraft.factions.entity.UConf;
import com.massivecraft.factions.entity.UPlayerColl;
import com.massivecraft.factions.entity.UPlayerColls;
import com.massivecraft.factions.event.FactionsEventPowerChange;
import com.massivecraft.factions.event.FactionsEventPowerChange.PowerChangeReason;
import com.massivecraft.factions.util.VisualizeUtil;
import com.massivecraft.mcore.ps.PS;
import com.massivecraft.mcore.util.MUtil;
import com.massivecraft.mcore.util.Txt;

public class FactionsListenerMain implements Listener
{
  // -------------------------------------------- //
  // INSTANCE & CONSTRUCT
  // -------------------------------------------- //
 
  private static FactionsListenerMain i = new FactionsListenerMain();
  public static FactionsListenerMain get() { return i; }
  public FactionsListenerMain() {}
 
  // -------------------------------------------- //
  // SETUP
  // -------------------------------------------- //
 
  public void setup()
  {
    Bukkit.getPluginManager().registerEvents(this, Factions.get());
  }

  // -------------------------------------------- //
  // CHUNK CHANGE: DETECT
  // -------------------------------------------- //
 
  @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
  public void chunkChangeDetect(PlayerMoveEvent event)
  {
    // If the player is moving from one chunk to another ...
    if (MUtil.isSameChunk(event)) return;
    Player player = event.getPlayer();
   
    // Check Disabled
    if (UConf.isDisabled(player)) return;
   
    // ... gather info on the player and the move ...
    UPlayer uplayer = UPlayerColls.get().get(event.getTo()).get(player);
   
    PS chunkFrom = PS.valueOf(event.getFrom()).getChunk(true);
    PS chunkTo = PS.valueOf(event.getTo()).getChunk(true);
   
    Faction factionFrom = BoardColls.get().getFactionAt(chunkFrom);
    Faction factionTo = BoardColls.get().getFactionAt(chunkTo);
   
    // ... and send info onwards.
    this.chunkChangeTerritoryInfo(uplayer, player, chunkFrom, chunkTo, factionFrom, factionTo);
    this.chunkChangeAutoClaim(uplayer, chunkTo);
  }
 
  // -------------------------------------------- //
  // CHUNK CHANGE: TERRITORY INFO
  // -------------------------------------------- //
 
  public void chunkChangeTerritoryInfo(UPlayer uplayer, Player player, PS chunkFrom, PS chunkTo, Faction factionFrom, Faction factionTo)
  {
    // send host faction info updates
    if (uplayer.isMapAutoUpdating())
    {
      uplayer.sendMessage(BoardColls.get().getMap(uplayer, chunkTo, player.getLocation().getYaw()));
    }
    else if (factionFrom != factionTo)
    {
      String msg = Txt.parse("<i>") + " ~ " + factionTo.getName(uplayer);
      if (factionTo.hasDescription())
      {
        msg += " - " + factionTo.getDescription();
      }
      player.sendMessage(msg);
    }

    // Show access level message if it changed.
    TerritoryAccess accessFrom = BoardColls.get().getTerritoryAccessAt(chunkFrom);
    Boolean hasTerritoryAccessFrom = accessFrom.hasTerritoryAccess(uplayer);
   
    TerritoryAccess accessTo = BoardColls.get().getTerritoryAccessAt(chunkTo);
    Boolean hasTerritoryAccessTo = accessTo.hasTerritoryAccess(uplayer);
   
    if (!MUtil.equals(hasTerritoryAccessFrom, hasTerritoryAccessTo))
    {
      if (hasTerritoryAccessTo == null)
      {
        uplayer.msg("<i>You have standard access to this area.");
      }
      else if (hasTerritoryAccessTo)
      {
        uplayer.msg("<g>You have elevated access to this area.");
      }
      else
      {
        uplayer.msg("<b>You have decreased access to this area.");
      }
    }
  }
 
  // -------------------------------------------- //
  // CHUNK CHANGE: AUTO CLAIM
  // -------------------------------------------- //
 
  public void chunkChangeAutoClaim(UPlayer uplayer, PS chunkTo)
  {
    // If the player is auto claiming ...
    Faction autoClaimFaction = uplayer.getAutoClaimFaction();
    if (autoClaimFaction == null) return;
   
    // ... try claim.
    uplayer.tryClaim(autoClaimFaction, chunkTo, true, true);
  }
 
  // -------------------------------------------- //
  // POWER LOSS ON DEATH
  // -------------------------------------------- //
 
  @EventHandler(priority = EventPriority.NORMAL)
  public void powerLossOnDeath(PlayerDeathEvent event)
  {
    // If a player dies ...
    Player player = event.getEntity();
   
    // Check Disabled
    if (UConf.isDisabled(player)) return;
   
    UPlayer uplayer = UPlayer.get(player);
   
    // ... and powerloss can happen here ...
    Faction faction = BoardColls.get().getFactionAt(PS.valueOf(player));
   
    if (!faction.getFlag(FFlag.POWERLOSS))
    {
      uplayer.msg("<i>You didn't lose any power since the territory you died in works that way.");
      return;
    }
   
    if (MConf.get().worldsNoPowerLoss.contains(player.getWorld().getName()))
    {
      uplayer.msg("<i>You didn't lose any power due to the world you died in.");
      return;
    }
   
    // ... alter the power ...
    double newPower = uplayer.getPower() + uplayer.getPowerPerDeath();
   
    FactionsEventPowerChange powerChangeEvent = new FactionsEventPowerChange(null, uplayer, PowerChangeReason.DEATH, newPower);
    powerChangeEvent.run();
    if (powerChangeEvent.isCancelled()) return;
    newPower = powerChangeEvent.getNewPower();
   
    uplayer.setPower(newPower);
   
    // ... and inform the player.
    // TODO: A progress bar here would be epic :)
    uplayer.msg("<i>Your power is now <h>%.2f / %.2f", newPower, uplayer.getPowerMax());
  }
 
  // -------------------------------------------- //
  // CAN COMBAT DAMAGE HAPPEN
  // -------------------------------------------- //
 
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void canCombatDamageHappen(EntityDamageEvent event)
  {
    // TODO: Can't we just listen to the class type the sub is of?
    if (!(event instanceof EntityDamageByEntityEvent)) return;
    EntityDamageByEntityEvent sub = (EntityDamageByEntityEvent)event;
   
    if (this.canCombatDamageHappen(sub, true)) return;
    event.setCancelled(true);
  }

  // mainly for flaming arrows; don't want allies or people in safe zones to be ignited even after damage event is cancelled
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void canCombatDamageHappen(EntityCombustByEntityEvent event)
  {
    EntityDamageByEntityEvent sub = new EntityDamageByEntityEvent(event.getCombuster(), event.getEntity(), EntityDamageEvent.DamageCause.FIRE, 0D);
    if (this.canCombatDamageHappen(sub, false)) return;
    event.setCancelled(true);
  }

  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void canCombatDamageHappen(PotionSplashEvent event)
  {
    // If a harmful potion is splashing ...
    if (!MUtil.isHarmfulPotion(event.getPotion())) return;
   
    Entity thrower = event.getPotion().getShooter();

    // ... scan through affected entities to make sure they're all valid targets.
    for (LivingEntity affectedEntity : event.getAffectedEntities())
    {
      EntityDamageByEntityEvent sub = new EntityDamageByEntityEvent(thrower, affectedEntity, EntityDamageEvent.DamageCause.CUSTOM, 0D);
      if (this.canCombatDamageHappen(sub, true)) continue;
     
      // affected entity list doesn't accept modification (iter.remove() is a no-go), but this works
      event.setIntensity(affectedEntity, 0.0);
    }
  }

  public boolean canCombatDamageHappen(EntityDamageByEntityEvent event, boolean notify)
  { 
    // If the defender is a player ...
    Entity edefender = event.getEntity();
    if (!(edefender instanceof Player)) return true;
    Player defender = (Player)edefender;
    UPlayer fdefender = UPlayer.get(edefender);
   
    // Check Disabled
    if (UConf.isDisabled(defender)) return true;
   
    // ... and the attacker is someone else ...
    Entity eattacker = event.getDamager();
    if (eattacker instanceof Projectile)
    {
      eattacker = ((Projectile)eattacker).getShooter();
    }
    if (eattacker.equals(edefender)) return true;
   
    // ... gather defender PS and faction information ...
    PS defenderPs = PS.valueOf(defender);
    Faction defenderPsFaction = BoardColls.get().getFactionAt(defenderPs);
   
    // ... PVP flag may cause a damage block ...
    if (defenderPsFaction.getFlag(FFlag.PVP) == false)
    {
      if (eattacker instanceof Player)
      {
        if (notify)
        {
          UPlayer attacker = UPlayer.get(eattacker);
          attacker.msg("<i>PVP is disabled in %s.", defenderPsFaction.describeTo(attacker));
        }
        return false;
      }
      return defenderPsFaction.getFlag(FFlag.MONSTERS);
    }

    // ... and if the attacker is a player ...
    if (!(eattacker instanceof Player)) return true;
    Player attacker = (Player)eattacker;
    UPlayer fattacker = UPlayer.get(attacker);
   
    // ... does this player bypass all protection? ...
    if (MConf.get().playersWhoBypassAllProtection.contains(attacker.getName())) return true;

    // ... gather attacker PS and faction information ...
    PS attackerPs = PS.valueOf(attacker);
    Faction attackerPsFaction = BoardColls.get().getFactionAt(attackerPs);

    // ... PVP flag may cause a damage block ...
    // (just checking the defender as above isn't enough. What about the attacker? It could be in a no-pvp area)
    // NOTE: This check is probably not that important but we could keep it anyways.
    if (attackerPsFaction.getFlag(FFlag.PVP) == false)
    {
      if (notify) fattacker.msg("<i>PVP is disabled in %s.", attackerPsFaction.describeTo(fattacker));
      return false;
    }

    // ... are PVP rules completely ignored in this world? ...
    if (MConf.get().worldsIgnorePvP.contains(defenderPs.getWorld())) return true;

    Faction defendFaction = fdefender.getFaction();
    Faction attackFaction = fattacker.getFaction();
    UConf uconf = UConf.get(attackFaction);

    if (attackFaction.isNone() && uconf.disablePVPForFactionlessPlayers)
    {
      if (notify) fattacker.msg("<i>You can't hurt other players until you join a faction.");
      return false;
    }
    else if (defendFaction.isNone())
    {
      if (defenderPsFaction == attackFaction && uconf.enablePVPAgainstFactionlessInAttackersLand)
      {
        // Allow PVP vs. Factionless in attacker's faction territory
        return true;
      }
      else if (uconf.disablePVPForFactionlessPlayers)
      {
        if (notify) fattacker.msg("<i>You can't hurt players who are not currently in a faction.");
        return false;
      }
    }

    Rel relation = defendFaction.getRelationTo(attackFaction);

    // Check the relation
    if (fdefender.hasFaction() && relation.isFriend() && defenderPsFaction.getFlag(FFlag.FRIENDLYFIRE) == false)
    {
      if (notify) fattacker.msg("<i>You can't hurt %s<i>.", relation.getDescPlayerMany());
      return false;
    }

    // You can not hurt neutrals in their own territory.
    boolean ownTerritory = fdefender.isInOwnTerritory();
    if (fdefender.hasFaction() && ownTerritory && relation == Rel.NEUTRAL)
    {
      if (notify)
      {
        fattacker.msg("<i>You can't hurt %s<i> in their own territory unless you declare them as an enemy.", fdefender.describeTo(fattacker));
        fdefender.msg("%s<i> tried to hurt you.", fattacker.describeTo(fdefender, true));
      }
      return false;
    }

    // Damage will be dealt. However check if the damage should be reduced.
    double damage = event.getDamage();
    if (damage > 0.0 && fdefender.hasFaction() && ownTerritory && uconf.territoryShieldFactor > 0)
    {
      int newDamage = (int)Math.ceil(damage * (1D - uconf.territoryShieldFactor));
      event.setDamage(newDamage);

      // Send message
      if (notify)
      {
        String perc = MessageFormat.format("{0,number,#%}", (uconf.territoryShieldFactor)); // TODO does this display correctly??
        fdefender.msg("<i>Enemy damage reduced by <rose>%s<i>.", perc);
      }
    }

    return true;
  }
 
  // -------------------------------------------- //
  // REMOVE PLAYER DATA WHEN BANNED
  // -------------------------------------------- //

  @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
  public void onPlayerKick(PlayerKickEvent event)
  {
    // If a player was kicked from the server ...
    Player player = event.getPlayer();

    // ... and if the if player was banned (not just kicked) ...
    if (!event.getReason().equals("Banned by admin.")) return;
   
    // ... and we remove player data when banned ...
    if (!MConf.get().removePlayerDataWhenBanned) return;
   
    // ... get rid of their stored info.
    for (UPlayerColl coll : UPlayerColls.get().getColls())
    {
      UPlayer uplayer = coll.get(player, false);
      if (uplayer == null) continue;
     
      if (uplayer.getRole() == Rel.LEADER)
      {
        uplayer.getFaction().promoteNewLeader();
      }
      uplayer.leave();
      uplayer.detach();
    }
  }
 
  // -------------------------------------------- //
  // VISUALIZE UTIL
  // -------------------------------------------- //
 
  @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
  public void onPlayerMoveClearVisualizations(PlayerMoveEvent event)
  {
    if (MUtil.isSameBlock(event)) return;
   
    VisualizeUtil.clear(event.getPlayer());
  }
 
  // -------------------------------------------- //
  // DENY COMMANDS
  // -------------------------------------------- //
 
  @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true)
  public void denyCommands(PlayerCommandPreprocessEvent event)
  {
    // If a player is trying to run a command ...
    Player player = event.getPlayer();
   
    // Check Disabled
    if (UConf.isDisabled(player)) return;
   
    UPlayer uplayer = UPlayer.get(player);
   
    // ... and the player does not have adminmode ...
    if (uplayer.isUsingAdminMode()) return;
   
    // ... clean up the command ...
    String command = event.getMessage();
    command = Txt.removeLeadingCommandDust(command);
    command = command.toLowerCase();
    command = command.trim();
   
    // ... the command may be denied for members of permanent factions ...
    if (uplayer.hasFaction() && uplayer.getFaction().getFlag(FFlag.PERMANENT) && containsCommand(command, UConf.get(player).denyCommandsPermanentFactionMember))
    {
      uplayer.msg("<b>You can't use \"<h>/%s<b>\" as member of a permanent faction.", command);
      event.setCancelled(true);
      return;
    }
   
    // ... if there is a faction at the players location ...
    PS ps = PS.valueOf(player).getChunk(true);
    Faction factionAtPs = BoardColls.get().getFactionAt(ps);
    if (factionAtPs.isNone()) return;
   
    // ... the command may be denied in the territory of this relation type ...
    Rel rel = factionAtPs.getRelationTo(uplayer);
   
    List<String> deniedCommands = UConf.get(player).denyCommandsTerritoryRelation.get(rel);
    if (deniedCommands == null) return;
    if (!containsCommand(command, deniedCommands)) return;
   
    uplayer.msg("<b>You can't use \"<h>/%s<b>\" in %s territory.", Txt.getNicedEnum(rel), command);
    event.setCancelled(true);
  }

  private static boolean containsCommand(String needle, Collection<String> haystack)
  {
    if (needle == null) return false;
    needle = Txt.removeLeadingCommandDust(needle);
    needle = needle.toLowerCase();
   
    for (String straw : haystack)
    {
      if (straw == null) continue;
      straw = Txt.removeLeadingCommandDust(straw);
      straw = straw.toLowerCase();
     
      if (needle.startsWith(straw)) return true;
    }
   
    return false;
  }
 
  // -------------------------------------------- //
  // FLAG: MONSTERS
  // -------------------------------------------- //
 
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockMonsters(CreatureSpawnEvent event)
  {
    // If a monster is spawning ...
    if ( ! Const.ENTITY_TYPES_MONSTERS.contains(event.getEntityType())) return;
   
    // Check Disabled
    if (UConf.isDisabled(event.getLocation())) return;
   
    // ... at a place where monsters are forbidden ...
    PS ps = PS.valueOf(event.getLocation());
    Faction faction = BoardColls.get().getFactionAt(ps);
    if (faction.getFlag(FFlag.MONSTERS)) return;
   
    // ... block the spawn.
    event.setCancelled(true);
  }

  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockMonsters(EntityTargetEvent event)
  {
    // If a monster ...
    if ( ! Const.ENTITY_TYPES_MONSTERS.contains(event.getEntityType())) return;
   
    // ... is targeting something ...
    Entity target = event.getTarget();
    if (target == null) return;
   
    // Check Disabled
    if (UConf.isDisabled(target)) return;
   
    // ... at a place where monsters are forbidden ...
    PS ps = PS.valueOf(target);
    Faction faction = BoardColls.get().getFactionAt(ps);
    if (faction.getFlag(FFlag.MONSTERS)) return;
   
    // ... then if ghast target nothing ...
    if (event.getEntityType() == EntityType.GHAST)
    {
      event.setTarget(null);
      return;
    }
   
    // ... otherwise simply cancel.
    event.setCancelled(true);
  }
 
  // -------------------------------------------- //
  // FLAG: EXPLOSIONS
  // -------------------------------------------- //
 
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockExplosion(HangingBreakEvent event)
  {
    // If a hanging entity was broken by an explosion ...
    if (event.getCause() != RemoveCause.EXPLOSION) return;
    Entity entity = event.getEntity();
   
    // Check Disabled
    if (UConf.isDisabled(entity)) return;
 
    // ... and the faction there has explosions disabled ...
    Faction faction = BoardColls.get().getFactionAt(PS.valueOf(entity));
    if (faction.getFlag(FFlag.EXPLOSIONS)) return;
   
    // ... then cancel.
    event.setCancelled(true);
  }
 
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockExplosion(EntityExplodeEvent event)
  {
    // If an explosion occurs at a location ...
    Location location = event.getLocation();
   
    // Check Disabled
    if (UConf.isDisabled(location)) return;
   
    // Check the entity. Are explosions disabled there?
    if (BoardColls.get().getFactionAt(PS.valueOf(location)).getFlag(FFlag.EXPLOSIONS) == false)
    {
      event.setCancelled(true);
      return;
    }
   
    // Individually check the flag state for each block
    Iterator<Block> iter = event.blockList().iterator();
    while (iter.hasNext())
    {
      Block block = iter.next();
      Faction faction = BoardColls.get().getFactionAt(PS.valueOf(block));
      if (faction.getFlag(FFlag.EXPLOSIONS) == false) iter.remove();
    }
  }
 
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockExplosion(EntityChangeBlockEvent event)
  {
    // If a wither is changing a block ...
    Entity entity = event.getEntity();
    if (!(entity instanceof Wither)) return;
   
    // Check Disabled
    if (UConf.isDisabled(entity)) return;

    // ... and the faction there has explosions disabled ...
    PS ps = PS.valueOf(event.getBlock());
    Faction faction = BoardColls.get().getFactionAt(ps);
    if (faction.getFlag(FFlag.EXPLOSIONS)) return;
   
    // ... stop the block alteration.
    event.setCancelled(true);
  }
 
  // -------------------------------------------- //
  // FLAG: ENDERGRIEF
  // -------------------------------------------- //
 
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockEndergrief(EntityChangeBlockEvent event)
  {
    // If an enderman is changing a block ...
    Entity entity = event.getEntity();
    if (!(entity instanceof Enderman)) return;
   
    // Check Disabled
    if (UConf.isDisabled(entity)) return;
   
    // ... and the faction there has endergrief disabled ...
    PS ps = PS.valueOf(event.getBlock());
    Faction faction = BoardColls.get().getFactionAt(ps);
    if (faction.getFlag(FFlag.ENDERGRIEF)) return;
   
    // ... stop the block alteration.
    event.setCancelled(true);
  }

  // -------------------------------------------- //
  // FLAG: FIRE SPREAD
  // -------------------------------------------- //
 
  public void blockFireSpread(Block block, Cancellable cancellable)
  {
    // Check Disabled
    if (UConf.isDisabled(block)) return;
   
    // If the faction at the block has firespread disabled ...
    PS ps = PS.valueOf(block);
    Faction faction = BoardColls.get().getFactionAt(ps);
     
    if (faction.getFlag(FFlag.FIRESPREAD)) return;
   
    // then cancel the event.
    cancellable.setCancelled(true);
  }
 
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockFireSpread(BlockIgniteEvent event)
  {
    // If fire is spreading ...
    if (event.getCause() != IgniteCause.SPREAD && event.getCause() != IgniteCause.LAVA) return;
   
    // ... consider blocking it.
    blockFireSpread(event.getBlock(), event);
  }
 
  // TODO: Is use of this event deprecated?
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockFireSpread(BlockSpreadEvent event)
  {
    // If fire is spreading ...
    if (event.getNewState().getTypeId() != 51) return;
   
    // ... consider blocking it.
    blockFireSpread(event.getBlock(), event);
  }
 
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockFireSpread(BlockBurnEvent event)
  {
    // If a block is burning ...
   
    // ... consider blocking it.
    blockFireSpread(event.getBlock(), event);
  }
 
  // -------------------------------------------- //
  // FLAG: BUILD
  // -------------------------------------------- //

  public static boolean canPlayerBuildAt(Player player, PS ps, boolean verboose)
  {
    String name = player.getName();
    if (MConf.get().playersWhoBypassAllProtection.contains(name)) return true;

    UPlayer uplayer = UPlayer.get(player);
    if (uplayer.isUsingAdminMode()) return true;

    if (!FPerm.BUILD.has(uplayer, ps, false) && FPerm.PAINBUILD.has(uplayer, ps, false))
    {
      if (verboose)
      {
        Faction hostFaction = BoardColls.get().getFactionAt(ps);
        uplayer.msg("<b>It is painful to build in the territory of %s<b>.", hostFaction.describeTo(uplayer));
        player.damage(UConf.get(player).actionDeniedPainAmount);
      }
      return true;
    }
   
    return FPerm.BUILD.has(uplayer, ps, verboose);
  }
 
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockBuild(HangingPlaceEvent event)
  {
    if (canPlayerBuildAt(event.getPlayer(), PS.valueOf(event.getEntity()), true)) return;
   
    event.setCancelled(true);
  }
 
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockBuild(HangingBreakEvent event)
  {
    if (! (event instanceof HangingBreakByEntityEvent)) return;
    HangingBreakByEntityEvent entityEvent = (HangingBreakByEntityEvent)event;
   
    Entity breaker = entityEvent.getRemover();
    if (! (breaker instanceof Player)) return;

    if ( ! canPlayerBuildAt((Player)breaker, PS.valueOf(event.getEntity()), true))
    {
      event.setCancelled(true);
    }
  }
 
  @EventHandler(priority = EventPriority.NORMAL)
  public void blockBuild(BlockPlaceEvent event)
  {
    if (!event.canBuild()) return;

    if (canPlayerBuildAt(event.getPlayer(), PS.valueOf(event.getBlock()), true)) return;
   
    event.setBuild(false);
    event.setCancelled(true);
  }

  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockBuild(BlockBreakEvent event)
  {
    if (canPlayerBuildAt(event.getPlayer(), PS.valueOf(event.getBlock()), true)) return;
   
    event.setCancelled(true);
  }

  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockBuild(BlockDamageEvent event)
  {
    if (!event.getInstaBreak()) return;

    if (canPlayerBuildAt(event.getPlayer(), PS.valueOf(event.getBlock()), true)) return;
   
    event.setCancelled(true);
  }

  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockBuild(BlockPistonExtendEvent event)
  {
    Block block = event.getBlock();

    Faction pistonFaction = BoardColls.get().getFactionAt(PS.valueOf(block));

    // target end-of-the-line empty (air) block which is being pushed into, including if piston itself would extend into air
    Block targetBlock = block.getRelative(event.getDirection(), event.getLength() + 1);

    // members of faction might not have build rights in their own territory, but pistons should still work regardless; so, address that corner case
    Faction targetFaction = BoardColls.get().getFactionAt(PS.valueOf(targetBlock));
    if (targetFaction == pistonFaction) return;

    // if potentially pushing into air/water/lava in another territory, we need to check it out
    if ((targetBlock.isEmpty() || targetBlock.isLiquid()) && ! FPerm.BUILD.has(pistonFaction, targetFaction))
    {
      event.setCancelled(true);
    }

    /*
     * note that I originally was testing the territory of each affected block, but since I found that pistons can only push
     * up to 12 blocks and the width of any territory is 16 blocks, it should be safe (and much more lightweight) to test
     * only the final target block as done above
     */
  }

  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void blockBuild(BlockPistonRetractEvent event)
  { 
    // if not a sticky piston, retraction should be fine
    if (!event.isSticky()) return;

    Block retractBlock = event.getRetractLocation().getBlock();
    PS retractPs = PS.valueOf(retractBlock);

    // if potentially retracted block is just air/water/lava, no worries
    if (retractBlock.isEmpty() || retractBlock.isLiquid()) return;

    Faction pistonFaction = BoardColls.get().getFactionAt(PS.valueOf(event.getBlock()));

    // members of faction might not have build rights in their own territory, but pistons should still work regardless; so, address that corner case
    Faction targetFaction = BoardColls.get().getFactionAt(retractPs);
    if (targetFaction == pistonFaction) return;

    if (!FPerm.BUILD.has(pistonFaction, targetFaction))
    {
      event.setCancelled(true);
    }
  }
 
  // -------------------------------------------- //
  // ASSORTED BUILD AND INTERACT
  // -------------------------------------------- //
 
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void onPlayerInteract(PlayerInteractEvent event)
  {
    // only need to check right-clicks and physical as of MC 1.4+; good performance boost
    if (event.getAction() != Action.RIGHT_CLICK_BLOCK && event.getAction() != Action.PHYSICAL) return;

    Block block = event.getClickedBlock();
    Player player = event.getPlayer();

    if (block == null) return// clicked in air, apparently

    if ( ! canPlayerUseBlock(player, block, false))
    {
      event.setCancelled(true);
      return;
    }

    if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return// only interested on right-clicks for below

    if ( ! playerCanUseItemHere(player, PS.valueOf(block), event.getMaterial(), false))
    {
      event.setCancelled(true);
      return;
    }
  }

  // TODO: Refactor ! justCheck    -> to informIfNot
  // TODO: Possibly incorporate pain build...
  public static boolean playerCanUseItemHere(Player player, PS ps, Material material, boolean justCheck)
  {
    if (!Const.MATERIALS_EDIT_TOOLS.contains(material)) return true;
   
    String name = player.getName();
    if (MConf.get().playersWhoBypassAllProtection.contains(name)) return true;

    UPlayer uplayer = UPlayer.get(player);
    if (uplayer.isUsingAdminMode()) return true;
   
    return FPerm.BUILD.has(uplayer, ps, !justCheck);
  }
 
  public static boolean canPlayerUseBlock(Player player, Block block, boolean justCheck)
  {
    String name = player.getName();
    if (MConf.get().playersWhoBypassAllProtection.contains(name)) return true;

    UPlayer me = UPlayer.get(player);
    if (me.isUsingAdminMode()) return true;
   
    PS ps = PS.valueOf(block);
    Material material = block.getType();
   
    if (Const.MATERIALS_EDIT_ON_INTERACT.contains(material) && ! FPerm.BUILD.has(me, ps, ! justCheck)) return false;
    if (Const.MATERIALS_CONTAINER.contains(material) && ! FPerm.CONTAINER.has(me, ps, ! justCheck)) return false;
    if (Const.MATERIALS_DOOR.contains(material) && ! FPerm.DOOR.has(me, ps, ! justCheck)) return false;
    if (material == Material.STONE_BUTTON && ! FPerm.BUTTON.has(me, ps, ! justCheck)) return false;
    if (material == Material.LEVER && ! FPerm.LEVER.has(me, ps, ! justCheck)) return false;
    return true;
  }

  // For some reason onPlayerInteract() sometimes misses bucket events depending on distance (something like 2-3 blocks away isn't detected),
  // but these separate bucket events below always fire without fail
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event)
  {
    Block block = event.getBlockClicked();
    Player player = event.getPlayer();
   
    if (playerCanUseItemHere(player, PS.valueOf(block), event.getBucket(), false)) return;
   
    event.setCancelled(true);
  }
 
  @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
  public void onPlayerBucketFill(PlayerBucketFillEvent event)
  {
    Block block = event.getBlockClicked();
    Player player = event.getPlayer();

    if (playerCanUseItemHere(player, PS.valueOf(block), event.getBucket(), false)) return;
   
    event.setCancelled(true);
  }
 
}
TOP

Related Classes of com.massivecraft.factions.listeners.FactionsListenerMain

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.