diff --git a/lib/spigot.jar b/lib/spigot.jar index 1d74b3f..5f01d4f 100644 Binary files a/lib/spigot.jar and b/lib/spigot.jar differ diff --git a/pom.xml b/pom.xml index fc33472..454e08b 100644 --- a/pom.xml +++ b/pom.xml @@ -33,19 +33,19 @@ org.spigotmc spigot-api - 1.8.8-R0.1-SNAPSHOT + 1.9-R0.1-SNAPSHOT provided org.bukkit bukkit - 1.8.8-R0.1-SNAPSHOT + 1.9-R0.1-SNAPSHOT provided org.spigotmc spigot - 1.8.8-R0.1-SNAPSHOT + 1.9-R0.1-SNAPSHOT system ${project.basedir}/lib/spigot.jar diff --git a/src/main/java/com/lenis0012/bukkit/marriage2/internal/data/DataManager.java b/src/main/java/com/lenis0012/bukkit/marriage2/internal/data/DataManager.java index f01b0af..e521b2b 100644 --- a/src/main/java/com/lenis0012/bukkit/marriage2/internal/data/DataManager.java +++ b/src/main/java/com/lenis0012/bukkit/marriage2/internal/data/DataManager.java @@ -1,12 +1,7 @@ package com.lenis0012.bukkit.marriage2.internal.data; import java.io.File; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; +import java.sql.*; import java.util.*; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -114,6 +109,15 @@ public class DataManager { ResultSet result = statement.executeQuery(String.format("SELECT * FROM %sversion;", prefix)); if(result.next()) { int dbVersion = result.getInt("version_id"); + if(dbVersion >= 2) { + // Fix for people that first installed on v2 + DatabaseMetaData metadata = connection.getMetaData(); + ResultSet res = metadata.getColumns(null, null, prefix + "players", "last_name"); + if(!res.next()) { + statement.execute("ALTER TABLE " + prefix + "players ADD last_name VARCHAR(16);"); + } + } + if(dbVersion < upgrade.getVersionId()) { upgrade.run(statement, dbVersion, prefix); PreparedStatement ps = connection.prepareStatement("UPDATE " + prefix + "version SET version_id=? WHERE version_id=?;"); diff --git a/src/main/java/com/lenis0012/bukkit/marriage2/internal/data/Driver.java b/src/main/java/com/lenis0012/bukkit/marriage2/internal/data/Driver.java index 52ecbd5..2ec7039 100644 --- a/src/main/java/com/lenis0012/bukkit/marriage2/internal/data/Driver.java +++ b/src/main/java/com/lenis0012/bukkit/marriage2/internal/data/Driver.java @@ -20,6 +20,7 @@ public enum Driver { public void runSetup(Statement statement, String prefix) throws SQLException { statement.executeUpdate(String.format("CREATE TABLE IF NOT EXISTS %splayers (" + "unique_user_id VARCHAR(128) NOT NULL UNIQUE," + + "last_name VARCHAR(16)," + "gender VARCHAR(32)," + "priest BIT," + "lastlogin BIGINT);", prefix)); diff --git a/src/main/java/com/lenis0012/bukkit/marriage2/listeners/KissListener.java b/src/main/java/com/lenis0012/bukkit/marriage2/listeners/KissListener.java index c70c59f..ab2b2b3 100644 --- a/src/main/java/com/lenis0012/bukkit/marriage2/listeners/KissListener.java +++ b/src/main/java/com/lenis0012/bukkit/marriage2/listeners/KissListener.java @@ -5,6 +5,8 @@ import com.lenis0012.bukkit.marriage2.MPlayer; import com.lenis0012.bukkit.marriage2.config.Settings; import com.lenis0012.bukkit.marriage2.internal.MarriageCore; import com.lenis0012.bukkit.marriage2.misc.Cooldown; +import com.lenis0012.bukkit.marriage2.misc.reflection.Packets; +import com.lenis0012.bukkit.marriage2.misc.reflection.Reflection; import net.minecraft.server.v1_8_R3.EnumParticle; import net.minecraft.server.v1_8_R3.PacketPlayOutWorldParticles; import org.bukkit.Location; @@ -15,10 +17,13 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerInteractEntityEvent; +import java.lang.reflect.Method; import java.util.Random; import java.util.concurrent.TimeUnit; public class KissListener implements Listener { + private final Method GET_PARTICLE_BY_ID = Reflection.getNMSMethod("EnumParticle", "a", int.class); + private final Cooldown cooldown; private final MarriageCore core; private final Random random = new Random(); @@ -34,30 +39,51 @@ public class KissListener implements Listener { final Player player = event.getPlayer(); Entity e = event.getRightClicked(); - if(e instanceof Player) { - final Player clicked = (Player) e; - if(player.isSneaking() && clicked.isSneaking()) { - MPlayer mp = core.getMPlayer(player.getUniqueId()); - if(mp.isMarried()) { - MData data = mp.getMarriage(); - if(clicked.getUniqueId().toString().equalsIgnoreCase(data.getOtherPlayer(player.getUniqueId()).toString())) { - if(cooldown.performCheck(player.getName()) && cooldown.performCheck(clicked.getName())) { - Location l1 = player.getEyeLocation(); - Location l2 = clicked.getEyeLocation(); - Location l = l1.clone().add((l2.getX() - l1.getX()) / 2, (l2.getY() - l1.getY()) / 2, (l2.getZ() - l1.getZ()) / 2); + if(!(e instanceof Player)) { + return; + } - int min = Settings.KISSES_AMOUNT_MIN.value(); - int max = Settings.KISSES_AMOUNT_MAX.value(); - int amount = min + random.nextInt(max - min + 1); - PacketPlayOutWorldParticles packet = new PacketPlayOutWorldParticles(EnumParticle.HEART, false, - (float) l.getX(), (float) l.getY(), (float) l.getZ(), 0.3F, 0.3F, 0.3F, 1F, amount); - for(Player p : player.getWorld().getPlayers()) { - ((CraftPlayer) p).getHandle().playerConnection.sendPacket(packet); - } - } - } - } - } + final Player clicked = (Player) e; + if(!player.isSneaking() || !clicked.isSneaking()) { + return; + } + + MPlayer mp = core.getMPlayer(player.getUniqueId()); + if(!mp.isMarried()) { + return; + } + + MData data = mp.getMarriage(); + if(!clicked.getUniqueId().toString().equalsIgnoreCase(data.getOtherPlayer(player.getUniqueId()).toString())) { + return; + } + + if(!cooldown.performCheck(player.getName()) || !cooldown.performCheck(clicked.getName())) { + return; + } + + Location l1 = player.getEyeLocation(); + Location l2 = clicked.getEyeLocation(); + sendPacket(l1, l2); + } + + private void sendPacket(Location eye1, Location eye2) { + Location l = eye1.clone().add((eye2.getX() - eye1.getX()) / 2, (eye2.getY() - eye1.getY()) / 2, (eye2.getZ() - eye1.getZ()) / 2); + int min = Settings.KISSES_AMOUNT_MIN.value(); + int max = Settings.KISSES_AMOUNT_MAX.value(); + int amount = min + random.nextInt(max - min + 1); + Object packet = Packets.createPacket("PacketPlayOutWorldParticles"); + Packets.set(packet, "a", Reflection.invokeMethod(int.class, GET_PARTICLE_BY_ID, null, 34)); + Packets.set(packet, "b", (float) l.getX()); + Packets.set(packet, "c", (float) l.getY()); + Packets.set(packet, "d", (float) l.getZ()); + Packets.set(packet, "e", 0.3F); + Packets.set(packet, "f", 0.3F); + Packets.set(packet, "g", 0.3F); + Packets.set(packet, "h", 1F); + Packets.set(packet, "i", amount); + for(Player player : l.getWorld().getPlayers()) { + Packets.send(player, packet); } } } diff --git a/src/main/java/com/lenis0012/bukkit/marriage2/misc/reflection/Packets.java b/src/main/java/com/lenis0012/bukkit/marriage2/misc/reflection/Packets.java new file mode 100644 index 0000000..683b591 --- /dev/null +++ b/src/main/java/com/lenis0012/bukkit/marriage2/misc/reflection/Packets.java @@ -0,0 +1,37 @@ +package com.lenis0012.bukkit.marriage2.misc.reflection; + +import com.google.common.collect.Maps; +import com.lenis0012.bukkit.marriage2.misc.reflection.Reflection.ClassReflection; +import org.bukkit.entity.Player; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Map; + +public class Packets { + private static final Map packetClasses = Maps.newConcurrentMap(); + private static final Method GET_HANDLE = Reflection.getCBMethod("entity.CraftPlayer", "getHandle"); + private static final Field PLAYER_CONNECTION = Reflection.getNMSField("EntityPlayer", "playerConnection"); + private static final Method SEND_PACKET = Reflection.getNMSMethod("PlayerConnection", "sendPacket", Reflection.getNMSClass("Packet")); + + public static Object createPacket(String name) { + ClassReflection ref = packetClasses.get(name); + if(ref == null) { + ref = new ClassReflection(Reflection.getNMSClass(name)); + packetClasses.put(name, ref); + } + + return ref.newInstance(); + } + + public static void set(Object packet, String fieldName, Object value) { + ClassReflection ref = packetClasses.get(packet.getClass().getSimpleName()); + ref.setFieldValue(fieldName, packet, value); + } + + public static void send(Player player, Object packet) { + Object entityPlayer = Reflection.invokeMethod(GET_HANDLE, player); + Object playerConnection = Reflection.getFieldValue(PLAYER_CONNECTION, entityPlayer); + Reflection.invokeMethod(SEND_PACKET, playerConnection, packet); + } +} diff --git a/src/main/java/com/lenis0012/bukkit/marriage2/misc/reflection/Reflection.java b/src/main/java/com/lenis0012/bukkit/marriage2/misc/reflection/Reflection.java new file mode 100644 index 0000000..981c27c --- /dev/null +++ b/src/main/java/com/lenis0012/bukkit/marriage2/misc/reflection/Reflection.java @@ -0,0 +1,168 @@ +package com.lenis0012.bukkit.marriage2.misc.reflection; + +import com.google.common.collect.Maps; +import org.bukkit.Bukkit; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.regex.Pattern; + +public class Reflection { + private static final String NMS_VERSION; + private static final String NMS_ROOT; + private static final String CB_ROOT; + + static { + String fullname = Bukkit.getServer().getClass().getName(); + NMS_VERSION = fullname.substring("org.bukkit.craftbukkit.".length()).split(Pattern.quote("."))[0]; + NMS_ROOT = "net.minecraft.server." + NMS_VERSION + "."; + CB_ROOT = "org.bukkit.craftbukkit." + NMS_VERSION + "."; + } + + public static Class getNMSClass(String name) { + try { + return Class.forName(NMS_ROOT + name); + } catch(ClassNotFoundException e) { + return null; + } + } + + public static Class getCBClass(String name) { + try { + return Class.forName(CB_ROOT + name); + } catch(ClassNotFoundException e) { + return null; + } + } + + public static Field getField(Class host, String name) { + try { + Field field = host.getDeclaredField(name); + field.setAccessible(true); + return field; + } catch(Exception e) { + return null; + } + } + + public static Field getNMSField(String hostName, String fieldName) { + return getField(getNMSClass(hostName), fieldName); + } + + public static Field getCBField(String hostName, String fieldName) { + return getField(getCBClass(hostName), fieldName); + } + + public static void setFieldValue(Field field, Object instance, Object value) { + try { + field.set(instance, value); + } catch(IllegalAccessException e) { + e.printStackTrace(); + } + } + + public static Object getFieldValue(Field field, Object instance) { + try { + return field.get(instance); + } catch(Exception e) { + e.printStackTrace(); + return null; + } + } + + public static T getFieldValue(Field field, Object instance, Class type) { + return type.cast(getFieldValue(field, instance)); + } + + public static Method getMethod(Class host, String methodName, Class... params) { + try { + Method method = host.getDeclaredMethod(methodName, params); + method.setAccessible(true); + return method; + } catch(Exception e) { + e.printStackTrace(); + return null; + } + } + + public static Method getNMSMethod(String hostName, String methodName, Class... params) { + return getMethod(getNMSClass(hostName), methodName, params); + } + + public static Method getCBMethod(String hostName, String methodName, Class... params) { + return getMethod(getCBClass(hostName), methodName, params); + } + + public static Object invokeMethod(Method method, Object instance, Object... args) { + try { + return method.invoke(instance, args); + } catch(Exception e) { + e.printStackTrace(); + return null; + } + } + + public static T invokeMethod(Class type, Method method, Object instance, Object... args) { + return type.cast(invokeMethod(method, instance, args)); + } + + public static final class ClassReflection { + private final Class handle; + private final Map fields = Maps.newConcurrentMap(); + private final Map methods = Maps.newConcurrentMap(); + + public ClassReflection(Class handle) { + this.handle = handle; + scanFields(handle); + scanMethods(handle); + } + + private void scanFields(Class host) { + if(host.getSuperclass() != null) { + scanFields(host.getSuperclass()); + } + + for(Field field : host.getDeclaredFields()) { + field.setAccessible(true); + fields.put(field.getName(), field); + } + } + + private void scanMethods(Class host) { + if(host.getSuperclass() != null) { + scanMethods(host.getSuperclass()); + } + + for(Method method : host.getDeclaredMethods()) { + method.setAccessible(true); + methods.put(method.getName(), method); + } + } + + public Object newInstance() { + try { + return handle.newInstance(); + } catch(Exception e) { + e.printStackTrace(); + return null; + } + } + + public Field getField(String name) { + return fields.get(name); + } + + public void setFieldValue(String fieldName, Object instance, Object value) { + Reflection.setFieldValue(getField(fieldName), instance, value); + } + + public T getFieldValue(String fieldName, Object instance, Class type) { + return Reflection.getFieldValue(getField(fieldName), instance, type); + } + + public Method getMethod(String name) { + return methods.get(name); + } + } +}