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);
+ }
+ }
+}