Remove the ID update routine and add NPC database guarding.

This commit is contained in:
Olof Larsson 2015-05-16 12:15:34 +02:00
parent ba361733b3
commit a374b02013
11 changed files with 127 additions and 259 deletions

View File

@ -42,7 +42,6 @@ import com.massivecraft.massivecore.collections.MassiveTreeMap;
import com.massivecraft.massivecore.collections.MassiveTreeMapDef;
import com.massivecraft.massivecore.collections.MassiveTreeSet;
import com.massivecraft.massivecore.collections.MassiveTreeSetDef;
import com.massivecraft.massivecore.event.EventMassiveCoreUuidUpdate;
import com.massivecraft.massivecore.integration.vault.IntegrationVault;
import com.massivecraft.massivecore.mixin.EngineTeleportMixinCause;
import com.massivecraft.massivecore.ps.PS;
@ -53,7 +52,6 @@ import com.massivecraft.massivecore.util.IdUtil;
import com.massivecraft.massivecore.util.MUtil;
import com.massivecraft.massivecore.util.PlayerUtil;
import com.massivecraft.massivecore.util.TimeUnit;
import com.massivecraft.massivecore.util.Txt;
import com.massivecraft.massivecore.xlib.gson.Gson;
import com.massivecraft.massivecore.xlib.gson.GsonBuilder;
import com.massivecraft.massivecore.xlib.gson.JsonArray;
@ -149,6 +147,14 @@ public class MassiveCore extends MassivePlugin
// OVERRIDE
// -------------------------------------------- //
@Override
public void onLoad()
{
super.onLoad();
// Attempting to fix a race condition within the class asynchronous class loader.
System.out.println("TimeUnit.MILLIS_PER_MINUTE: " + TimeUnit.MILLIS_PER_MINUTE);
}
@Override
public void onEnable()
{
@ -163,9 +169,6 @@ public class MassiveCore extends MassivePlugin
if ( ! preEnable()) return;
// TODO: This seems to fix most race conditions within the class asynchronous class loader.
System.out.println("TimeUnit.MILLIS_PER_MINUTE: " + TimeUnit.MILLIS_PER_MINUTE);
// Load Server Config
ConfServer.get().load();
@ -215,23 +218,6 @@ public class MassiveCore extends MassivePlugin
MassiveCoreTaskDeleteFiles.get().run();
Bukkit.getScheduler().scheduleSyncDelayedTask(this, MassiveCoreTaskDeleteFiles.get());
Bukkit.getScheduler().scheduleSyncDelayedTask(this, new Runnable()
{
@Override
public void run()
{
IdUtil.loadDatas();
log(Txt.parse("<i>Upgrading from player name to player uuid..."));
EventMassiveCoreUuidUpdate event = new EventMassiveCoreUuidUpdate();
event.run();
log(Txt.parse("<g> ... done!"));
log(Txt.parse("<i>(database saving will now commence which might lock the server for a while)"));
}
});
this.postEnable();
}

View File

@ -6,6 +6,7 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import org.bukkit.Bukkit;
@ -37,6 +38,7 @@ import com.massivecraft.massivecore.mixin.Mixin;
import com.massivecraft.massivecore.store.Coll;
import com.massivecraft.massivecore.store.SenderColl;
import com.massivecraft.massivecore.util.IdUtil;
import com.massivecraft.massivecore.util.MUtil;
import com.massivecraft.massivecore.util.SmokeUtil;
import com.massivecraft.massivecore.xlib.gson.JsonElement;
@ -82,6 +84,8 @@ public class MassiveCoreEngineMain extends EngineAbstract
// Prepare vars
EventMassiveCorePlayerToRecipientChat recipientEvent;
final Player sender = event.getPlayer();
if (MUtil.isNpc(sender)) return;
String message = event.getMessage();
String format = event.getFormat();
@ -135,6 +139,7 @@ public class MassiveCoreEngineMain extends EngineAbstract
{
// So the player is watching ...
Player watcher = event.getPlayer();
if (MUtil.isNpc(watcher)) return;
// Get the lowercased token
String tokenlc = event.getLastToken().toLowerCase();
@ -181,6 +186,8 @@ public class MassiveCoreEngineMain extends EngineAbstract
// This method sets the sender reference to what you decide.
public static void setSenderReferences(CommandSender sender, CommandSender reference)
{
if (MUtil.isNpc(sender)) return;
String id = IdUtil.getId(sender);
if (id != null)
{
@ -257,39 +264,51 @@ public class MassiveCoreEngineMain extends EngineAbstract
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void after(PlayerTeleportEvent event)
{
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
Bukkit.getScheduler().scheduleSyncDelayedTask(MassiveCore.get(), new EventMassiveCoreAfterPlayerTeleport(event), 0);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void after(PlayerRespawnEvent event)
{
Bukkit.getScheduler().scheduleSyncDelayedTask(MassiveCore.get(), new EventMassiveCoreAfterPlayerRespawn(event, event.getPlayer().getLocation()), 0);
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
Bukkit.getScheduler().scheduleSyncDelayedTask(MassiveCore.get(), new EventMassiveCoreAfterPlayerRespawn(event, player.getLocation()), 0);
}
// -------------------------------------------- //
// EVENT TOOL: causedByKick
// -------------------------------------------- //
public static Map<String,String> kickedPlayerReasons = new HashMap<String,String>();
public static Map<UUID, String> kickedPlayerReasons = new HashMap<UUID, String>();
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void causedByKick(PlayerKickEvent event)
{
final String name = event.getPlayer().getName();
kickedPlayerReasons.put(name, event.getReason());
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
final UUID uuid = player.getUniqueId();
kickedPlayerReasons.put(uuid, event.getReason());
}
@EventHandler(priority = EventPriority.MONITOR)
public void causedByKick(PlayerQuitEvent event)
{
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
final UUID uuid = player.getUniqueId();
// We do the schedule in order for the set to be correct through out the whole MONITOR priority state.
final String name = event.getPlayer().getName();
Bukkit.getScheduler().scheduleSyncDelayedTask(MassiveCore.get(), new Runnable()
{
@Override
public void run()
{
kickedPlayerReasons.remove(name);
kickedPlayerReasons.remove(uuid);
}
});
}
@ -301,26 +320,36 @@ public class MassiveCoreEngineMain extends EngineAbstract
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void leaveEventKickCall(PlayerKickEvent event)
{
new EventMassiveCorePlayerLeave(event.getPlayer(), true, "kick", event.getReason()).run();
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
new EventMassiveCorePlayerLeave(player, true, "kick", event.getReason()).run();
}
@EventHandler(priority = EventPriority.MONITOR)
public void leaveEventQuitCall(PlayerQuitEvent event)
{
new EventMassiveCorePlayerLeave(event.getPlayer(), false, "quit", null).run();
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
new EventMassiveCorePlayerLeave(player, false, "quit", null).run();
}
@EventHandler(priority = EventPriority.MONITOR)
public void leaveEventQuitClear(PlayerQuitEvent event)
{
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
final UUID uuid = player.getUniqueId();
// We do the schedule in order for the set to be correct through out the whole MONITOR priority state.
final String name = event.getPlayer().getName();
Bukkit.getScheduler().scheduleSyncDelayedTask(MassiveCore.get(), new Runnable()
{
@Override
public void run()
{
EventMassiveCorePlayerLeave.player2event.remove(name);
EventMassiveCorePlayerLeave.player2event.remove(uuid);
}
});
}
@ -415,7 +444,9 @@ public class MassiveCoreEngineMain extends EngineAbstract
public void massiveStoreLoginSync(PlayerLoginEvent event)
{
// Get player id ...
final String playerId = event.getPlayer().getUniqueId().toString();
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
final String playerId = player.getUniqueId().toString();
// ... get remote entries ...
Map<SenderColl<?>, Entry<JsonElement, Long>> remoteEntries = getRemoteEntries(playerId);

View File

@ -18,6 +18,7 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.plugin.Plugin;
import com.massivecraft.massivecore.util.IdUtil;
import com.massivecraft.massivecore.util.MUtil;
import com.massivecraft.massivecore.util.Txt;
public class MassiveCoreEngineVariable extends EngineAbstract
@ -46,13 +47,19 @@ public class MassiveCoreEngineVariable extends EngineAbstract
@EventHandler(priority = EventPriority.NORMAL)
public void variable(PlayerCommandPreprocessEvent event)
{
event.setMessage(variable(event.getPlayer(), event.getMessage()));
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
event.setMessage(variable(player, event.getMessage()));
}
@EventHandler(priority = EventPriority.LOW)
public void variable(AsyncPlayerChatEvent event)
{
event.setMessage(variable(event.getPlayer(), event.getMessage()));
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
event.setMessage(variable(player, event.getMessage()));
}
public static String variable(Player player, String message)

View File

@ -2,6 +2,7 @@ package com.massivecraft.massivecore.event;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@ -66,16 +67,18 @@ public class EventMassiveCorePlayerLeave extends Event implements Runnable
@Override
public void run()
{
UUID uuid = this.player.getUniqueId();
// Someone may already have issued a player leave event for this disconnect.
// We ignore that since we want one leave event called per disconnect only.
boolean doit = !player2event.containsKey(this.player.getName());
boolean doit = !player2event.containsKey(uuid);
//MassiveCore.p.log("EventMassiveCorePlayerLeave", "caller:", caller, "doit:", doit, "player:", player.getDisplayName(), "preDisconnect:", preDisconnect, "message:", message);
if (doit)
{
//MassiveCore.p.log("EventMassiveCorePlayerLeave", caller, player.getDisplayName(), preDisconnect, message);
player2event.put(this.player.getName(), this);
player2event.put(uuid, this);
Bukkit.getPluginManager().callEvent(this);
}
}
@ -83,6 +86,6 @@ public class EventMassiveCorePlayerLeave extends Event implements Runnable
// -------------------------------------------- //
// STORING THE ACTIVE PLAYER EVENT
// -------------------------------------------- //
public static Map<String,EventMassiveCorePlayerLeave> player2event = new HashMap<String,EventMassiveCorePlayerLeave>();
public static Map<UUID, EventMassiveCorePlayerLeave> player2event = new HashMap<UUID, EventMassiveCorePlayerLeave>();
}

View File

@ -1,15 +0,0 @@
package com.massivecraft.massivecore.event;
import org.bukkit.event.HandlerList;
public class EventMassiveCoreUuidUpdate extends EventMassiveCore
{
// -------------------------------------------- //
// REQUIRED EVENT CODE
// -------------------------------------------- //
private static final HandlerList handlers = new HandlerList();
@Override public HandlerList getHandlers() { return handlers; }
public static HandlerList getHandlerList() { return handlers; }
}

View File

@ -12,6 +12,7 @@ import com.massivecraft.massivecore.Predictate;
import com.massivecraft.massivecore.cmd.arg.ARSenderEntity;
import com.massivecraft.massivecore.cmd.arg.ARSenderId;
import com.massivecraft.massivecore.util.IdUtil;
import com.massivecraft.massivecore.util.MUtil;
public class SenderColl<E extends SenderEntity<E>> extends Coll<E> implements SenderIdSource
{
@ -48,6 +49,25 @@ public class SenderColl<E extends SenderEntity<E>> extends Coll<E> implements Se
// OVERRIDE: Coll
// -------------------------------------------- //
public static void denyNpc(Object oid)
{
if (MUtil.isNpc(oid)) throw new IllegalArgumentException("NPCs are not allowed: " + oid);
}
@Override
public E get(Object oid)
{
denyNpc(oid);
return super.get(oid);
}
@Override
public E get(Object oid, boolean creative)
{
denyNpc(oid);
return super.get(oid, creative);
}
@Override
public String fixId(Object oid)
{

View File

@ -94,6 +94,8 @@ public class EngineScheduledTeleport extends EngineAbstract
public void cancelTeleport(Player player)
{
if (MUtil.isNpc(player)) return;
// If there there is a ScheduledTeleport ...
ScheduledTeleport scheduledTeleport = teleporteeIdToScheduledTeleport.get(IdUtil.getId(player));
if (scheduledTeleport == null) return;
@ -112,7 +114,8 @@ public class EngineScheduledTeleport extends EngineAbstract
if (MUtil.isSameBlock(event.getFrom(), event.getTo())) return;
// ... cancel teleport!
this.cancelTeleport(event.getPlayer());
Player player = event.getPlayer();
this.cancelTeleport(player);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)

View File

@ -1,106 +0,0 @@
package com.massivecraft.massivecore.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import com.massivecraft.massivecore.MassiveCore;
import com.massivecraft.massivecore.store.Coll;
import com.massivecraft.massivecore.store.Entity;
public class IdUpdateUtil
{
// -------------------------------------------- //
// SINGLE
// -------------------------------------------- //
public static String update(String string, boolean force)
{
if (string == null) return null;
String ret = IdUtil.getId(string);
if (ret != null) return ret;
if (!force) return string;
return null;
}
// -------------------------------------------- //
// COLL
// -------------------------------------------- //
public static void update(Collection<String> from, Collection<String> to, boolean force)
{
for (String string : from)
{
string = update(string, force);
if (string == null) continue;
to.add(string);
}
}
public static List<String> update(List<String> strings, boolean force)
{
List<String> ret = new ArrayList<String>();
update(strings, ret, force);
return ret;
}
public static Set<String> update(Set<String> strings, boolean force)
{
Set<String> ret = new LinkedHashSet<String>();
update(strings, ret, force);
return ret;
}
// -------------------------------------------- //
// COLL
// -------------------------------------------- //
public static <E extends Entity<E>> void update(Coll<E> coll)
{
update(coll, false);
}
public static <E extends Entity<E>> void update(Coll<E> coll, boolean force)
{
long pre = System.currentTimeMillis();
MassiveCore.get().log(Txt.parse("<i>Pre update <h>%s<i>.", coll.getName()));
int countTotal = coll.getAll().size();
int countUpdate = 0;
for (E entity : coll.getAll())
{
if (update(coll, entity, force)) countUpdate++;
}
long post = System.currentTimeMillis();
long delta = post - pre;
MassiveCore.get().log(Txt.parse("<i>Post update <h>%s<i>. Took <h>%dms<i>. <h>%d/%d <i>changed.", coll.getName(), delta, countUpdate, countTotal));
}
public static <E extends Entity<E>> boolean update(Coll<E> coll, E entity, boolean force)
{
// Before and After
String before = coll.getId(entity);
if (before == null) return false;
String after = update(before, force);
if (after == null && !force) return false;
// NoChange
if (MUtil.equals(before, after)) return false;
// Apply
coll.detachEntity(entity);
if (after == null) return true;
coll.attach(entity, after);
coll.syncId(after);
return true;
}
}

View File

@ -2,14 +2,11 @@ package com.massivecraft.massivecore.util;
import java.io.File;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
@ -30,11 +27,7 @@ import com.massivecraft.massivecore.MassiveCore;
import com.massivecraft.massivecore.event.EventMassiveCorePlayerLeave;
import com.massivecraft.massivecore.event.EventMassiveCoreSenderRegister;
import com.massivecraft.massivecore.event.EventMassiveCoreSenderUnregister;
import com.massivecraft.massivecore.fetcher.Fetcher;
import com.massivecraft.massivecore.fetcher.IdAndName;
import com.massivecraft.massivecore.mixin.Mixin;
import com.massivecraft.massivecore.store.Coll;
import com.massivecraft.massivecore.store.SenderColl;
import com.massivecraft.massivecore.store.SenderEntity;
import com.massivecraft.massivecore.xlib.gson.reflect.TypeToken;
@ -394,6 +387,8 @@ public class IdUtil implements Listener, Runnable
public void playerLoginLowest(PlayerLoginEvent event)
{
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
UUID uuid = player.getUniqueId();
String id = uuid.toString();
String name = player.getName();
@ -409,6 +404,8 @@ public class IdUtil implements Listener, Runnable
public void playerJoinLowest(PlayerJoinEvent event)
{
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
UUID uuid = player.getUniqueId();
String id = uuid.toString();
String name = player.getName();
@ -822,20 +819,6 @@ public class IdUtil implements Listener, Runnable
update(id, name, true);
}
if (Bukkit.getServer().getOnlineMode())
{
MassiveCore.get().log(Txt.parse("<i>Loading Dbmojangapi datas..."));
for (IdData data : getDbmojangapiDatas())
{
update(data.getId(), data.getName(), data.getMillis());
}
}
else
{
MassiveCore.get().log(Txt.parse("<i>Skipping Dbmojangapi datas since offline mode..."));
}
MassiveCore.get().log(Txt.parse("<i>Saving Cachefile..."));
saveCachefileDatas();
}
@ -904,78 +887,4 @@ public class IdUtil implements Listener, Runnable
return ret;
}
// -------------------------------------------- //
// DBMOJANGAPI DATAS
// -------------------------------------------- //
// This data source searches the database for player names and ids (strings).
// It then discards the strings already present in IdUtil.
// The renaming strings are queried through the Mojang API.
public static Set<IdData> getDbmojangapiDatas()
{
Set<IdData> ret = new LinkedHashSet<IdData>();
// Add valid names from DB
Set<String> strings = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
for (Coll<?> coll : Coll.getInstances())
{
if (!(coll instanceof SenderColl<?>)) continue;
for (String id : coll.getIds())
{
// https://github.com/Mojang/AccountsClient/issues/2
// Would have been nice but no. Mojang did not have time to implement this feature for us :/
//if (MUtil.isValidPlayerName(id) || MUtil.isValidUUID(id))
if (MUtil.isValidPlayerName(id))
{
strings.add(id);
}
}
}
MassiveCore.get().log(Txt.parse("<k>Player Strings Found: <v>%d", strings.size()));
// Remove Cached
Iterator<String> iter = strings.iterator();
int cached = 0;
while (iter.hasNext())
{
String string = iter.next();
if (getData(string) != null)
{
cached++;
iter.remove();
}
}
MassiveCore.get().log(Txt.parse("<k>Player Strings Cached: <v>%d", cached));
MassiveCore.get().log(Txt.parse("<k>Player Strings Remaining: <v>%d", strings.size()));
// Fetch
MassiveCore.get().log(Txt.parse("<i>Now fetching the remaining players from Mojang API ..."));
Collection<IdAndName> idAndNames = null;
try
{
idAndNames = Fetcher.fetch(strings);
}
catch (Exception e)
{
e.printStackTrace();
return null;
}
MassiveCore.get().log(Txt.parse("<i> ... done!"));
long millis = System.currentTimeMillis();
// Add
for (IdAndName idAndName : idAndNames)
{
String id = null;
UUID uuid = idAndName.getId();
if (uuid != null) id = uuid.toString();
String name = idAndName.getName();
ret.add(new IdData(id, name, millis));
}
return ret;
}
}

View File

@ -49,6 +49,7 @@ import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.PotionMeta;
import org.bukkit.metadata.Metadatable;
import org.bukkit.potion.Potion;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
@ -207,6 +208,17 @@ public class MUtil
return asUuid(string) != null;
}
// -------------------------------------------- //
// NPC
// -------------------------------------------- //
public static boolean isNpc(Object object)
{
if (!(object instanceof Metadatable)) return false;
Metadatable metadatable = (Metadatable)object;
return metadatable.hasMetadata("NPC");
}
// -------------------------------------------- //
// STACK TRACE: GET
// -------------------------------------------- //
@ -1092,7 +1104,11 @@ public class MUtil
public static String kickReason(PlayerQuitEvent event)
{
return MassiveCoreEngineMain.kickedPlayerReasons.get(event.getPlayer().getName());
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return null;
UUID uuid = player.getUniqueId();
return MassiveCoreEngineMain.kickedPlayerReasons.get(uuid);
}
public static boolean causedByKick(PlayerQuitEvent event)

View File

@ -92,7 +92,10 @@ public class PlayerUtil extends EngineAbstract
@EventHandler(priority = EventPriority.MONITOR)
public void isJoined(PlayerJoinEvent event)
{
final UUID id = event.getPlayer().getUniqueId();
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
final UUID id = player.getUniqueId();
Bukkit.getScheduler().scheduleSyncDelayedTask(MassiveCore.get(), new Runnable()
{
@Override
@ -106,7 +109,10 @@ public class PlayerUtil extends EngineAbstract
@EventHandler(priority = EventPriority.MONITOR)
public void isJoined(PlayerQuitEvent event)
{
final UUID id = event.getPlayer().getUniqueId();
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
final UUID id = player.getUniqueId();
joinedPlayerIds.remove(id);
}
@ -184,6 +190,7 @@ public class PlayerUtil extends EngineAbstract
public static void setLastDamageMillis(Player player, long millis)
{
if (MUtil.isNpc(player)) return;
if (player == null) return;
idToLastDamageMillis.put(player.getUniqueId(), millis);
}
@ -219,6 +226,7 @@ public class PlayerUtil extends EngineAbstract
public static long getLastDamageMillis(Player player)
{
if (player == null) return 0;
if (MUtil.isNpc(player)) return 0;
Long ret = idToLastDamageMillis.get(player.getUniqueId());
if (ret == null) return 0;
return ret;
@ -227,6 +235,7 @@ public class PlayerUtil extends EngineAbstract
public static long getNoDamageMillis(Player player)
{
if (player == null) return 0;
if (MUtil.isNpc(player)) return 0;
if (player.isDead()) return 0;
if (!player.isOnline()) return 0;
@ -313,7 +322,9 @@ public class PlayerUtil extends EngineAbstract
if (event.getAnimationType() != PlayerAnimationType.ARM_SWING) return false;
// Get the id ...
final UUID id = event.getPlayer().getUniqueId();
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return false;
final UUID id = player.getUniqueId();
// ... get current ...
PlayerAnimationEvent current = idToArmSwingEvent.get(id);
@ -384,6 +395,7 @@ public class PlayerUtil extends EngineAbstract
{
// If we have a player ...
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
// ... and the player is alive ...
if (player.isDead()) return;
@ -423,6 +435,7 @@ public class PlayerUtil extends EngineAbstract
{
// If we have a player ...
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
// ... and the player is alive ...
if (player.isDead()) return;
@ -436,6 +449,7 @@ public class PlayerUtil extends EngineAbstract
{
// If we have a player ...
Player player = event.getPlayer();
if (MUtil.isNpc(player)) return;
// ... and the player is alive ...
if (player.isDead()) return;