001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.bukkit.listener; 020 021import com.plotsquared.bukkit.util.BukkitEntityUtil; 022import com.plotsquared.bukkit.util.BukkitUtil; 023import com.plotsquared.core.PlotSquared; 024import com.plotsquared.core.configuration.Settings; 025import com.plotsquared.core.location.Location; 026import com.plotsquared.core.plot.Plot; 027import com.plotsquared.core.plot.PlotArea; 028import com.plotsquared.core.plot.flag.implementations.DoneFlag; 029import io.papermc.lib.PaperLib; 030import org.bukkit.Chunk; 031import org.bukkit.World; 032import org.bukkit.block.Block; 033import org.bukkit.entity.ArmorStand; 034import org.bukkit.entity.EnderCrystal; 035import org.bukkit.entity.Entity; 036import org.bukkit.entity.EntityType; 037import org.bukkit.entity.Item; 038import org.bukkit.entity.Vehicle; 039import org.bukkit.event.EventHandler; 040import org.bukkit.event.EventPriority; 041import org.bukkit.event.Listener; 042import org.bukkit.event.entity.CreatureSpawnEvent; 043import org.bukkit.event.entity.EntitySpawnEvent; 044import org.bukkit.event.entity.EntityTeleportEvent; 045import org.bukkit.event.vehicle.VehicleBlockCollisionEvent; 046import org.bukkit.event.vehicle.VehicleCreateEvent; 047import org.bukkit.event.vehicle.VehicleMoveEvent; 048import org.bukkit.event.vehicle.VehicleUpdateEvent; 049import org.bukkit.event.world.ChunkLoadEvent; 050import org.bukkit.metadata.FixedMetadataValue; 051import org.bukkit.metadata.MetadataValue; 052import org.bukkit.plugin.Plugin; 053import org.checkerframework.checker.nullness.qual.NonNull; 054 055import java.util.List; 056 057public class EntitySpawnListener implements Listener { 058 059 private static final String KEY = "P2"; 060 private static boolean ignoreTP = false; 061 private static boolean hasPlotArea = false; 062 private static String areaName = null; 063 064 public static void testNether(final Entity entity) { 065 @NonNull World world = entity.getWorld(); 066 if (world.getEnvironment() != World.Environment.NETHER && world.getEnvironment() != World.Environment.THE_END) { 067 return; 068 } 069 test(entity); 070 } 071 072 public static void testCreate(final Entity entity) { 073 @NonNull World world = entity.getWorld(); 074 if (!world.getName().equals(areaName)) { 075 areaName = world.getName(); 076 hasPlotArea = PlotSquared.get().getPlotAreaManager().hasPlotArea(areaName); 077 } 078 if (!hasPlotArea) { 079 return; 080 } 081 test(entity); 082 } 083 084 public static void test(Entity entity) { 085 @NonNull World world = entity.getWorld(); 086 List<MetadataValue> meta = entity.getMetadata(KEY); 087 if (meta.isEmpty()) { 088 if (PlotSquared.get().getPlotAreaManager().hasPlotArea(world.getName())) { 089 entity.setMetadata(KEY, new FixedMetadataValue((Plugin) PlotSquared.platform(), entity.getLocation())); 090 } 091 } else { 092 org.bukkit.Location origin = (org.bukkit.Location) meta.get(0).value(); 093 World originWorld = origin.getWorld(); 094 if (!originWorld.equals(world)) { 095 if (!ignoreTP) { 096 if (!world.getName().equalsIgnoreCase(originWorld + "_the_end")) { 097 if (entity.getType() == EntityType.PLAYER) { 098 return; 099 } 100 try { 101 ignoreTP = true; 102 PaperLib.teleportAsync(entity, origin); 103 } finally { 104 ignoreTP = false; 105 } 106 if (entity.getLocation().getWorld().equals(world)) { 107 entity.remove(); 108 } 109 } 110 } else { 111 if (entity.getType() == EntityType.PLAYER) { 112 return; 113 } 114 entity.remove(); 115 } 116 } 117 } 118 } 119 120 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 121 public void creatureSpawnEvent(EntitySpawnEvent event) { 122 Entity entity = event.getEntity(); 123 Location location = BukkitUtil.adapt(entity.getLocation()); 124 PlotArea area = location.getPlotArea(); 125 if (!location.isPlotArea() || area == null) { 126 return; 127 } 128 if (PaperLib.isPaper()) { 129 //noinspection ConstantValue - getEntitySpawnReason annotated as NotNull, but is not NotNull. lol. 130 if (area.isSpawnCustom() && entity.getEntitySpawnReason() != null && "CUSTOM".equals(entity.getEntitySpawnReason().name())) { 131 return; 132 } 133 } 134 Plot plot = location.getOwnedPlotAbs(); 135 EntityType type = entity.getType(); 136 if (plot == null) { 137 if (entity instanceof Item) { 138 if (Settings.Enabled_Components.KILL_ROAD_ITEMS) { 139 event.setCancelled(true); 140 } 141 return; 142 } 143 if (!area.isMobSpawning()) { 144 if (type == EntityType.PLAYER) { 145 return; 146 } 147 if (type.isAlive()) { 148 event.setCancelled(true); 149 } 150 } 151 if (!area.isMiscSpawnUnowned() && !type.isAlive()) { 152 event.setCancelled(true); 153 } 154 return; 155 } 156 if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { 157 event.setCancelled(true); 158 } 159 if (entity instanceof EnderCrystal || type == EntityType.ARMOR_STAND) { 160 if (BukkitEntityUtil.checkEntity(entity, plot)) { 161 event.setCancelled(true); 162 } 163 return; 164 } 165 if (type == EntityType.SHULKER) { 166 if (!entity.hasMetadata("shulkerPlot")) { 167 entity.setMetadata("shulkerPlot", new FixedMetadataValue((Plugin) PlotSquared.platform(), plot.getId())); 168 } 169 } 170 } 171 172 @EventHandler 173 public void onChunkLoad(ChunkLoadEvent event) { 174 @NonNull Chunk chunk = event.getChunk(); 175 for (final Entity entity : chunk.getEntities()) { 176 testCreate(entity); 177 } 178 } 179 180 @EventHandler 181 public void onVehicle(VehicleUpdateEvent event) { 182 testNether(event.getVehicle()); 183 } 184 185 @EventHandler 186 public void onVehicle(VehicleCreateEvent event) { 187 testCreate(event.getVehicle()); 188 } 189 190 @EventHandler 191 public void onVehicle(VehicleBlockCollisionEvent event) { 192 testNether(event.getVehicle()); 193 } 194 195 @EventHandler 196 public void onTeleport(EntityTeleportEvent event) { 197 Entity entity = event.getEntity(); 198 Entity fromLocation = event.getEntity(); 199 Block toLocation = event.getTo().getBlock(); 200 final Location fromLocLocation = BukkitUtil.adapt(fromLocation.getLocation()); 201 final PlotArea fromArea = fromLocLocation.getPlotArea(); 202 Location toLocLocation = BukkitUtil.adapt(toLocation.getLocation()); 203 PlotArea toArea = toLocLocation.getPlotArea(); 204 205 if (toArea == null) { 206 if (fromLocation.getType() == EntityType.SHULKER && fromArea != null) { 207 event.setCancelled(true); 208 } 209 return; 210 } 211 Plot toPlot = toArea.getOwnedPlot(toLocLocation); 212 if (fromLocation.getType() == EntityType.SHULKER && fromArea != null) { 213 final Plot fromPlot = fromArea.getOwnedPlot(fromLocLocation); 214 215 if (fromPlot != null || toPlot != null) { 216 if ((fromPlot == null || !fromPlot.equals(toPlot)) && (toPlot == null || !toPlot.equals(fromPlot))) { 217 event.setCancelled(true); 218 return; 219 } 220 } 221 } 222 if (entity instanceof Vehicle || entity instanceof ArmorStand) { 223 testNether(event.getEntity()); 224 } 225 } 226 227 @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) 228 public void vehicleMove(VehicleMoveEvent event) { 229 testNether(event.getVehicle()); 230 } 231 232 @EventHandler 233 public void spawn(CreatureSpawnEvent event) { 234 if (event.getEntityType() == EntityType.ARMOR_STAND) { 235 testCreate(event.getEntity()); 236 } 237 } 238 239}