Citizens2/src/main/java/net/citizensnpcs/EventListen.java

385 lines
15 KiB
Java
Raw Normal View History

2012-01-19 08:38:40 +01:00
package net.citizensnpcs;
2012-09-10 11:58:12 +02:00
import java.util.List;
import java.util.Map;
2012-09-10 11:58:12 +02:00
2012-08-29 15:37:00 +02:00
import net.citizensnpcs.Settings.Setting;
2012-05-17 15:34:03 +02:00
import net.citizensnpcs.api.CitizensAPI;
2013-04-14 08:55:09 +02:00
import net.citizensnpcs.api.event.CommandSenderCreateNPCEvent;
2012-11-21 13:10:21 +01:00
import net.citizensnpcs.api.event.DespawnReason;
import net.citizensnpcs.api.event.EntityTargetNPCEvent;
2012-09-01 12:05:22 +02:00
import net.citizensnpcs.api.event.NPCCombustByBlockEvent;
import net.citizensnpcs.api.event.NPCCombustByEntityEvent;
import net.citizensnpcs.api.event.NPCCombustEvent;
2012-08-15 18:13:46 +02:00
import net.citizensnpcs.api.event.NPCDamageByBlockEvent;
import net.citizensnpcs.api.event.NPCDamageByEntityEvent;
import net.citizensnpcs.api.event.NPCDamageEvent;
import net.citizensnpcs.api.event.NPCDeathEvent;
import net.citizensnpcs.api.event.NPCDespawnEvent;
2012-03-11 07:43:18 +01:00
import net.citizensnpcs.api.event.NPCLeftClickEvent;
import net.citizensnpcs.api.event.NPCRightClickEvent;
2013-04-18 16:03:27 +02:00
import net.citizensnpcs.api.event.PlayerCreateNPCEvent;
2012-01-19 08:38:40 +01:00
import net.citizensnpcs.api.npc.NPC;
2012-05-17 15:34:03 +02:00
import net.citizensnpcs.api.npc.NPCRegistry;
2012-08-29 15:37:00 +02:00
import net.citizensnpcs.api.trait.trait.Owner;
import net.citizensnpcs.api.util.Messaging;
2012-02-27 14:01:38 +01:00
import net.citizensnpcs.editor.Editor;
import net.citizensnpcs.npc.ai.NPCHolder;
import net.citizensnpcs.trait.Controllable;
import net.citizensnpcs.trait.CurrentLocation;
import net.citizensnpcs.util.Messages;
import net.citizensnpcs.util.NMS;
2012-01-19 08:38:40 +01:00
2012-01-23 15:30:15 +01:00
import org.bukkit.Bukkit;
2012-02-19 18:45:43 +01:00
import org.bukkit.Chunk;
2012-01-19 11:52:58 +01:00
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
2012-01-19 08:38:40 +01:00
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
2012-01-19 08:38:40 +01:00
import org.bukkit.event.Listener;
import org.bukkit.event.entity.CreatureSpawnEvent;
2012-09-01 12:05:22 +02:00
import org.bukkit.event.entity.EntityCombustByBlockEvent;
import org.bukkit.event.entity.EntityCombustByEntityEvent;
import org.bukkit.event.entity.EntityCombustEvent;
2012-08-15 18:13:46 +02:00
import org.bukkit.event.entity.EntityDamageByBlockEvent;
2012-01-19 08:38:40 +01:00
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
2012-01-19 08:38:40 +01:00
import org.bukkit.event.entity.EntityTargetEvent;
2012-02-26 07:35:44 +01:00
import org.bukkit.event.player.PlayerChangedWorldEvent;
2012-01-23 15:30:15 +01:00
import org.bukkit.event.player.PlayerInteractEntityEvent;
2012-02-27 14:01:38 +01:00
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.vehicle.VehicleEnterEvent;
2012-01-19 08:38:40 +01:00
import org.bukkit.event.world.ChunkLoadEvent;
import org.bukkit.event.world.ChunkUnloadEvent;
2012-02-26 06:23:43 +01:00
import org.bukkit.event.world.WorldLoadEvent;
import org.bukkit.event.world.WorldUnloadEvent;
2012-01-19 08:38:40 +01:00
2012-03-02 11:59:40 +01:00
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterables;
2012-03-02 11:59:40 +01:00
import com.google.common.collect.ListMultimap;
2012-01-19 08:38:40 +01:00
public class EventListen implements Listener {
private final NPCRegistry npcRegistry = CitizensAPI.getNPCRegistry();
private final Map<String, NPCRegistry> registries;
2013-02-10 15:26:58 +01:00
private final ListMultimap<ChunkCoord, NPC> toRespawn = ArrayListMultimap.create();
EventListen(Map<String, NPCRegistry> registries) {
this.registries = registries;
}
2012-01-22 08:10:25 +01:00
2013-04-18 16:03:27 +02:00
private void checkCreationEvent(CommandSenderCreateNPCEvent event) {
if (event.getCreator().hasPermission("citizens.admin.avoid-limits"))
return;
int limit = Setting.DEFAULT_NPC_LIMIT.asInt();
int maxChecks = Setting.MAX_NPC_LIMIT_CHECKS.asInt();
for (int i = maxChecks; i >= 0; i--) {
if (!event.getCreator().hasPermission("citizens.npc.limit." + i))
continue;
limit = i;
break;
}
if (limit < 0)
return;
int owned = 0;
for (NPC npc : npcRegistry) {
if (!event.getNPC().equals(npc) && npc.hasTrait(Owner.class)
&& npc.getTrait(Owner.class).isOwnedBy(event.getCreator()))
owned++;
}
int wouldOwn = owned + 1;
if (wouldOwn > limit) {
2013-04-18 16:03:27 +02:00
event.setCancelled(true);
event.setCancelReason(Messaging.tr(Messages.OVER_NPC_LIMIT, limit));
}
}
2013-02-10 15:26:58 +01:00
private Iterable<NPC> getAllNPCs() {
return Iterables.<NPC> concat(npcRegistry, Iterables.concat(registries.values()));
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
2012-01-19 12:43:21 +01:00
public void onChunkLoad(ChunkLoadEvent event) {
2013-04-14 08:55:09 +02:00
respawnAllFromCoord(toCoord(event.getChunk()));
2012-01-19 12:43:21 +01:00
}
2012-01-19 08:38:40 +01:00
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
2012-01-19 12:43:21 +01:00
public void onChunkUnload(ChunkUnloadEvent event) {
ChunkCoord coord = toCoord(event.getChunk());
2013-04-14 08:55:09 +02:00
Location loc = new Location(null, 0, 0, 0);
for (NPC npc : getAllNPCs()) {
2012-01-28 21:16:30 +01:00
if (!npc.isSpawned())
2012-02-26 06:23:43 +01:00
continue;
2013-11-05 12:29:18 +01:00
loc = npc.getEntity().getLocation(loc);
2013-04-14 08:55:09 +02:00
boolean sameChunkCoordinates = coord.z == loc.getBlockZ() >> 4 && coord.x == loc.getBlockX() >> 4;
if (!sameChunkCoordinates || !event.getWorld().equals(loc.getWorld()))
continue;
if (!npc.despawn(DespawnReason.CHUNK_UNLOAD)) {
event.setCancelled(true);
Messaging.debug("Cancelled chunk unload at [" + coord.x + "," + coord.z + "]");
respawnAllFromCoord(coord);
return;
2012-01-19 12:43:21 +01:00
}
2013-04-14 08:55:09 +02:00
toRespawn.put(coord, npc);
Messaging.debug("Despawned id", npc.getId(), "due to chunk unload at [" + coord.x + "," + coord.z + "]");
}
}
@EventHandler(ignoreCancelled = true)
public void onCommandSenderCreateNPC(CommandSenderCreateNPCEvent event) {
2013-04-18 16:03:27 +02:00
checkCreationEvent(event);
2012-02-26 06:23:43 +01:00
}
2012-01-23 09:45:34 +01:00
/*
* Entity events
*/
2012-09-01 12:05:22 +02:00
@EventHandler
public void onEntityCombust(EntityCombustEvent event) {
NPC npc = npcRegistry.getNPC(event.getEntity());
if (npc == null)
return;
event.setCancelled(npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true));
2012-09-01 12:05:22 +02:00
if (event instanceof EntityCombustByEntityEvent) {
2012-12-30 13:25:49 +01:00
Bukkit.getPluginManager().callEvent(new NPCCombustByEntityEvent((EntityCombustByEntityEvent) event, npc));
2012-09-01 12:05:22 +02:00
} else if (event instanceof EntityCombustByBlockEvent) {
2012-12-30 13:25:49 +01:00
Bukkit.getPluginManager().callEvent(new NPCCombustByBlockEvent((EntityCombustByBlockEvent) event, npc));
2012-09-01 12:05:22 +02:00
} else {
Bukkit.getPluginManager().callEvent(new NPCCombustEvent(event, npc));
}
}
@EventHandler
2012-01-23 09:45:34 +01:00
public void onEntityDamage(EntityDamageEvent event) {
NPC npc = npcRegistry.getNPC(event.getEntity());
if (npc == null)
return;
event.setCancelled(npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true));
2012-01-23 09:45:34 +01:00
if (event instanceof EntityDamageByEntityEvent) {
2012-12-30 13:25:49 +01:00
NPCDamageByEntityEvent damageEvent = new NPCDamageByEntityEvent(npc, (EntityDamageByEntityEvent) event);
2012-05-14 13:45:16 +02:00
Bukkit.getPluginManager().callEvent(damageEvent);
2012-05-14 13:45:16 +02:00
if (!damageEvent.isCancelled() || !(damageEvent.getDamager() instanceof Player))
return;
2012-05-14 13:45:16 +02:00
Player damager = (Player) damageEvent.getDamager();
// Call left-click event
NPCLeftClickEvent leftClickEvent = new NPCLeftClickEvent(npc, damager);
Bukkit.getPluginManager().callEvent(leftClickEvent);
2012-08-15 18:13:46 +02:00
} else if (event instanceof EntityDamageByBlockEvent) {
2012-12-30 13:25:49 +01:00
Bukkit.getPluginManager().callEvent(new NPCDamageByBlockEvent(npc, (EntityDamageByBlockEvent) event));
} else {
Bukkit.getPluginManager().callEvent(new NPCDamageEvent(npc, event));
2012-01-23 09:45:34 +01:00
}
}
@EventHandler(ignoreCancelled = true)
2012-03-27 16:42:15 +02:00
public void onEntityDeath(EntityDeathEvent event) {
2013-07-14 11:28:35 +02:00
final NPC npc = npcRegistry.getNPC(event.getEntity());
2013-09-26 17:55:12 +02:00
if (npc == null) {
return;
2013-09-26 17:55:12 +02:00
}
Bukkit.getPluginManager().callEvent(new NPCDeathEvent(npc, event));
2013-11-05 12:29:18 +01:00
final Location location = npc.getEntity().getLocation();
2012-11-21 13:10:21 +01:00
npc.despawn(DespawnReason.DEATH);
2013-07-14 11:28:35 +02:00
if (npc.data().get(NPC.RESPAWN_DELAY_METADATA, -1) >= 0) {
int delay = npc.data().get(NPC.RESPAWN_DELAY_METADATA, -1);
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), new Runnable() {
@Override
public void run() {
if (!npc.isSpawned()) {
npc.spawn(location);
}
}
2013-07-24 16:46:43 +02:00
}, delay + 2);
2013-07-14 11:28:35 +02:00
}
2012-03-27 16:42:15 +02:00
}
2012-09-02 04:48:29 +02:00
@EventHandler(priority = EventPriority.HIGHEST)
public void onEntitySpawn(CreatureSpawnEvent event) {
2013-07-14 11:28:35 +02:00
if (event.isCancelled() && npcRegistry.isNPC(event.getEntity())) {
event.setCancelled(false);
2013-07-14 11:28:35 +02:00
}
}
@EventHandler
2012-01-23 09:45:34 +01:00
public void onEntityTarget(EntityTargetEvent event) {
NPC npc = npcRegistry.getNPC(event.getTarget());
if (npc == null)
return;
event.setCancelled(!npc.data().get(NPC.TARGETABLE_METADATA,
!npc.data().get(NPC.DEFAULT_PROTECTED_METADATA, true)));
Bukkit.getPluginManager().callEvent(new EntityTargetNPCEvent(event, npc));
2012-01-23 15:30:15 +01:00
}
@EventHandler
public void onNeedsRespawn(NPCNeedsRespawnEvent event) {
ChunkCoord coord = toCoord(event.getSpawnLocation());
if (toRespawn.containsEntry(coord, event.getNPC()))
return;
toRespawn.put(coord, event.getNPC());
}
@EventHandler
public void onNPCDespawn(NPCDespawnEvent event) {
2013-03-16 06:28:26 +01:00
if (event.getReason() == DespawnReason.PLUGIN || event.getReason() == DespawnReason.REMOVAL) {
2013-11-05 12:29:18 +01:00
toRespawn.remove(toCoord(event.getNPC().getEntity().getLocation()), event.getNPC());
2013-03-16 06:28:26 +01:00
}
}
@EventHandler(ignoreCancelled = true)
2012-03-02 11:36:54 +01:00
public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
if (!(event.getPlayer() instanceof NPCHolder))
2012-03-02 11:36:54 +01:00
return;
NMS.removeFromServerPlayerList(event.getPlayer());
// on teleport, player NPCs are added to the server player list. this is
// undesirable as player NPCs are not real players and confuse plugins.
2012-02-27 14:01:38 +01:00
}
2013-04-18 16:03:27 +02:00
@EventHandler(ignoreCancelled = true)
public void onPlayerCreateNPC(PlayerCreateNPCEvent event) {
checkCreationEvent(event);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
2012-01-23 15:30:15 +01:00
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
NPC npc = npcRegistry.getNPC(event.getRightClicked());
2013-02-17 14:47:20 +01:00
if (npc == null) {
2012-01-23 15:30:15 +01:00
return;
2013-02-17 14:47:20 +01:00
}
2012-01-23 15:30:15 +01:00
Player player = event.getPlayer();
NPCRightClickEvent rightClickEvent = new NPCRightClickEvent(npc, player);
Bukkit.getPluginManager().callEvent(rightClickEvent);
2012-01-23 09:45:34 +01:00
}
2012-02-26 07:35:44 +01:00
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerQuit(PlayerQuitEvent event) {
Editor.leave(event.getPlayer());
if (event.getPlayer().isInsideVehicle()) {
NPC npc = npcRegistry.getNPC(event.getPlayer().getVehicle());
if (npc != null) {
event.getPlayer().leaveVehicle();
}
}
}
@EventHandler(ignoreCancelled = true)
public void onVehicleEnter(VehicleEnterEvent event) {
if (!npcRegistry.isNPC(event.getEntered()))
return;
NPC npc = npcRegistry.getNPC(event.getEntered());
2013-11-05 12:29:18 +01:00
if (npc.getEntity().getType() == EntityType.HORSE && !npc.getTrait(Controllable.class).isEnabled()) {
event.setCancelled(true);
}
}
@EventHandler(ignoreCancelled = true)
2012-03-02 11:36:54 +01:00
public void onWorldLoad(WorldLoadEvent event) {
for (ChunkCoord chunk : toRespawn.keySet()) {
2012-10-31 08:03:13 +01:00
if (!chunk.worldName.equals(event.getWorld().getName())
|| !event.getWorld().isChunkLoaded(chunk.x, chunk.z))
2012-03-02 11:59:40 +01:00
continue;
2013-04-14 08:55:09 +02:00
respawnAllFromCoord(chunk);
2012-03-02 11:36:54 +01:00
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
2012-03-02 11:36:54 +01:00
public void onWorldUnload(WorldUnloadEvent event) {
for (NPC npc : getAllNPCs()) {
2013-11-05 12:29:18 +01:00
if (!npc.isSpawned() || !npc.getEntity().getWorld().equals(event.getWorld()))
2012-03-02 11:36:54 +01:00
continue;
2013-04-14 12:23:21 +02:00
boolean despawned = npc.despawn(DespawnReason.WORLD_UNLOAD);
if (event.isCancelled() || !despawned) {
for (ChunkCoord coord : toRespawn.keySet()) {
if (event.getWorld().getName().equals(coord.worldName)) {
2013-04-14 12:23:21 +02:00
respawnAllFromCoord(coord);
}
2013-04-14 12:23:21 +02:00
}
return;
2013-04-14 12:23:21 +02:00
}
storeForRespawn(npc);
Messaging.debug("Despawned", npc.getId() + "due to world unload at", event.getWorld().getName());
2012-03-02 11:36:54 +01:00
}
2012-02-26 07:35:44 +01:00
}
2012-03-02 11:59:40 +01:00
private void respawnAllFromCoord(ChunkCoord coord) {
List<NPC> ids = toRespawn.get(coord);
for (int i = 0; i < ids.size(); i++) {
2013-04-14 08:55:09 +02:00
NPC npc = ids.get(i);
boolean success = spawn(npc);
if (!success) {
2013-04-14 08:55:09 +02:00
Messaging.debug("Couldn't respawn id", npc.getId(), "during chunk event at [" + coord.x + "," + coord.z
+ "]");
continue;
}
2013-01-19 16:26:19 +01:00
ids.remove(i--);
2013-04-14 08:55:09 +02:00
Messaging.debug("Spawned id", npc.getId(), "due to chunk event at [" + coord.x + "," + coord.z + "]");
}
}
private boolean spawn(NPC npc) {
2012-11-21 13:10:21 +01:00
Location spawn = npc.getTrait(CurrentLocation.class).getLocation();
if (spawn == null) {
2013-04-14 08:55:09 +02:00
Messaging.debug("Couldn't find a spawn location for despawned NPC id", npc.getId());
2012-12-29 16:00:15 +01:00
return false;
2012-11-21 13:10:21 +01:00
}
2012-12-29 16:00:15 +01:00
return npc.spawn(spawn);
2012-11-04 09:16:06 +01:00
}
private void storeForRespawn(NPC npc) {
2013-11-05 12:29:18 +01:00
toRespawn.put(toCoord(npc.getEntity().getLocation()), npc);
}
private ChunkCoord toCoord(Chunk chunk) {
return new ChunkCoord(chunk);
}
private ChunkCoord toCoord(Location loc) {
return new ChunkCoord(loc.getWorld().getName(), loc.getBlockX() >> 4, loc.getBlockZ() >> 4);
}
private static class ChunkCoord {
2012-10-31 08:03:13 +01:00
private final String worldName;
private final int x;
private final int z;
private ChunkCoord(Chunk chunk) {
this(chunk.getWorld().getName(), chunk.getX(), chunk.getZ());
}
private ChunkCoord(String worldName, int x, int z) {
2012-07-22 08:18:24 +02:00
this.x = x;
this.z = z;
2012-10-31 08:03:13 +01:00
this.worldName = worldName;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
ChunkCoord other = (ChunkCoord) obj;
2012-10-31 08:03:13 +01:00
if (worldName == null) {
if (other.worldName != null) {
return false;
}
2012-10-31 08:03:13 +01:00
} else if (!worldName.equals(other.worldName)) {
return false;
}
2013-04-14 08:55:09 +02:00
return x == other.x && z == other.z;
2012-07-22 08:18:24 +02:00
}
2012-10-26 06:26:54 +02:00
@Override
public int hashCode() {
final int prime = 31;
2012-10-31 08:03:13 +01:00
int result = prime + ((worldName == null) ? 0 : worldName.hashCode());
2012-10-26 06:26:54 +02:00
result = prime * result + x;
2013-04-14 08:55:09 +02:00
return prime * result + z;
2012-10-26 06:26:54 +02:00
}
2012-03-02 11:59:40 +01:00
}
2012-01-19 08:38:40 +01:00
}