diff --git a/pom.xml b/pom.xml
index 2506636..999b8c3 100755
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
4.0.0
com.trc202
combattag
- 6.4.0-SNAPSHOT
+ 6.4.0
CombatTag
1.6
diff --git a/src/main/java/com/trc202/CombatTag/CombatTag.java b/src/main/java/com/trc202/CombatTag/CombatTag.java
index aac69f0..c620d2a 100755
--- a/src/main/java/com/trc202/CombatTag/CombatTag.java
+++ b/src/main/java/com/trc202/CombatTag/CombatTag.java
@@ -2,6 +2,7 @@
import java.io.File;
import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -18,6 +19,7 @@
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.HumanEntity;
+import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
@@ -37,6 +39,8 @@
import com.trc202.settings.SettingsHelper;
import com.trc202.settings.SettingsLoader;
+import static com.trc202.CombatTag.Reflection.*;
+
public class CombatTag extends JavaPlugin {
private final SettingsHelper settingsHelper;
@@ -87,11 +91,13 @@ public CombatTag() {
*/
@Override
public void onDisable() {
- for (NPC npc : npcm.getNPCs()) {
- UUID uuid = npcm.getNPCIdFromEntity(npc.getEntity());
- despawnNPC(uuid, NpcDespawnReason.PLUGIN_DISABLED);
- if (isDebugEnabled()) {
- log.info("[CombatTag] Disabling npc with ID of: " + uuid);
+ if (npcm != null) {
+ for (NPC npc : npcm.getNPCs()) {
+ UUID uuid = npcm.getNPCIdFromEntity(npc.getEntity());
+ despawnNPC(uuid, NpcDespawnReason.PLUGIN_DISABLED);
+ if (isDebugEnabled()) {
+ log.info("[CombatTag] Disabling npc with ID of: " + uuid);
+ }
}
}
//Just in case...
@@ -367,7 +373,7 @@ public boolean onCommand(CommandSender sender, Command command, String commandLa
sender.sendMessage("Please specify a player to force into combat");
return true;
}
- if (isInCombat(toForce.getUniqueId())) {
+ if (!isInCombat(toForce.getUniqueId())) {
tagged.put(toForce.getUniqueId(), PvPTimeout(60));
if (!toForce.equals(sender)) sender.sendMessage("You have been forced into combat for one minute");
sender.sendMessage("Sucessfuly forced " + toForce.getName() + " into combat.");
@@ -457,7 +463,7 @@ public void updatePlayerData(NPC npc, UUID playerUUID) {
emptyArmorStack[x] = airItem;
}
target.getInventory().setArmorContents(emptyArmorStack);
- target.setHealth(0);
+ setHealth(target, healthCheck(source.getHealth()));
} else {
copyTo(target, source);
}
@@ -480,13 +486,7 @@ public void copyTo(Player target, Player source) {
target.setExhaustion(source.getExhaustion());
target.setSaturation(source.getSaturation());
target.setFireTicks(source.getFireTicks());
- if (target instanceof HumanEntity) {
- HumanEntity humanTarget = (HumanEntity) target;
- double healthSet = healthCheck(source.getHealth());
- humanTarget.setHealth((float) healthSet);
- } else {
- log.info("[CombatTag] An error has occurred! Target is not a HumanEntity!");
- }
+ setHealth(target, healthCheck(source.getHealth()));
}
public double healthCheck(double health) {
@@ -506,13 +506,22 @@ public SettingsHelper getSettingsHelper() {
public static boolean isVersionSupported() {
return NPCLib.isSupported();
}
-
- public static final Field ENTITY_PLAYER_INVULNERABLE_TICKS_FIELD = Reflection.makeField(Reflection.getNmsClass("EntityPlayer"), "invulnerableTicks");
-
+
+ public static final Field ENTITY_PLAYER_INVULNERABLE_TICKS_FIELD = Reflection.makeField(getNmsClass("EntityPlayer"), "invulnerableTicks");
+ public static final Method ENTITY_LIVING_SET_HEALTH_METHOD = Reflection.makeMethod(getNmsClass("EntityLiving"), "setHealth", float.class);
+
public static void setInvulnerableTicks(Entity bukkitEntity, int invulnerableTicks) { //Entity.setNoDamageTicks() doesn't set EntityPlayer.invulnerableTicks
Object entity = Reflection.getHandle(bukkitEntity);
- if (Reflection.getNmsClass("EntityPlayer").isInstance(entity)) {
+ if (getNmsClass("EntityPlayer").isInstance(entity)) {
Reflection.setField(ENTITY_PLAYER_INVULNERABLE_TICKS_FIELD, entity, invulnerableTicks);
}
}
+ /*
+ * EntityLiving.setHealth() calls die() if the entity is a player.
+ * EntityPlayer.die() tries to close any open inventories, causing the offline player to throw an exception.
+ */
+ public static void setHealth(LivingEntity bukkitEntity, double health) {
+ Object entity = Reflection.getHandle(bukkitEntity);
+ Reflection.callMethod(ENTITY_LIVING_SET_HEALTH_METHOD, entity, (float)health);
+ }
}
diff --git a/src/main/java/com/trc202/CombatTag/NPCManager.java b/src/main/java/com/trc202/CombatTag/NPCManager.java
index 5bde27f..2d81c95 100755
--- a/src/main/java/com/trc202/CombatTag/NPCManager.java
+++ b/src/main/java/com/trc202/CombatTag/NPCManager.java
@@ -16,6 +16,7 @@
public class NPCManager {
public NPCManager(CombatTag plugin) {
this.plugin = plugin;
+ getRegistry();
}
private final CombatTag plugin;
diff --git a/src/main/java/com/trc202/CombatTag/OfflinePlayerLoader.java b/src/main/java/com/trc202/CombatTag/OfflinePlayerLoader.java
index c1c934b..4042d2d 100755
--- a/src/main/java/com/trc202/CombatTag/OfflinePlayerLoader.java
+++ b/src/main/java/com/trc202/CombatTag/OfflinePlayerLoader.java
@@ -1,209 +1,156 @@
-/**
-* The MIT License
-* Copyright (c) 2015 Techcable
-*
-* Permission is hereby granted, free of charge, to any person obtaining a copy
-* of this software and associated documentation files (the "Software"), to deal
-* in the Software without restriction, including without limitation the rights
-* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to whom the Software is
-* furnished to do so, subject to the following conditions:
-*
-* The above copyright notice and this permission notice shall be included in
-* all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-* THE SOFTWARE.
-*/
-
-package com.trc202.CombatTag;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.UUID;
-
-import org.bukkit.Bukkit;
-import org.bukkit.OfflinePlayer;
-import org.bukkit.entity.Entity;
-import org.bukkit.entity.Player;
-
-/**
-* Loads the data of offline players
-*
-* Should be compatible with versions later than 1.6.4
-*
-* @author Techcable
-*/
-public class OfflinePlayerLoader {
-/**
-* Returns the given players data
-*
-* Loads the player's data from its file if it is offline
-* If the player is online the online version is returned
-*
-* Players returned by this method may or may not be spawned and should only be used to access data
-*
-* @param name the player's name
-*
-* @return a player's data
-*
-* @throws RuntimeException if the loading failed
-*/
-public static Player loadPlayer(String name) {
-return loadPlayer(Bukkit.getOfflinePlayer(name));
-}
-/**
-* Returns the given players data
-*
-* Loads the player's data from its file if it is offline
-* If the player is online the online version is returned
-*
-* Players returned by this method may or may not be spawned and should only be used to access data
-*
-* @param id the player's uuid
-*
-* @return a player's data
-*
-* @throws RuntimeException if the loading failed
-*/
-public static Player loadPlayer(UUID id) {
-return loadPlayer(Bukkit.getOfflinePlayer(id));
-}
-/**
-* Returns the given players data
-*
-* Loads the player's data from its file if it is offline
-* If the player is online the online version is returned
-*
-* Players returned by this method may or may not be spawned and should only be used to access data
-*
-* @param player the player
-*
-* @return a player's data
-*
-* @throws RuntimeException if the loading failed
-*/
-public static Player loadPlayer(OfflinePlayer player) {
-if (player == null) return null;
-if (player instanceof Player) {
-return (Player) player;
-}
-return loadPlayer(player.getUniqueId(), player.getName());
-}
-private static Player loadPlayer(UUID id, String name) {
-Object server = getHandle(Bukkit.getServer());
-Object interactManager = newPlayerInteractManager();
-Object worldServer = getWorldServer();
-Object profile = newGameProfile(id, name);
-Class> entityPlayerClass = getNmsClass("EntityPlayer");
-Constructor entityPlayerConstructor = makeConstructor(entityPlayerClass, server.getClass(), worldServer.getClass(), profile.getClass(), interactManager.getClass());
-Object entityPlayer = callConstructor(entityPlayerConstructor, server, worldServer, profile, interactManager);
-Player player = (Player) getBukkitEntity(entityPlayer);
-return player;
-}
-private static Object newGameProfile(UUID id, String name) {
-Class> gameProfileClass = getUtilClass("com.mojang.authlib.GameProfile");
-if (gameProfileClass == null) { //Before uuids
-return name;
-}
-Constructor gameProfileConstructor = null;
-gameProfileConstructor = makeConstructor(gameProfileClass, UUID.class, String.class);
-if (gameProfileConstructor == null) { //Verson has string constructor
-gameProfileConstructor = makeConstructor(gameProfileClass, String.class, String.class);
-return callConstructor(gameProfileConstructor, id.toString(), name);
-} else { //Version has uuid constructor
-return callConstructor(gameProfileConstructor, id, name);
-}
-}
-private static Object newPlayerInteractManager() {
-Object worldServer = getWorldServer();
-Class> playerInteractClass = getNmsClass("PlayerInteractManager");
-Constructor c = makeConstructor(playerInteractClass, worldServer.getClass());
-return callConstructor(c, worldServer);
-}
-private static Object getWorldServer() {
-Object server = getHandle(Bukkit.getServer());
-Method getWorldServer = makeMethod(server.getClass(), "getWorldServer", int.class);
-return callMethod(getWorldServer, server, 0);
-}
-//NMS Utils
-private static Entity getBukkitEntity(Object o) {
-Method getBukkitEntity = makeMethod(o.getClass(), "getBukkitEntity");
-return callMethod(getBukkitEntity, o);
-}
-private static Class> getNmsClass(String name) {
-String className = "net.minecraft.server" + getVersion() + "." + name;
-try {
-return Class.forName(className);
-} catch (ClassNotFoundException ex) {
-return null;
-}
-}
-private static Class> getUtilClass(String name) {
-try {
-return Class.forName(name); //Try before 1.8 first
-} catch (ClassNotFoundException ex) {
-try {
-return Class.forName("net.minecraft.util." + name); //Not 1.8
-} catch (ClassNotFoundException ex2) {
-return null;
-}
-}
-}
-private static String getVersion() {
-Bukkit.getServer();
-String packageName = Bukkit.getServer().getClass().getPackage().getName();
-return packageName.substring(packageName.lastIndexOf('.') + 1);
-}
-private static Object getHandle(Object wrapper) {
-Method getHandle = makeMethod(wrapper.getClass(), "getHandle");
-return callMethod(getHandle, wrapper);
-}
-//Utils
-private static Method makeMethod(Class> clazz, String methodName, Class>... paramaters) {
-try {
-return clazz.getDeclaredMethod(methodName, paramaters);
-} catch (NoSuchMethodException ex) {
-return null;
-} catch (Exception ex) {
-throw new RuntimeException(ex);
-}
-}
-private static T callMethod(Method method, Object instance, Object... paramaters) {
-if (method == null) throw new RuntimeException("No such method");
-method.setAccessible(true);
-try {
-return (T) method.invoke(instance, paramaters);
-} catch (InvocationTargetException ex) {
-throw new RuntimeException(ex.getCause());
-} catch (Exception ex) {
-throw new RuntimeException(ex);
-}
-}
-private static Constructor makeConstructor(Class> clazz, Class>... paramaterTypes) {
-try {
-return (Constructor) clazz.getConstructor(paramaterTypes);
-} catch (NoSuchMethodException ex) {
-return null;
-} catch (Exception ex) {
-throw new RuntimeException(ex);
-}
-}
-private static T callConstructor(Constructor constructor, Object... paramaters) {
-if (constructor == null) throw new RuntimeException("No such constructor");
-constructor.setAccessible(true);
-try {
-return (T) constructor.newInstance(paramaters);
-} catch (InvocationTargetException ex) {
-throw new RuntimeException(ex.getCause());
-} catch (Exception ex) {
-throw new RuntimeException(ex);
-}
-}
-}
\ No newline at end of file
+/**
+ * The MIT License
+ * Copyright (c) 2014-2015 Techcable
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+package com.trc202.CombatTag;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+
+import static com.trc202.CombatTag.Reflection.*;
+
+/**
+ * Loads the data of offline players
+ *
+ * Should be compatible with versions later than 1.6.4
+ *
+ * @author Techcable
+ */
+class OfflinePlayerLoader {
+
+ /**
+ * Returns the given players data
+ *
+ * Loads the player's data from its file if it is offline
+ * If the player is online the online version is returned
+ *
+ * Players returned by this method may or may not be spawned and should only be used to access data
+ *
+ * @param name the player's name
+ *
+ * @return a player's data
+ *
+ * @throws RuntimeException if the loading failed
+ */
+ public static Player loadPlayer(String name) {
+ return loadPlayer(Bukkit.getOfflinePlayer(name));
+ }
+
+ /**
+ * Returns the given players data
+ *
+ * Loads the player's data from its file if it is offline
+ * If the player is online the online version is returned
+ *
+ * Players returned by this method may or may not be spawned and should only be used to access data
+ *
+ * @param id the player's uuid
+ *
+ * @return a player's data
+ *
+ * @throws RuntimeException if the loading failed
+ */
+ public static Player loadPlayer(UUID id) {
+ return loadPlayer(Bukkit.getOfflinePlayer(id));
+ }
+
+ /**
+ * Returns the given players data
+ *
+ * Loads the player's data from its file if it is offline
+ * If the player is online the online version is returned
+ *
+ * Players returned by this method may or may not be spawned and should only be used to access data
+ *
+ * @param player the player
+ *
+ * @return a player's data
+ *
+ * @throws RuntimeException if the loading failed
+ */
+ public static Player loadPlayer(OfflinePlayer player) {
+ if (player == null) return null;
+ if (player instanceof Player) {
+ return (Player) player;
+ }
+ return loadPlayer(player.getUniqueId(), player.getName());
+ }
+
+ private static Player loadPlayer(UUID id, String name) {
+ Object server = getMinecraftServer();
+ Object interactManager = newPlayerInteractManager();
+ Object worldServer = getWorldServer();
+ Object profile = newGameProfile(id, name);
+ Class> entityPlayerClass = getNmsClass("EntityPlayer");
+ Constructor entityPlayerConstructor = makeConstructor(entityPlayerClass, getNmsClass("MinecraftServer"), getNmsClass("WorldServer"), getUtilClass("com.mojang.authlib.GameProfile"), getNmsClass("PlayerInteractManager"));
+ Object entityPlayer = callConstructor(entityPlayerConstructor, server, worldServer, profile, interactManager);
+ Player player = (Player) getBukkitEntity(entityPlayer);
+ return player;
+ }
+
+ private static Object newGameProfile(UUID id, String name) {
+ Class> gameProfileClass = getUtilClass("com.mojang.authlib.GameProfile");
+ if (gameProfileClass == null) { //Before uuids
+ return name;
+ }
+ Constructor gameProfileConstructor = null;
+ gameProfileConstructor = makeConstructor(gameProfileClass, UUID.class, String.class);
+ if (gameProfileConstructor == null) { //Verson has string constructor
+ gameProfileConstructor = makeConstructor(gameProfileClass, String.class, String.class);
+ return callConstructor(gameProfileConstructor, id.toString(), name);
+ } else { //Version has uuid constructor
+ return callConstructor(gameProfileConstructor, id, name);
+ }
+ }
+
+ private static Object newPlayerInteractManager() {
+ Object worldServer = getWorldServer();
+ Class> playerInteractClass = getNmsClass("PlayerInteractManager");
+ Class> worldClass = getNmsClass("World");
+ Constructor c = makeConstructor(playerInteractClass, worldClass);
+ return callConstructor(c, worldServer);
+ }
+
+ private static Object getWorldServer() {
+ Object server = getMinecraftServer();
+ Class> minecraftServerClass = getNmsClass("MinecraftServer");
+ Method getWorldServer = makeMethod(minecraftServerClass, "getWorldServer", int.class);
+ return callMethod(getWorldServer, server, 0);
+ }
+
+ //NMS Utils
+
+ private static Object getMinecraftServer() {
+ return callMethod(makeMethod(getCbClass("CraftServer"), "getServer"), Bukkit.getServer());
+ }
+
+ private static Entity getBukkitEntity(Object o) {
+ Method getBukkitEntity = makeMethod(o.getClass(), "getBukkitEntity");
+ return callMethod(getBukkitEntity, o);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/trc202/CombatTag/Reflection.java b/src/main/java/com/trc202/CombatTag/Reflection.java
old mode 100644
new mode 100755
index 318e33a..571c470
--- a/src/main/java/com/trc202/CombatTag/Reflection.java
+++ b/src/main/java/com/trc202/CombatTag/Reflection.java
@@ -12,7 +12,7 @@ public static Class> getNmsClass(String name) {
String className = "net.minecraft.server." + getVersion() + "." + name;
return getClass(className);
}
-
+
public static Class> getCbClass(String name) {
String className = "org.bukkit.craftbukkit." + getVersion() + "." + name;
return getClass(className);
diff --git a/src/main/java/com/trc202/CombatTagListeners/NoPvpPlayerListener.java b/src/main/java/com/trc202/CombatTagListeners/NoPvpPlayerListener.java
index 9b1c7e4..3ba7374 100755
--- a/src/main/java/com/trc202/CombatTagListeners/NoPvpPlayerListener.java
+++ b/src/main/java/com/trc202/CombatTagListeners/NoPvpPlayerListener.java
@@ -81,7 +81,7 @@ public void onPlayerQuit(PlayerQuitEvent e) {
NPC npc = plugin.spawnNpc(quitPlr, quitPlr.getLocation());
Player npcPlayer = (Player) npc.getEntity();
plugin.copyContentsNpc(npc, quitPlr);
- npcPlayer.setHealth(plugin.healthCheck(quitPlr.getHealth()));
+ CombatTag.setHealth(npcPlayer, plugin.healthCheck(quitPlr.getHealth()));
quitPlr.getWorld().createExplosion(quitPlr.getLocation(), -1); //Create the smoke effect
CombatTag.setInvulnerableTicks(npcPlayer, 0);
if (plugin.settings.getNpcDespawnTime() > 0) {