2017-01-17 16:05:13 +01:00
|
|
|
From dbda96c0e643167a28b173be02282cd92ab43046 Mon Sep 17 00:00:00 2001
|
2016-05-28 18:34:39 +02:00
|
|
|
From: Techcable <Techcable@outlook.com>
|
|
|
|
Date: Mon, 14 Mar 2016 15:40:44 -0700
|
|
|
|
Subject: [PATCH] Optimize uuid conversions
|
|
|
|
|
|
|
|
Optimizes converting to and from mojang format.
|
|
|
|
Manually decode uuids to and from hex.
|
|
|
|
|
|
|
|
diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/utils/Hex.java b/api/src/main/java/io/github/waterfallmc/waterfall/utils/Hex.java
|
|
|
|
new file mode 100644
|
2017-01-17 16:05:13 +01:00
|
|
|
index 00000000..ece5f798
|
2016-05-28 18:34:39 +02:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/utils/Hex.java
|
|
|
|
@@ -0,0 +1,113 @@
|
|
|
|
+package io.github.waterfallmc.waterfall.utils;
|
|
|
|
+
|
|
|
|
+import java.util.Arrays;
|
|
|
|
+import java.util.Objects;
|
|
|
|
+
|
|
|
|
+public class Hex {
|
|
|
|
+
|
|
|
|
+ public static byte[] decode(CharSequence chars) {
|
|
|
|
+ byte[] bytes = new byte[chars.length() >> 1];
|
|
|
|
+ decode(chars, 0, bytes, 0, bytes.length);
|
|
|
|
+ return bytes;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void decode(char[] chars, int charOffset, byte[] dest, int offset, int length) {
|
|
|
|
+ decode(new CharSequence() {
|
|
|
|
+ @Override
|
|
|
|
+ public int length() {
|
|
|
|
+ return chars.length;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public char charAt(int index) {
|
|
|
|
+ return chars[index];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public CharSequence subSequence(int start, int end) {
|
|
|
|
+ return toString().substring(start, end);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public String toString() {
|
|
|
|
+ return new String(chars, charOffset, chars.length);
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void decode(CharSequence chars, int charOffset, byte[] dest, int offset, int length) {
|
|
|
|
+ Objects.requireNonNull(chars, "Null chars");
|
|
|
|
+ Objects.requireNonNull(chars, "Null destination");
|
|
|
|
+ final int numChars = chars.length();
|
|
|
|
+ if ((numChars & 0x01) != 0) {
|
|
|
|
+ throw new IllegalArgumentException("Odd number of characters: " + numChars);
|
|
|
|
+ } else if (length < (numChars - charOffset) >> 1) {
|
|
|
|
+ throw new IllegalArgumentException("Too many bytes to fill with " + numChars + " characters: " + length);
|
|
|
|
+ } else if (offset < 0 || charOffset < 0 || length < 0 || length * 2 > numChars - charOffset || length > dest.length - offset) {
|
|
|
|
+ throw new IndexOutOfBoundsException();
|
|
|
|
+ }
|
|
|
|
+ for (int i = 0, charIndex = charOffset; i < length; i++) {
|
|
|
|
+ char first = chars.charAt(charIndex++);
|
|
|
|
+ char second = chars.charAt(charIndex++);
|
|
|
|
+ dest[i + offset] = (byte) ((toDigit(first) << 4) | (toDigit(second)));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static String encodeString(byte[] bytes) {
|
|
|
|
+ return new String(encode(bytes));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static char[] encode(byte[] bytes) {
|
|
|
|
+ char[] chars = new char[bytes.length << 1];
|
|
|
|
+ encode(chars, 0, bytes, 0, bytes.length);
|
|
|
|
+ return chars;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static void encode(char[] chars, int charOffset, byte[] source, int offset, int length) {
|
|
|
|
+ Objects.requireNonNull(chars, "Null chars");
|
|
|
|
+ Objects.requireNonNull(chars, "Null bytes");
|
|
|
|
+ if (offset < 0 || charOffset < 0 || length < 0 || length * 2 > chars.length - charOffset || length > source.length - offset) {
|
|
|
|
+ throw new IndexOutOfBoundsException();
|
|
|
|
+ } else if (length == 0) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ for (int i = 0, charIndex = charOffset; i < length; i++) {
|
|
|
|
+ byte b = source[i + offset];
|
|
|
|
+ chars[charIndex++] = fromDigit((byte) ((b >> 4) & 0xF));
|
|
|
|
+ chars[charIndex++] = fromDigit((byte) (b & 0xF));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ private static final char[] ENCODE_TABLE = new char[]{
|
|
|
|
+ '0', '1', '2', '3', '4', '5', '6', '7',
|
|
|
|
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
|
|
|
|
+ };
|
|
|
|
+ private static final byte[] DECODE_TABLE = new byte[128];
|
|
|
|
+
|
|
|
|
+ static {
|
|
|
|
+ Arrays.fill(DECODE_TABLE, (byte) -1);
|
|
|
|
+ for (int value = 0; value < ENCODE_TABLE.length; value++) {
|
|
|
|
+ char c = ENCODE_TABLE[value];
|
|
|
|
+ DECODE_TABLE[c] = (byte) value;
|
|
|
|
+ char upper;
|
|
|
|
+ if ((upper = Character.toUpperCase(c)) != c) {
|
|
|
|
+ DECODE_TABLE[upper] = (byte) value;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static byte toDigit(char c) {
|
|
|
|
+ byte value;
|
|
|
|
+ if (c < DECODE_TABLE.length) {
|
|
|
|
+ value = DECODE_TABLE[c];
|
|
|
|
+ } else {
|
|
|
|
+ value = -1;
|
|
|
|
+ }
|
|
|
|
+ if (value < 0) throw new IllegalArgumentException("Invalid character " + c);
|
|
|
|
+ return value;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static char fromDigit(byte b) {
|
|
|
|
+ assert (b & 0xF) == b : "Out of range " + b;
|
|
|
|
+ return ENCODE_TABLE[b];
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
\ No newline at end of file
|
|
|
|
diff --git a/api/src/main/java/io/github/waterfallmc/waterfall/utils/UUIDUtils.java b/api/src/main/java/io/github/waterfallmc/waterfall/utils/UUIDUtils.java
|
|
|
|
new file mode 100644
|
2017-01-17 16:05:13 +01:00
|
|
|
index 00000000..cc24dd35
|
2016-05-28 18:34:39 +02:00
|
|
|
--- /dev/null
|
|
|
|
+++ b/api/src/main/java/io/github/waterfallmc/waterfall/utils/UUIDUtils.java
|
2016-12-09 13:56:14 +01:00
|
|
|
@@ -0,0 +1,74 @@
|
2016-05-28 18:34:39 +02:00
|
|
|
+package io.github.waterfallmc.waterfall.utils;
|
|
|
|
+import java.util.UUID;
|
|
|
|
+
|
|
|
|
+import com.google.common.base.Preconditions;
|
|
|
|
+import com.google.common.primitives.Longs;
|
|
|
|
+
|
|
|
|
+public class UUIDUtils {
|
|
|
|
+ private UUIDUtils() {}
|
|
|
|
+
|
2016-12-09 13:56:14 +01:00
|
|
|
+ public static String undash(String id) {
|
|
|
|
+ return new StringBuilder( 32 ).append( id, 0, 8 ).append( id, 9, 13 ).append( id, 14, 18 ).append( id, 19, 23 ).append( id, 24, 36 ).toString();
|
|
|
|
+ }
|
|
|
|
+
|
2016-05-28 18:34:39 +02:00
|
|
|
+ public static String toMojangString(UUID id) {
|
|
|
|
+ Preconditions.checkNotNull(id, "Null id");
|
|
|
|
+ return Hex.encodeString(toBytes(id));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static UUID fromString(String s) {
|
|
|
|
+ Preconditions.checkNotNull(s, "Null string");
|
|
|
|
+ if (s.length() == 36) { // UUID.toString() uuid
|
2016-12-09 13:56:14 +01:00
|
|
|
+ s = UUIDUtils.undash(s);
|
2016-05-28 18:34:39 +02:00
|
|
|
+ } else if (s.length() != 32) {
|
|
|
|
+ throw new IllegalArgumentException("Invalid UUID: " + s);
|
|
|
|
+ }
|
|
|
|
+ return fromMojangString0(s);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static UUID fromMojangString(String s) {
|
|
|
|
+ Preconditions.checkNotNull(s, "Null string");
|
|
|
|
+ if (s.length() != 32) {
|
|
|
|
+ throw new IllegalArgumentException("UUID not in mojang format: " + s);
|
|
|
|
+ }
|
|
|
|
+ return fromMojangString0(s);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static UUID fromMojangString0(String s) {
|
|
|
|
+ assert s != null : "Null string";
|
|
|
|
+ assert s.length() == 32 : "invalid length: " + s;
|
|
|
|
+ try {
|
|
|
|
+ return fromBytes(Hex.decode(s));
|
|
|
|
+ } catch (IllegalArgumentException e) {
|
|
|
|
+ throw new IllegalArgumentException("Invalid UUID: " + s);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static byte[] toBytes(UUID id) {
|
|
|
|
+ Preconditions.checkNotNull(id, "Null id");
|
|
|
|
+ byte[] result = new byte[16];
|
|
|
|
+ long lsb = id.getLeastSignificantBits();
|
|
|
|
+ for (int i = 15; i >= 8; i--) {
|
|
|
|
+ result[i] = (byte) (lsb & 0xffL);
|
|
|
|
+ lsb >>= 8;
|
|
|
|
+ }
|
|
|
|
+ long msb = id.getMostSignificantBits();
|
|
|
|
+ for (int i = 7; i >= 0; i--) {
|
|
|
|
+ result[i] = (byte) (msb & 0xffL);
|
|
|
|
+ msb >>= 8;
|
|
|
|
+ }
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public static UUID fromBytes(byte[] bytes) {
|
|
|
|
+ Preconditions.checkNotNull(bytes, "Null bytes");
|
|
|
|
+ if (bytes.length != 16) {
|
|
|
|
+ throw new IllegalArgumentException("Invalid length: " + bytes.length);
|
|
|
|
+ }
|
|
|
|
+ long msb = Longs.fromBytes(bytes[0], bytes[1], bytes[2], bytes[3],
|
|
|
|
+ bytes[4], bytes[5], bytes[6], bytes[7]);
|
|
|
|
+ long lsb = Longs.fromBytes(bytes[8], bytes[9], bytes[10], bytes[11],
|
|
|
|
+ bytes[12], bytes[13], bytes[14], bytes[15]);
|
|
|
|
+ return new UUID(msb, lsb);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
\ No newline at end of file
|
|
|
|
diff --git a/api/src/main/java/net/md_5/bungee/Util.java b/api/src/main/java/net/md_5/bungee/Util.java
|
2017-01-17 16:05:13 +01:00
|
|
|
index 86a00555..6c9c6d61 100644
|
2016-05-28 18:34:39 +02:00
|
|
|
--- a/api/src/main/java/net/md_5/bungee/Util.java
|
|
|
|
+++ b/api/src/main/java/net/md_5/bungee/Util.java
|
|
|
|
@@ -1,11 +1,15 @@
|
|
|
|
package net.md_5.bungee;
|
|
|
|
|
|
|
|
import com.google.common.base.Joiner;
|
|
|
|
+import com.google.common.primitives.Ints;
|
|
|
|
import java.net.InetSocketAddress;
|
|
|
|
import java.net.URI;
|
|
|
|
import java.net.URISyntaxException;
|
|
|
|
import java.util.UUID;
|
|
|
|
|
|
|
|
+import io.github.waterfallmc.waterfall.utils.Hex;
|
|
|
|
+import io.github.waterfallmc.waterfall.utils.UUIDUtils;
|
|
|
|
+
|
|
|
|
/**
|
|
|
|
* Series of utility classes to perform various operations.
|
|
|
|
*/
|
|
|
|
@@ -42,7 +46,7 @@ public class Util
|
|
|
|
*/
|
|
|
|
public static String hex(int i)
|
|
|
|
{
|
|
|
|
- return String.format( "0x%02X", i );
|
|
|
|
+ return Hex.encodeString(Ints.toByteArray(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2016-05-31 19:42:10 +02:00
|
|
|
@@ -78,6 +82,6 @@ public class Util
|
2016-05-28 18:34:39 +02:00
|
|
|
*/
|
|
|
|
public static UUID getUUID(String uuid)
|
|
|
|
{
|
|
|
|
- return UUID.fromString( uuid.substring( 0, 8 ) + "-" + uuid.substring( 8, 12 ) + "-" + uuid.substring( 12, 16 ) + "-" + uuid.substring( 16, 20 ) + "-" + uuid.substring( 20, 32 ) );
|
|
|
|
+ return UUIDUtils.fromString(uuid);
|
|
|
|
}
|
2016-05-31 19:42:10 +02:00
|
|
|
}
|
2016-12-09 13:56:14 +01:00
|
|
|
diff --git a/api/src/main/java/net/md_5/bungee/api/ServerPing.java b/api/src/main/java/net/md_5/bungee/api/ServerPing.java
|
2017-01-17 16:05:13 +01:00
|
|
|
index 27b51849..8bf17f9c 100644
|
2016-12-09 13:56:14 +01:00
|
|
|
--- a/api/src/main/java/net/md_5/bungee/api/ServerPing.java
|
|
|
|
+++ b/api/src/main/java/net/md_5/bungee/api/ServerPing.java
|
2016-12-10 00:54:35 +01:00
|
|
|
@@ -75,7 +75,7 @@ public class ServerPing
|
2016-12-09 13:56:14 +01:00
|
|
|
|
|
|
|
public String getId()
|
|
|
|
{
|
|
|
|
- return uniqueId.toString().replaceAll( "-", "" );
|
|
|
|
+ return io.github.waterfallmc.waterfall.utils.UUIDUtils.undash( uniqueId.toString() ); // Waterfall
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
diff --git a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java
|
2017-01-17 16:05:13 +01:00
|
|
|
index 9852a0a0..0353f954 100644
|
2016-12-09 13:56:14 +01:00
|
|
|
--- a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java
|
|
|
|
+++ b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java
|
2017-01-17 16:05:13 +01:00
|
|
|
@@ -597,7 +597,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
2016-12-09 13:56:14 +01:00
|
|
|
@Override
|
|
|
|
public String getUUID()
|
|
|
|
{
|
|
|
|
- return uniqueId.toString().replaceAll( "-", "" );
|
|
|
|
+ return io.github.waterfallmc.waterfall.utils.UUIDUtils.undash( uniqueId.toString() ); // Waterfall
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2016-05-28 18:34:39 +02:00
|
|
|
--
|
2017-01-17 16:05:13 +01:00
|
|
|
2.11.0
|
2016-05-28 18:34:39 +02:00
|
|
|
|