gt:                         plot.debug(player.getName() + " could not attack " + entityType
context: /*
   *       _____  _       _    _____                                _
   *      |  __ \| |     | |  / ____|                              | |
   *      | |__) | | ___ | |_| (___   __ _ _   _  __ _ _ __ ___  __| |
   *      |  ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
   *      | |    | | (_) | |_ ____) | (_| | |_| | (_| | | |  __/ (_| |
   *      |_|    |_|\___/ \__|_____/ \__, |\__,_|\__,_|_|  \___|\__,_|
   *                                    | |
   *                                    |_|
   *            PlotSquared plot management system for Minecraft
   *                  Copyright (C) 2021 IntellectualSites
   *
   *     This program is free software: you can redistribute it and/or modify
   *     it under the terms of the GNU General Public License as published by
   *     the Free Software Foundation, either version 3 of the License, or
   *     (at your option) any later version.
   *
   *     This program is distributed in the hope that it will be useful,
   *     but WITHOUT ANY WARRANTY; without even the implied warranty of
   *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *     GNU General Public License for more details.
   *
   *     You should have received a copy of the GNU General Public License
   *     along with this program.  If not, see <https://www.gnu.org/licenses/>.
   */
  package com.plotsquared.bukkit.util;
  
  import com.plotsquared.bukkit.player.BukkitPlayer;
  import com.plotsquared.core.configuration.Settings;
  import com.plotsquared.core.configuration.caption.TranslatableCaption;
  import com.plotsquared.core.location.Location;
  import com.plotsquared.core.permissions.Permission;
  import com.plotsquared.core.plot.Plot;
  import com.plotsquared.core.plot.PlotArea;
  import com.plotsquared.core.plot.flag.implementations.AnimalAttackFlag;
  import com.plotsquared.core.plot.flag.implementations.AnimalCapFlag;
  import com.plotsquared.core.plot.flag.implementations.DoneFlag;
  import com.plotsquared.core.plot.flag.implementations.EntityCapFlag;
  import com.plotsquared.core.plot.flag.implementations.HangingBreakFlag;
  import com.plotsquared.core.plot.flag.implementations.HostileAttackFlag;
  import com.plotsquared.core.plot.flag.implementations.HostileCapFlag;
  import com.plotsquared.core.plot.flag.implementations.MiscBreakFlag;
  import com.plotsquared.core.plot.flag.implementations.MiscCapFlag;
  import com.plotsquared.core.plot.flag.implementations.MobCapFlag;
  import com.plotsquared.core.plot.flag.implementations.PveFlag;
  import com.plotsquared.core.plot.flag.implementations.PvpFlag;
  import com.plotsquared.core.plot.flag.implementations.TamedAttackFlag;
  import com.plotsquared.core.plot.flag.implementations.VehicleCapFlag;
  import com.plotsquared.core.util.EntityUtil;
  import com.plotsquared.core.util.Permissions;
  import com.plotsquared.core.util.entity.EntityCategories;
  import com.sk89q.worldedit.bukkit.BukkitAdapter;
  import net.kyori.adventure.text.minimessage.placeholder.Placeholder;
  import org.bukkit.entity.Arrow;
  import org.bukkit.entity.Creature;
  import org.bukkit.entity.Entity;
  import org.bukkit.entity.EntityType;
  import org.bukkit.entity.Player;
  import org.bukkit.entity.Projectile;
  import org.bukkit.event.entity.EntityDamageEvent;
  import org.bukkit.projectiles.BlockProjectileSource;
  import org.bukkit.projectiles.ProjectileSource;
  
  import java.util.Objects;
  
  public class BukkitEntityUtil {
  
      public static final com.sk89q.worldedit.world.entity.EntityType FAKE_ENTITY_TYPE =
              new com.sk89q.worldedit.world.entity.EntityType("plotsquared:fake");
  
      public static boolean entityDamage(Entity damager, Entity victim) {
          return entityDamage(damager, victim, null);
      }
  
      public static boolean entityDamage(Entity damager, Entity victim, EntityDamageEvent.DamageCause cause) {
          Location dloc = BukkitUtil.adapt(damager.getLocation());
          Location vloc = BukkitUtil.adapt(victim.getLocation());
          PlotArea dArea = dloc.getPlotArea();
          PlotArea vArea;
          if (dArea != null && dArea.contains(vloc.getX(), vloc.getZ())) {
              vArea = dArea;
          } else {
              vArea = vloc.getPlotArea();
          }
          if (dArea == null && vArea == null) {
              return true;
          }
  
          Plot dplot;
          if (dArea != null) {
              dplot = dArea.getPlot(dloc);
          } else {
              dplot = null;
          }
          Plot vplot;
          if (vArea != null) {
              vplot = vArea.getPlot(vloc);
          } else {
              vplot = null;
          }
  
          Plot plot;
          String stub;
          boolean isPlot = true;
          if (dplot == null && vplot == null) {
              if (dArea == null) {
                  return true;
              }
              plot = null;
              stub = "road";
              isPlot = false;
          } else {
              // Prioritize plots for close to seamless pvp zones
              if (victim.getTicksLived() > damager.getTicksLived()) {
                  if (dplot == null || !(victim instanceof Player)) {
                      if (vplot == null) {
                          plot = dplot;
                      } else {
                          plot = vplot;
                      }
                  } else {
                      plot = dplot;
                  }
              } else if (dplot == null || !(victim instanceof Player)) {
                  if (vplot == null) {
                      plot = dplot;
                  } else {
                      plot = vplot;
                  }
              } else if (vplot == null) {
                  plot = dplot;
              } else {
                  plot = vplot;
              }
              if (plot.hasOwner()) {
                  stub = "other";
              } else {
                  stub = "unowned";
              }
          }
          boolean roadFlags = vArea != null ? vArea.isRoadFlags() : dArea.isRoadFlags();
          PlotArea area = vArea != null ? vArea : dArea;
  
          Player player;
          if (damager instanceof Player) { // attacker is player
              player = (Player) damager;
          } else if (damager instanceof Projectile projectile) {
              ProjectileSource shooter = projectile.getShooter();
              if (shooter instanceof Player) { // shooter is player
                  player = (Player) shooter;
              } else { // shooter is not player
                  if (shooter instanceof BlockProjectileSource) {
                      Location sLoc = BukkitUtil
                              .adapt(((BlockProjectileSource) shooter).getBlock().getLocation());
                      dplot = dArea.getPlot(sLoc);
                  }
                  player = null;
              }
          } else { // Attacker is not player
              player = null;
          }
          if (player != null) {
              BukkitPlayer plotPlayer = BukkitUtil.adapt(player);
  
              final com.sk89q.worldedit.world.entity.EntityType entityType;
  
              // Create a fake entity type if the type does not have a name
              if (victim.getType().getName() == null) {
                  entityType = FAKE_ENTITY_TYPE;
              } else {
                  entityType = BukkitAdapter.adapt(victim.getType());
              }
  
              if (EntityCategories.HANGING.contains(entityType)) { // hanging
                  if (plot != null && (plot.getFlag(HangingBreakFlag.class) || plot
                          .isAdded(plotPlayer.getUUID()))) {
                      if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) {
                          if (!Permissions
                                  .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_BUILD_OTHER)) {
                              plotPlayer.sendMessage(
                                      TranslatableCaption.miniMessage("done.building_restricted")
                              );
                              return false;
                          }
                      }
                      return true;
                  }
                  if (!Permissions.hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_DESTROY + "." + stub)) {
                      plotPlayer.sendMessage(
                              TranslatableCaption.miniMessage("permission.no_permission_event"),
                              Placeholder.miniMessage("node", Permission.PERMISSION_ADMIN_DESTROY + "." + stub)
                      );
                      return false;
                  }
              } else if (victim.getType() == EntityType.ARMOR_STAND) {
                  if (plot != null && (plot.getFlag(MiscBreakFlag.class) || plot
                          .isAdded(plotPlayer.getUUID()))) {
                      return true;
                  }
                  if (!Permissions.hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_DESTROY + "." + stub)) {
                      plotPlayer.sendMessage(
                              TranslatableCaption.miniMessage("permission.no_permission_event"),
                              Placeholder.miniMessage("node", Permission.PERMISSION_ADMIN_DESTROY + "." + stub)
                      );
                      if (plot != null) {
                          plot.debug(player.getName()
                                  + " could not break armor stand because misc-break = false");
                      }
                      return false;
                  }
              } else if (EntityCategories.HOSTILE.contains(entityType)) {
                  if (isPlot) {
                      if (plot.getFlag(HostileAttackFlag.class) || plot.getFlag(PveFlag.class) || plot
                              .isAdded(plotPlayer.getUUID())) {
                          return true;
                      }
                  } else if (roadFlags && (area.getRoadFlag(HostileAttackFlag.class) || area
                          .getFlag(PveFlag.class))) {
                      return true;
                  }
                  if (!Permissions.hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_PVE + "." + stub)) {
                      plotPlayer.sendMessage(
                              TranslatableCaption.miniMessage("permission.no_permission_event"),
                              Placeholder.miniMessage("node", Permission.PERMISSION_ADMIN_PVE + "." + stub)
                      );
                      if (plot != null) {
                          plot.debug(player.getName() + " could not attack " + entityType
                                  + " because pve = false OR hostile-attack = false");
                      }
                      return false;
                  }
              } else if (EntityCategories.TAMEABLE.contains(entityType)) { // victim is tameable
                  if (isPlot) {
                      if (plot.getFlag(TamedAttackFlag.class) || plot.getFlag(PveFlag.class) || plot
                              .isAdded(plotPlayer.getUUID())) {
                          return true;
                      }
                  } else if (roadFlags && (area.getRoadFlag(TamedAttackFlag.class) || area
                          .getFlag(PveFlag.class))) {
                      return true;
                  }
                  if (!Permissions.hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_PVE + "." + stub)) {
                      plotPlayer.sendMessage(
                              TranslatableCaption.miniMessage("permission.no_permission_event"),
                              Placeholder.miniMessage("node", Permission.PERMISSION_ADMIN_PVE + "." + stub)
                      );
                      if (plot != null) {
                          plot.debug(player.getName() + " could not attack " + entityType
                                  + " because pve = false OR tamed-attack = false");
                      }
                      return false;
                  }
              } else if (EntityCategories.PLAYER.contains(entityType)) {
                  if (isPlot) {
                      if (!plot.getFlag(PvpFlag.class) && !Permissions
                              .hasPermission(plotPlayer, Permission.PERMISSION_ADMIN_PVP + "." + stub)) {
                          plotPlayer.sendMessage(
                                  TranslatableCaption.miniMessage("permission.no_permission_event"),
                                  Placeholder.miniMessage("node", Permission.PERMISSION_ADMIN_PVP + "." + stub)
                          );
  