From 4c0157d6dec1cf10b1e65c5fd64d787cebacbf7e Mon Sep 17 00:00:00 2001 From: Bukkit/Spigot Date: Tue, 30 Apr 2019 09:36:30 +1000 Subject: [PATCH] SPIGOT-4815: Location.equals() not working By: md_5 --- .../src/main/java/org/bukkit/Location.java | 8 ++- .../test/java/org/bukkit/LocationTest.java | 11 +++- .../src/test/java/org/bukkit/TestWorld.java | 64 +++++++++++++++++++ 3 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 paper-api/src/test/java/org/bukkit/TestWorld.java diff --git a/paper-api/src/main/java/org/bukkit/Location.java b/paper-api/src/main/java/org/bukkit/Location.java index b5ec7eb5ac..44e3bca618 100644 --- a/paper-api/src/main/java/org/bukkit/Location.java +++ b/paper-api/src/main/java/org/bukkit/Location.java @@ -543,7 +543,9 @@ public class Location implements Cloneable, ConfigurationSerializable { } final Location other = (Location) obj; - if (this.world != other.world && (this.world == null || !this.world.equals(other.world))) { + World world = (this.world == null) ? null : this.world.get(); + World otherWorld = (other.world == null) ? null : other.world.get(); + if (world != otherWorld && (world == null || !world.equals(otherWorld))) { return false; } if (Double.doubleToLongBits(this.x) != Double.doubleToLongBits(other.x)) { @@ -568,7 +570,7 @@ public class Location implements Cloneable, ConfigurationSerializable { public int hashCode() { int hash = 3; - World world = (this.world == null) ? null : getWorld(); + World world = (this.world == null) ? null : this.world.get(); hash = 19 * hash + (world != null ? world.hashCode() : 0); hash = 19 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32)); hash = 19 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32)); @@ -580,7 +582,7 @@ public class Location implements Cloneable, ConfigurationSerializable { @Override public String toString() { - World world = (this.world == null) ? null : getWorld(); + World world = (this.world == null) ? null : this.world.get(); return "Location{" + "world=" + world + ",x=" + x + ",y=" + y + ",z=" + z + ",pitch=" + pitch + ",yaw=" + yaw + '}'; } diff --git a/paper-api/src/test/java/org/bukkit/LocationTest.java b/paper-api/src/test/java/org/bukkit/LocationTest.java index f3191ef25c..5cd8a0d362 100644 --- a/paper-api/src/test/java/org/bukkit/LocationTest.java +++ b/paper-api/src/test/java/org/bukkit/LocationTest.java @@ -176,12 +176,21 @@ public class LocationTest { assertThat(vector.getZ(), is(closeTo(z, delta))); } + @Test + public void testEquals() { + Location first = getLocation().add(getVector()); + Location second = getLocation().add(getVector()); + + assertThat(first.hashCode(), is(second.hashCode())); + assertThat(first, is(second)); + } + private Vector getVector() { return new Vector(x, y, z); } private static Location getEmptyLocation() { - return new Location(null, 0, 0, 0); + return new Location(TestWorld.INSTANCE, 0, 0, 0); } private Location getLocation() { diff --git a/paper-api/src/test/java/org/bukkit/TestWorld.java b/paper-api/src/test/java/org/bukkit/TestWorld.java new file mode 100644 index 0000000000..beb15c7c81 --- /dev/null +++ b/paper-api/src/test/java/org/bukkit/TestWorld.java @@ -0,0 +1,64 @@ +package org.bukkit; + +import com.google.common.collect.ImmutableMap; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Map; + +public final class TestWorld implements InvocationHandler { + + private static interface MethodHandler { + + Object handle(TestWorld server, Object[] args); + } + + private static final Map methods; + public static final World INSTANCE; + + static { + try { + ImmutableMap.Builder methodMap = ImmutableMap.builder(); + methodMap.put( + Object.class.getMethod("equals", Object.class), + new MethodHandler() { + @Override + public Object handle(TestWorld server, Object[] args) { + return this == args[0]; + } + } + ); + methodMap.put( + Object.class.getMethod("hashCode"), + new MethodHandler() { + @Override + public Object handle(TestWorld server, Object[] args) { + return this.hashCode(); + } + } + ); + methods = methodMap.build(); + + TestWorld world = new TestWorld(); + INSTANCE = Proxy.getProxyClass(World.class.getClassLoader(), World.class).asSubclass(World.class).getConstructor(InvocationHandler.class).newInstance(world); + } catch (Throwable t) { + throw new Error(t); + } + } + + private TestWorld() { + } + + public static Server getInstance() { + return Bukkit.getServer(); + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) { + MethodHandler handler = methods.get(method); + if (handler != null) { + return handler.handle(this, args); + } + throw new UnsupportedOperationException(String.valueOf(method)); + } +}