2017-12-30 08:36:36 +01:00
|
|
|
package net.citizensnpcs;
|
|
|
|
|
2023-06-12 15:20:51 +02:00
|
|
|
import java.lang.reflect.Method;
|
2017-12-30 08:36:36 +01:00
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
import org.bukkit.Bukkit;
|
|
|
|
import org.bukkit.Location;
|
|
|
|
import org.bukkit.Material;
|
2020-04-13 15:56:48 +02:00
|
|
|
import org.bukkit.entity.Entity;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.entity.EntityType;
|
|
|
|
import org.bukkit.entity.FishHook;
|
2018-03-09 13:54:20 +01:00
|
|
|
import org.bukkit.entity.LivingEntity;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.entity.Minecart;
|
|
|
|
import org.bukkit.entity.Player;
|
2023-01-26 18:54:13 +01:00
|
|
|
import org.bukkit.entity.Snowman;
|
2022-06-11 09:17:17 +02:00
|
|
|
import org.bukkit.entity.Vehicle;
|
2019-04-26 17:39:15 +02:00
|
|
|
import org.bukkit.event.Cancellable;
|
2020-06-28 11:36:24 +02:00
|
|
|
import org.bukkit.event.Event;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.event.EventHandler;
|
|
|
|
import org.bukkit.event.EventPriority;
|
2023-06-12 15:20:51 +02:00
|
|
|
import org.bukkit.event.HandlerList;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.event.Listener;
|
2023-01-26 18:54:13 +01:00
|
|
|
import org.bukkit.event.block.EntityBlockFormEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
|
|
|
import org.bukkit.event.entity.EntityCombustByBlockEvent;
|
|
|
|
import org.bukkit.event.entity.EntityCombustByEntityEvent;
|
|
|
|
import org.bukkit.event.entity.EntityCombustEvent;
|
|
|
|
import org.bukkit.event.entity.EntityDamageByBlockEvent;
|
|
|
|
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
|
|
|
import org.bukkit.event.entity.EntityDamageEvent;
|
|
|
|
import org.bukkit.event.entity.EntityDeathEvent;
|
2018-10-01 12:36:12 +02:00
|
|
|
import org.bukkit.event.entity.EntityPortalEvent;
|
2023-07-19 17:53:43 +02:00
|
|
|
import org.bukkit.event.entity.EntityTameEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.event.entity.EntityTargetEvent;
|
2022-09-09 12:13:01 +02:00
|
|
|
import org.bukkit.event.entity.EntityTransformEvent;
|
2023-02-14 23:02:00 +01:00
|
|
|
import org.bukkit.event.entity.ItemDespawnEvent;
|
2023-06-13 14:13:21 +02:00
|
|
|
import org.bukkit.event.entity.PlayerDeathEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.event.entity.PlayerLeashEntityEvent;
|
2018-03-09 13:54:20 +01:00
|
|
|
import org.bukkit.event.entity.PotionSplashEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.event.entity.ProjectileHitEvent;
|
|
|
|
import org.bukkit.event.player.PlayerChangedWorldEvent;
|
|
|
|
import org.bukkit.event.player.PlayerFishEvent;
|
|
|
|
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
|
|
|
import org.bukkit.event.player.PlayerJoinEvent;
|
|
|
|
import org.bukkit.event.player.PlayerMoveEvent;
|
|
|
|
import org.bukkit.event.player.PlayerQuitEvent;
|
|
|
|
import org.bukkit.event.player.PlayerRespawnEvent;
|
2023-12-21 21:15:00 +01:00
|
|
|
import org.bukkit.event.player.PlayerShearEntityEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.event.player.PlayerTeleportEvent;
|
|
|
|
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
|
2021-07-14 15:23:55 +02:00
|
|
|
import org.bukkit.event.server.PluginDisableEvent;
|
2020-05-13 07:23:59 +02:00
|
|
|
import org.bukkit.event.vehicle.VehicleDamageEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.event.vehicle.VehicleDestroyEvent;
|
|
|
|
import org.bukkit.event.vehicle.VehicleEnterEvent;
|
2022-08-04 05:48:48 +02:00
|
|
|
import org.bukkit.event.world.ChunkEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.event.world.ChunkLoadEvent;
|
|
|
|
import org.bukkit.event.world.ChunkUnloadEvent;
|
2023-05-07 14:09:37 +02:00
|
|
|
import org.bukkit.event.world.EntitiesLoadEvent;
|
|
|
|
import org.bukkit.event.world.EntitiesUnloadEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.event.world.WorldLoadEvent;
|
|
|
|
import org.bukkit.event.world.WorldUnloadEvent;
|
2021-07-15 13:41:03 +02:00
|
|
|
import org.bukkit.plugin.PluginDescriptionFile;
|
2023-06-12 15:20:51 +02:00
|
|
|
import org.bukkit.plugin.RegisteredListener;
|
2017-12-30 08:36:36 +01:00
|
|
|
import org.bukkit.scheduler.BukkitRunnable;
|
2023-06-12 15:20:51 +02:00
|
|
|
import org.bukkit.util.Vector;
|
2017-12-30 08:36:36 +01:00
|
|
|
|
2023-01-03 13:55:27 +01:00
|
|
|
import com.google.common.base.Joiner;
|
2017-12-30 08:36:36 +01:00
|
|
|
import com.google.common.base.Predicates;
|
|
|
|
import com.google.common.collect.ArrayListMultimap;
|
|
|
|
import com.google.common.collect.Iterables;
|
|
|
|
import com.google.common.collect.ListMultimap;
|
2020-04-22 14:25:17 +02:00
|
|
|
import com.google.common.collect.Lists;
|
2017-12-30 08:36:36 +01:00
|
|
|
|
|
|
|
import net.citizensnpcs.Settings.Setting;
|
|
|
|
import net.citizensnpcs.api.CitizensAPI;
|
|
|
|
import net.citizensnpcs.api.ai.event.NavigationBeginEvent;
|
|
|
|
import net.citizensnpcs.api.ai.event.NavigationCompleteEvent;
|
|
|
|
import net.citizensnpcs.api.event.CitizensPreReloadEvent;
|
|
|
|
import net.citizensnpcs.api.event.CommandSenderCreateNPCEvent;
|
|
|
|
import net.citizensnpcs.api.event.DespawnReason;
|
|
|
|
import net.citizensnpcs.api.event.EntityTargetNPCEvent;
|
|
|
|
import net.citizensnpcs.api.event.NPCCombustByBlockEvent;
|
|
|
|
import net.citizensnpcs.api.event.NPCCombustByEntityEvent;
|
|
|
|
import net.citizensnpcs.api.event.NPCCombustEvent;
|
|
|
|
import net.citizensnpcs.api.event.NPCDamageByBlockEvent;
|
|
|
|
import net.citizensnpcs.api.event.NPCDamageByEntityEvent;
|
|
|
|
import net.citizensnpcs.api.event.NPCDamageEntityEvent;
|
|
|
|
import net.citizensnpcs.api.event.NPCDamageEvent;
|
|
|
|
import net.citizensnpcs.api.event.NPCDeathEvent;
|
|
|
|
import net.citizensnpcs.api.event.NPCDespawnEvent;
|
2023-06-12 15:20:51 +02:00
|
|
|
import net.citizensnpcs.api.event.NPCKnockbackEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.event.NPCLeftClickEvent;
|
2023-10-29 18:37:00 +01:00
|
|
|
import net.citizensnpcs.api.event.NPCLinkToPlayerEvent;
|
2023-06-12 15:20:51 +02:00
|
|
|
import net.citizensnpcs.api.event.NPCPushEvent;
|
2021-04-05 10:38:10 +02:00
|
|
|
import net.citizensnpcs.api.event.NPCRemoveEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.event.NPCRightClickEvent;
|
2023-04-16 19:47:32 +02:00
|
|
|
import net.citizensnpcs.api.event.NPCSeenByPlayerEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.event.NPCSpawnEvent;
|
2020-05-13 07:23:59 +02:00
|
|
|
import net.citizensnpcs.api.event.NPCVehicleDamageEvent;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.event.PlayerCreateNPCEvent;
|
2018-08-08 10:08:38 +02:00
|
|
|
import net.citizensnpcs.api.event.SpawnReason;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.npc.NPC;
|
|
|
|
import net.citizensnpcs.api.trait.trait.Owner;
|
2023-04-16 19:47:32 +02:00
|
|
|
import net.citizensnpcs.api.trait.trait.PlayerFilter;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.api.util.Messaging;
|
|
|
|
import net.citizensnpcs.editor.Editor;
|
2023-06-12 15:20:51 +02:00
|
|
|
import net.citizensnpcs.npc.ai.NPCHolder;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.npc.skin.SkinUpdateTracker;
|
2020-07-17 03:52:00 +02:00
|
|
|
import net.citizensnpcs.trait.ClickRedirectTrait;
|
2019-09-23 14:29:31 +02:00
|
|
|
import net.citizensnpcs.trait.CommandTrait;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.trait.Controllable;
|
|
|
|
import net.citizensnpcs.trait.CurrentLocation;
|
2023-10-29 18:37:00 +01:00
|
|
|
import net.citizensnpcs.trait.HologramTrait;
|
2022-10-22 04:42:44 +02:00
|
|
|
import net.citizensnpcs.trait.ShopTrait;
|
2023-12-03 05:33:46 +01:00
|
|
|
import net.citizensnpcs.trait.versioned.SnowmanTrait;
|
2019-05-29 10:45:18 +02:00
|
|
|
import net.citizensnpcs.util.ChunkCoord;
|
2017-12-30 08:36:36 +01:00
|
|
|
import net.citizensnpcs.util.Messages;
|
|
|
|
import net.citizensnpcs.util.NMS;
|
2022-10-02 17:10:23 +02:00
|
|
|
import net.citizensnpcs.util.PlayerAnimation;
|
2018-04-07 10:02:35 +02:00
|
|
|
import net.citizensnpcs.util.Util;
|
2017-12-30 08:36:36 +01:00
|
|
|
|
|
|
|
public class EventListen implements Listener {
|
2023-05-07 14:09:37 +02:00
|
|
|
private Listener chunkEventListener;
|
2023-11-05 13:58:37 +01:00
|
|
|
private SkinUpdateTracker skinUpdateTracker;
|
2020-11-14 11:41:21 +01:00
|
|
|
private final ListMultimap<ChunkCoord, NPC> toRespawn = ArrayListMultimap.create(64, 4);
|
2017-12-30 08:36:36 +01:00
|
|
|
|
2023-09-03 17:41:38 +02:00
|
|
|
EventListen() {
|
2023-11-05 13:58:37 +01:00
|
|
|
skinUpdateTracker = new SkinUpdateTracker();
|
2022-08-05 06:01:07 +02:00
|
|
|
try {
|
2023-05-07 14:09:37 +02:00
|
|
|
Class.forName("org.bukkit.event.world.EntitiesLoadEvent");
|
|
|
|
Bukkit.getPluginManager().registerEvents(new Listener() {
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
|
|
|
public void onEntitiesLoad(EntitiesLoadEvent event) {
|
|
|
|
loadNPCs(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
|
|
|
public void onEntitiesUnload(EntitiesUnloadEvent event) {
|
2024-01-13 15:48:27 +01:00
|
|
|
List<NPC> toDespawn = Lists
|
|
|
|
.newArrayList(CitizensAPI.getLocationLookup().getNearbyNPCs(event.getWorld(),
|
|
|
|
new double[] { (event.getChunk().getX() << 4) - 0.5, 0,
|
|
|
|
(event.getChunk().getZ() << 4) - 0.5 },
|
|
|
|
new double[] { (event.getChunk().getX() + 1 << 4) + 0.5, 256,
|
|
|
|
(event.getChunk().getZ() + 1 << 4) + 0.5 }));
|
|
|
|
for (Entity entity : event.getEntities()) {
|
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(entity);
|
|
|
|
// XXX npc#isSpawned() checks valid status which is now inconsistent on chunk unload
|
|
|
|
// between different server software so check for npc.getEntity() == null instead.
|
|
|
|
if (npc == null || npc.getEntity() == null || toDespawn.contains(npc))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
toDespawn.add(npc);
|
|
|
|
}
|
|
|
|
if (toDespawn.isEmpty())
|
|
|
|
return;
|
|
|
|
unloadNPCs(event, toDespawn);
|
2023-05-07 14:09:37 +02:00
|
|
|
}
|
|
|
|
}, CitizensAPI.getPlugin());
|
2022-08-05 06:01:07 +02:00
|
|
|
} catch (Throwable ex) {
|
|
|
|
}
|
2022-09-12 18:56:03 +02:00
|
|
|
try {
|
2022-10-25 19:25:30 +02:00
|
|
|
Class.forName("org.bukkit.event.entity.EntityTransformEvent");
|
2022-09-12 18:56:03 +02:00
|
|
|
Bukkit.getPluginManager().registerEvents(new Listener() {
|
|
|
|
@EventHandler
|
|
|
|
public void onEntityTransform(EntityTransformEvent event) {
|
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
|
|
|
|
if (npc == null)
|
|
|
|
return;
|
|
|
|
if (npc.isProtected()) {
|
|
|
|
event.setCancelled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}, CitizensAPI.getPlugin());
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
}
|
2023-06-12 15:20:51 +02:00
|
|
|
Class<?> kbc = null;
|
|
|
|
try {
|
|
|
|
kbc = Class.forName("com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent");
|
|
|
|
} catch (ClassNotFoundException e) {
|
|
|
|
}
|
|
|
|
if (kbc != null) {
|
|
|
|
registerKnockbackEvent(kbc);
|
|
|
|
}
|
|
|
|
Class<?> pbeac = null;
|
|
|
|
try {
|
|
|
|
pbeac = Class.forName("io.papermc.paper.event.entity.EntityPushedByEntityAttackEvent");
|
|
|
|
} catch (ClassNotFoundException e) {
|
|
|
|
}
|
|
|
|
if (pbeac != null) {
|
|
|
|
registerPushEvent(pbeac);
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2022-07-25 09:40:39 +02:00
|
|
|
private void checkCreationEvent(CommandSenderCreateNPCEvent event) {
|
2017-12-30 08:36:36 +01:00
|
|
|
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--) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (!event.getCreator().hasPermission("citizens.npc.limit." + i)) {
|
2017-12-30 08:36:36 +01:00
|
|
|
continue;
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
limit = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (limit < 0)
|
2020-09-14 11:57:58 +02:00
|
|
|
return;
|
2017-12-30 08:36:36 +01:00
|
|
|
int owned = 0;
|
2019-01-18 17:18:43 +01:00
|
|
|
for (NPC npc : CitizensAPI.getNPCRegistry()) {
|
2017-12-30 08:36:36 +01:00
|
|
|
if (!event.getNPC().equals(npc) && npc.hasTrait(Owner.class)
|
2020-09-14 11:57:58 +02:00
|
|
|
&& npc.getTraitNullable(Owner.class).isOwnedBy(event.getCreator())) {
|
2017-12-30 08:36:36 +01:00
|
|
|
owned++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
int wouldOwn = owned + 1;
|
|
|
|
if (wouldOwn > limit) {
|
|
|
|
event.setCancelled(true);
|
|
|
|
event.setCancelReason(Messaging.tr(Messages.OVER_NPC_LIMIT, limit));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Iterable<NPC> getAllNPCs() {
|
2023-09-03 17:41:38 +02:00
|
|
|
return Iterables.filter(Iterables.concat(CitizensAPI.getNPCRegistries()), Predicates.notNull());
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2022-08-05 06:01:07 +02:00
|
|
|
void loadNPCs(ChunkEvent event) {
|
2022-03-13 21:25:42 +01:00
|
|
|
ChunkCoord coord = new ChunkCoord(event.getChunk());
|
2023-06-25 15:58:09 +02:00
|
|
|
Runnable runnable = () -> respawnAllFromCoord(coord, event);
|
2022-03-13 21:25:42 +01:00
|
|
|
if (Messaging.isDebugging() && Setting.DEBUG_CHUNK_LOADS.asBoolean() && toRespawn.containsKey(coord)) {
|
|
|
|
new Exception("CITIZENS CHUNK LOAD DEBUG " + coord).printStackTrace();
|
2020-12-24 12:03:21 +01:00
|
|
|
}
|
2019-07-07 08:44:08 +02:00
|
|
|
if (event instanceof Cancellable) {
|
|
|
|
runnable.run();
|
|
|
|
} else {
|
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), runnable);
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2022-08-04 05:48:48 +02:00
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
|
|
|
public void onChunkLoad(ChunkLoadEvent event) {
|
2022-08-05 06:01:07 +02:00
|
|
|
if (chunkEventListener != null)
|
2022-08-04 05:48:48 +02:00
|
|
|
return;
|
|
|
|
loadNPCs(event);
|
|
|
|
}
|
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
2023-11-05 13:58:37 +01:00
|
|
|
public void onChunkUnload(ChunkUnloadEvent event) {
|
2022-10-18 19:47:07 +02:00
|
|
|
if (chunkEventListener != null)
|
2020-04-22 14:25:17 +02:00
|
|
|
return;
|
2024-01-13 15:48:27 +01:00
|
|
|
List<NPC> toDespawn = Lists.newArrayList(CitizensAPI.getLocationLookup().getNearbyNPCs(event.getWorld(),
|
|
|
|
new double[] { (event.getChunk().getX() << 4) - 0.5, 0, (event.getChunk().getZ() << 4) - 0.5 },
|
|
|
|
new double[] { (event.getChunk().getX() + 1 << 4) + 0.5, 256,
|
|
|
|
(event.getChunk().getZ() + 1 << 4) + 0.5 }));
|
|
|
|
for (Entity entity : event.getChunk().getEntities()) {
|
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(entity);
|
|
|
|
// XXX npc#isSpawned() checks valid status which is now inconsistent on chunk unload
|
|
|
|
// between different server software so check for npc.getEntity() == null instead.
|
|
|
|
if (npc == null || npc.getEntity() == null || toDespawn.contains(npc))
|
|
|
|
continue;
|
2023-10-28 20:09:08 +02:00
|
|
|
|
2024-01-13 15:48:27 +01:00
|
|
|
toDespawn.add(npc);
|
|
|
|
}
|
|
|
|
if (toDespawn.isEmpty())
|
|
|
|
return;
|
|
|
|
unloadNPCs(event, toDespawn);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR)
|
|
|
|
public void onCitizensReload(CitizensPreReloadEvent event) {
|
|
|
|
skinUpdateTracker.reset();
|
|
|
|
toRespawn.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onCommandSenderCreateNPC(CommandSenderCreateNPCEvent event) {
|
|
|
|
checkCreationEvent(event);
|
|
|
|
}
|
|
|
|
|
2023-01-26 18:54:13 +01:00
|
|
|
@EventHandler
|
|
|
|
public void onEntityBlockForm(EntityBlockFormEvent event) {
|
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
|
|
|
|
if (npc == null)
|
|
|
|
return;
|
|
|
|
if (npc.getEntity() instanceof Snowman) {
|
2023-12-03 05:33:46 +01:00
|
|
|
boolean formSnow = npc.hasTrait(SnowmanTrait.class)
|
|
|
|
? npc.getTraitNullable(SnowmanTrait.class).shouldFormSnow()
|
|
|
|
: npc.useMinecraftAI();
|
|
|
|
event.setCancelled(!formSnow);
|
2023-01-26 18:54:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
@EventHandler
|
|
|
|
public void onEntityCombust(EntityCombustEvent event) {
|
2019-01-18 17:33:05 +01:00
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
|
2017-12-30 08:36:36 +01:00
|
|
|
if (npc == null)
|
|
|
|
return;
|
2023-08-31 20:36:04 +02:00
|
|
|
|
2022-05-22 11:36:48 +02:00
|
|
|
event.setCancelled(npc.isProtected());
|
2023-08-31 20:36:04 +02:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
if (event instanceof EntityCombustByEntityEvent) {
|
|
|
|
Bukkit.getPluginManager().callEvent(new NPCCombustByEntityEvent((EntityCombustByEntityEvent) event, npc));
|
|
|
|
} else if (event instanceof EntityCombustByBlockEvent) {
|
|
|
|
Bukkit.getPluginManager().callEvent(new NPCCombustByBlockEvent((EntityCombustByBlockEvent) event, npc));
|
|
|
|
} else {
|
|
|
|
Bukkit.getPluginManager().callEvent(new NPCCombustEvent(event, npc));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-24 15:27:15 +02:00
|
|
|
@EventHandler(priority = EventPriority.LOWEST)
|
2017-12-30 08:36:36 +01:00
|
|
|
public void onEntityDamage(EntityDamageEvent event) {
|
2019-01-18 17:18:43 +01:00
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
|
2017-12-30 08:36:36 +01:00
|
|
|
if (npc == null) {
|
|
|
|
if (event instanceof EntityDamageByEntityEvent) {
|
2019-01-18 17:18:43 +01:00
|
|
|
npc = CitizensAPI.getNPCRegistry().getNPC(((EntityDamageByEntityEvent) event).getDamager());
|
2017-12-30 08:36:36 +01:00
|
|
|
if (npc == null)
|
|
|
|
return;
|
2023-01-01 08:26:35 +01:00
|
|
|
event.setCancelled(!npc.data().get(NPC.Metadata.DAMAGE_OTHERS, true));
|
2017-12-30 08:36:36 +01:00
|
|
|
NPCDamageEntityEvent damageEvent = new NPCDamageEntityEvent(npc, (EntityDamageByEntityEvent) event);
|
|
|
|
Bukkit.getPluginManager().callEvent(damageEvent);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2023-10-24 17:10:03 +02:00
|
|
|
event.setCancelled(npc.isProtected());
|
2023-10-22 19:58:06 +02:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
if (event instanceof EntityDamageByEntityEvent) {
|
|
|
|
NPCDamageByEntityEvent damageEvent = new NPCDamageByEntityEvent(npc, (EntityDamageByEntityEvent) event);
|
|
|
|
Bukkit.getPluginManager().callEvent(damageEvent);
|
|
|
|
if (!damageEvent.isCancelled() || !(damageEvent.getDamager() instanceof Player))
|
|
|
|
return;
|
2022-12-02 17:20:04 +01:00
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
Player damager = (Player) damageEvent.getDamager();
|
|
|
|
|
2020-07-17 03:52:00 +02:00
|
|
|
if (npc.hasTrait(ClickRedirectTrait.class)) {
|
2020-09-14 11:57:58 +02:00
|
|
|
npc = npc.getTraitNullable(ClickRedirectTrait.class).getRedirectNPC();
|
2020-07-17 03:52:00 +02:00
|
|
|
if (npc == null)
|
|
|
|
return;
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
NPCLeftClickEvent leftClickEvent = new NPCLeftClickEvent(npc, damager);
|
|
|
|
Bukkit.getPluginManager().callEvent(leftClickEvent);
|
2019-09-23 14:29:31 +02:00
|
|
|
if (npc.hasTrait(CommandTrait.class)) {
|
2020-09-14 11:57:58 +02:00
|
|
|
npc.getTraitNullable(CommandTrait.class).dispatch(damager, CommandTrait.Hand.LEFT);
|
2019-09-23 14:29:31 +02:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
} else if (event instanceof EntityDamageByBlockEvent) {
|
|
|
|
Bukkit.getPluginManager().callEvent(new NPCDamageByBlockEvent(npc, (EntityDamageByBlockEvent) event));
|
|
|
|
} else {
|
|
|
|
Bukkit.getPluginManager().callEvent(new NPCDamageEvent(npc, event));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onEntityDeath(EntityDeathEvent event) {
|
2023-11-05 13:58:37 +01:00
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
|
2023-08-31 20:36:04 +02:00
|
|
|
if (npc == null)
|
2017-12-30 08:36:36 +01:00
|
|
|
return;
|
|
|
|
|
2023-01-01 08:26:35 +01:00
|
|
|
if (!npc.data().get(NPC.Metadata.DROPS_ITEMS, false)) {
|
2017-12-30 08:36:36 +01:00
|
|
|
event.getDrops().clear();
|
|
|
|
}
|
2023-11-05 13:58:37 +01:00
|
|
|
Location location = npc.getStoredLocation();
|
2017-12-30 08:36:36 +01:00
|
|
|
Bukkit.getPluginManager().callEvent(new NPCDeathEvent(npc, event));
|
|
|
|
npc.despawn(DespawnReason.DEATH);
|
|
|
|
|
2023-01-01 08:26:35 +01:00
|
|
|
int delay = npc.data().get(NPC.Metadata.RESPAWN_DELAY, -1);
|
2020-05-09 16:15:22 +02:00
|
|
|
if (delay < 0)
|
|
|
|
return;
|
2023-08-31 20:36:04 +02:00
|
|
|
|
2021-02-08 12:52:30 +01:00
|
|
|
int deathAnimationTicks = event.getEntity() instanceof LivingEntity ? 20 : 2;
|
2023-06-13 14:13:21 +02:00
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
|
|
|
|
if (!npc.isSpawned() && npc.getOwningRegistry().getByUniqueId(npc.getUniqueId()) == npc) {
|
|
|
|
npc.spawn(location, SpawnReason.TIMED_RESPAWN);
|
2020-05-09 16:15:22 +02:00
|
|
|
}
|
2020-12-28 04:04:14 +01:00
|
|
|
}, delay + deathAnimationTicks);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2018-10-01 12:36:12 +02:00
|
|
|
@EventHandler
|
|
|
|
public void onEntityPortal(EntityPortalEvent event) {
|
2019-01-18 17:18:43 +01:00
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
|
2022-01-16 07:05:23 +01:00
|
|
|
if (npc == null || npc.getEntity().getType() != EntityType.PLAYER)
|
2018-10-01 12:36:12 +02:00
|
|
|
return;
|
2023-11-04 19:03:57 +01:00
|
|
|
|
2018-10-01 12:36:12 +02:00
|
|
|
event.setCancelled(true);
|
|
|
|
npc.despawn(DespawnReason.PENDING_RESPAWN);
|
|
|
|
event.getTo().getChunk();
|
|
|
|
npc.spawn(event.getTo(), SpawnReason.RESPAWN);
|
|
|
|
}
|
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
@EventHandler(priority = EventPriority.HIGHEST)
|
|
|
|
public void onEntitySpawn(CreatureSpawnEvent event) {
|
2019-01-18 17:18:43 +01:00
|
|
|
if (event.isCancelled() && CitizensAPI.getNPCRegistry().isNPC(event.getEntity())) {
|
2017-12-30 08:36:36 +01:00
|
|
|
event.setCancelled(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-19 17:53:43 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onEntityTame(EntityTameEvent event) {
|
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
|
|
|
|
if (npc == null || !npc.isProtected())
|
|
|
|
return;
|
|
|
|
event.setCancelled(true);
|
|
|
|
}
|
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
@EventHandler
|
|
|
|
public void onEntityTarget(EntityTargetEvent event) {
|
2019-01-18 17:18:43 +01:00
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getTarget());
|
2017-12-30 08:36:36 +01:00
|
|
|
if (npc == null)
|
|
|
|
return;
|
2023-08-31 20:36:04 +02:00
|
|
|
|
2023-01-01 08:26:35 +01:00
|
|
|
event.setCancelled(!npc.data().get(NPC.Metadata.TARGETABLE, !npc.isProtected()));
|
2017-12-30 08:36:36 +01:00
|
|
|
Bukkit.getPluginManager().callEvent(new EntityTargetNPCEvent(event, npc));
|
|
|
|
}
|
|
|
|
|
2023-02-14 23:02:00 +01:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onItemDespawn(ItemDespawnEvent event) {
|
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
|
|
|
|
if (npc == null)
|
|
|
|
return;
|
2023-08-31 20:36:04 +02:00
|
|
|
|
2023-02-14 23:02:00 +01:00
|
|
|
event.setCancelled(true);
|
|
|
|
}
|
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
@EventHandler
|
|
|
|
public void onNavigationBegin(NavigationBeginEvent event) {
|
|
|
|
skinUpdateTracker.onNPCNavigationBegin(event.getNPC());
|
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler
|
|
|
|
public void onNavigationComplete(NavigationCompleteEvent event) {
|
|
|
|
skinUpdateTracker.onNPCNavigationComplete(event.getNPC());
|
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler
|
|
|
|
public void onNeedsRespawn(NPCNeedsRespawnEvent event) {
|
2019-05-29 10:45:18 +02:00
|
|
|
ChunkCoord coord = new ChunkCoord(event.getSpawnLocation());
|
2017-12-30 08:36:36 +01:00
|
|
|
if (toRespawn.containsEntry(coord, event.getNPC()))
|
|
|
|
return;
|
2023-10-28 20:09:08 +02:00
|
|
|
|
2022-03-13 21:25:42 +01:00
|
|
|
Messaging.debug("Stored", event.getNPC(), "for respawn from NPCNeedsRespawnEvent");
|
2017-12-30 08:36:36 +01:00
|
|
|
toRespawn.put(coord, event.getNPC());
|
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
|
|
|
public void onNPCDespawn(NPCDespawnEvent event) {
|
|
|
|
if (event.getReason() == DespawnReason.PLUGIN || event.getReason() == DespawnReason.REMOVAL
|
|
|
|
|| event.getReason() == DespawnReason.RELOAD) {
|
2023-01-03 13:55:27 +01:00
|
|
|
Messaging.idebug(() -> Joiner.on(' ').join("Preventing further respawns of", event.getNPC(),
|
|
|
|
"due to DespawnReason." + event.getReason()));
|
2020-10-12 17:04:12 +02:00
|
|
|
toRespawn.values().remove(event.getNPC());
|
2023-01-03 13:55:27 +01:00
|
|
|
} else {
|
|
|
|
Messaging.idebug(() -> Joiner.on(' ').join("Removing", event.getNPC(),
|
|
|
|
"from skin tracker due to DespawnReason." + event.getReason().name()));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
skinUpdateTracker.onNPCDespawn(event.getNPC());
|
|
|
|
}
|
|
|
|
|
2023-06-14 17:47:42 +02:00
|
|
|
@EventHandler
|
|
|
|
public void onNPCKnockback(NPCKnockbackEvent event) {
|
|
|
|
if (event.getNPC().data().has(NPC.Metadata.KNOCKBACK)) {
|
|
|
|
event.setCancelled(!event.getNPC().data().get(NPC.Metadata.KNOCKBACK, true));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-29 18:37:00 +01:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onNPCLinkToPlayer(NPCLinkToPlayerEvent event) {
|
|
|
|
NPC npc = event.getNPC();
|
2023-10-30 15:49:02 +01:00
|
|
|
if (npc.isSpawned() && npc.getEntity().getType() == EntityType.PLAYER) {
|
|
|
|
onNPCPlayerLinkToPlayer(event);
|
|
|
|
}
|
2023-10-29 18:37:00 +01:00
|
|
|
ClickRedirectTrait crt = npc.getTraitNullable(ClickRedirectTrait.class);
|
|
|
|
if (crt != null) {
|
|
|
|
HologramTrait ht = crt.getRedirectNPC().getTraitNullable(HologramTrait.class);
|
|
|
|
if (ht != null) {
|
2023-10-30 15:49:02 +01:00
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(),
|
2023-11-04 19:03:57 +01:00
|
|
|
() -> ht.onHologramSeenByPlayer(npc, event.getPlayer()), 2);
|
2023-10-29 18:37:00 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void onNPCPlayerLinkToPlayer(NPCLinkToPlayerEvent event) {
|
|
|
|
Entity tracker = event.getNPC().getEntity();
|
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
|
|
|
|
if (!tracker.isValid() || !event.getPlayer().isValid())
|
|
|
|
return;
|
|
|
|
|
2024-01-07 10:06:55 +01:00
|
|
|
NMS.sendPositionUpdateNearby(tracker, false, null, null, NMS.getHeadYaw(tracker));
|
2023-10-29 18:37:00 +01:00
|
|
|
}, Setting.TABLIST_REMOVE_PACKET_DELAY.asTicks() + 1);
|
|
|
|
|
|
|
|
boolean resetYaw = event.getNPC().data().get(NPC.Metadata.RESET_YAW_ON_SPAWN,
|
|
|
|
Setting.RESET_YAW_ON_SPAWN.asBoolean());
|
|
|
|
boolean sendTabRemove = NMS.sendTabListAdd(event.getPlayer(), (Player) tracker);
|
|
|
|
if (!sendTabRemove || !Setting.DISABLE_TABLIST.asBoolean()) {
|
|
|
|
if (resetYaw) {
|
2023-10-30 15:49:02 +01:00
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(),
|
|
|
|
() -> PlayerAnimation.ARM_SWING.play((Player) tracker, event.getPlayer()));
|
2023-10-29 18:37:00 +01:00
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
|
|
|
|
if (!tracker.isValid() || !event.getPlayer().isValid())
|
|
|
|
return;
|
|
|
|
|
|
|
|
NMS.sendTabListRemove(event.getPlayer(), (Player) tracker);
|
|
|
|
if (resetYaw) {
|
2023-10-30 15:49:02 +01:00
|
|
|
PlayerAnimation.ARM_SWING.play((Player) tracker, event.getPlayer());
|
2023-10-29 18:37:00 +01:00
|
|
|
}
|
|
|
|
}, Setting.TABLIST_REMOVE_PACKET_DELAY.asTicks());
|
|
|
|
}
|
|
|
|
|
2021-04-05 10:38:10 +02:00
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
|
|
|
public void onNPCRemove(NPCRemoveEvent event) {
|
|
|
|
toRespawn.values().remove(event.getNPC());
|
|
|
|
}
|
|
|
|
|
2023-04-16 19:47:32 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onNPCSeenByPlayer(NPCSeenByPlayerEvent event) {
|
2023-06-20 17:29:36 +02:00
|
|
|
NPC npc = event.getNPC();
|
2023-11-05 13:58:37 +01:00
|
|
|
PlayerFilter pf = npc.getTraitNullable(PlayerFilter.class);
|
|
|
|
if (pf != null) {
|
|
|
|
event.setCancelled(pf.onSeenByPlayer(event.getPlayer()));
|
|
|
|
}
|
2023-10-29 18:37:00 +01:00
|
|
|
ClickRedirectTrait crt = npc.getTraitNullable(ClickRedirectTrait.class);
|
|
|
|
if (crt != null) {
|
|
|
|
npc = crt.getRedirectNPC();
|
2023-06-20 17:29:36 +02:00
|
|
|
}
|
2023-11-05 13:58:37 +01:00
|
|
|
pf = npc.getTraitNullable(PlayerFilter.class);
|
2023-10-29 18:37:00 +01:00
|
|
|
if (pf != null) {
|
|
|
|
event.setCancelled(pf.onSeenByPlayer(event.getPlayer()));
|
2023-04-16 19:47:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-15 14:21:15 +02:00
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
2017-12-30 08:36:36 +01:00
|
|
|
public void onNPCSpawn(NPCSpawnEvent event) {
|
|
|
|
skinUpdateTracker.onNPCSpawn(event.getNPC());
|
2023-01-03 13:55:27 +01:00
|
|
|
Messaging.idebug(() -> Joiner.on(' ').join("Removing respawns of", event.getNPC(),
|
|
|
|
"due to SpawnReason." + event.getReason()));
|
2020-10-12 17:04:12 +02:00
|
|
|
toRespawn.values().remove(event.getNPC());
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2023-05-11 19:09:45 +02:00
|
|
|
@EventHandler
|
2017-12-30 08:36:36 +01:00
|
|
|
public void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
|
2023-02-08 14:06:10 +01:00
|
|
|
skinUpdateTracker.removePlayer(event.getPlayer().getUniqueId());
|
2023-05-11 19:09:45 +02:00
|
|
|
skinUpdateTracker.updatePlayer(event.getPlayer(), 20, true);
|
2019-01-18 17:18:43 +01:00
|
|
|
if (CitizensAPI.getNPCRegistry().getNPC(event.getPlayer()) == null)
|
2017-12-30 08:36:36 +01:00
|
|
|
return;
|
2023-08-31 20:36:04 +02:00
|
|
|
|
2023-05-11 19:09:45 +02:00
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
|
|
|
|
NMS.replaceTracker(event.getPlayer());
|
|
|
|
NMS.removeFromServerPlayerList(event.getPlayer());
|
|
|
|
}, 1);
|
2017-12-30 08:36:36 +01:00
|
|
|
// on teleport, player NPCs are added to the server player list. this is
|
|
|
|
// undesirable as player NPCs are not real players and confuse plugins.
|
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onPlayerCreateNPC(PlayerCreateNPCEvent event) {
|
|
|
|
checkCreationEvent(event);
|
|
|
|
}
|
|
|
|
|
2023-06-13 14:13:21 +02:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onPlayerDeath(PlayerDeathEvent event) {
|
2023-08-31 20:36:04 +02:00
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
|
|
|
|
if (npc == null)
|
2023-06-13 14:13:21 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (npc.requiresNameHologram()) {
|
2023-08-31 20:36:04 +02:00
|
|
|
event.setDeathMessage(event.getDeathMessage().replace(event.getEntity().getName(), npc.getFullName()));
|
2023-06-13 14:13:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onPlayerFish(PlayerFishEvent event) {
|
2019-01-18 17:33:05 +01:00
|
|
|
if (CitizensAPI.getNPCRegistry().isNPC(event.getCaught())
|
|
|
|
&& CitizensAPI.getNPCRegistry().getNPC(event.getCaught()).isProtected()) {
|
2017-12-30 08:36:36 +01:00
|
|
|
event.setCancelled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-14 23:02:00 +01:00
|
|
|
@EventHandler(ignoreCancelled = true, priority = EventPriority.HIGHEST)
|
2017-12-30 08:36:36 +01:00
|
|
|
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
|
2019-01-18 17:18:43 +01:00
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getRightClicked());
|
2023-08-31 20:36:04 +02:00
|
|
|
if (npc == null || Util.isOffHand(event))
|
2017-12-30 08:36:36 +01:00
|
|
|
return;
|
2023-08-31 20:36:04 +02:00
|
|
|
|
|
|
|
ClickRedirectTrait crt = npc.getTraitNullable(ClickRedirectTrait.class);
|
|
|
|
if (crt != null && (npc = crt.getRedirectNPC()) == null)
|
|
|
|
return;
|
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
Player player = event.getPlayer();
|
|
|
|
NPCRightClickEvent rightClickEvent = new NPCRightClickEvent(npc, player);
|
2022-12-26 13:07:16 +01:00
|
|
|
if (event.getPlayer().getItemInHand().getType() == Material.NAME_TAG) {
|
2022-12-22 16:17:28 +01:00
|
|
|
rightClickEvent.setCancelled(npc.isProtected());
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
Bukkit.getPluginManager().callEvent(rightClickEvent);
|
2020-04-20 15:44:50 +02:00
|
|
|
if (rightClickEvent.isCancelled()) {
|
|
|
|
event.setCancelled(true);
|
2022-10-02 17:10:23 +02:00
|
|
|
return;
|
2020-04-20 15:44:50 +02:00
|
|
|
}
|
2019-09-23 14:29:31 +02:00
|
|
|
if (npc.hasTrait(CommandTrait.class)) {
|
2020-09-14 11:57:58 +02:00
|
|
|
npc.getTraitNullable(CommandTrait.class).dispatch(player, CommandTrait.Hand.RIGHT);
|
2023-03-01 16:05:25 +01:00
|
|
|
rightClickEvent.setDelayedCancellation(true);
|
2019-09-23 14:29:31 +02:00
|
|
|
}
|
2022-10-22 04:42:44 +02:00
|
|
|
if (npc.hasTrait(ShopTrait.class)) {
|
|
|
|
npc.getTraitNullable(ShopTrait.class).onRightClick(player);
|
2023-03-01 16:05:25 +01:00
|
|
|
rightClickEvent.setDelayedCancellation(true);
|
|
|
|
}
|
|
|
|
if (rightClickEvent.isDelayedCancellation()) {
|
|
|
|
event.setCancelled(true);
|
2022-10-22 04:42:44 +02:00
|
|
|
}
|
2023-08-31 20:36:04 +02:00
|
|
|
if (event.isCancelled()) {
|
|
|
|
if (SUPPORT_STOP_USE_ITEM) {
|
|
|
|
try {
|
|
|
|
PlayerAnimation.STOP_USE_ITEM.play(player);
|
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(),
|
|
|
|
() -> PlayerAnimation.STOP_USE_ITEM.play(player));
|
|
|
|
} catch (UnsupportedOperationException e) {
|
|
|
|
SUPPORT_STOP_USE_ITEM = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR)
|
|
|
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
2023-03-12 15:29:41 +01:00
|
|
|
skinUpdateTracker.updatePlayer(event.getPlayer(), Setting.INITIAL_PLAYER_JOIN_SKIN_PACKET_DELAY.asTicks(),
|
2020-12-24 12:00:35 +01:00
|
|
|
true);
|
2022-12-24 12:53:59 +01:00
|
|
|
CitizensAPI.getLocationLookup().onJoin(event);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onPlayerLeashEntity(PlayerLeashEntityEvent event) {
|
2019-01-18 17:18:43 +01:00
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
|
2023-08-31 20:36:04 +02:00
|
|
|
if (npc == null)
|
2017-12-30 08:36:36 +01:00
|
|
|
return;
|
2023-08-31 20:36:04 +02:00
|
|
|
|
2022-05-08 15:57:15 +02:00
|
|
|
boolean leashProtected = npc.isProtected();
|
2023-01-01 08:26:35 +01:00
|
|
|
if (npc.data().get(NPC.Metadata.LEASH_PROTECTED, leashProtected)) {
|
2017-12-30 08:36:36 +01:00
|
|
|
event.setCancelled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// recalculate player NPCs the first time a player moves and every time
|
|
|
|
// a player moves a certain distance from their last position.
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
2023-11-05 13:58:37 +01:00
|
|
|
public void onPlayerMove(PlayerMoveEvent event) {
|
2017-12-30 08:36:36 +01:00
|
|
|
skinUpdateTracker.onPlayerMove(event.getPlayer());
|
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
|
|
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
|
|
|
Editor.leave(event.getPlayer());
|
|
|
|
if (event.getPlayer().isInsideVehicle()) {
|
2019-01-18 17:18:43 +01:00
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getPlayer().getVehicle());
|
2017-12-30 08:36:36 +01:00
|
|
|
if (npc != null) {
|
|
|
|
event.getPlayer().leaveVehicle();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skinUpdateTracker.removePlayer(event.getPlayer().getUniqueId());
|
2022-12-24 12:53:59 +01:00
|
|
|
CitizensAPI.getLocationLookup().onQuit(event);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(priority = EventPriority.MONITOR)
|
|
|
|
public void onPlayerRespawn(PlayerRespawnEvent event) {
|
|
|
|
skinUpdateTracker.updatePlayer(event.getPlayer(), 15, true);
|
|
|
|
}
|
|
|
|
|
2023-12-21 21:15:00 +01:00
|
|
|
@EventHandler
|
|
|
|
public void onPlayerShearEntityEvent(PlayerShearEntityEvent event) {
|
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getEntity());
|
|
|
|
if (npc == null)
|
|
|
|
return;
|
|
|
|
if (npc.isProtected()) {
|
|
|
|
event.setCancelled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2023-11-05 13:58:37 +01:00
|
|
|
public void onPlayerTeleport(PlayerTeleportEvent event) {
|
2022-12-22 16:17:28 +01:00
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getPlayer());
|
2023-10-13 15:49:21 +02:00
|
|
|
if (event.getCause() == TeleportCause.PLUGIN && npc != null && !npc.data().has("citizens-force-teleporting")
|
|
|
|
&& Setting.PLAYER_TELEPORT_DELAY.asTicks() > 0) {
|
2017-12-30 08:36:36 +01:00
|
|
|
event.setCancelled(true);
|
2023-08-31 20:36:04 +02:00
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
|
2023-10-13 15:49:21 +02:00
|
|
|
npc.data().set("citizens-force-teleporting", true);
|
2023-08-31 20:36:04 +02:00
|
|
|
event.getPlayer().teleport(event.getTo());
|
2023-10-13 15:49:21 +02:00
|
|
|
npc.data().remove("citizens-force-teleporting");
|
2023-03-12 15:29:41 +01:00
|
|
|
}, Setting.PLAYER_TELEPORT_DELAY.asTicks());
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
skinUpdateTracker.updatePlayer(event.getPlayer(), 15, true);
|
|
|
|
}
|
|
|
|
|
2021-07-15 13:41:03 +02:00
|
|
|
@EventHandler
|
|
|
|
public void onPluginDisable(PluginDisableEvent event) {
|
|
|
|
// hack: Spigot now unloads plugin classes on disable in reverse order so prefer unloading at the start of
|
|
|
|
// plugin disable cycle
|
|
|
|
PluginDescriptionFile file = event.getPlugin().getDescription();
|
|
|
|
for (String plugin : Iterables.concat(file.getDepend(), file.getSoftDepend())) {
|
2021-07-16 11:25:04 +02:00
|
|
|
if (plugin.equalsIgnoreCase("citizens") && CitizensAPI.hasImplementation()) {
|
2021-07-21 12:51:04 +02:00
|
|
|
((Citizens) CitizensAPI.getPlugin()).onDependentPluginDisable();
|
2021-07-15 13:41:03 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-09 13:54:20 +01:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onPotionSplashEvent(PotionSplashEvent event) {
|
|
|
|
for (LivingEntity entity : event.getAffectedEntities()) {
|
2019-01-18 17:18:43 +01:00
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(entity);
|
2023-11-05 13:58:37 +01:00
|
|
|
if (npc == null) {
|
2018-03-09 13:54:20 +01:00
|
|
|
continue;
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
2018-03-09 13:54:20 +01:00
|
|
|
if (npc.isProtected()) {
|
|
|
|
event.setIntensity(entity, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
@EventHandler(ignoreCancelled = true)
|
2023-11-05 13:58:37 +01:00
|
|
|
public void onProjectileHit(ProjectileHitEvent event) {
|
2017-12-30 08:36:36 +01:00
|
|
|
if (!(event.getEntity() instanceof FishHook))
|
|
|
|
return;
|
2023-09-20 16:05:05 +02:00
|
|
|
NMS.removeHookIfNecessary((FishHook) event.getEntity());
|
2017-12-30 08:36:36 +01:00
|
|
|
new BukkitRunnable() {
|
|
|
|
int n = 0;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void run() {
|
2023-09-20 16:05:05 +02:00
|
|
|
if (n++ > 5 || !CitizensAPI.hasImplementation()) {
|
2017-12-30 08:36:36 +01:00
|
|
|
cancel();
|
2023-09-20 16:05:05 +02:00
|
|
|
return;
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2023-09-20 16:05:05 +02:00
|
|
|
NMS.removeHookIfNecessary((FishHook) event.getEntity());
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}.runTaskTimer(CitizensAPI.getPlugin(), 0, 1);
|
|
|
|
}
|
|
|
|
|
2020-05-13 07:23:59 +02:00
|
|
|
@EventHandler
|
|
|
|
public void onVehicleDamage(VehicleDamageEvent event) {
|
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getVehicle());
|
2023-08-31 20:36:04 +02:00
|
|
|
if (npc == null)
|
2020-05-13 07:23:59 +02:00
|
|
|
return;
|
2023-08-31 20:36:04 +02:00
|
|
|
|
2022-07-05 13:13:31 +02:00
|
|
|
event.setCancelled(npc.isProtected());
|
2020-05-13 07:23:59 +02:00
|
|
|
|
|
|
|
NPCVehicleDamageEvent damageEvent = new NPCVehicleDamageEvent(npc, event);
|
|
|
|
Bukkit.getPluginManager().callEvent(damageEvent);
|
|
|
|
|
|
|
|
if (!damageEvent.isCancelled() || !(damageEvent.getDamager() instanceof Player))
|
|
|
|
return;
|
2023-08-31 20:36:04 +02:00
|
|
|
|
2020-05-13 07:23:59 +02:00
|
|
|
Player damager = (Player) damageEvent.getDamager();
|
|
|
|
|
|
|
|
NPCLeftClickEvent leftClickEvent = new NPCLeftClickEvent(npc, damager);
|
|
|
|
Bukkit.getPluginManager().callEvent(leftClickEvent);
|
|
|
|
if (npc.hasTrait(CommandTrait.class)) {
|
2020-09-14 11:57:58 +02:00
|
|
|
npc.getTraitNullable(CommandTrait.class).dispatch(damager, CommandTrait.Hand.LEFT);
|
2020-05-13 07:23:59 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-30 08:36:36 +01:00
|
|
|
@EventHandler
|
|
|
|
public void onVehicleDestroy(VehicleDestroyEvent event) {
|
2019-01-18 17:18:43 +01:00
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getVehicle());
|
2023-08-31 20:36:04 +02:00
|
|
|
if (npc == null)
|
2017-12-30 08:36:36 +01:00
|
|
|
return;
|
2023-08-31 20:36:04 +02:00
|
|
|
|
2022-07-05 13:13:31 +02:00
|
|
|
event.setCancelled(npc.isProtected());
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(ignoreCancelled = true)
|
2023-11-05 13:58:37 +01:00
|
|
|
public void onVehicleEnter(VehicleEnterEvent event) {
|
2019-01-18 17:18:43 +01:00
|
|
|
NPC npc = CitizensAPI.getNPCRegistry().getNPC(event.getVehicle());
|
2021-04-22 16:22:46 +02:00
|
|
|
NPC rider = CitizensAPI.getNPCRegistry().getNPC(event.getEntered());
|
|
|
|
if (npc == null) {
|
2022-06-11 09:17:17 +02:00
|
|
|
if (rider != null && rider.isProtected() && (event.getVehicle().getType().name().contains("BOAT")
|
|
|
|
|| event.getVehicle() instanceof Minecart)) {
|
2021-04-22 16:22:46 +02:00
|
|
|
event.setCancelled(true);
|
|
|
|
}
|
2019-05-26 09:40:54 +02:00
|
|
|
return;
|
2021-04-22 16:22:46 +02:00
|
|
|
}
|
2023-11-04 19:03:57 +01:00
|
|
|
if (rider != null || !(npc instanceof Vehicle))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!npc.hasTrait(Controllable.class) || !npc.getTraitNullable(Controllable.class).isEnabled()) {
|
2017-12-30 08:36:36 +01:00
|
|
|
event.setCancelled(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@EventHandler(ignoreCancelled = true)
|
|
|
|
public void onWorldLoad(WorldLoadEvent event) {
|
|
|
|
for (ChunkCoord chunk : toRespawn.keySet()) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (!chunk.worldUUID.equals(event.getWorld().getUID())
|
|
|
|
|| !event.getWorld().isChunkLoaded(chunk.x, chunk.z)) {
|
2017-12-30 08:36:36 +01:00
|
|
|
continue;
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
2020-06-28 11:36:24 +02:00
|
|
|
respawnAllFromCoord(chunk, event);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-14 23:02:00 +01:00
|
|
|
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
|
2017-12-30 08:36:36 +01:00
|
|
|
public void onWorldUnload(WorldUnloadEvent event) {
|
|
|
|
for (NPC npc : getAllNPCs()) {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (npc == null || !npc.isSpawned() || !npc.getEntity().getWorld().equals(event.getWorld())) {
|
2017-12-30 08:36:36 +01:00
|
|
|
continue;
|
2023-11-05 13:58:37 +01:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
boolean despawned = npc.despawn(DespawnReason.WORLD_UNLOAD);
|
|
|
|
if (event.isCancelled() || !despawned) {
|
|
|
|
for (ChunkCoord coord : toRespawn.keySet()) {
|
2018-08-08 01:50:08 +02:00
|
|
|
if (event.getWorld().getUID().equals(coord.worldUUID)) {
|
2020-06-28 11:36:24 +02:00
|
|
|
respawnAllFromCoord(coord, event);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
event.setCancelled(true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (npc.isSpawned()) {
|
2020-10-12 14:44:11 +02:00
|
|
|
toRespawn.put(new ChunkCoord(npc.getEntity().getLocation()), npc);
|
2022-03-13 21:25:42 +01:00
|
|
|
Messaging.debug("Despawned", npc, "due to world unload at", event.getWorld().getName());
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
}
|
2023-02-09 14:09:53 +01:00
|
|
|
CitizensAPI.getLocationLookup().onWorldUnload(event);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
2023-06-12 15:20:51 +02:00
|
|
|
private void registerKnockbackEvent(Class<?> kbc) {
|
|
|
|
try {
|
|
|
|
HandlerList handlers = (HandlerList) kbc.getMethod("getHandlerList").invoke(null);
|
|
|
|
Method getEntity = kbc.getMethod("getEntity");
|
|
|
|
Method getHitBy = kbc.getMethod("getHitBy");
|
|
|
|
Method getKnockbackStrength = kbc.getMethod("getKnockbackStrength");
|
|
|
|
Method getAcceleration = kbc.getMethod("getAcceleration");
|
|
|
|
handlers.register(new RegisteredListener(new Listener() {
|
|
|
|
}, (listener, event) -> {
|
|
|
|
try {
|
2023-06-19 14:39:50 +02:00
|
|
|
if (event.getClass() != kbc)
|
|
|
|
return;
|
2023-06-12 15:20:51 +02:00
|
|
|
Entity entity = (Entity) getEntity.invoke(event);
|
|
|
|
if (!(entity instanceof NPCHolder))
|
|
|
|
return;
|
|
|
|
NPC npc = ((NPCHolder) entity).getNPC();
|
|
|
|
Entity hitBy = (Entity) getHitBy.invoke(event);
|
|
|
|
float strength = (float) getKnockbackStrength.invoke(event);
|
|
|
|
Vector vector = (Vector) getAcceleration.invoke(event);
|
|
|
|
NPCKnockbackEvent kb = new NPCKnockbackEvent(npc, strength, vector, hitBy);
|
|
|
|
Bukkit.getPluginManager().callEvent(kb);
|
|
|
|
((Cancellable) event).setCancelled(kb.isCancelled());
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
ex.printStackTrace();
|
|
|
|
}
|
|
|
|
}, EventPriority.NORMAL, CitizensAPI.getPlugin(), true));
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
Messaging.severe("Error registering knockback event forwarder");
|
|
|
|
ex.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void registerPushEvent(Class<?> clazz) {
|
|
|
|
try {
|
|
|
|
HandlerList handlers = (HandlerList) clazz.getMethod("getHandlerList").invoke(null);
|
|
|
|
Method getEntity = clazz.getMethod("getEntity");
|
|
|
|
Method getPushedBy = clazz.getMethod("getPushedBy");
|
|
|
|
Method getAcceleration = clazz.getMethod("getAcceleration");
|
|
|
|
handlers.register(new RegisteredListener(new Listener() {
|
|
|
|
}, (listener, event) -> {
|
2023-11-05 13:58:37 +01:00
|
|
|
if (NPCPushEvent.getHandlerList().getRegisteredListeners().length == 0 || event.getClass() != clazz)
|
2023-06-19 14:39:50 +02:00
|
|
|
return;
|
2023-06-12 15:20:51 +02:00
|
|
|
try {
|
|
|
|
Entity entity = (Entity) getEntity.invoke(event);
|
|
|
|
if (!(entity instanceof NPCHolder))
|
|
|
|
return;
|
|
|
|
NPC npc = ((NPCHolder) entity).getNPC();
|
|
|
|
Entity pushedBy = (Entity) getPushedBy.invoke(event);
|
|
|
|
Vector vector = (Vector) getAcceleration.invoke(event);
|
|
|
|
NPCPushEvent push = new NPCPushEvent(npc, vector, pushedBy);
|
|
|
|
Bukkit.getPluginManager().callEvent(push);
|
|
|
|
((Cancellable) event).setCancelled(push.isCancelled());
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
ex.printStackTrace();
|
|
|
|
}
|
|
|
|
}, EventPriority.NORMAL, CitizensAPI.getPlugin(), true));
|
|
|
|
} catch (Throwable ex) {
|
|
|
|
Messaging.severe("Error registering push event forwarder");
|
|
|
|
ex.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-28 11:36:24 +02:00
|
|
|
private void respawnAllFromCoord(ChunkCoord coord, Event event) {
|
2020-10-15 14:30:50 +02:00
|
|
|
List<NPC> ids = Lists.newArrayList(toRespawn.get(coord));
|
2020-10-13 13:51:53 +02:00
|
|
|
if (ids.size() > 0) {
|
2024-01-13 15:48:27 +01:00
|
|
|
Messaging.idebug(() -> Joiner.on(' ').join("Respawning all NPCs at", coord, "due to", event, "at", coord));
|
2020-10-13 13:51:53 +02:00
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
for (int i = 0; i < ids.size(); i++) {
|
|
|
|
NPC npc = ids.get(i);
|
2019-10-03 07:14:20 +02:00
|
|
|
if (npc.getOwningRegistry().getById(npc.getId()) != npc) {
|
2023-01-03 13:55:27 +01:00
|
|
|
Messaging.idebug(() -> "Prevented deregistered NPC from respawning " + npc);
|
2019-10-03 07:14:20 +02:00
|
|
|
continue;
|
|
|
|
}
|
2020-05-12 16:13:22 +02:00
|
|
|
if (npc.isSpawned()) {
|
2023-01-03 13:55:27 +01:00
|
|
|
Messaging.idebug(() -> "Can't respawn NPC " + npc + ": already spawned");
|
2020-05-12 16:13:22 +02:00
|
|
|
continue;
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
boolean success = spawn(npc);
|
|
|
|
if (!success) {
|
2020-10-15 14:30:50 +02:00
|
|
|
ids.remove(i--);
|
2023-01-03 13:55:27 +01:00
|
|
|
Messaging.idebug(() -> Joiner.on(' ').join("Couldn't respawn", npc, "during", event, "at", coord));
|
2017-12-30 08:36:36 +01:00
|
|
|
continue;
|
|
|
|
}
|
2023-01-03 13:55:27 +01:00
|
|
|
Messaging.idebug(() -> Joiner.on(' ').join("Spawned", npc, "during", event, "at", coord));
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2020-10-15 14:30:50 +02:00
|
|
|
for (NPC npc : ids) {
|
|
|
|
toRespawn.remove(coord, npc);
|
|
|
|
}
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private boolean spawn(NPC npc) {
|
2020-09-14 11:57:58 +02:00
|
|
|
Location spawn = npc.getOrAddTrait(CurrentLocation.class).getLocation();
|
2017-12-30 08:36:36 +01:00
|
|
|
if (spawn == null) {
|
2024-01-13 15:48:27 +01:00
|
|
|
Messaging.idebug(() -> "Couldn't find a spawn location for despawned NPC " + npc);
|
2017-12-30 08:36:36 +01:00
|
|
|
return false;
|
|
|
|
}
|
2019-06-12 15:06:06 +02:00
|
|
|
return npc.spawn(spawn, SpawnReason.CHUNK_LOAD);
|
2017-12-30 08:36:36 +01:00
|
|
|
}
|
2022-10-04 16:18:05 +02:00
|
|
|
|
2024-01-13 15:48:27 +01:00
|
|
|
private void unloadNPCs(ChunkEvent event, List<NPC> toDespawn) {
|
2022-10-18 19:47:07 +02:00
|
|
|
ChunkCoord coord = new ChunkCoord(event.getChunk());
|
|
|
|
boolean loadChunk = false;
|
|
|
|
for (NPC npc : toDespawn) {
|
2024-01-13 15:48:27 +01:00
|
|
|
if (toRespawn.containsValue(npc))
|
|
|
|
continue;
|
2022-10-18 19:47:07 +02:00
|
|
|
if (!npc.despawn(DespawnReason.CHUNK_UNLOAD)) {
|
|
|
|
if (!(event instanceof Cancellable)) {
|
2023-01-03 13:55:27 +01:00
|
|
|
Messaging.idebug(() -> Joiner.on(' ').join("Reloading chunk because", npc, "couldn't despawn"));
|
2022-10-18 19:47:07 +02:00
|
|
|
loadChunk = true;
|
|
|
|
toRespawn.put(coord, npc);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
((Cancellable) event).setCancelled(true);
|
2024-01-13 15:48:27 +01:00
|
|
|
Messaging.idebug(() -> "Cancelled chunk unload at " + coord);
|
2022-10-18 19:47:07 +02:00
|
|
|
respawnAllFromCoord(coord, event);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
toRespawn.put(coord, npc);
|
2023-01-03 13:55:27 +01:00
|
|
|
Messaging.idebug(() -> Joiner.on(' ').join("Despawned", npc, "due to chunk unload at", coord));
|
2022-10-18 19:47:07 +02:00
|
|
|
}
|
|
|
|
if (Messaging.isDebugging() && Setting.DEBUG_CHUNK_LOADS.asBoolean()) {
|
|
|
|
new Exception("CITIZENS CHUNK UNLOAD DEBUG " + coord).printStackTrace();
|
|
|
|
}
|
|
|
|
if (loadChunk) {
|
2023-01-03 13:55:27 +01:00
|
|
|
Messaging.idebug(() -> Joiner.on(' ').join("Loading chunk in 10 ticks due to forced chunk load at", coord));
|
2023-08-31 20:36:04 +02:00
|
|
|
Bukkit.getScheduler().scheduleSyncDelayedTask(CitizensAPI.getPlugin(), () -> {
|
|
|
|
if (!event.getChunk().isLoaded()) {
|
|
|
|
event.getChunk().load();
|
2022-10-18 19:47:07 +02:00
|
|
|
}
|
|
|
|
}, 10);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-04 16:18:05 +02:00
|
|
|
private static boolean SUPPORT_STOP_USE_ITEM = true;
|
2022-08-05 06:01:07 +02:00
|
|
|
}
|