Compare commits
38 Commits
8b195d1d21
...
7340f1a035
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7340f1a035 | ||
![]() |
8a80435e64 | ||
![]() |
20a71b06a9 | ||
![]() |
b376f61578 | ||
![]() |
373dab05ad | ||
![]() |
f6b40b1186 | ||
![]() |
81b118a8ba | ||
![]() |
7a42f12716 | ||
![]() |
4886c4be01 | ||
![]() |
7338d0f444 | ||
![]() |
8212e10c7c | ||
![]() |
2593130b3e | ||
![]() |
6ea49962c5 | ||
![]() |
672db9fe47 | ||
![]() |
2bacf6572b | ||
![]() |
9813e46e66 | ||
![]() |
01a5f36012 | ||
![]() |
f0a30c43cd | ||
![]() |
acb85e30fa | ||
![]() |
9437cedc48 | ||
![]() |
a89cf5f36d | ||
![]() |
b309e4ac50 | ||
![]() |
477ea5983c | ||
![]() |
eca6090f1e | ||
![]() |
8f8c270f3b | ||
![]() |
84ac7ab944 | ||
![]() |
5fbcc6b119 | ||
![]() |
79f85a2ce2 | ||
![]() |
d32eedd333 | ||
![]() |
e1d4b6adc7 | ||
![]() |
534148763f | ||
![]() |
cd56fb32c2 | ||
![]() |
6b612302e1 | ||
![]() |
e49759025f | ||
![]() |
c310e3339f | ||
![]() |
b64615e298 | ||
![]() |
45d2f44003 | ||
![]() |
a57adcce00 |
@ -113,4 +113,18 @@ public interface PendingConnection extends Connection
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
CompletableFuture<byte[]> retrieveCookie(String cookie);
|
||||
|
||||
/**
|
||||
* Sends a login payload request to the client.
|
||||
*
|
||||
* @param channel the channel to send this data via
|
||||
* @param data the data to send
|
||||
* @return a {@link CompletableFuture} that will be completed when the Login
|
||||
* Payload response is received. If the Vanilla client doesn't know the
|
||||
* channel, the {@link CompletableFuture} will complete with a null value
|
||||
* @throws IllegalStateException if the player's version is not at least
|
||||
* 1.13
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
CompletableFuture<byte[]> sendData(String channel, byte[] data);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
<version>2.11.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.AccessLevel;
|
||||
@ -129,6 +130,10 @@ public abstract class BaseComponent
|
||||
{
|
||||
setColor( component.getColorRaw() );
|
||||
}
|
||||
if ( replace || !style.hasShadowColor() )
|
||||
{
|
||||
setShadowColor( component.getShadowColorRaw() );
|
||||
}
|
||||
if ( replace || !style.hasFont() )
|
||||
{
|
||||
setFont( component.getFontRaw() );
|
||||
@ -175,6 +180,7 @@ public abstract class BaseComponent
|
||||
if ( retention == FormatRetention.EVENTS || retention == FormatRetention.NONE )
|
||||
{
|
||||
setColor( null );
|
||||
setShadowColor( null );
|
||||
setBold( null );
|
||||
setItalic( null );
|
||||
setUnderlined( null );
|
||||
@ -295,6 +301,46 @@ public abstract class BaseComponent
|
||||
return style.getColor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this component's shadow color.
|
||||
*
|
||||
* @param color the component shadow color, or null to use the default
|
||||
*/
|
||||
public void setShadowColor(Color color)
|
||||
{
|
||||
this.style.setShadowColor( color );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shadow color of this component. This uses the parent's shadow color if this
|
||||
* component doesn't have one. null is returned if no shadow color is found.
|
||||
*
|
||||
* @return the shadow color of this component
|
||||
*/
|
||||
public Color getShadowColor()
|
||||
{
|
||||
if ( !style.hasShadowColor() )
|
||||
{
|
||||
if ( parent == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return parent.getShadowColor();
|
||||
}
|
||||
return style.getShadowColor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shadow color of this component without checking the parents
|
||||
* shadow color. May return null
|
||||
*
|
||||
* @return the shadow color of this component
|
||||
*/
|
||||
public Color getShadowColorRaw()
|
||||
{
|
||||
return style.getShadowColor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this component's font.
|
||||
*
|
||||
@ -536,6 +582,10 @@ public abstract class BaseComponent
|
||||
{
|
||||
setColor( style.getColor() );
|
||||
}
|
||||
if ( style.hasShadowColor() )
|
||||
{
|
||||
setShadowColor( style.getShadowColor() );
|
||||
}
|
||||
if ( style.hasFont() )
|
||||
{
|
||||
setFont( style.getFont() );
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import java.awt.Color;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
@ -23,6 +24,10 @@ public final class ComponentStyle implements Cloneable
|
||||
* {@link ChatColor#color} should not be null).</b>
|
||||
*/
|
||||
private ChatColor color;
|
||||
/**
|
||||
* The shadow color of this style.
|
||||
*/
|
||||
private Color shadowColor;
|
||||
/**
|
||||
* The font of this style.
|
||||
*/
|
||||
@ -68,6 +73,26 @@ public final class ComponentStyle implements Cloneable
|
||||
return ( color != null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shadow color of this style. May return null.
|
||||
*
|
||||
* @return the shadow color of this style, or null if default color
|
||||
*/
|
||||
public Color getShadowColor()
|
||||
{
|
||||
return shadowColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not this style has a shadow color set.
|
||||
*
|
||||
* @return whether a shadow color is set
|
||||
*/
|
||||
public boolean hasShadowColor()
|
||||
{
|
||||
return ( shadowColor != null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the font of this style. May return null.
|
||||
*
|
||||
@ -195,7 +220,7 @@ public final class ComponentStyle implements Cloneable
|
||||
*/
|
||||
public boolean isEmpty()
|
||||
{
|
||||
return color == null && font == null && bold == null
|
||||
return color == null && shadowColor == null && font == null && bold == null
|
||||
&& italic == null && underlined == null
|
||||
&& strikethrough == null && obfuscated == null;
|
||||
}
|
||||
@ -203,7 +228,7 @@ public final class ComponentStyle implements Cloneable
|
||||
@Override
|
||||
public ComponentStyle clone()
|
||||
{
|
||||
return new ComponentStyle( color, font, bold, italic, underlined, strikethrough, obfuscated );
|
||||
return new ComponentStyle( color, shadowColor, font, bold, italic, underlined, strikethrough, obfuscated );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -227,6 +252,7 @@ public final class ComponentStyle implements Cloneable
|
||||
{
|
||||
return new ComponentStyleBuilder()
|
||||
.color( other.color )
|
||||
.shadowColor( other.shadowColor )
|
||||
.font( other.font )
|
||||
.bold( other.bold )
|
||||
.italic( other.italic )
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.md_5.bungee.api.chat;
|
||||
|
||||
import java.awt.Color;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
/**
|
||||
@ -26,6 +27,7 @@ public final class ComponentStyleBuilder
|
||||
{
|
||||
|
||||
private ChatColor color;
|
||||
private Color shadowColor;
|
||||
private String font;
|
||||
private Boolean bold, italic, underlined, strikethrough, obfuscated;
|
||||
|
||||
@ -41,6 +43,18 @@ public final class ComponentStyleBuilder
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the style shadow color.
|
||||
*
|
||||
* @param shadowColor the shadow color to set, or null to use the default
|
||||
* @return this ComponentStyleBuilder for chaining
|
||||
*/
|
||||
public ComponentStyleBuilder shadowColor(Color shadowColor)
|
||||
{
|
||||
this.shadowColor = shadowColor;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the style font.
|
||||
*
|
||||
@ -121,6 +135,6 @@ public final class ComponentStyleBuilder
|
||||
*/
|
||||
public ComponentStyle build()
|
||||
{
|
||||
return new ComponentStyle( color, font, bold, italic, underlined, strikethrough, obfuscated );
|
||||
return new ComponentStyle( color, shadowColor, font, bold, italic, underlined, strikethrough, obfuscated );
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import net.md_5.bungee.api.chat.ScoreComponent;
|
||||
import net.md_5.bungee.api.chat.SelectorComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.chat.TranslatableComponent;
|
||||
import net.md_5.bungee.api.chat.hover.content.Content;
|
||||
import net.md_5.bungee.api.chat.hover.content.Entity;
|
||||
import net.md_5.bungee.api.chat.hover.content.EntitySerializer;
|
||||
import net.md_5.bungee.api.chat.hover.content.Item;
|
||||
@ -158,11 +159,28 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
|
||||
return gson.toJsonTree( style );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object the object to serialize
|
||||
* @return the JSON string representation of the object
|
||||
* @deprecated Error-prone, be careful which object you input here
|
||||
*/
|
||||
@Deprecated
|
||||
public static String toString(Object object)
|
||||
{
|
||||
return gson.toJson( object );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param content the content to serialize
|
||||
* @return the JSON string representation of the object
|
||||
* @deprecated for legacy internal use only
|
||||
*/
|
||||
@Deprecated
|
||||
public static String toString(Content content)
|
||||
{
|
||||
return gson.toJson( content );
|
||||
}
|
||||
|
||||
public static String toString(BaseComponent component)
|
||||
{
|
||||
return gson.toJson( component );
|
||||
|
@ -1,5 +1,6 @@
|
||||
package net.md_5.bungee.chat;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonDeserializationContext;
|
||||
import com.google.gson.JsonDeserializer;
|
||||
import com.google.gson.JsonElement;
|
||||
@ -8,6 +9,7 @@ import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
import java.awt.Color;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Map;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
@ -67,6 +69,10 @@ public class ComponentStyleSerializer implements JsonSerializer<ComponentStyle>,
|
||||
{
|
||||
object.addProperty( "color", style.getColor().getName() );
|
||||
}
|
||||
if ( style.hasShadowColor() )
|
||||
{
|
||||
object.addProperty( "shadow_color", style.getShadowColor().getRGB() );
|
||||
}
|
||||
if ( style.hasFont() )
|
||||
{
|
||||
object.addProperty( "font", style.getFont() );
|
||||
@ -102,6 +108,17 @@ public class ComponentStyleSerializer implements JsonSerializer<ComponentStyle>,
|
||||
case "color":
|
||||
builder.color( ChatColor.of( value.getAsString() ) );
|
||||
break;
|
||||
case "shadow_color":
|
||||
if ( value.isJsonArray() )
|
||||
{
|
||||
JsonArray array = value.getAsJsonArray();
|
||||
|
||||
builder.shadowColor( new Color( array.get( 0 ).getAsFloat(), array.get( 1 ).getAsFloat(), array.get( 2 ).getAsFloat(), array.get( 3 ).getAsFloat() ) );
|
||||
} else if ( value.isJsonPrimitive() )
|
||||
{
|
||||
builder.shadowColor( new Color( value.getAsNumber().intValue(), true ) );
|
||||
}
|
||||
break;
|
||||
case "font":
|
||||
builder.font( value.getAsString() );
|
||||
break;
|
||||
|
@ -22,7 +22,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.code.gson</groupId>
|
||||
<artifactId>gson</artifactId>
|
||||
<version>2.10.1</version>
|
||||
<version>2.11.0</version>
|
||||
<scope>compile</scope>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
29
native/compile-native-arm.sh
Executable file
29
native/compile-native-arm.sh
Executable file
@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
CWD=$(pwd)
|
||||
|
||||
echo "Compiling mbedtls"
|
||||
(cd mbedtls && CFLAGS="-fPIC -I$CWD/src/main/c -DMBEDTLS_USER_CONFIG_FILE='<mbedtls_custom_config.h>'" make CC=aarch64-linux-gnu-gcc AR=aarch64-linux-gnu-ar no_test)
|
||||
|
||||
echo "Compiling zlib"
|
||||
(cd zlib && CFLAGS="-fPIC -DNO_GZIP" CC=aarch64-linux-gnu-gcc CHOST=arm64 ./configure --target="aarch64" --static && make CFLAGS="-fPIC -march=armv8-a+crc" CC=aarch64-linux-gnu-gcc AR=aarch64-linux-gnu-ar)
|
||||
|
||||
CC="aarch64-linux-gnu-gcc"
|
||||
CFLAGS="-c -fPIC -O3 -Wall -Werror -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/"
|
||||
LDFLAGS="-shared"
|
||||
|
||||
echo "Compiling bungee"
|
||||
$CC $CFLAGS -o shared.o src/main/c/shared.c
|
||||
$CC $CFLAGS -Imbedtls/include -o NativeCipherImpl.o src/main/c/NativeCipherImpl.c
|
||||
$CC $CFLAGS -Izlib -o NativeCompressImpl.o src/main/c/NativeCompressImpl.c
|
||||
|
||||
echo "Linking native-cipher-arm.so"
|
||||
$CC $LDFLAGS -o src/main/resources/native-cipher-arm.so shared.o NativeCipherImpl.o mbedtls/library/libmbedcrypto.a
|
||||
|
||||
echo "Linking native-compress-arm.so"
|
||||
$CC $LDFLAGS -o src/main/resources/native-compress-arm.so shared.o NativeCompressImpl.o zlib/libz.a
|
||||
|
||||
echo "Cleaning up"
|
||||
rm shared.o NativeCipherImpl.o NativeCompressImpl.o
|
@ -2,11 +2,13 @@
|
||||
|
||||
set -eu
|
||||
|
||||
CWD=$(pwd)
|
||||
|
||||
echo "Compiling mbedtls"
|
||||
(cd mbedtls && make no_test)
|
||||
(cd mbedtls && CFLAGS="-fPIC -I$CWD/src/main/c -DMBEDTLS_USER_CONFIG_FILE='<mbedtls_custom_config.h>'" make no_test)
|
||||
|
||||
echo "Compiling zlib"
|
||||
(cd zlib && CFLAGS=-fPIC ./configure --static && make)
|
||||
(cd zlib && CFLAGS="-fPIC -DNO_GZIP" ./configure --static && make)
|
||||
|
||||
CC="gcc"
|
||||
CFLAGS="-c -fPIC -O3 -Wall -Werror -I$JAVA_HOME/include/ -I$JAVA_HOME/include/linux/"
|
||||
|
@ -5,11 +5,15 @@
|
||||
#include "shared.h"
|
||||
#include "net_md_5_bungee_jni_cipher_NativeCipherImpl.h"
|
||||
|
||||
// Hack to keep the compiler from optimizing the memset away
|
||||
static void *(*const volatile memset_func)(void *, int, size_t) = memset;
|
||||
|
||||
typedef unsigned char byte;
|
||||
|
||||
typedef struct crypto_context {
|
||||
int mode;
|
||||
mbedtls_aes_context cipher;
|
||||
int keyLen;
|
||||
byte key[];
|
||||
} crypto_context;
|
||||
|
||||
@ -22,6 +26,7 @@ jlong JNICALL Java_net_md_15_bungee_jni_cipher_NativeCipherImpl_init(JNIEnv* env
|
||||
return 0;
|
||||
}
|
||||
|
||||
crypto->keyLen = (int) keyLen;
|
||||
(*env)->GetByteArrayRegion(env, key, 0, keyLen, (jbyte*) &crypto->key);
|
||||
|
||||
mbedtls_aes_init(&crypto->cipher);
|
||||
@ -36,6 +41,7 @@ void Java_net_md_15_bungee_jni_cipher_NativeCipherImpl_free(JNIEnv* env, jobject
|
||||
crypto_context *crypto = (crypto_context*) ctx;
|
||||
|
||||
mbedtls_aes_free(&crypto->cipher);
|
||||
memset_func(crypto->key, 0, (size_t) crypto->keyLen);
|
||||
free(crypto);
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,9 @@
|
||||
|
||||
#include <zlib.h>
|
||||
#include "shared.h"
|
||||
#if !defined(__aarch64__)
|
||||
#include "cpuid_helper.h"
|
||||
#endif
|
||||
#include "net_md_5_bungee_jni_zlib_NativeCompressImpl.h"
|
||||
|
||||
typedef unsigned char byte;
|
||||
@ -26,6 +29,14 @@ jint throwException(JNIEnv *env, const char* message, int err) {
|
||||
return (*env)->Throw(env, throwable);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_checkSupported(JNIEnv* env, jobject obj) {
|
||||
#if !defined(__aarch64__)
|
||||
return (jboolean) checkCompressionNativesSupport();
|
||||
#else
|
||||
return JNI_TRUE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_reset(JNIEnv* env, jobject obj, jlong ctx, jboolean compress) {
|
||||
z_stream* stream = (z_stream*) ctx;
|
||||
int ret = (compress) ? deflateReset(stream) : inflateReset(stream);
|
||||
|
19
native/src/main/c/cpuid_helper.h
Normal file
19
native/src/main/c/cpuid_helper.h
Normal file
@ -0,0 +1,19 @@
|
||||
// Header to check for SSE 2, SSSE 3, and SSE 4.2 support in compression natives
|
||||
// GCC only!
|
||||
|
||||
#ifndef _INCLUDE_CPUID_HELPER_H
|
||||
#define _INCLUDE_CPUID_HELPER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <cpuid.h>
|
||||
|
||||
static inline bool checkCompressionNativesSupport() {
|
||||
unsigned int eax, ebx, ecx, edx;
|
||||
if(__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
|
||||
return (edx & bit_SSE2) != 0 && (ecx & bit_SSSE3) != 0 && (ecx & bit_SSE4_2) != 0;
|
||||
}else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _INCLUDE_CPUID_HELPER_H
|
31
native/src/main/c/mbedtls_custom_config.h
Normal file
31
native/src/main/c/mbedtls_custom_config.h
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
// This is a hack to deal with a glitch that happens when mbedtls is compiled against glibc
|
||||
// but then run on a linux distro that uses musl libc. This implementation of the zeroize
|
||||
// is compatible with both glibc and musl without requiring the library to be recompiled.
|
||||
|
||||
// I checked with a disassembler and for BungeeCord's usage of the library, implementing
|
||||
// this function as a static function only resulted in 2 different subroutines referencing
|
||||
// different versions of memset_func, so we might as well keep things simple and use a
|
||||
// static function here instead of requiring the mbedtls makefile to be modified to add
|
||||
// additional source files.
|
||||
|
||||
#ifndef _INCLUDE_MBEDTLS_CUSTOM_CONFIG_H
|
||||
#define _INCLUDE_MBEDTLS_CUSTOM_CONFIG_H
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define MBEDTLS_PLATFORM_ZEROIZE_ALT
|
||||
|
||||
#define mbedtls_platform_zeroize mbedtls_platform_zeroize_impl
|
||||
|
||||
// hack to prevent compilers from optimizing the memset away
|
||||
static void *(*const volatile memset_func)(void *, int, size_t) = memset;
|
||||
|
||||
static void mbedtls_platform_zeroize_impl(void *buf, size_t len) {
|
||||
if (len > 0) {
|
||||
memset_func(buf, 0, len);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // _INCLUDE_MBEDTLS_CUSTOM_CONFIG_H
|
||||
|
@ -15,6 +15,14 @@ extern "C" {
|
||||
JNIEXPORT void JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_initFields
|
||||
(JNIEnv *, jclass);
|
||||
|
||||
/*
|
||||
* Class: net_md_5_bungee_jni_zlib_NativeCompressImpl
|
||||
* Method: checkSupported
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_net_md_15_bungee_jni_zlib_NativeCompressImpl_checkSupported
|
||||
(JNIEnv *, jobject);
|
||||
|
||||
/*
|
||||
* Class: net_md_5_bungee_jni_zlib_NativeCompressImpl
|
||||
* Method: end
|
||||
|
@ -15,14 +15,23 @@ public final class NativeCode<T>
|
||||
private final String name;
|
||||
private final Supplier<? extends T> javaImpl;
|
||||
private final Supplier<? extends T> nativeImpl;
|
||||
private final boolean enableNativeFlag;
|
||||
private final boolean extendedSupportCheck;
|
||||
//
|
||||
private boolean loaded;
|
||||
|
||||
public NativeCode(String name, Supplier<? extends T> javaImpl, Supplier<? extends T> nativeImpl)
|
||||
{
|
||||
this( name, javaImpl, nativeImpl, false );
|
||||
}
|
||||
|
||||
public NativeCode(String name, Supplier<? extends T> javaImpl, Supplier<? extends T> nativeImpl, boolean extendedSupportCheck)
|
||||
{
|
||||
this.name = name;
|
||||
this.javaImpl = javaImpl;
|
||||
this.nativeImpl = nativeImpl;
|
||||
this.enableNativeFlag = Boolean.parseBoolean( System.getProperty( "net.md_5.bungee.jni." + name + ".enable", "true" ) );
|
||||
this.extendedSupportCheck = extendedSupportCheck;
|
||||
}
|
||||
|
||||
public T newInstance()
|
||||
@ -32,8 +41,9 @@ public final class NativeCode<T>
|
||||
|
||||
public boolean load()
|
||||
{
|
||||
if ( !loaded && isSupported() )
|
||||
if ( enableNativeFlag && !loaded && isSupported() )
|
||||
{
|
||||
String name = this.name + ( isAarch64() ? "-arm" : "" );
|
||||
String fullName = "bungeecord-" + name;
|
||||
|
||||
try
|
||||
@ -59,6 +69,13 @@ public final class NativeCode<T>
|
||||
}
|
||||
|
||||
System.load( temp.getPath() );
|
||||
|
||||
if ( extendedSupportCheck )
|
||||
{
|
||||
// Should throw NativeCodeException if incompatible
|
||||
nativeImpl.get();
|
||||
}
|
||||
|
||||
loaded = true;
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
@ -66,6 +83,9 @@ public final class NativeCode<T>
|
||||
} catch ( UnsatisfiedLinkError ex )
|
||||
{
|
||||
System.out.println( "Could not load native library: " + ex.getMessage() );
|
||||
} catch ( NativeCodeException ex )
|
||||
{
|
||||
System.out.println( "Native library " + name + " is incompatible: " + ex.getMessage() );
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -75,6 +95,16 @@ public final class NativeCode<T>
|
||||
|
||||
public static boolean isSupported()
|
||||
{
|
||||
return "Linux".equals( System.getProperty( "os.name" ) ) && "amd64".equals( System.getProperty( "os.arch" ) );
|
||||
return "Linux".equals( System.getProperty( "os.name" ) ) && ( isAmd64() || isAarch64() );
|
||||
}
|
||||
|
||||
private static boolean isAmd64()
|
||||
{
|
||||
return "amd64".equals( System.getProperty( "os.arch" ) );
|
||||
}
|
||||
|
||||
private static boolean isAarch64()
|
||||
{
|
||||
return "aarch64".equals( System.getProperty( "os.arch" ) );
|
||||
}
|
||||
}
|
||||
|
@ -7,4 +7,10 @@ public class NativeCodeException extends RuntimeException
|
||||
{
|
||||
super( message + " : " + reason );
|
||||
}
|
||||
|
||||
public NativeCodeException(String message)
|
||||
{
|
||||
super( message );
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,4 +18,10 @@ public interface BungeeCipher
|
||||
void cipher(ByteBuf in, ByteBuf out) throws GeneralSecurityException;
|
||||
|
||||
ByteBuf cipher(ChannelHandlerContext ctx, ByteBuf in) throws GeneralSecurityException;
|
||||
|
||||
/*
|
||||
* This indicates whether the input ByteBuf is allowed to be a CompositeByteBuf.
|
||||
* If you need access to a memory address, you should not allow composite buffers.
|
||||
*/
|
||||
boolean allowComposite();
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package net.md_5.bungee.jni.cipher;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.util.concurrent.FastThreadLocal;
|
||||
import java.security.GeneralSecurityException;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
@ -12,10 +13,10 @@ public class JavaCipher implements BungeeCipher
|
||||
{
|
||||
|
||||
private final Cipher cipher;
|
||||
private static final ThreadLocal<byte[]> heapInLocal = new EmptyByteThreadLocal();
|
||||
private static final ThreadLocal<byte[]> heapOutLocal = new EmptyByteThreadLocal();
|
||||
private static final FastThreadLocal<byte[]> heapInLocal = new EmptyByteThreadLocal();
|
||||
private static final FastThreadLocal<byte[]> heapOutLocal = new EmptyByteThreadLocal();
|
||||
|
||||
private static class EmptyByteThreadLocal extends ThreadLocal<byte[]>
|
||||
private static class EmptyByteThreadLocal extends FastThreadLocal<byte[]>
|
||||
{
|
||||
|
||||
@Override
|
||||
@ -88,4 +89,10 @@ public class JavaCipher implements BungeeCipher
|
||||
in.readBytes( heapIn, 0, readableBytes );
|
||||
return heapIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowComposite()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -71,4 +71,10 @@ public class NativeCipher implements BungeeCipher
|
||||
|
||||
return heapOut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowComposite()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,17 @@ import java.util.zip.DataFormatException;
|
||||
public interface BungeeZlib
|
||||
{
|
||||
|
||||
public static final int OUTPUT_BUFFER_SIZE = 8192;
|
||||
|
||||
void init(boolean compress, int level);
|
||||
|
||||
void free();
|
||||
|
||||
void process(ByteBuf in, ByteBuf out) throws DataFormatException;
|
||||
|
||||
/*
|
||||
* This indicates whether the input ByteBuf is allowed to be a CompositeByteBuf.
|
||||
* If you need access to a memory address, you should not allow composite buffers.
|
||||
*/
|
||||
boolean allowComposite();
|
||||
}
|
||||
|
@ -73,4 +73,10 @@ public class JavaZlib implements BungeeZlib
|
||||
inflater.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowComposite()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ public class NativeCompressImpl
|
||||
|
||||
static native void initFields();
|
||||
|
||||
native boolean checkSupported();
|
||||
|
||||
native void end(long ctx, boolean compress);
|
||||
|
||||
native void reset(long ctx, boolean compress);
|
||||
|
@ -15,6 +15,14 @@ public class NativeZlib implements BungeeZlib
|
||||
private boolean compress;
|
||||
private long ctx;
|
||||
|
||||
public NativeZlib()
|
||||
{
|
||||
if ( !nativeCompress.checkSupported() )
|
||||
{
|
||||
throw new NativeCodeException( "This CPU does not support the required SSE 4.2 and/or PCLMUL extensions!" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(boolean compress, int level)
|
||||
{
|
||||
@ -47,7 +55,7 @@ public class NativeZlib implements BungeeZlib
|
||||
|
||||
while ( !nativeCompress.finished && ( compress || in.isReadable() ) )
|
||||
{
|
||||
out.ensureWritable( 8192 );
|
||||
out.ensureWritable( OUTPUT_BUFFER_SIZE );
|
||||
|
||||
int processed;
|
||||
try
|
||||
@ -66,4 +74,10 @@ public class NativeZlib implements BungeeZlib
|
||||
nativeCompress.consumed = 0;
|
||||
nativeCompress.finished = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowComposite()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
BIN
native/src/main/resources/native-cipher-arm.so
Executable file
BIN
native/src/main/resources/native-cipher-arm.so
Executable file
Binary file not shown.
Binary file not shown.
BIN
native/src/main/resources/native-compress-arm.so
Executable file
BIN
native/src/main/resources/native-compress-arm.so
Executable file
Binary file not shown.
Binary file not shown.
@ -15,7 +15,7 @@ import org.junit.jupiter.api.Test;
|
||||
public class NativeZlibTest
|
||||
{
|
||||
|
||||
private final NativeCode<BungeeZlib> factory = new NativeCode<>( "native-compress", JavaZlib::new, NativeZlib::new );
|
||||
private final NativeCode<BungeeZlib> factory = new NativeCode<>( "native-compress", JavaZlib::new, NativeZlib::new, true );
|
||||
|
||||
@Test
|
||||
public void doTest() throws DataFormatException
|
||||
|
4
pom.xml
4
pom.xml
@ -83,7 +83,7 @@
|
||||
<dependency>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-bom</artifactId>
|
||||
<version>4.1.110.Final</version>
|
||||
<version>4.1.115.Final</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
@ -99,7 +99,7 @@
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>32.1.2-jre</version>
|
||||
<version>33.3.1-jre</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -499,7 +499,7 @@ public abstract class DefinedPacket
|
||||
|
||||
public static BitSet readFixedBitSet(int i, ByteBuf buf)
|
||||
{
|
||||
byte[] bits = new byte[ ( i + 8 ) >> 3 ];
|
||||
byte[] bits = new byte[ ( i + 7 ) >> 3 ];
|
||||
buf.readBytes( bits );
|
||||
|
||||
return BitSet.valueOf( bits );
|
||||
@ -511,7 +511,7 @@ public abstract class DefinedPacket
|
||||
{
|
||||
throw new OverflowPacketException( "BitSet too large (expected " + size + " got " + bits.size() + ")" );
|
||||
}
|
||||
buf.writeBytes( Arrays.copyOf( bits.toByteArray(), ( size + 8 ) >> 3 ) );
|
||||
buf.writeBytes( Arrays.copyOf( bits.toByteArray(), ( size + 7 ) >> 3 ) );
|
||||
}
|
||||
|
||||
public void read(ByteBuf buf)
|
||||
|
@ -98,7 +98,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_3, 0x1F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x23 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x24 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x26 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x26 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x27 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
Login.class,
|
||||
@ -115,7 +116,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_3, 0x24 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x28 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x29 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x2B )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x2B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x2C )
|
||||
);
|
||||
TO_CLIENT.registerPacket( Chat.class,
|
||||
Chat::new,
|
||||
@ -146,7 +148,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x41 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x43 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x45 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x47 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x47 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x4C )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
BossBar.class,
|
||||
@ -206,7 +209,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x58 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x5C ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x5E )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x5E ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x64 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
ScoreboardScore.class,
|
||||
@ -224,13 +228,15 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5D ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x5F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x61 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x61 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x68 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
ScoreboardScoreReset.class,
|
||||
ScoreboardScoreReset::new,
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x42 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x44 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x44 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x49 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
ScoreboardDisplay.class,
|
||||
@ -248,7 +254,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x51 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x53 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x55 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x57 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x57 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x5C )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
Team.class,
|
||||
@ -266,7 +273,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5C ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x5E ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x60 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x60 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x67 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
PluginMessage.class,
|
||||
@ -321,7 +329,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x61 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x63 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x65 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x65 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x6C )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
ClearTitles.class,
|
||||
@ -342,7 +351,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5D ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x61 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x63 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x63 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x6A )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
TitleTimes.class,
|
||||
@ -354,7 +364,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x60 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x62 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x64 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x66 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x66 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x6D )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
SystemChat.class,
|
||||
@ -365,7 +376,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x64 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x67 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x69 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x6C )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x6C ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x73 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
PlayerListHeaderFooter.class,
|
||||
@ -387,7 +399,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x65 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x68 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x6A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x6D )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x6D ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x74 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
EntityStatus.class,
|
||||
@ -432,7 +445,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_3, 0x1C ),
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x20 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x22 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x22 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x23 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
ViewDistance.class,
|
||||
@ -447,7 +461,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x4F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x51 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x53 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x55 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x55 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x59 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
ServerData.class,
|
||||
@ -458,7 +473,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x45 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x47 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x49 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x4B )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x4B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x50 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
PlayerListItemRemove.class,
|
||||
@ -466,7 +482,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_3, 0x35 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x39 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x3B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x3D )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x3D ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x3F )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
PlayerListItemUpdate.class,
|
||||
@ -474,14 +491,16 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_3, 0x36 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x3A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x3C ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x3E )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x3E ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x40 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
StartConfiguration.class,
|
||||
StartConfiguration::new,
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x65 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x67 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x69 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x69 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x70 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
CookieRequest.class,
|
||||
@ -491,22 +510,26 @@ public enum Protocol
|
||||
TO_CLIENT.registerPacket(
|
||||
StoreCookie.class,
|
||||
StoreCookie::new,
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x6B )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x6B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x72 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
Transfer.class,
|
||||
Transfer::new,
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x73 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x73 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x7A )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
DisconnectReportDetails.class,
|
||||
DisconnectReportDetails::new,
|
||||
map( ProtocolConstants.MINECRAFT_1_21, 0x7A )
|
||||
map( ProtocolConstants.MINECRAFT_1_21, 0x7A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x81 )
|
||||
);
|
||||
TO_CLIENT.registerPacket(
|
||||
ServerLinks.class,
|
||||
ServerLinks::new,
|
||||
map( ProtocolConstants.MINECRAFT_1_21, 0x7B )
|
||||
map( ProtocolConstants.MINECRAFT_1_21, 0x7B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x82 )
|
||||
);
|
||||
|
||||
TO_SERVER.registerPacket(
|
||||
@ -526,7 +549,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x12 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x14 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x15 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x18 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x18 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x1A )
|
||||
);
|
||||
TO_SERVER.registerPacket( Chat.class,
|
||||
Chat::new,
|
||||
@ -542,19 +566,23 @@ public enum Protocol
|
||||
ClientCommand::new,
|
||||
map( ProtocolConstants.MINECRAFT_1_19, 0x03 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_19_1, 0x04 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x05 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x05 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x06 )
|
||||
);
|
||||
TO_SERVER.registerPacket(
|
||||
UnsignedClientCommand.class,
|
||||
UnsignedClientCommand::new,
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x04 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x04 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x05 )
|
||||
|
||||
);
|
||||
TO_SERVER.registerPacket(
|
||||
ClientChat.class,
|
||||
ClientChat::new,
|
||||
map( ProtocolConstants.MINECRAFT_1_19, 0x04 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_19_1, 0x05 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x06 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x06 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x07 )
|
||||
);
|
||||
TO_SERVER.registerPacket(
|
||||
TabCompleteRequest.class,
|
||||
@ -570,7 +598,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_3, 0x08 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x09 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0B )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x0D )
|
||||
);
|
||||
TO_SERVER.registerPacket(
|
||||
ClientSettings.class,
|
||||
@ -585,7 +614,8 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_3, 0x07 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x08 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x09 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0A )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0A ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x0C )
|
||||
);
|
||||
TO_SERVER.registerPacket(
|
||||
PluginMessage.class,
|
||||
@ -603,18 +633,21 @@ public enum Protocol
|
||||
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0D ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0F ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_3, 0x10 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x12 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x12 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x14 )
|
||||
);
|
||||
TO_SERVER.registerPacket(
|
||||
StartConfiguration.class,
|
||||
StartConfiguration::new,
|
||||
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0B ),
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0C )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x0C ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x0E )
|
||||
);
|
||||
TO_SERVER.registerPacket(
|
||||
CookieResponse.class,
|
||||
CookieResponse::new,
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x11 )
|
||||
map( ProtocolConstants.MINECRAFT_1_20_5, 0x11 ),
|
||||
map( ProtocolConstants.MINECRAFT_1_21_2, 0x13 )
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@ -47,6 +47,8 @@ public class ProtocolConstants
|
||||
public static final int MINECRAFT_1_20_3 = 765;
|
||||
public static final int MINECRAFT_1_20_5 = 766;
|
||||
public static final int MINECRAFT_1_21 = 767;
|
||||
public static final int MINECRAFT_1_21_2 = 768;
|
||||
public static final int MINECRAFT_1_21_4 = 769;
|
||||
public static final List<String> SUPPORTED_VERSIONS;
|
||||
public static final List<Integer> SUPPORTED_VERSION_IDS;
|
||||
|
||||
@ -108,13 +110,15 @@ public class ProtocolConstants
|
||||
ProtocolConstants.MINECRAFT_1_20_2,
|
||||
ProtocolConstants.MINECRAFT_1_20_3,
|
||||
ProtocolConstants.MINECRAFT_1_20_5,
|
||||
ProtocolConstants.MINECRAFT_1_21
|
||||
ProtocolConstants.MINECRAFT_1_21,
|
||||
ProtocolConstants.MINECRAFT_1_21_2,
|
||||
ProtocolConstants.MINECRAFT_1_21_4
|
||||
);
|
||||
|
||||
if ( SNAPSHOT_SUPPORT )
|
||||
{
|
||||
// supportedVersions.add( "1.21.x" );
|
||||
// supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_21 );
|
||||
// supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_21_4 );
|
||||
}
|
||||
|
||||
SUPPORTED_VERSIONS = supportedVersions.build();
|
||||
|
@ -1,27 +1,38 @@
|
||||
package net.md_5.bungee.protocol;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import java.util.List;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* Prepend length of the message as a Varint21 by writing length and data to a
|
||||
* new buffer
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
public class Varint21LengthFieldPrepender extends MessageToByteEncoder<ByteBuf>
|
||||
public class Varint21LengthFieldPrepender extends MessageToMessageEncoder<ByteBuf>
|
||||
{
|
||||
|
||||
@Setter
|
||||
private boolean compose = true;
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> list) throws Exception
|
||||
{
|
||||
int bodyLen = msg.readableBytes();
|
||||
int headerLen = varintSize( bodyLen );
|
||||
out.ensureWritable( headerLen + bodyLen );
|
||||
|
||||
DefinedPacket.writeVarInt( bodyLen, out );
|
||||
out.writeBytes( msg );
|
||||
if ( compose )
|
||||
{
|
||||
ByteBuf buf = ctx.alloc().directBuffer( headerLen );
|
||||
DefinedPacket.writeVarInt( bodyLen, buf );
|
||||
list.add( ctx.alloc().compositeDirectBuffer( 2 ).addComponents( true, buf, msg.retain() ) );
|
||||
} else
|
||||
{
|
||||
ByteBuf buf = ctx.alloc().directBuffer( headerLen + bodyLen );
|
||||
DefinedPacket.writeVarInt( bodyLen, buf );
|
||||
buf.writeBytes( msg );
|
||||
list.add( buf );
|
||||
}
|
||||
}
|
||||
|
||||
static int varintSize(int paramInt)
|
||||
|
@ -32,7 +32,7 @@ public class ClientCommand extends DefinedPacket
|
||||
@Override
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
command = readString( buf, 256 );
|
||||
command = readString( buf, ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 ) ? 32767 : 256 );
|
||||
timestamp = buf.readLong();
|
||||
salt = buf.readLong();
|
||||
|
||||
|
@ -25,6 +25,7 @@ public class ClientSettings extends DefinedPacket
|
||||
private int mainHand;
|
||||
private boolean disableTextFiltering;
|
||||
private boolean allowServerListing;
|
||||
private ParticleStatus particleStatus;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
@ -46,6 +47,10 @@ public class ClientSettings extends DefinedPacket
|
||||
{
|
||||
allowServerListing = buf.readBoolean();
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_21_2 )
|
||||
{
|
||||
particleStatus = ParticleStatus.values()[readVarInt( buf )];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -74,6 +79,10 @@ public class ClientSettings extends DefinedPacket
|
||||
{
|
||||
buf.writeBoolean( allowServerListing );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_21_2 )
|
||||
{
|
||||
writeVarInt( particleStatus.ordinal(), buf );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -81,4 +90,11 @@ public class ClientSettings extends DefinedPacket
|
||||
{
|
||||
handler.handle( this );
|
||||
}
|
||||
|
||||
public enum ParticleStatus
|
||||
{
|
||||
ALL,
|
||||
DECREASED,
|
||||
MINIMAL;
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ public class CookieResponse extends DefinedPacket
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
cookie = readString( buf );
|
||||
data = readNullable( DefinedPacket::readArray, buf );
|
||||
data = readNullable( read -> DefinedPacket.readArray( read, 5120 ), buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -45,6 +45,10 @@ public class EncryptionResponse extends DefinedPacket
|
||||
writeArray( verifyToken, buf );
|
||||
} else
|
||||
{
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19 && protocolVersion <= ProtocolConstants.MINECRAFT_1_19_3 )
|
||||
{
|
||||
buf.writeBoolean( false );
|
||||
}
|
||||
buf.writeLong( encryptionData.getSalt() );
|
||||
writeArray( encryptionData.getSignature(), buf );
|
||||
}
|
||||
|
@ -41,6 +41,7 @@ public class Login extends DefinedPacket
|
||||
private boolean flat;
|
||||
private Location deathLocation;
|
||||
private int portalCooldown;
|
||||
private int seaLevel;
|
||||
private boolean secureProfile;
|
||||
|
||||
@Override
|
||||
@ -161,7 +162,10 @@ public class Login extends DefinedPacket
|
||||
{
|
||||
portalCooldown = readVarInt( buf );
|
||||
}
|
||||
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_21_2 )
|
||||
{
|
||||
seaLevel = readVarInt( buf );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 )
|
||||
{
|
||||
secureProfile = buf.readBoolean();
|
||||
@ -293,7 +297,10 @@ public class Login extends DefinedPacket
|
||||
{
|
||||
writeVarInt( portalCooldown, buf );
|
||||
}
|
||||
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_21_2 )
|
||||
{
|
||||
writeVarInt( seaLevel, buf );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 )
|
||||
{
|
||||
buf.writeBoolean( secureProfile );
|
||||
|
@ -37,7 +37,7 @@ public class LoginSuccess extends DefinedPacket
|
||||
{
|
||||
properties = readProperties( buf );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 )
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 && protocolVersion < ProtocolConstants.MINECRAFT_1_21_2 )
|
||||
{
|
||||
// Whether the client should disconnect on its own if it receives invalid data from the server
|
||||
buf.readBoolean();
|
||||
@ -59,7 +59,7 @@ public class LoginSuccess extends DefinedPacket
|
||||
{
|
||||
writeProperties( properties, buf );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 )
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_5 && protocolVersion < ProtocolConstants.MINECRAFT_1_21_2 )
|
||||
{
|
||||
// Whether the client should disconnect on its own if it receives invalid data from the server
|
||||
// Vanilla sends true so we also send true
|
||||
|
@ -145,5 +145,10 @@ public class PlayerListItem extends DefinedPacket
|
||||
// ADD_PLAYER & UPDATE_DISPLAY_NAME
|
||||
BaseComponent displayName;
|
||||
|
||||
// UPDATE_LIST_ORDER 1.21.2
|
||||
Integer listOrder;
|
||||
|
||||
// UPDATE_HAT 1.21.4
|
||||
Boolean showHat;
|
||||
}
|
||||
}
|
||||
|
@ -61,6 +61,12 @@ public class PlayerListItemUpdate extends DefinedPacket
|
||||
item.displayName = DefinedPacket.readBaseComponent( buf, protocolVersion );
|
||||
}
|
||||
break;
|
||||
case UPDATE_LIST_ORDER:
|
||||
item.listOrder = DefinedPacket.readVarInt( buf );
|
||||
break;
|
||||
case UPDATE_HAT:
|
||||
item.showHat = buf.readBoolean();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -109,6 +115,12 @@ public class PlayerListItemUpdate extends DefinedPacket
|
||||
DefinedPacket.writeBaseComponent( item.displayName, buf, protocolVersion );
|
||||
}
|
||||
break;
|
||||
case UPDATE_LIST_ORDER:
|
||||
DefinedPacket.writeVarInt( item.listOrder, buf );
|
||||
break;
|
||||
case UPDATE_HAT:
|
||||
buf.writeBoolean( item.showHat );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,6 +140,8 @@ public class PlayerListItemUpdate extends DefinedPacket
|
||||
UPDATE_GAMEMODE,
|
||||
UPDATE_LISTED,
|
||||
UPDATE_LATENCY,
|
||||
UPDATE_DISPLAY_NAME;
|
||||
UPDATE_DISPLAY_NAME,
|
||||
UPDATE_LIST_ORDER,
|
||||
UPDATE_HAT;
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ public class Respawn extends DefinedPacket
|
||||
private byte copyMeta;
|
||||
private Location deathLocation;
|
||||
private int portalCooldown;
|
||||
private int seaLevel;
|
||||
|
||||
@Override
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
@ -84,6 +85,10 @@ public class Respawn extends DefinedPacket
|
||||
{
|
||||
portalCooldown = readVarInt( buf );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_21_2 )
|
||||
{
|
||||
seaLevel = readVarInt( buf );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
|
||||
{
|
||||
copyMeta = buf.readByte();
|
||||
@ -148,6 +153,10 @@ public class Respawn extends DefinedPacket
|
||||
{
|
||||
writeVarInt( portalCooldown, buf );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_21_2 )
|
||||
{
|
||||
writeVarInt( seaLevel, buf );
|
||||
}
|
||||
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
|
||||
{
|
||||
buf.writeByte( copyMeta );
|
||||
|
@ -21,7 +21,7 @@ public class UnsignedClientCommand extends DefinedPacket
|
||||
@Override
|
||||
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
|
||||
{
|
||||
command = readString( buf, 256 );
|
||||
command = readString( buf );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -11,19 +11,18 @@ import java.security.Key;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.Signature;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.Arrays;
|
||||
import java.util.Base64;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import lombok.Getter;
|
||||
import net.md_5.bungee.jni.NativeCode;
|
||||
import net.md_5.bungee.jni.cipher.BungeeCipher;
|
||||
import net.md_5.bungee.jni.cipher.JavaCipher;
|
||||
@ -41,8 +40,6 @@ public class EncryptionUtil
|
||||
private static final Random random = new Random();
|
||||
private static final Base64.Encoder MIME_ENCODER = Base64.getMimeEncoder( 76, "\n".getBytes( StandardCharsets.UTF_8 ) );
|
||||
public static final KeyPair keys;
|
||||
@Getter
|
||||
private static final SecretKey secret = new SecretKeySpec( new byte[ 16 ], "AES" );
|
||||
public static final NativeCode<BungeeCipher> nativeFactory = new NativeCode<>( "native-cipher", JavaCipher::new, NativeCipher::new );
|
||||
private static final PublicKey MOJANG_KEY;
|
||||
|
||||
@ -111,17 +108,17 @@ public class EncryptionUtil
|
||||
return signature.verify( resp.getEncryptionData().getSignature() );
|
||||
} else
|
||||
{
|
||||
Cipher cipher = Cipher.getInstance( "RSA" );
|
||||
Cipher cipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" );
|
||||
cipher.init( Cipher.DECRYPT_MODE, keys.getPrivate() );
|
||||
byte[] decrypted = cipher.doFinal( resp.getVerifyToken() );
|
||||
|
||||
return Arrays.equals( request.getVerifyToken(), decrypted );
|
||||
return MessageDigest.isEqual( request.getVerifyToken(), decrypted );
|
||||
}
|
||||
}
|
||||
|
||||
public static SecretKey getSecret(EncryptionResponse resp, EncryptionRequest request) throws GeneralSecurityException
|
||||
{
|
||||
Cipher cipher = Cipher.getInstance( "RSA" );
|
||||
Cipher cipher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" );
|
||||
cipher.init( Cipher.DECRYPT_MODE, keys.getPrivate() );
|
||||
return new SecretKeySpec( cipher.doFinal( resp.getSharedSecret() ), "AES" );
|
||||
}
|
||||
@ -146,7 +143,7 @@ public class EncryptionUtil
|
||||
|
||||
public static byte[] encrypt(Key key, byte[] b) throws GeneralSecurityException
|
||||
{
|
||||
Cipher hasher = Cipher.getInstance( "RSA" );
|
||||
Cipher hasher = Cipher.getInstance( "RSA/ECB/PKCS1Padding" );
|
||||
hasher.init( Cipher.ENCRYPT_MODE, key );
|
||||
return hasher.doFinal( b );
|
||||
}
|
||||
|
@ -5,7 +5,6 @@ import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -32,7 +31,7 @@ public class ServerConnection implements Server
|
||||
private final boolean forgeServer = false;
|
||||
@Getter
|
||||
private final Queue<KeepAliveData> keepAlives = new ArrayDeque<>();
|
||||
private final Queue<DefinedPacket> packetQueue = new ConcurrentLinkedQueue<>();
|
||||
private final Queue<DefinedPacket> packetQueue = new ArrayDeque<>();
|
||||
|
||||
private final Unsafe unsafe = new Unsafe()
|
||||
{
|
||||
@ -45,23 +44,37 @@ public class ServerConnection implements Server
|
||||
|
||||
public void sendPacketQueued(DefinedPacket packet)
|
||||
{
|
||||
Protocol encodeProtocol = ch.getEncodeProtocol();
|
||||
if ( !encodeProtocol.TO_SERVER.hasPacket( packet.getClass(), ch.getEncodeVersion() ) )
|
||||
ch.scheduleIfNecessary( () ->
|
||||
{
|
||||
packetQueue.add( packet );
|
||||
} else
|
||||
{
|
||||
unsafe().sendPacket( packet );
|
||||
}
|
||||
if ( ch.isClosed() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
Protocol encodeProtocol = ch.getEncodeProtocol();
|
||||
if ( !encodeProtocol.TO_SERVER.hasPacket( packet.getClass(), ch.getEncodeVersion() ) )
|
||||
{
|
||||
packetQueue.add( packet );
|
||||
} else
|
||||
{
|
||||
unsafe().sendPacket( packet );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public void sendQueuedPackets()
|
||||
{
|
||||
DefinedPacket packet;
|
||||
while ( ( packet = packetQueue.poll() ) != null )
|
||||
ch.scheduleIfNecessary( () ->
|
||||
{
|
||||
unsafe().sendPacket( packet );
|
||||
}
|
||||
if ( ch.isClosed() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
DefinedPacket packet;
|
||||
while ( ( packet = packetQueue.poll() ) != null )
|
||||
{
|
||||
unsafe().sendPacket( packet );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -81,6 +94,7 @@ public class ServerConnection implements Server
|
||||
{
|
||||
Preconditions.checkArgument( reason.length == 0, "Server cannot have disconnect reason" );
|
||||
|
||||
isObsolete = true;
|
||||
ch.close();
|
||||
}
|
||||
|
||||
|
@ -137,6 +137,15 @@ public class ServerConnector extends PacketHandler
|
||||
public void disconnected(ChannelWrapper channel) throws Exception
|
||||
{
|
||||
user.getPendingConnects().remove( target );
|
||||
|
||||
if ( user.getServer() == null && !obsolete && user.getPendingConnects().isEmpty() && thisState == State.LOGIN_SUCCESS )
|
||||
{
|
||||
// this is called if we get disconnected but not have received any response after we send the handshake
|
||||
// in this case probably an exception was thrown because the handshake could not be read correctly
|
||||
// because of the extra ip forward data, also we skip the disconnect if another server is also in the
|
||||
// pendingConnects queue because we don't want to lose the player
|
||||
user.disconnect( "Unexpected disconnect during server login, did you forget to enable BungeeCord / IP forwarding on your server?" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -252,7 +261,7 @@ public class ServerConnector extends PacketHandler
|
||||
// Set tab list size, TODO: what shall we do about packet mutability
|
||||
Login modLogin = new Login( login.getEntityId(), login.isHardcore(), login.getGameMode(), login.getPreviousGameMode(), login.getWorldNames(), login.getDimensions(), login.getDimension(), login.getWorldName(), login.getSeed(), login.getDifficulty(),
|
||||
(byte) user.getPendingConnection().getListener().getTabListSize(), login.getLevelType(), login.getViewDistance(), login.getSimulationDistance(), login.isReducedDebugInfo(), login.isNormalRespawn(), login.isLimitedCrafting(), login.isDebug(), login.isFlat(), login.getDeathLocation(),
|
||||
login.getPortalCooldown(), login.isSecureProfile() );
|
||||
login.getPortalCooldown(), login.getSeaLevel(), login.isSecureProfile() );
|
||||
|
||||
user.unsafe().sendPacket( modLogin );
|
||||
|
||||
@ -270,7 +279,7 @@ public class ServerConnector extends PacketHandler
|
||||
user.getSentBossBars().clear();
|
||||
|
||||
user.unsafe().sendPacket( new Respawn( login.getDimension(), login.getWorldName(), login.getSeed(), login.getDifficulty(), login.getGameMode(), login.getPreviousGameMode(), login.getLevelType(), login.isDebug(), login.isFlat(), (byte) 0, login.getDeathLocation(),
|
||||
login.getPortalCooldown() ) );
|
||||
login.getPortalCooldown(), login.getSeaLevel() ) );
|
||||
} else
|
||||
{
|
||||
user.unsafe().sendPacket( BungeeCord.getInstance().registerChannels( user.getPendingConnection().getVersion() ) );
|
||||
@ -332,12 +341,12 @@ public class ServerConnector extends PacketHandler
|
||||
if ( login.getDimension() == user.getDimension() )
|
||||
{
|
||||
user.unsafe().sendPacket( new Respawn( (Integer) login.getDimension() >= 0 ? -1 : 0, login.getWorldName(), login.getSeed(), login.getDifficulty(), login.getGameMode(), login.getPreviousGameMode(), login.getLevelType(), login.isDebug(), login.isFlat(),
|
||||
(byte) 0, login.getDeathLocation(), login.getPortalCooldown() ) );
|
||||
(byte) 0, login.getDeathLocation(), login.getPortalCooldown(), login.getSeaLevel() ) );
|
||||
}
|
||||
|
||||
user.setServerEntityId( login.getEntityId() );
|
||||
user.unsafe().sendPacket( new Respawn( login.getDimension(), login.getWorldName(), login.getSeed(), login.getDifficulty(), login.getGameMode(), login.getPreviousGameMode(), login.getLevelType(), login.isDebug(), login.isFlat(),
|
||||
(byte) 0, login.getDeathLocation(), login.getPortalCooldown() ) );
|
||||
(byte) 0, login.getDeathLocation(), login.getPortalCooldown(), login.getSeaLevel() ) );
|
||||
if ( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_14 )
|
||||
{
|
||||
user.unsafe().sendPacket( new ViewDistance( login.getViewDistance() ) );
|
||||
@ -361,7 +370,10 @@ public class ServerConnector extends PacketHandler
|
||||
if ( user.getServer() != null )
|
||||
{
|
||||
// Begin config mode
|
||||
user.unsafe().sendPacket( new StartConfiguration() );
|
||||
if ( user.getCh().getEncodeProtocol() != Protocol.CONFIGURATION )
|
||||
{
|
||||
user.unsafe().sendPacket( new StartConfiguration() );
|
||||
}
|
||||
} else
|
||||
{
|
||||
LoginResult loginProfile = user.getPendingConnection().getLoginProfile();
|
||||
@ -373,7 +385,6 @@ public class ServerConnector extends PacketHandler
|
||||
// Remove from old servers
|
||||
if ( user.getServer() != null )
|
||||
{
|
||||
user.getServer().setObsolete( true );
|
||||
user.getServer().disconnect( "Quitting" );
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ import io.netty.channel.ChannelOption;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
@ -21,7 +22,6 @@ import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.logging.Level;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
@ -146,7 +146,7 @@ public final class UserConnection implements ProxiedPlayer
|
||||
@Setter
|
||||
private ForgeServerHandler forgeServerHandler;
|
||||
/*========================================================================*/
|
||||
private final Queue<DefinedPacket> packetQueue = new ConcurrentLinkedQueue<>();
|
||||
private final Queue<DefinedPacket> packetQueue = new ArrayDeque<>();
|
||||
private final Unsafe unsafe = new Unsafe()
|
||||
{
|
||||
@Override
|
||||
@ -186,23 +186,37 @@ public final class UserConnection implements ProxiedPlayer
|
||||
|
||||
public void sendPacketQueued(DefinedPacket packet)
|
||||
{
|
||||
Protocol encodeProtocol = ch.getEncodeProtocol();
|
||||
if ( !encodeProtocol.TO_CLIENT.hasPacket( packet.getClass(), getPendingConnection().getVersion() ) )
|
||||
ch.scheduleIfNecessary( () ->
|
||||
{
|
||||
packetQueue.add( packet );
|
||||
} else
|
||||
{
|
||||
unsafe().sendPacket( packet );
|
||||
}
|
||||
if ( ch.isClosed() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
Protocol encodeProtocol = ch.getEncodeProtocol();
|
||||
if ( !encodeProtocol.TO_CLIENT.hasPacket( packet.getClass(), getPendingConnection().getVersion() ) )
|
||||
{
|
||||
packetQueue.add( packet );
|
||||
} else
|
||||
{
|
||||
unsafe().sendPacket( packet );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
public void sendQueuedPackets()
|
||||
{
|
||||
DefinedPacket packet;
|
||||
while ( ( packet = packetQueue.poll() ) != null )
|
||||
ch.scheduleIfNecessary( () ->
|
||||
{
|
||||
unsafe().sendPacket( packet );
|
||||
}
|
||||
if ( ch.isClosed() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
DefinedPacket packet;
|
||||
while ( ( packet = packetQueue.poll() ) != null )
|
||||
{
|
||||
unsafe().sendPacket( packet );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@ -306,6 +320,11 @@ public final class UserConnection implements ProxiedPlayer
|
||||
{
|
||||
Preconditions.checkNotNull( request, "request" );
|
||||
|
||||
ch.getHandle().eventLoop().execute( () -> connect0( request ) );
|
||||
}
|
||||
|
||||
private void connect0(final ServerConnectRequest request)
|
||||
{
|
||||
final Callback<ServerConnectRequest.Result> callback = request.getCallback();
|
||||
ServerConnectEvent event = new ServerConnectEvent( this, request.getTarget(), request.getReason(), request );
|
||||
if ( bungee.getPluginManager().callEvent( event ).isCancelled() )
|
||||
@ -315,10 +334,6 @@ public final class UserConnection implements ProxiedPlayer
|
||||
callback.done( ServerConnectRequest.Result.EVENT_CANCEL, null );
|
||||
}
|
||||
|
||||
if ( getServer() == null && !ch.isClosing() )
|
||||
{
|
||||
throw new IllegalStateException( "Cancelled ServerConnectEvent with no server or disconnect." );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -439,7 +454,6 @@ public final class UserConnection implements ProxiedPlayer
|
||||
|
||||
if ( server != null )
|
||||
{
|
||||
server.setObsolete( true );
|
||||
server.disconnect( "Quitting" );
|
||||
}
|
||||
}
|
||||
|
@ -8,5 +8,5 @@ import net.md_5.bungee.jni.zlib.NativeZlib;
|
||||
public class CompressFactory
|
||||
{
|
||||
|
||||
public static final NativeCode<BungeeZlib> zlib = new NativeCode<>( "native-compress", JavaZlib::new, NativeZlib::new );
|
||||
public static final NativeCode<BungeeZlib> zlib = new NativeCode<>( "native-compress", JavaZlib::new, NativeZlib::new, true );
|
||||
}
|
||||
|
@ -2,18 +2,23 @@ package net.md_5.bungee.compress;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import java.util.List;
|
||||
import java.util.zip.Deflater;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.md_5.bungee.jni.zlib.BungeeZlib;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
|
||||
public class PacketCompressor extends MessageToByteEncoder<ByteBuf>
|
||||
public class PacketCompressor extends MessageToMessageEncoder<ByteBuf>
|
||||
{
|
||||
|
||||
@Getter
|
||||
private final BungeeZlib zlib = CompressFactory.zlib.newInstance();
|
||||
@Setter
|
||||
private int threshold = 256;
|
||||
@Setter
|
||||
private boolean compose = true;
|
||||
|
||||
@Override
|
||||
public void handlerAdded(ChannelHandlerContext ctx) throws Exception
|
||||
@ -28,18 +33,25 @@ public class PacketCompressor extends MessageToByteEncoder<ByteBuf>
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception
|
||||
protected void encode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception
|
||||
{
|
||||
int origSize = msg.readableBytes();
|
||||
if ( origSize < threshold )
|
||||
{
|
||||
DefinedPacket.writeVarInt( 0, out );
|
||||
out.writeBytes( msg );
|
||||
if ( compose )
|
||||
{
|
||||
// create a virtual buffer to avoid copying of data
|
||||
out.add( ctx.alloc().compositeDirectBuffer( 2 ).addComponents( true, ctx.alloc().directBuffer( 1 ).writeByte( 0 ), msg.retain() ) );
|
||||
} else
|
||||
{
|
||||
out.add( ctx.alloc().directBuffer( origSize + 1 ).writeByte( 0 ).writeBytes( msg ) );
|
||||
}
|
||||
} else
|
||||
{
|
||||
DefinedPacket.writeVarInt( origSize, out );
|
||||
|
||||
zlib.process( msg, out );
|
||||
ByteBuf buf = ctx.alloc().directBuffer( BungeeZlib.OUTPUT_BUFFER_SIZE );
|
||||
DefinedPacket.writeVarInt( origSize, buf );
|
||||
zlib.process( msg, buf );
|
||||
out.add( buf );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ public class YamlConfig implements ConfigurationAdapter
|
||||
} ) );
|
||||
set( "permissions.admin", Arrays.asList( new String[]
|
||||
{
|
||||
"bungeecord.command.alert", "bungeecord.command.end", "bungeecord.command.ip", "bungeecord.command.reload", "bungeecord.command.kick"
|
||||
"bungeecord.command.alert", "bungeecord.command.end", "bungeecord.command.ip", "bungeecord.command.reload", "bungeecord.command.kick", "bungeecord.command.send", "bungeecord.command.find"
|
||||
} ) );
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,10 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.MessageDigest;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@ -66,6 +68,8 @@ import net.md_5.bungee.protocol.packet.Handshake;
|
||||
import net.md_5.bungee.protocol.packet.Kick;
|
||||
import net.md_5.bungee.protocol.packet.LegacyHandshake;
|
||||
import net.md_5.bungee.protocol.packet.LegacyPing;
|
||||
import net.md_5.bungee.protocol.packet.LoginAcknowledged;
|
||||
import net.md_5.bungee.protocol.packet.LoginPayloadRequest;
|
||||
import net.md_5.bungee.protocol.packet.LoginPayloadResponse;
|
||||
import net.md_5.bungee.protocol.packet.LoginRequest;
|
||||
import net.md_5.bungee.protocol.packet.LoginSuccess;
|
||||
@ -95,6 +99,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
@Getter
|
||||
private final Set<String> registeredChannels = new HashSet<>();
|
||||
private State thisState = State.HANDSHAKE;
|
||||
private int loginPayloadId;
|
||||
private final Map<Integer, CompletableFuture<byte[]>> requestedLoginPayloads = new HashMap<>();
|
||||
private final Queue<CookieFuture> requestedCookies = new LinkedList<>();
|
||||
|
||||
@Data
|
||||
@ -190,6 +196,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
@Override
|
||||
public void handle(LegacyHandshake legacyHandshake) throws Exception
|
||||
{
|
||||
Preconditions.checkState( !this.legacy, "Not expecting LegacyHandshake" );
|
||||
this.legacy = true;
|
||||
ch.close( bungee.getTranslation( "outdated_client", bungee.getGameVersion() ) );
|
||||
}
|
||||
@ -197,6 +204,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
@Override
|
||||
public void handle(LegacyPing ping) throws Exception
|
||||
{
|
||||
Preconditions.checkState( !this.legacy, "Not expecting LegacyPing" );
|
||||
this.legacy = true;
|
||||
final boolean v1_5 = ping.isV1_5();
|
||||
|
||||
@ -336,7 +344,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
@Override
|
||||
public void handle(Handshake handshake) throws Exception
|
||||
{
|
||||
Preconditions.checkState( thisState == State.HANDSHAKE, "Not expecting HANDSHAKE" );
|
||||
Preconditions.checkState( thisState == State.HANDSHAKE && !this.legacy, "Not expecting HANDSHAKE" );
|
||||
this.handshake = handshake;
|
||||
ch.setVersion( handshake.getProtocolVersion() );
|
||||
ch.getHandle().pipeline().remove( PipelineUtils.LEGACY_KICKER );
|
||||
@ -414,7 +422,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
@Override
|
||||
public void handle(LoginRequest loginRequest) throws Exception
|
||||
{
|
||||
Preconditions.checkState( thisState == State.USERNAME, "Not expecting USERNAME" );
|
||||
Preconditions.checkState( thisState == State.USERNAME && this.loginRequest == null, "Not expecting USERNAME" );
|
||||
|
||||
if ( !AllowedCharacters.isValidName( loginRequest.getData(), onlineMode ) )
|
||||
{
|
||||
@ -507,6 +515,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
ch.addBefore( PipelineUtils.FRAME_DECODER, PipelineUtils.DECRYPT_HANDLER, new CipherDecoder( decrypt ) );
|
||||
BungeeCipher encrypt = EncryptionUtil.getCipher( true, sharedKey );
|
||||
ch.addBefore( PipelineUtils.FRAME_PREPENDER, PipelineUtils.ENCRYPT_HANDLER, new CipherEncoder( encrypt ) );
|
||||
// disable use of composite buffers if we use natives
|
||||
ch.updateComposite();
|
||||
|
||||
String encName = URLEncoder.encode( InitialHandler.this.getName(), "UTF-8" );
|
||||
|
||||
@ -580,34 +590,24 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
}
|
||||
}
|
||||
|
||||
ProxiedPlayer oldName = bungee.getPlayer( getName() );
|
||||
if ( oldName != null )
|
||||
{
|
||||
// TODO See #1218
|
||||
disconnect( bungee.getTranslation( "already_connected_proxy" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( isOnlineMode() )
|
||||
{
|
||||
// Check for multiple connections
|
||||
// We have to check for the old name first
|
||||
ProxiedPlayer oldName = bungee.getPlayer( getName() );
|
||||
if ( oldName != null )
|
||||
{
|
||||
// TODO See #1218
|
||||
disconnect( bungee.getTranslation( "already_connected_proxy" ) );
|
||||
}
|
||||
// And then also for their old UUID
|
||||
ProxiedPlayer oldID = bungee.getPlayer( getUniqueId() );
|
||||
if ( oldID != null )
|
||||
{
|
||||
// TODO See #1218
|
||||
disconnect( bungee.getTranslation( "already_connected_proxy" ) );
|
||||
}
|
||||
} else
|
||||
{
|
||||
// In offline mode the existing user stays and we kick the new one
|
||||
ProxiedPlayer oldName = bungee.getPlayer( getName() );
|
||||
if ( oldName != null )
|
||||
{
|
||||
// TODO See #1218
|
||||
disconnect( bungee.getTranslation( "already_connected_proxy" ) );
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Callback<LoginEvent> complete = new Callback<LoginEvent>()
|
||||
@ -697,7 +697,20 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
@Override
|
||||
public void handle(LoginPayloadResponse response) throws Exception
|
||||
{
|
||||
disconnect( "Unexpected custom LoginPayloadResponse" );
|
||||
CompletableFuture<byte[]> future;
|
||||
synchronized ( requestedLoginPayloads )
|
||||
{
|
||||
future = requestedLoginPayloads.remove( response.getId() );
|
||||
}
|
||||
Preconditions.checkState( future != null, "Unexpected custom LoginPayloadResponse" );
|
||||
future.complete( response.getData() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(LoginAcknowledged loginAcknowledged) throws Exception
|
||||
{
|
||||
// this packet should only be sent after the login success (it should be handled in the UpstreamBridge)
|
||||
disconnect( "Unexpected LoginAcknowledged" );
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -726,6 +739,10 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
|
||||
throw CancelSendSignal.INSTANCE;
|
||||
}
|
||||
|
||||
// if there is no userCon we can't have a connection to a backend server that could have requested this cookie
|
||||
// which means that this cookie is invalid as the proxy also has not requested it
|
||||
Preconditions.checkState( userCon != null, "not requested cookie received" );
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -882,4 +899,22 @@ public class InitialHandler extends PacketHandler implements PendingConnection
|
||||
|
||||
return future;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<byte[]> sendData(String channel, byte[] data)
|
||||
{
|
||||
Preconditions.checkState( getVersion() >= ProtocolConstants.MINECRAFT_1_13, "LoginPayloads are only supported in 1.13 and above" );
|
||||
Preconditions.checkState( ch.getEncodeProtocol() == Protocol.LOGIN, "LoginPayloads are only supported in the login phase" );
|
||||
|
||||
CompletableFuture<byte[]> future = new CompletableFuture<>();
|
||||
final int id;
|
||||
synchronized ( requestedLoginPayloads )
|
||||
{
|
||||
// thread safe loginPayloadId
|
||||
id = loginPayloadId++;
|
||||
requestedLoginPayloads.put( id, future );
|
||||
}
|
||||
unsafe.sendPacket( new LoginPayloadRequest( id, channel, data ) );
|
||||
return future;
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ import net.md_5.bungee.protocol.packet.CookieResponse;
|
||||
import net.md_5.bungee.protocol.packet.FinishConfiguration;
|
||||
import net.md_5.bungee.protocol.packet.KeepAlive;
|
||||
import net.md_5.bungee.protocol.packet.LoginAcknowledged;
|
||||
import net.md_5.bungee.protocol.packet.LoginPayloadResponse;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
||||
import net.md_5.bungee.protocol.packet.PlayerListItemRemove;
|
||||
import net.md_5.bungee.protocol.packet.PluginMessage;
|
||||
@ -101,7 +102,8 @@ public class UpstreamBridge extends PacketHandler
|
||||
{
|
||||
if ( player.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_19_3 )
|
||||
{
|
||||
player.unsafe().sendPacket( newPacket );
|
||||
// need to queue, because players in config state could receive it
|
||||
( (UserConnection) player ).sendPacketQueued( newPacket );
|
||||
} else
|
||||
{
|
||||
player.unsafe().sendPacket( oldPacket );
|
||||
@ -377,6 +379,12 @@ public class UpstreamBridge extends PacketHandler
|
||||
con.getPendingConnection().handle( cookieResponse );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(LoginPayloadResponse loginPayloadResponse) throws Exception
|
||||
{
|
||||
con.getPendingConnection().handle( loginPayloadResponse );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
@ -89,6 +89,10 @@ public abstract class EntityMap
|
||||
case ProtocolConstants.MINECRAFT_1_20_5:
|
||||
case ProtocolConstants.MINECRAFT_1_21:
|
||||
return EntityMap_1_16_2.INSTANCE_1_20_5;
|
||||
case ProtocolConstants.MINECRAFT_1_21_2:
|
||||
return EntityMap_1_16_2.INSTANCE_1_21_2;
|
||||
case ProtocolConstants.MINECRAFT_1_21_4:
|
||||
return EntityMap_1_16_2.INSTANCE_1_21_4;
|
||||
}
|
||||
throw new RuntimeException( "Version " + version + " has no entity map" );
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ class EntityMap_1_16_2 extends EntityMap
|
||||
static final EntityMap_1_16_2 INSTANCE_1_20_2 = new EntityMap_1_16_2( -1, 0x33 );
|
||||
static final EntityMap_1_16_2 INSTANCE_1_20_3 = new EntityMap_1_16_2( -1, 0x34 );
|
||||
static final EntityMap_1_16_2 INSTANCE_1_20_5 = new EntityMap_1_16_2( -1, 0x37 );
|
||||
static final EntityMap_1_16_2 INSTANCE_1_21_2 = new EntityMap_1_16_2( -1, 0x39 );
|
||||
static final EntityMap_1_16_2 INSTANCE_1_21_4 = new EntityMap_1_16_2( -1, 0x3B );
|
||||
//
|
||||
private final int spawnPlayerId;
|
||||
private final int spectateId;
|
||||
@ -31,6 +33,10 @@ class EntityMap_1_16_2 extends EntityMap
|
||||
@SuppressFBWarnings("DLS_DEAD_LOCAL_STORE")
|
||||
public void rewriteClientbound(ByteBuf packet, int oldId, int newId, int protocolVersion)
|
||||
{
|
||||
if ( spawnPlayerId == -1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Special cases
|
||||
int readerIndex = packet.readerIndex();
|
||||
int packetId = DefinedPacket.readVarInt( packet );
|
||||
|
@ -7,6 +7,7 @@ import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import lombok.Data;
|
||||
import net.md_5.bungee.Util;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
|
||||
@Data
|
||||
public class JenkinsModuleSource implements ModuleSource
|
||||
@ -15,7 +16,7 @@ public class JenkinsModuleSource implements ModuleSource
|
||||
@Override
|
||||
public void retrieve(ModuleSpec module, ModuleVersion version)
|
||||
{
|
||||
System.out.println( "Attempting to Jenkins download module " + module.getName() + " v" + version.getBuild() );
|
||||
ProxyServer.getInstance().getLogger().info( "Attempting to Jenkins download module " + module.getName() + " v" + version.getBuild() );
|
||||
try
|
||||
{
|
||||
URL website = new URL( "https://ci.md-5.net/job/BungeeCord/" + version.getBuild() + "/artifact/module/" + module.getName().replace( '_', '-' ) + "/target/" + module.getName() + ".jar" );
|
||||
@ -25,10 +26,10 @@ public class JenkinsModuleSource implements ModuleSource
|
||||
con.setReadTimeout( 15000 );
|
||||
|
||||
Files.write( ByteStreams.toByteArray( con.getInputStream() ), module.getFile() );
|
||||
System.out.println( "Download complete" );
|
||||
ProxyServer.getInstance().getLogger().info( "Download complete" );
|
||||
} catch ( IOException ex )
|
||||
{
|
||||
System.out.println( "Failed to download: " + Util.exception( ex ) );
|
||||
ProxyServer.getInstance().getLogger().warning( "Failed to download: " + Util.exception( ex ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class ModuleManager
|
||||
ModuleVersion bungeeVersion = ModuleVersion.parse( proxy.getVersion() );
|
||||
if ( bungeeVersion == null )
|
||||
{
|
||||
System.out.println( "Couldn't detect bungee version. Custom build?" );
|
||||
proxy.getLogger().warning( "Couldn't detect bungee version. Custom build?" );
|
||||
return;
|
||||
}
|
||||
|
||||
@ -105,19 +105,19 @@ public class ModuleManager
|
||||
ModuleSource source = knownSources.get( uri.getScheme() );
|
||||
if ( source == null )
|
||||
{
|
||||
System.out.println( "Unknown module source: " + s );
|
||||
proxy.getLogger().warning( "Unknown module source: " + s );
|
||||
continue;
|
||||
}
|
||||
String name = uri.getAuthority();
|
||||
if ( name == null )
|
||||
{
|
||||
System.out.println( "Unknown module host: " + s );
|
||||
proxy.getLogger().warning( "Unknown module host: " + s );
|
||||
continue;
|
||||
}
|
||||
|
||||
ModuleSpec spec = new ModuleSpec( name, new File( moduleDirectory, name + ".jar" ), source );
|
||||
modules.add( spec );
|
||||
System.out.println( "Discovered module: " + spec );
|
||||
proxy.getLogger().info( "Discovered module: " + spec );
|
||||
}
|
||||
|
||||
for ( ModuleSpec module : modules )
|
||||
@ -126,7 +126,7 @@ public class ModuleManager
|
||||
|
||||
if ( !bungeeVersion.equals( moduleVersion ) )
|
||||
{
|
||||
System.out.println( "Attempting to update plugin from " + moduleVersion + " to " + bungeeVersion );
|
||||
proxy.getLogger().info( "Attempting to update plugin from " + moduleVersion + " to " + bungeeVersion );
|
||||
module.getProvider().retrieve( module, bungeeVersion );
|
||||
}
|
||||
}
|
||||
|
@ -7,15 +7,19 @@ import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.compress.PacketCompressor;
|
||||
import net.md_5.bungee.compress.PacketDecompressor;
|
||||
import net.md_5.bungee.netty.cipher.CipherEncoder;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.MinecraftDecoder;
|
||||
import net.md_5.bungee.protocol.MinecraftEncoder;
|
||||
import net.md_5.bungee.protocol.PacketWrapper;
|
||||
import net.md_5.bungee.protocol.Protocol;
|
||||
import net.md_5.bungee.protocol.Varint21LengthFieldPrepender;
|
||||
import net.md_5.bungee.protocol.packet.Kick;
|
||||
|
||||
public class ChannelWrapper
|
||||
@ -38,23 +42,22 @@ public class ChannelWrapper
|
||||
|
||||
public Protocol getDecodeProtocol()
|
||||
{
|
||||
return ch.pipeline().get( MinecraftDecoder.class ).getProtocol();
|
||||
return getMinecraftDecoder().getProtocol();
|
||||
}
|
||||
|
||||
public void setDecodeProtocol(Protocol protocol)
|
||||
{
|
||||
ch.pipeline().get( MinecraftDecoder.class ).setProtocol( protocol );
|
||||
getMinecraftDecoder().setProtocol( protocol );
|
||||
}
|
||||
|
||||
public Protocol getEncodeProtocol()
|
||||
{
|
||||
return ch.pipeline().get( MinecraftEncoder.class ).getProtocol();
|
||||
|
||||
return getMinecraftEncoder().getProtocol();
|
||||
}
|
||||
|
||||
public void setEncodeProtocol(Protocol protocol)
|
||||
{
|
||||
ch.pipeline().get( MinecraftEncoder.class ).setProtocol( protocol );
|
||||
getMinecraftEncoder().setProtocol( protocol );
|
||||
}
|
||||
|
||||
public void setProtocol(Protocol protocol)
|
||||
@ -65,13 +68,23 @@ public class ChannelWrapper
|
||||
|
||||
public void setVersion(int protocol)
|
||||
{
|
||||
ch.pipeline().get( MinecraftDecoder.class ).setProtocolVersion( protocol );
|
||||
ch.pipeline().get( MinecraftEncoder.class ).setProtocolVersion( protocol );
|
||||
getMinecraftDecoder().setProtocolVersion( protocol );
|
||||
getMinecraftEncoder().setProtocolVersion( protocol );
|
||||
}
|
||||
|
||||
public MinecraftDecoder getMinecraftDecoder()
|
||||
{
|
||||
return ch.pipeline().get( MinecraftDecoder.class );
|
||||
}
|
||||
|
||||
public MinecraftEncoder getMinecraftEncoder()
|
||||
{
|
||||
return ch.pipeline().get( MinecraftEncoder.class );
|
||||
}
|
||||
|
||||
public int getEncodeVersion()
|
||||
{
|
||||
return ch.pipeline().get( MinecraftEncoder.class ).getProtocolVersion();
|
||||
return getMinecraftEncoder().getProtocolVersion();
|
||||
}
|
||||
|
||||
public void write(Object packet)
|
||||
@ -187,5 +200,47 @@ public class ChannelWrapper
|
||||
{
|
||||
ch.pipeline().remove( "decompress" );
|
||||
}
|
||||
// disable use of composite buffers if we use natives
|
||||
updateComposite();
|
||||
}
|
||||
|
||||
/*
|
||||
* Should be called on encryption add and on compressor add or remove
|
||||
*/
|
||||
public void updateComposite()
|
||||
{
|
||||
CipherEncoder cipherEncoder = ch.pipeline().get( CipherEncoder.class );
|
||||
PacketCompressor packetCompressor = ch.pipeline().get( PacketCompressor.class );
|
||||
Varint21LengthFieldPrepender prepender = ch.pipeline().get( Varint21LengthFieldPrepender.class );
|
||||
boolean compressorCompose = cipherEncoder == null || cipherEncoder.getCipher().allowComposite();
|
||||
boolean prependerCompose = compressorCompose && ( packetCompressor == null || packetCompressor.getZlib().allowComposite() );
|
||||
|
||||
if ( prepender != null )
|
||||
{
|
||||
ProxyServer.getInstance().getLogger().log( Level.FINE, "set prepender compose to {0} for {1}", new Object[]
|
||||
{
|
||||
prependerCompose, ch
|
||||
} );
|
||||
prepender.setCompose( prependerCompose );
|
||||
}
|
||||
if ( packetCompressor != null )
|
||||
{
|
||||
ProxyServer.getInstance().getLogger().log( Level.FINE, "set packetCompressor compose to {0} for {1}", new Object[]
|
||||
{
|
||||
compressorCompose, ch
|
||||
} );
|
||||
packetCompressor.setCompose( compressorCompose );
|
||||
}
|
||||
}
|
||||
|
||||
public void scheduleIfNecessary(Runnable task)
|
||||
{
|
||||
if ( ch.eventLoop().inEventLoop() )
|
||||
{
|
||||
task.run();
|
||||
return;
|
||||
}
|
||||
|
||||
ch.eventLoop().execute( task );
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +93,6 @@ public class PipelineUtils
|
||||
public static final Base BASE = new Base( false );
|
||||
public static final Base BASE_SERVERSIDE = new Base( true );
|
||||
private static final KickStringWriter legacyKicker = new KickStringWriter();
|
||||
private static final Varint21LengthFieldPrepender framePrepender = new Varint21LengthFieldPrepender();
|
||||
private static final Varint21LengthFieldExtraBufPrepender serverFramePrepender = new Varint21LengthFieldExtraBufPrepender();
|
||||
public static final String TIMEOUT_HANDLER = "timeout";
|
||||
public static final String PACKET_DECODER = "packet-decoder";
|
||||
@ -202,7 +201,7 @@ public class PipelineUtils
|
||||
ch.pipeline().addLast( TIMEOUT_HANDLER, new ReadTimeoutHandler( BungeeCord.getInstance().config.getTimeout(), TimeUnit.MILLISECONDS ) );
|
||||
// No encryption bungee -> server, therefore use extra buffer to avoid copying everything for length prepending
|
||||
// Not used bungee -> client as header would need to be encrypted separately through expensive JNI call
|
||||
ch.pipeline().addLast( FRAME_PREPENDER, ( toServer ) ? serverFramePrepender : framePrepender );
|
||||
ch.pipeline().addLast( FRAME_PREPENDER, ( toServer ) ? serverFramePrepender : new Varint21LengthFieldPrepender() );
|
||||
|
||||
ch.pipeline().addLast( BOSS_HANDLER, new HandlerBoss() );
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package net.md_5.bungee.netty.cipher;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.md_5.bungee.jni.cipher.BungeeCipher;
|
||||
|
||||
@ -10,6 +11,7 @@ import net.md_5.bungee.jni.cipher.BungeeCipher;
|
||||
public class CipherEncoder extends MessageToByteEncoder<ByteBuf>
|
||||
{
|
||||
|
||||
@Getter
|
||||
private final BungeeCipher cipher;
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user