Compare commits

..

33 Commits

Author SHA1 Message Date
ba212a8a61 new event TabCompleteRequestEvent and deprecate TabCompleteEvent 2023-09-22 00:03:48 +02:00
bf44147805 Add CommandsDeclareEvent to declare commands with brigadier API 2023-09-22 00:03:42 +02:00
e47394e10d Server branding now includes the backend server name 2023-09-21 23:55:32 +02:00
3ba71310b8 Multi-session with same Minecraft account with specific permission
Players with permission bungeecord.multiple_connect can have multiple connections with the same Minecraft account.
The UUID and player name is altered to avoid collision with other player:
UUID : xxxxxxxx-xxxx-VIxx-xxxx-xxxxxxxxxxxx
- The UUID version (V above) is now the provided version + 8 (for online player, it is 4, so it becomes C).
- The I digit will follow the index of the duplicated player : first duplicated player is 1, second one is 2.
- The name of the player will be the real player name, followed by the character "." (dot) followed by the duplication index.

Bedrock accounts connected using the Floodgate plugin will not be able to connect multiple times due to the risk of xUID collision.
2023-09-21 23:55:32 +02:00
fe2baa08b5 Change projet configuration and POM for Pandacube 2023-09-21 23:55:32 +02:00
fb1c808d0e Remove modules and startup delay
We don’t need them for Pandacube
2023-09-21 23:55:29 +02:00
md_5
5a1e342e0d
Minecraft 1.20.2 support 2023-09-22 02:40:00 +10:00
md_5
d9bbdc3281
Add Java 21 compilation support 2023-09-20 18:06:33 +10:00
Parker Hawke
cfe00fa47c
#3490: Add ComponentBuilder#build() and ComponentSerializer#deserialize()
Components traditionally use the extra data to represent components as a single BaseComponent object. While BaseComponent typically mirrors this behaviour, somewhere along the development of BungeeChat this practice was made unclear. Because ComponentBuilder#create() returns an array of BaseComponents, it has sort of been silently accepted that all components should be represented as arrays, which is incorrect. This heavily influenced the direction of Spigot's component API (with additions such as CommandSender#sendMessage(BaseComponent[])) which emphasizes this misconception of "all components are arrays".

Adding new methods to ComponentBuilder and ComponentSerializer should steer use of the BungeeChat API to be more oriented towards single component instances, not arrays.
2023-09-19 07:14:18 +10:00
md_5
d68ebd1eaf
Minecraft 1.20.2-rc1 support 2023-09-17 08:10:42 +10:00
dependabot[bot]
a7cd79eb41
#3516: Bump org.apache.maven.plugins:maven-javadoc-plugin from 3.5.0 to 3.6.0
Bumps [org.apache.maven.plugins:maven-javadoc-plugin](https://github.com/apache/maven-javadoc-plugin) from 3.5.0 to 3.6.0.
- [Release notes](https://github.com/apache/maven-javadoc-plugin/releases)
- [Commits](https://github.com/apache/maven-javadoc-plugin/compare/maven-javadoc-plugin-3.5.0...maven-javadoc-plugin-3.6.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-javadoc-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-16 10:22:07 +10:00
Outfluencer
9e83ee6f0c
#3508: Use same compression threshold checks as Vanilla 2023-09-12 20:29:01 +10:00
dependabot[bot]
7c81d91740
#3513: Bump org.apache.maven.plugins:maven-enforcer-plugin from 3.4.0 to 3.4.1
Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.4.0 to 3.4.1.
- [Release notes](https://github.com/apache/maven-enforcer/releases)
- [Commits](https://github.com/apache/maven-enforcer/compare/enforcer-3.4.0...enforcer-3.4.1)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-enforcer-plugin
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-12 20:28:08 +10:00
md_5
5b126b7f4d
Fix javadoc plugin version in non-dist builds 2023-09-10 11:41:56 +10:00
dependabot[bot]
9fe7d21f4b
#3510: Bump actions/checkout from 3 to 4
Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-08 19:33:56 +10:00
dependabot[bot]
94ea0271ba
#3505: Bump io.netty:netty-bom from 4.1.96.Final to 4.1.97.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.96.Final to 4.1.97.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.96.Final...netty-4.1.97.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-24 20:07:19 +10:00
dependabot[bot]
3af672d2f2
#3504: Bump org.apache.maven.plugins:maven-enforcer-plugin from 3.3.0 to 3.4.0
Bumps [org.apache.maven.plugins:maven-enforcer-plugin](https://github.com/apache/maven-enforcer) from 3.3.0 to 3.4.0.
- [Release notes](https://github.com/apache/maven-enforcer/releases)
- [Commits](https://github.com/apache/maven-enforcer/compare/enforcer-3.3.0...enforcer-3.4.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-enforcer-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-24 20:07:00 +10:00
md_5
0dd7b98428
Bump version to 1.20-R0.2-SNAPSHOT 2023-08-07 08:01:47 +10:00
md_5
a793692a2c
Release 1.20-R0.1 2023-08-07 07:56:00 +10:00
dependabot[bot]
23fb838227
#3493: Bump io.netty:netty-bom from 4.1.95.Final to 4.1.96.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.95.Final to 4.1.96.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.95.Final...netty-4.1.96.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-02 20:01:19 +10:00
dependabot[bot]
2d6d89d668
#3492: Bump io.netty:netty-bom from 4.1.94.Final to 4.1.95.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.94.Final to 4.1.95.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.94.Final...netty-4.1.95.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-24 18:46:54 +10:00
BoomEaro
0199cb90ff
#3489: Add command string length limit when decoding ClientCommand 2023-07-15 10:44:41 +10:00
dependabot[bot]
958cef5084
#3488: Bump scriptus from 0.4.1 to 0.5.0
Bumps [scriptus](https://github.com/SpigotMC/Scriptus) from 0.4.1 to 0.5.0.
- [Commits](https://github.com/SpigotMC/Scriptus/commits)

---
updated-dependencies:
- dependency-name: net.md-5:scriptus
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-15 10:29:22 +10:00
Outfluencer
9f5ace9025
#3418: Add tab completion for bungee command names in pre-1.13 versions 2023-07-05 19:58:23 +10:00
dependabot[bot]
3a6e2631bf
#3479: Bump netty-bom from 4.1.93.Final to 4.1.94.Final
Bumps [netty-bom](https://github.com/netty/netty) from 4.1.93.Final to 4.1.94.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.93.Final...netty-4.1.94.Final)

---
updated-dependencies:
- dependency-name: io.netty:netty-bom
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-03 18:08:33 +10:00
md_5
c7adcf9fdf
Disable maven enforcer for now 2023-06-18 20:55:47 +10:00
md_5
da3616e636
SPIGOT-7400: Downgrade maven-resolver due to issues resolving certain depends 2023-06-18 20:37:33 +10:00
dependabot[bot]
b371fe67a5
#3478: Bump maven-shade-plugin from 3.4.1 to 3.5.0
Bumps [maven-shade-plugin](https://github.com/apache/maven-shade-plugin) from 3.4.1 to 3.5.0.
- [Release notes](https://github.com/apache/maven-shade-plugin/releases)
- [Commits](https://github.com/apache/maven-shade-plugin/compare/maven-shade-plugin-3.4.1...maven-shade-plugin-3.5.0)

---
updated-dependencies:
- dependency-name: org.apache.maven.plugins:maven-shade-plugin
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-17 07:59:06 +10:00
Outfluencer
6324c7d527
#3401: Only synchronize necessary parts of the BungeeServerInfo#sendData method 2023-06-10 18:06:37 +10:00
Outfluencer
6263fe283b
#3426: Made find command output hover and clickable 2023-06-10 18:03:02 +10:00
Ruan
9a7617f9b8
#3475: Add KickPlayerRaw channel 2023-06-10 18:01:01 +10:00
Janmm14
9a71358dfa
#3439: Add GetPlayerServer bungee plugin message subchannel 2023-06-10 18:00:33 +10:00
Outfluencer
a96a2e80a1
#3437: Remove unused enum in ServerConnector and add color to exception message 2023-06-10 17:58:14 +10:00
42 changed files with 1093 additions and 246 deletions

View File

@ -13,9 +13,10 @@ updates:
- dependency-name: "com.puppycrawl.tools:checkstyle"
# Newer versions have issues, see #1909 and #2050
- dependency-name: "jline:jline"
# Needs to be synchronised with maven-resolver-provider dependencies
# Later versions of these Maven dependencies are incompatible and require careful management - see SPIGOT-7400
- dependency-name: "org.apache.maven.resolver:maven-resolver-connector-basic"
- dependency-name: "org.apache.maven.resolver:maven-resolver-transport-http"
- dependency-name: "org.apache.maven:maven-resolver-provider"
# Used with maven-resolver dependencies; 2.0 update breaks other providers
- dependency-name: "org.slf4j:slf4j-api"
update-types: ["version-update:semver-major"]

View File

@ -9,12 +9,12 @@ jobs:
strategy:
fail-fast: false
matrix:
java: [8, 11, 17]
java: [8, 11, 17, 21]
name: Java ${{ matrix.java }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/setup-java@v3
with:
distribution: zulu

View File

@ -6,12 +6,12 @@
<parent>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>bungeecord-api</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-API</name>
@ -50,28 +50,28 @@
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-resolver-provider</artifactId>
<version>3.9.2</version>
<version>3.8.5</version>
<!-- not part of the API proper -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-connector-basic</artifactId>
<version>1.9.10</version>
<version>1.7.3</version>
<!-- not part of the API proper -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-transport-http</artifactId>
<version>1.9.10</version>
<version>1.7.3</version>
<!-- not part of the API proper -->
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.0</version>
<version>2.2</version>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@ -6,12 +6,12 @@
<parent>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>bungeecord-bootstrap</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Bootstrap</name>
@ -52,7 +52,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<version>3.5.0</version>
<executions>
<execution>
<phase>package</phase>

View File

@ -6,12 +6,12 @@
<parent>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>bungeecord-chat</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Chat</name>
@ -21,7 +21,7 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version>
<version>2.10.1</version>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@ -454,9 +454,32 @@ public final class ComponentBuilder
return this;
}
/**
* Returns the component built by this builder. If this builder is
* empty, an empty text component will be returned.
*
* @return the component
*/
public BaseComponent build()
{
TextComponent base = new TextComponent();
if ( !parts.isEmpty() )
{
List<BaseComponent> cloned = new ArrayList<>( parts );
cloned.replaceAll( BaseComponent::duplicate );
base.setExtra( cloned );
}
return base;
}
/**
* Returns the components needed to display the message created by this
* builder.git
* <p>
* <strong>NOTE:</strong> {@link #build()} is preferred as it will
* consolidate all components into a single BaseComponent with extra
* contents as opposed to an array of components which is non-standard
* and may result in unexpected behavior.
*
* @return the created components
*/

View File

@ -23,6 +23,12 @@ public class Text extends Content
this.value = value;
}
public Text(BaseComponent value)
{
// For legacy serialization reasons, this has to be an array of components
this( new BaseComponent[]{value} );
}
public Text(String value)
{
this.value = value;

View File

@ -27,7 +27,6 @@ import net.md_5.bungee.api.chat.hover.content.TextSerializer;
public class ComponentSerializer implements JsonDeserializer<BaseComponent>
{
private static final JsonParser JSON_PARSER = new JsonParser();
private static final Gson gson = new GsonBuilder().
registerTypeAdapter( BaseComponent.class, new ComponentSerializer() ).
registerTypeAdapter( TextComponent.class, new TextComponentSerializer() ).
@ -43,9 +42,25 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
public static final ThreadLocal<Set<BaseComponent>> serializedComponents = new ThreadLocal<Set<BaseComponent>>();
/**
* Parse a JSON-compliant String as an array of base components. The input
* can be one of either an array of components, or a single component object.
* If the input is an array, each component will be parsed individually and
* returned in the order that they were parsed. If the input is a single
* component object, a single-valued array with the component will be returned.
* <p>
* <strong>NOTE:</strong> {@link #deserialize(String)} is preferred as it will
* parse only one component as opposed to an array of components which is non-
* standard behavior. This method is still appropriate for parsing multiple
* components at once, although such use case is rarely (if at all) exhibited
* in vanilla Minecraft.
*
* @param json the component json to parse
* @return an array of all parsed components
*/
public static BaseComponent[] parse(String json)
{
JsonElement jsonElement = JSON_PARSER.parse( json );
JsonElement jsonElement = JsonParser.parseString( json );
if ( jsonElement.isJsonArray() )
{
@ -59,6 +74,26 @@ public class ComponentSerializer implements JsonDeserializer<BaseComponent>
}
}
/**
* Deserialize a JSON-compliant String as a single component. The input is
* expected to be a JSON object that represents only one component.
*
* @param json the component json to parse
* @return the deserialized component
* @throws IllegalArgumentException if anything other than a JSON object is
* passed as input
*/
public static BaseComponent deserialize(String json)
{
JsonElement jsonElement = JsonParser.parseString( json );
if ( !jsonElement.isJsonObject() )
{
throw new IllegalArgumentException( "Malformatted JSON. Expected object, got array for input \"" + json + "\"." );
}
return gson.fromJson( jsonElement, BaseComponent.class );
}
public static String toString(Object object)
{
return gson.toJson( object );

View File

@ -1,6 +1,11 @@
package net.md_5.bungee.api.chat;
import java.awt.Color;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.ObjIntConsumer;
import java.util.function.Supplier;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.hover.content.Item;
import net.md_5.bungee.api.chat.hover.content.Text;
@ -18,11 +23,25 @@ public class ComponentsTest
Assert.assertEquals( TextComponent.toLegacyText( parsed ), TextComponent.toLegacyText( components ) );
}
public static void testDissembleReassemble(String json)
public static void testDissembleReassemble(BaseComponent component)
{
String json = ComponentSerializer.toString( component );
BaseComponent[] parsed = ComponentSerializer.parse( json );
Assert.assertEquals( TextComponent.toLegacyText( parsed ), TextComponent.toLegacyText( component ) );
}
public static void testAssembleDissemble(String json, boolean modern)
{
if ( modern )
{
BaseComponent deserialized = ComponentSerializer.deserialize( json );
Assert.assertEquals( json, ComponentSerializer.toString( deserialized ) );
} else
{
BaseComponent[] parsed = ComponentSerializer.parse( json );
Assert.assertEquals( json, ComponentSerializer.toString( parsed ) );
}
}
@Test
public void testItemParse()
@ -41,8 +60,10 @@ public class ComponentsTest
{
textComponent
} );
testDissembleReassemble( textComponent );
json = "{\"hoverEvent\":{\"action\":\"show_item\",\"value\":[{\"text\":\"{id:\\\"minecraft:netherrack\\\",Count:47b}\"}]},\"text\":\"Test\"}";
testDissembleReassemble( json );
testAssembleDissemble( json, false );
testAssembleDissemble( json, true );
//////////
String hoverVal = "{\"text\":\"{id:\\\"minecraft:dirt\\\",Count:1b}\"}";
json = "{\"extra\":[{\"text\":\"[\"},{\"extra\":[{\"translate\":\"block.minecraft.dirt\"}],\"text\":\"\"},{\"text\":\"]\"}],\"hoverEvent\":{\"action\":\"show_item\",\"value\":[" + hoverVal + "]},\"text\":\"\"}";
@ -66,18 +87,37 @@ public class ComponentsTest
}
@Test
public void testEmptyComponentBuilder()
public void testEmptyComponentBuilderCreate()
{
this.testEmptyComponentBuilder(
ComponentBuilder::create,
(components) -> Assert.assertEquals( components.length, 0 ),
(components, size) -> Assert.assertEquals( size, components.length )
);
}
@Test
public void testEmptyComponentBuilderBuild()
{
this.testEmptyComponentBuilder(
ComponentBuilder::build,
(component) -> Assert.assertNull( component.getExtra() ),
(component, size) -> Assert.assertEquals( component.getExtra().size(), size )
);
}
private <T> void testEmptyComponentBuilder(Function<ComponentBuilder, T> componentBuilder, Consumer<T> emptyAssertion, ObjIntConsumer<T> sizedAssertion)
{
ComponentBuilder builder = new ComponentBuilder();
BaseComponent[] parts = builder.create();
Assert.assertEquals( parts.length, 0 );
T component = componentBuilder.apply( builder );
emptyAssertion.accept( component );
for ( int i = 0; i < 3; i++ )
{
builder.append( "part:" + i );
parts = builder.create();
Assert.assertEquals( parts.length, i + 1 );
component = componentBuilder.apply( builder );
sizedAssertion.accept( component, i + 1 );
}
}
@ -213,7 +253,7 @@ public class ComponentsTest
}
@Test
public void testHoverEventContents()
public void testHoverEventContentsCreate()
{
// First do the text using the newer contents system
HoverEvent hoverEvent = new HoverEvent(
@ -222,21 +262,53 @@ public class ComponentsTest
new Text( new ComponentBuilder( "Second" ).create() )
);
this.testHoverEventContents(
hoverEvent,
ComponentSerializer::parse,
(components) -> components[0].getHoverEvent(),
ComponentsTest::testDissembleReassemble // BaseComponent
);
// check the test still works with the value method
hoverEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Sample text" ).create() );
TextComponent component = new TextComponent( "Sample text" );
component.setHoverEvent( hoverEvent );
Assert.assertEquals( hoverEvent.getContents().size(), 1 );
Assert.assertTrue( hoverEvent.isLegacy() );
String serialized = ComponentSerializer.toString( component );
BaseComponent[] deserialized = ComponentSerializer.parse( serialized );
Assert.assertEquals( component.getHoverEvent(), deserialized[0].getHoverEvent() );
}
@Test
public void testHoverEventContentsBuild()
{
// First do the text using the newer contents system
HoverEvent hoverEvent = new HoverEvent(
HoverEvent.Action.SHOW_TEXT,
new Text( new ComponentBuilder( "First" ).build() ),
new Text( new ComponentBuilder( "Second" ).build() )
);
this.testHoverEventContents(
hoverEvent,
ComponentSerializer::deserialize,
BaseComponent::getHoverEvent,
ComponentsTest::testDissembleReassemble // BaseComponent
);
}
private <T> void testHoverEventContents(HoverEvent hoverEvent, Function<String, T> deserializer, Function<T, HoverEvent> hoverEventGetter, Consumer<T> dissembleReassembleTest)
{
TextComponent component = new TextComponent( "Sample text" );
component.setHoverEvent( hoverEvent );
Assert.assertEquals( hoverEvent.getContents().size(), 2 );
Assert.assertFalse( hoverEvent.isLegacy() );
String serialized = ComponentSerializer.toString( component );
BaseComponent[] deserialized = ComponentSerializer.parse( serialized );
Assert.assertEquals( component.getHoverEvent(), deserialized[0].getHoverEvent() );
// check the test still works with the value method
hoverEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Sample text" ).create() );
Assert.assertEquals( hoverEvent.getContents().size(), 1 );
Assert.assertTrue( hoverEvent.isLegacy() );
serialized = ComponentSerializer.toString( component );
deserialized = ComponentSerializer.parse( serialized );
Assert.assertEquals( component.getHoverEvent(), deserialized[0].getHoverEvent() );
String serialized = ComponentSerializer.toString( component );
T deserialized = deserializer.apply( serialized );
Assert.assertEquals( component.getHoverEvent(), hoverEventGetter.apply( deserialized ) );
// Test single content:
String json = "{\"italic\":true,\"color\":\"gray\",\"translate\":\"chat.type.admin\",\"with\":[{\"text\":\"@\"}"
@ -248,17 +320,28 @@ public class ComponentsTest
+ "\"/tell Name \"},\"hoverEvent\":{\"action\":\"show_entity\",\"contents\":"
+ "{\"type\":\"minecraft:player\",\"id\":\"00000000-0000-0000-0000-00000000000000\",\"name\":"
+ "{\"text\":\"Name\"}}},\"text\":\"Name\"}]}]}";
testDissembleReassemble( ComponentSerializer.parse( json ) );
dissembleReassembleTest.accept( deserializer.apply( json ) );
}
@Test
public void testFormatRetentionCopyFormatting()
public void testFormatRetentionCopyFormattingCreate()
{
this.testFormatRetentionCopyFormatting( () -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Test" ).create() ) );
}
@Test
public void testFormatRetentionCopyFormattingBuild()
{
this.testFormatRetentionCopyFormatting( () -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "Test" ).build() ) ) );
}
private void testFormatRetentionCopyFormatting(Supplier<HoverEvent> hoverEventSupplier)
{
TextComponent first = new TextComponent( "Hello" );
first.setBold( true );
first.setColor( ChatColor.RED );
first.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "test" ) );
first.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Test" ).create() ) );
first.setHoverEvent( hoverEventSupplier.get() );
TextComponent second = new TextComponent( " world" );
second.copyFormatting( first, ComponentBuilder.FormatRetention.ALL, true );
@ -269,16 +352,44 @@ public class ComponentsTest
}
@Test
public void testBuilderClone()
public void testBuilderCloneCreate()
{
this.testBuilderClone( (builder) -> TextComponent.toLegacyText( builder.create() ) );
}
@Test
public void testBuilderCloneBuild()
{
this.testBuilderClone( (builder) -> TextComponent.toLegacyText( builder.build() ) );
}
private void testBuilderClone(Function<ComponentBuilder, String> legacyTextFunction)
{
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.RED ).append( "world" ).color( ChatColor.DARK_RED );
ComponentBuilder cloned = new ComponentBuilder( builder );
Assert.assertEquals( TextComponent.toLegacyText( builder.create() ), TextComponent.toLegacyText( cloned.create() ) );
Assert.assertEquals( legacyTextFunction.apply( builder ), legacyTextFunction.apply( cloned ) );
}
@Test
public void testBuilderAppendMixedComponents()
public void testBuilderAppendCreateMixedComponents()
{
this.testBuilderAppendMixedComponents(
ComponentBuilder::create,
(components, index) -> components[index]
);
}
@Test
public void testBuilderAppendBuildMixedComponents()
{
this.testBuilderAppendMixedComponents(
ComponentBuilder::build,
(component, index) -> component.getExtra().get( index )
);
}
private <T> void testBuilderAppendMixedComponents(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter)
{
ComponentBuilder builder = new ComponentBuilder( "Hello " );
TextComponent textComponent = new TextComponent( "world " );
@ -291,11 +402,11 @@ public class ComponentsTest
} );
ScoreComponent scoreComponent = new ScoreComponent( "myscore", "myobjective" );
builder.append( scoreComponent ); // non array based BaseComponent append
BaseComponent[] components = builder.create();
Assert.assertEquals( "Hello ", components[0].toPlainText() );
Assert.assertEquals( textComponent.toPlainText(), components[1].toPlainText() );
Assert.assertEquals( translatableComponent.toPlainText(), components[2].toPlainText() );
Assert.assertEquals( scoreComponent.toPlainText(), components[3].toPlainText() );
T component = componentBuilder.apply( builder );
Assert.assertEquals( "Hello ", extraGetter.apply( component, 0 ).toPlainText() );
Assert.assertEquals( textComponent.toPlainText(), extraGetter.apply( component, 1 ).toPlainText() );
Assert.assertEquals( translatableComponent.toPlainText(), extraGetter.apply( component, 2 ).toPlainText() );
Assert.assertEquals( scoreComponent.toPlainText(), extraGetter.apply( component, 3 ).toPlainText() );
}
@Test
@ -309,32 +420,80 @@ public class ComponentsTest
}
@Test
public void testBuilderAppend()
public void testBuilderAppendCreate()
{
ClickEvent clickEvent = new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/help " );
HoverEvent hoverEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Hello world" ).create() );
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.YELLOW );
builder.append( new ComponentBuilder( "world!" ).color( ChatColor.GREEN ).event( hoverEvent ).event( clickEvent ).create() );
BaseComponent[] components = builder.create();
Assert.assertEquals( components[1].getHoverEvent(), hoverEvent );
Assert.assertEquals( components[1].getClickEvent(), clickEvent );
Assert.assertEquals( "Hello world!", BaseComponent.toPlainText( components ) );
Assert.assertEquals( ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!", BaseComponent.toLegacyText( components ) );
this.testBuilderAppend(
() -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "Hello world" ).create() ),
ComponentBuilder::create,
(components, index) -> components[index],
BaseComponent::toPlainText,
ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!",
BaseComponent::toLegacyText
);
}
@Test
public void testBuilderAppendLegacy()
public void testBuilderAppendBuild()
{
this.testBuilderAppend(
() -> new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "Hello world" ).build() ) ),
ComponentBuilder::build,
(component, index) -> component.getExtra().get( index ),
(component) -> BaseComponent.toPlainText( component ),
// An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component
ChatColor.WHITE.toString() + ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!",
(component) -> BaseComponent.toLegacyText( component )
);
}
private <T> void testBuilderAppend(Supplier<HoverEvent> hoverEventSupplier, Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter, Function<T, String> toPlainTextFunction, String expectedLegacyText, Function<T, String> toLegacyTextFunction)
{
ClickEvent clickEvent = new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/help " );
HoverEvent hoverEvent = hoverEventSupplier.get();
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.YELLOW );
builder.append( new ComponentBuilder( "world!" ).color( ChatColor.GREEN ).event( hoverEvent ).event( clickEvent ).create() ); // Intentionally using create() to append multiple individual components
T component = componentBuilder.apply( builder );
Assert.assertEquals( extraGetter.apply( component, 1 ).getHoverEvent(), hoverEvent );
Assert.assertEquals( extraGetter.apply( component, 1 ).getClickEvent(), clickEvent );
Assert.assertEquals( "Hello world!", toPlainTextFunction.apply( component ) );
Assert.assertEquals( expectedLegacyText, toLegacyTextFunction.apply( component ) );
}
@Test
public void testBuilderAppendLegacyCreate()
{
this.testBuilderAppendLegacy(
ComponentBuilder::create,
BaseComponent::toPlainText,
ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!",
BaseComponent::toLegacyText
);
}
@Test
public void testBuilderAppendLegacyBuild()
{
this.testBuilderAppendLegacy(
ComponentBuilder::build,
(component) -> BaseComponent.toPlainText( component ),
// An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component
ChatColor.WHITE.toString() + ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!",
(component) -> BaseComponent.toLegacyText( component )
);
}
private <T> void testBuilderAppendLegacy(Function<ComponentBuilder, T> componentBuilder, Function<T, String> toPlainTextFunction, String expectedLegacyString, Function<T, String> toLegacyTextFunction)
{
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.YELLOW );
builder.appendLegacy( "§aworld!" );
BaseComponent[] components = builder.create();
T component = componentBuilder.apply( builder );
Assert.assertEquals( "Hello world!", BaseComponent.toPlainText( components ) );
Assert.assertEquals( ChatColor.YELLOW + "Hello " + ChatColor.GREEN + "world!", BaseComponent.toLegacyText( components ) );
Assert.assertEquals( "Hello world!", toPlainTextFunction.apply( component ) );
Assert.assertEquals( expectedLegacyString, toLegacyTextFunction.apply( component ) );
}
@Test
@ -397,57 +556,114 @@ public class ComponentsTest
}
@Test
public void testBuilder()
public void testBuilderCreate()
{
BaseComponent[] components = new ComponentBuilder( "Hello " ).color( ChatColor.RED ).
this.testBuilder(
ComponentBuilder::create,
BaseComponent::toPlainText,
ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD
+ "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
BaseComponent::toLegacyText
);
}
@Test
public void testBuilderBuild()
{
this.testBuilder(
ComponentBuilder::build,
(component) -> BaseComponent.toPlainText( component ),
// An extra format code is appended to the beginning because there is an empty TextComponent at the start of every component
ChatColor.WHITE.toString() + ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD
+ "World" + ChatColor.YELLOW + ChatColor.BOLD + "!",
(component) -> BaseComponent.toLegacyText( component )
);
}
private <T> void testBuilder(Function<ComponentBuilder, T> componentBuilder, Function<T, String> toPlainTextFunction, String expectedLegacyString, Function<T, String> toLegacyTextFunction)
{
T component = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED ).
append( "World" ).bold( true ).color( ChatColor.BLUE ).
append( "!" ).color( ChatColor.YELLOW ).create();
append( "!" ).color( ChatColor.YELLOW ) );
Assert.assertEquals( "Hello World!", BaseComponent.toPlainText( components ) );
Assert.assertEquals( ChatColor.RED + "Hello " + ChatColor.BLUE + ChatColor.BOLD
+ "World" + ChatColor.YELLOW + ChatColor.BOLD + "!", BaseComponent.toLegacyText( components ) );
Assert.assertEquals( "Hello World!", toPlainTextFunction.apply( component ) );
Assert.assertEquals( expectedLegacyString, toLegacyTextFunction.apply( component ) );
}
@Test
public void testBuilderReset()
public void testBuilderCreateReset()
{
BaseComponent[] components = new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World" ).reset().create();
Assert.assertEquals( components[0].getColor(), ChatColor.RED );
Assert.assertEquals( components[1].getColor(), ChatColor.WHITE );
this.testBuilderReset(
ComponentBuilder::create,
(components, index) -> components[index]
);
}
@Test
public void testBuilderFormatRetention()
public void testBuilderBuildReset()
{
BaseComponent[] noneRetention = new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World", ComponentBuilder.FormatRetention.NONE ).create();
this.testBuilderReset(
ComponentBuilder::build,
(component, index) -> component.getExtra().get( index )
);
}
Assert.assertEquals( noneRetention[0].getColor(), ChatColor.RED );
Assert.assertEquals( noneRetention[1].getColor(), ChatColor.WHITE );
private <T> void testBuilderReset(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter)
{
T component = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World" ).reset() );
HoverEvent testEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( "test" ).create() );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( component, 0 ).getColor() );
Assert.assertEquals( ChatColor.WHITE, extraGetter.apply( component, 1 ).getColor() );
}
BaseComponent[] formattingRetention = new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).append( "World", ComponentBuilder.FormatRetention.FORMATTING ).create();
@Test
public void testBuilderCreateFormatRetention()
{
this.testBuilderFormatRetention(
ComponentBuilder::create,
(components, index) -> components[index]
);
}
Assert.assertEquals( formattingRetention[0].getColor(), ChatColor.RED );
Assert.assertEquals( formattingRetention[0].getHoverEvent(), testEvent );
Assert.assertEquals( formattingRetention[1].getColor(), ChatColor.RED );
Assert.assertNull( formattingRetention[1].getHoverEvent() );
@Test
public void testBuilderBuildFormatRetention()
{
this.testBuilderFormatRetention(
ComponentBuilder::build,
(component, index) -> component.getExtra().get( index )
);
}
private <T> void testBuilderFormatRetention(Function<ComponentBuilder, T> componentBuilder, BiFunction<T, Integer, BaseComponent> extraGetter)
{
T noneRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World", ComponentBuilder.FormatRetention.NONE ) );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( noneRetention, 0 ).getColor() );
Assert.assertEquals( ChatColor.WHITE, extraGetter.apply( noneRetention, 1 ).getColor() );
HoverEvent testEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "test" ).build() ) );
T formattingRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).append( "World", ComponentBuilder.FormatRetention.FORMATTING ) );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( formattingRetention, 0 ).getColor() );
Assert.assertEquals( testEvent, extraGetter.apply( formattingRetention, 0 ).getHoverEvent() );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( formattingRetention, 1 ).getColor() );
Assert.assertNull( extraGetter.apply( formattingRetention, 1 ).getHoverEvent() );
ClickEvent testClickEvent = new ClickEvent( ClickEvent.Action.OPEN_URL, "http://www.example.com" );
BaseComponent[] eventRetention = new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).event( testClickEvent ).append( "World", ComponentBuilder.FormatRetention.EVENTS ).create();
T eventRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).event( testClickEvent ).append( "World", ComponentBuilder.FormatRetention.EVENTS ) );
Assert.assertEquals( eventRetention[0].getColor(), ChatColor.RED );
Assert.assertEquals( eventRetention[0].getHoverEvent(), testEvent );
Assert.assertEquals( eventRetention[0].getClickEvent(), testClickEvent );
Assert.assertEquals( eventRetention[1].getColor(), ChatColor.WHITE );
Assert.assertEquals( eventRetention[1].getHoverEvent(), testEvent );
Assert.assertEquals( eventRetention[1].getClickEvent(), testClickEvent );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( eventRetention, 0 ).getColor() );
Assert.assertEquals( testEvent, extraGetter.apply( eventRetention, 0 ).getHoverEvent() );
Assert.assertEquals( testClickEvent, extraGetter.apply( eventRetention, 0 ).getClickEvent() );
Assert.assertEquals( ChatColor.WHITE, extraGetter.apply( eventRetention, 1 ).getColor() );
Assert.assertEquals( testEvent, extraGetter.apply( eventRetention, 1 ).getHoverEvent() );
Assert.assertEquals( testClickEvent, extraGetter.apply( eventRetention, 1 ).getClickEvent() );
}
@Test(expected = IllegalArgumentException.class)
@ -572,12 +788,29 @@ public class ComponentsTest
Assert.assertArrayEquals( hexColored, reColored );
}
/**
@Test
public void testLegacyResetInBuilderCreate()
{
this.testLegacyResetInBuilder(
ComponentBuilder::create,
ComponentSerializer::toString
);
}
@Test
public void testLegacyResetInBuilderBuild()
{
this.testLegacyResetInBuilder(
ComponentBuilder::build,
ComponentSerializer::toString
);
}
/*
* In legacy chat, colors and reset both reset all formatting.
* Make sure it works in combination with ComponentBuilder.
*/
@Test
public void testLegacyResetInBuilder()
private <T> void testLegacyResetInBuilder(Function<ComponentBuilder, T> componentBuilder, Function<T, String> componentSerializer)
{
ComponentBuilder builder = new ComponentBuilder();
BaseComponent[] a = TextComponent.fromLegacyText( "§4§n44444§rdd§6§l6666" );
@ -588,13 +821,13 @@ public class ComponentsTest
builder.append( a );
String test1 = ComponentSerializer.toString( builder.create() );
String test1 = componentSerializer.apply( componentBuilder.apply( builder ) );
Assert.assertEquals( expected, test1 );
BaseComponent[] b = TextComponent.fromLegacyText( "§rrrrr" );
builder.append( b );
String test2 = ComponentSerializer.toString( builder.create() );
String test2 = componentSerializer.apply( componentBuilder.apply( builder ) );
Assert.assertEquals(
"{\"extra\":[{\"underlined\":true,\"color\":\"dark_red\",\"text\":\"44444\"},"
+ "{\"color\":\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"},"

View File

@ -6,12 +6,12 @@
<parent>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>bungeecord-config</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Config</name>
@ -21,14 +21,14 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version>
<version>2.10.1</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.0</version>
<version>2.2</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>

View File

@ -6,12 +6,12 @@
<parent>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>bungeecord-event</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Event</name>

View File

@ -6,12 +6,12 @@
<parent>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>bungeecord-log</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Log</name>

View File

@ -6,12 +6,12 @@
<parent>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>bungeecord-native</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Native</name>

24
pom.xml
View File

@ -5,7 +5,7 @@
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>pom</packaging>
<name>BungeeCord-Parent</name>
@ -71,7 +71,7 @@
<properties>
<build.number>unknown</build.number>
<lombok.version>1.18.28</lombok.version>
<lombok.version>1.18.30</lombok.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
@ -82,7 +82,7 @@
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-bom</artifactId>
<version>4.1.93.Final</version>
<version>4.1.97.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
@ -98,7 +98,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>31.1-jre</version>
<version>32.1.2-jre</version>
<scope>compile</scope>
</dependency>
<dependency>
@ -116,11 +116,20 @@
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.0</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>net.md-5</groupId>
<artifactId>scriptus</artifactId>
<version>0.4.1</version>
<version>0.5.0</version>
<configuration>
<format>git:${project.name}-Pandacube:${project.version}:%s:${build.number}</format>
</configuration>
@ -186,7 +195,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.3.0</version>
<version>3.4.1</version>
<executions>
<execution>
<id>enforce</id>
@ -203,7 +212,7 @@
</rules>
</configuration>
<goals>
<goal>enforce</goal>
<!--<goal>enforce</goal>--> <!-- Disabled until maven-resolver is upgraded again. -->
</goals>
</execution>
</executions>
@ -304,7 +313,6 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.5.0</version>
<executions>
<!-- Execute Javadoc once normally to catch any warnings -->
<execution>

View File

@ -6,12 +6,12 @@
<parent>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>bungeecord-protocol</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Protocol</name>

View File

@ -11,6 +11,7 @@ import net.md_5.bungee.protocol.packet.Commands;
import net.md_5.bungee.protocol.packet.EncryptionRequest;
import net.md_5.bungee.protocol.packet.EncryptionResponse;
import net.md_5.bungee.protocol.packet.EntityStatus;
import net.md_5.bungee.protocol.packet.FinishConfiguration;
import net.md_5.bungee.protocol.packet.GameState;
import net.md_5.bungee.protocol.packet.Handshake;
import net.md_5.bungee.protocol.packet.KeepAlive;
@ -18,6 +19,7 @@ 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.Login;
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;
@ -34,6 +36,7 @@ import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.ServerData;
import net.md_5.bungee.protocol.packet.SetCompression;
import net.md_5.bungee.protocol.packet.StartConfiguration;
import net.md_5.bungee.protocol.packet.StatusRequest;
import net.md_5.bungee.protocol.packet.StatusResponse;
import net.md_5.bungee.protocol.packet.Subtitle;
@ -223,4 +226,16 @@ public abstract class AbstractPacketHandler
public void handle(ServerData serverData) throws Exception
{
}
public void handle(LoginAcknowledged loginAcknowledged) throws Exception
{
}
public void handle(StartConfiguration startConfiguration) throws Exception
{
}
public void handle(FinishConfiguration finishConfiguration) throws Exception
{
}
}

View File

@ -15,7 +15,9 @@ import java.util.EnumSet;
import java.util.List;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
import se.llbit.nbt.ErrorTag;
import se.llbit.nbt.NamedTag;
import se.llbit.nbt.SpecificTag;
import se.llbit.nbt.Tag;
@RequiredArgsConstructor
@ -293,14 +295,35 @@ public abstract class DefinedPacket
return null;
}
public static Tag readTag(ByteBuf input)
public static Tag readTag(ByteBuf input, int protocolVersion)
{
Tag tag = NamedTag.read( new DataInputStream( new ByteBufInputStream( input ) ) );
DataInputStream in = new DataInputStream( new ByteBufInputStream( input ) );
Tag tag;
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
try
{
byte type = in.readByte();
if ( type == 0 )
{
return Tag.END;
} else
{
tag = SpecificTag.read( type, in );
}
} catch ( IOException ex )
{
tag = new ErrorTag( "IOException while reading tag type:\n" + ex.getMessage() );
}
} else
{
tag = NamedTag.read( in );
}
Preconditions.checkArgument( !tag.isError(), "Error reading tag: %s", tag.error() );
return tag;
}
public static void writeTag(Tag tag, ByteBuf output)
public static void writeTag(Tag tag, ByteBuf output, int protocolVersion)
{
try
{
@ -378,6 +401,11 @@ public abstract class DefinedPacket
write( buf );
}
public Protocol nextProtocol()
{
return null;
}
public abstract void handle(AbstractPacketHandler handler) throws Exception;
@Override

View File

@ -5,12 +5,14 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageDecoder;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@AllArgsConstructor
public class MinecraftDecoder extends MessageToMessageDecoder<ByteBuf>
{
@Getter
@Setter
private Protocol protocol;
private final boolean server;

View File

@ -4,12 +4,14 @@ import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@AllArgsConstructor
public class MinecraftEncoder extends MessageToByteEncoder<DefinedPacket>
{
@Getter
@Setter
private Protocol protocol;
private boolean server;

View File

@ -19,11 +19,13 @@ import net.md_5.bungee.protocol.packet.Commands;
import net.md_5.bungee.protocol.packet.EncryptionRequest;
import net.md_5.bungee.protocol.packet.EncryptionResponse;
import net.md_5.bungee.protocol.packet.EntityStatus;
import net.md_5.bungee.protocol.packet.FinishConfiguration;
import net.md_5.bungee.protocol.packet.GameState;
import net.md_5.bungee.protocol.packet.Handshake;
import net.md_5.bungee.protocol.packet.KeepAlive;
import net.md_5.bungee.protocol.packet.Kick;
import net.md_5.bungee.protocol.packet.Login;
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;
@ -40,6 +42,7 @@ import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.ServerData;
import net.md_5.bungee.protocol.packet.SetCompression;
import net.md_5.bungee.protocol.packet.StartConfiguration;
import net.md_5.bungee.protocol.packet.StatusRequest;
import net.md_5.bungee.protocol.packet.StatusResponse;
import net.md_5.bungee.protocol.packet.Subtitle;
@ -85,7 +88,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x1E ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x20 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x1F ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x23 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x23 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x24 )
);
TO_CLIENT.registerPacket(
Login.class,
@ -100,7 +104,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x23 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x25 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x24 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x28 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x28 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x29 )
);
TO_CLIENT.registerPacket( Chat.class,
Chat::new,
@ -128,7 +133,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x3B ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x3E ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x3D ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x41 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x41 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x43 )
);
TO_CLIENT.registerPacket(
BossBar.class,
@ -138,7 +144,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_16, 0x0C ),
map( ProtocolConstants.MINECRAFT_1_17, 0x0D ),
map( ProtocolConstants.MINECRAFT_1_19, 0x0A ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0xB )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0B ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0A )
);
TO_CLIENT.registerPacket(
PlayerListItem.class, // PlayerInfo
@ -168,7 +175,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x11 ),
map( ProtocolConstants.MINECRAFT_1_19, 0x0E ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x0D ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0xF )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x10 )
);
TO_CLIENT.registerPacket(
ScoreboardObjective.class,
@ -183,7 +191,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x53 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x56 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x54 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x58 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x58 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5A )
);
TO_CLIENT.registerPacket(
ScoreboardScore.class,
@ -198,7 +207,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x56 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x59 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x57 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5B )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5B ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5D )
);
TO_CLIENT.registerPacket(
ScoreboardDisplay.class,
@ -213,7 +223,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x4C ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x4F ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x4D ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x51 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x51 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x53 )
);
TO_CLIENT.registerPacket(
Team.class,
@ -228,7 +239,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x55 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x58 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x56 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5A )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5A ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5C )
);
TO_CLIENT.registerPacket(
PluginMessage.class,
@ -244,7 +256,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x15 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x16 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x15 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x17 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x17 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x18 )
);
TO_CLIENT.registerPacket(
Kick.class,
@ -260,7 +273,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x17 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x19 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x17 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1A )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1A ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x1B )
);
TO_CLIENT.registerPacket(
Title.class,
@ -276,7 +290,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_18, 0x5A ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x5D ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x5B ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5F )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x61 )
);
TO_CLIENT.registerPacket(
ClearTitles.class,
@ -284,7 +299,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x10 ),
map( ProtocolConstants.MINECRAFT_1_19, 0x0D ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x0C ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0xE )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0E ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0F )
);
TO_CLIENT.registerPacket(
Subtitle.class,
@ -293,7 +309,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_18, 0x58 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x5B ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x59 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5D )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x5D ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x5F )
);
TO_CLIENT.registerPacket(
TitleTimes.class,
@ -302,7 +319,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_18, 0x5B ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x5E ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x5C ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x60 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x60 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x62 )
);
TO_CLIENT.registerPacket(
SystemChat.class,
@ -310,7 +328,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x5F ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x62 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x60 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x64 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x64 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x67 )
);
TO_CLIENT.registerPacket(
PlayerListHeaderFooter.class,
@ -329,7 +348,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x60 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x63 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x61 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x65 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x65 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x68 )
);
TO_CLIENT.registerPacket(
EntityStatus.class,
@ -345,7 +365,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x18 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x1A ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x19 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1C )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1C ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x1D )
);
TO_CLIENT.registerPacket(
Commands.class,
@ -357,7 +378,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_17, 0x12 ),
map( ProtocolConstants.MINECRAFT_1_19, 0x0F ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x0E ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x10 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x10 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x11 )
);
TO_CLIENT.registerPacket(
GameState.class,
@ -369,7 +391,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x1B ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x1D ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x1C ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1F )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x1F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x20 )
);
TO_CLIENT.registerPacket(
ViewDistance.class,
@ -381,7 +404,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x49 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x4C ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x4B ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x4F )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x4F ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x51 )
);
TO_CLIENT.registerPacket(
ServerData.class,
@ -389,19 +413,27 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x3F ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x42 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x41 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x45 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x45 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x47 )
);
TO_CLIENT.registerPacket(
PlayerListItemRemove.class,
PlayerListItemRemove::new,
map( ProtocolConstants.MINECRAFT_1_19_3, 0x35 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x39 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x39 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x3B )
);
TO_CLIENT.registerPacket(
PlayerListItemUpdate.class,
PlayerListItemUpdate::new,
map( ProtocolConstants.MINECRAFT_1_19_3, 0x36 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x3A )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x3A ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x3C )
);
TO_CLIENT.registerPacket(
StartConfiguration.class,
StartConfiguration::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x65 )
);
TO_SERVER.registerPacket(
@ -418,7 +450,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x11 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x12 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x11 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x12 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x12 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x14 )
);
TO_SERVER.registerPacket( Chat.class,
Chat::new,
@ -453,7 +486,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x08 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x09 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x08 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x09 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x09 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0A )
);
TO_SERVER.registerPacket(
ClientSettings.class,
@ -466,7 +500,8 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x07 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x08 ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x07 ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x08 )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x08 ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x09 )
);
TO_SERVER.registerPacket(
PluginMessage.class,
@ -481,7 +516,13 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x0C ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x0D ),
map( ProtocolConstants.MINECRAFT_1_19_3, 0x0C ),
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0D )
map( ProtocolConstants.MINECRAFT_1_19_4, 0x0D ),
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0F )
);
TO_SERVER.registerPacket(
StartConfiguration.class,
StartConfiguration::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x0B )
);
}
},
@ -559,6 +600,59 @@ public enum Protocol
LoginPayloadResponse::new,
map( ProtocolConstants.MINECRAFT_1_13, 0x02 )
);
TO_SERVER.registerPacket(
LoginAcknowledged.class,
LoginAcknowledged::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x03 )
);
}
},
// 3
CONFIGURATION
{
{
TO_CLIENT.registerPacket(
PluginMessage.class,
PluginMessage::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x00 )
);
TO_CLIENT.registerPacket(
Kick.class,
Kick::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x01 )
);
TO_CLIENT.registerPacket(
FinishConfiguration.class,
FinishConfiguration::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x02 )
);
TO_CLIENT.registerPacket(
KeepAlive.class,
KeepAlive::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x03 )
);
TO_SERVER.registerPacket(
ClientSettings.class,
ClientSettings::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x00 )
);
TO_SERVER.registerPacket(
PluginMessage.class,
PluginMessage::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x01 )
);
TO_SERVER.registerPacket(
FinishConfiguration.class,
FinishConfiguration::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x02 )
);
TO_SERVER.registerPacket(
KeepAlive.class,
KeepAlive::new,
map( ProtocolConstants.MINECRAFT_1_20_2, 0x03 )
);
}
};
/*========================================================================*/

View File

@ -43,6 +43,7 @@ public class ProtocolConstants
public static final int MINECRAFT_1_19_3 = 761;
public static final int MINECRAFT_1_19_4 = 762;
public static final int MINECRAFT_1_20 = 763;
public static final int MINECRAFT_1_20_2 = 764;
public static final List<String> SUPPORTED_VERSIONS;
public static final List<Integer> SUPPORTED_VERSION_IDS;
@ -99,13 +100,14 @@ public class ProtocolConstants
ProtocolConstants.MINECRAFT_1_19_1,
ProtocolConstants.MINECRAFT_1_19_3,
ProtocolConstants.MINECRAFT_1_19_4,
ProtocolConstants.MINECRAFT_1_20
ProtocolConstants.MINECRAFT_1_20,
ProtocolConstants.MINECRAFT_1_20_2
);
if ( SNAPSHOT_SUPPORT )
{
// supportedVersions.add( "1.20.x" );
// supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_20 );
// supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_20_2 );
}
SUPPORTED_VERSIONS = supportedVersions.build();

View File

@ -32,7 +32,7 @@ public class ClientCommand extends DefinedPacket
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
command = readString( buf );
command = readString( buf, 256 );
timestamp = buf.readLong();
salt = buf.readLong();

View File

@ -0,0 +1,37 @@
package net.md_5.bungee.protocol.packet;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
@Data
@EqualsAndHashCode(callSuper = false)
public class FinishConfiguration extends DefinedPacket
{
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
}
@Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
}
@Override
public Protocol nextProtocol()
{
return Protocol.GAME;
}
@Override
public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}
}

View File

@ -36,6 +36,7 @@ public class Login extends DefinedPacket
private int simulationDistance;
private boolean reducedDebugInfo;
private boolean normalRespawn;
private boolean limitedCrafting;
private boolean debug;
private boolean flat;
private Location deathLocation;
@ -49,10 +50,16 @@ public class Login extends DefinedPacket
{
hardcore = buf.readBoolean();
}
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
gameMode = buf.readUnsignedByte();
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
{
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
previousGameMode = buf.readUnsignedByte();
}
worldNames = new HashSet<>();
int worldCount = readVarInt( buf );
@ -61,19 +68,25 @@ public class Login extends DefinedPacket
worldNames.add( readString( buf ) );
}
dimensions = readTag( buf );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
dimensions = readTag( buf, protocolVersion );
}
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16_2 && protocolVersion < ProtocolConstants.MINECRAFT_1_19 )
{
dimension = readTag( buf );
} else
dimension = readTag( buf, protocolVersion );
} else if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
dimension = readString( buf );
}
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
worldName = readString( buf );
}
} else if ( protocolVersion > ProtocolConstants.MINECRAFT_1_9 )
{
dimension = buf.readInt();
@ -81,7 +94,7 @@ public class Login extends DefinedPacket
{
dimension = (int) buf.readByte();
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_15 )
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_15 && protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
seed = buf.readLong();
}
@ -116,6 +129,15 @@ public class Login extends DefinedPacket
{
normalRespawn = buf.readBoolean();
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
limitedCrafting = buf.readBoolean();
dimension = readString( buf );
worldName = readString( buf );
seed = buf.readLong();
gameMode = buf.readUnsignedByte();
previousGameMode = buf.readByte();
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
{
debug = buf.readBoolean();
@ -142,10 +164,16 @@ public class Login extends DefinedPacket
{
buf.writeBoolean( hardcore );
}
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeByte( gameMode );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
{
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeByte( previousGameMode );
}
writeVarInt( worldNames.size(), buf );
for ( String world : worldNames )
@ -153,19 +181,25 @@ public class Login extends DefinedPacket
writeString( world, buf );
}
writeTag( dimensions, buf );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
writeTag( dimensions, buf, protocolVersion );
}
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16_2 && protocolVersion < ProtocolConstants.MINECRAFT_1_19 )
{
writeTag( (Tag) dimension, buf );
} else
writeTag( (Tag) dimension, buf, protocolVersion );
} else if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
writeString( (String) dimension, buf );
}
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
writeString( worldName, buf );
}
} else if ( protocolVersion > ProtocolConstants.MINECRAFT_1_9 )
{
buf.writeInt( (Integer) dimension );
@ -174,9 +208,12 @@ public class Login extends DefinedPacket
buf.writeByte( (Integer) dimension );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_15 )
{
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeLong( seed );
}
}
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 )
{
buf.writeByte( difficulty );
@ -208,6 +245,15 @@ public class Login extends DefinedPacket
{
buf.writeBoolean( normalRespawn );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeBoolean( limitedCrafting );
writeString( (String) dimension, buf );
writeString( worldName, buf );
buf.writeLong( seed );
buf.writeByte( gameMode );
buf.writeByte( previousGameMode );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16 )
{
buf.writeBoolean( debug );

View File

@ -0,0 +1,37 @@
package net.md_5.bungee.protocol.packet;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
@Data
@EqualsAndHashCode(callSuper = false)
public class LoginAcknowledged extends DefinedPacket
{
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
}
@Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
}
@Override
public Protocol nextProtocol()
{
return Protocol.CONFIGURATION;
}
@Override
public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}
}

View File

@ -32,7 +32,7 @@ public class LoginRequest extends DefinedPacket
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 )
{
if ( buf.readBoolean() )
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 || buf.readBoolean() )
{
uuid = readUUID( buf );
}
@ -48,6 +48,11 @@ public class LoginRequest extends DefinedPacket
writePublicKey( publicKey, buf );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 )
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
writeUUID( uuid, buf );
} else
{
if ( uuid != null )
{
@ -59,6 +64,7 @@ public class LoginRequest extends DefinedPacket
}
}
}
}
@Override
public void handle(AbstractPacketHandler handler) throws Exception

View File

@ -27,7 +27,7 @@ public class Respawn extends DefinedPacket
private String levelType;
private boolean debug;
private boolean flat;
private boolean copyMeta;
private byte copyMeta;
private Location deathLocation;
private int portalCooldown;
@ -38,7 +38,7 @@ public class Respawn extends DefinedPacket
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16_2 && protocolVersion < ProtocolConstants.MINECRAFT_1_19 )
{
dimension = readTag( buf );
dimension = readTag( buf, protocolVersion );
} else
{
dimension = readString( buf );
@ -62,7 +62,10 @@ public class Respawn extends DefinedPacket
previousGameMode = buf.readUnsignedByte();
debug = buf.readBoolean();
flat = buf.readBoolean();
copyMeta = buf.readBoolean();
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
copyMeta = buf.readByte();
}
} else
{
levelType = readString( buf );
@ -78,6 +81,10 @@ public class Respawn extends DefinedPacket
{
portalCooldown = readVarInt( buf );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
copyMeta = buf.readByte();
}
}
@Override
@ -87,7 +94,7 @@ public class Respawn extends DefinedPacket
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_16_2 && protocolVersion < ProtocolConstants.MINECRAFT_1_19 )
{
writeTag( (Tag) dimension, buf );
writeTag( (Tag) dimension, buf, protocolVersion );
} else
{
writeString( (String) dimension, buf );
@ -111,7 +118,10 @@ public class Respawn extends DefinedPacket
buf.writeByte( previousGameMode );
buf.writeBoolean( debug );
buf.writeBoolean( flat );
buf.writeBoolean( copyMeta );
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeByte( copyMeta );
}
} else
{
writeString( levelType, buf );
@ -132,6 +142,10 @@ public class Respawn extends DefinedPacket
{
writeVarInt( portalCooldown, buf );
}
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
buf.writeByte( copyMeta );
}
}
@Override

View File

@ -7,6 +7,7 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
@Data
@NoArgsConstructor
@ -18,20 +19,32 @@ public class ScoreboardDisplay extends DefinedPacket
/**
* 0 = list, 1 = side, 2 = below.
*/
private byte position;
private int position;
private String name;
@Override
public void read(ByteBuf buf)
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
position = readVarInt( buf );
} else
{
position = buf.readByte();
}
name = readString( buf );
}
@Override
public void write(ByteBuf buf)
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_20_2 )
{
writeVarInt( position, buf );
} else
{
buf.writeByte( position );
}
writeString( name, buf );
}

View File

@ -0,0 +1,37 @@
package net.md_5.bungee.protocol.packet;
import io.netty.buffer.ByteBuf;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
@Data
@EqualsAndHashCode(callSuper = false)
public class StartConfiguration extends DefinedPacket
{
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
}
@Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
}
@Override
public Protocol nextProtocol()
{
return Protocol.CONFIGURATION;
}
@Override
public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}
}

View File

@ -6,12 +6,12 @@
<parent>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>bungeecord-proxy</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Proxy</name>
@ -95,26 +95,26 @@
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
<version>8.1.0</version>
<scope>runtime</scope>
</dependency>
<!-- add these back in as they are not exposed by the API -->
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-resolver-provider</artifactId>
<version>3.9.2</version>
<version>3.8.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-connector-basic</artifactId>
<version>1.9.10</version>
<version>1.7.3</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-transport-http</artifactId>
<version>1.9.10</version>
<version>1.7.3</version>
<scope>runtime</scope>
</dependency>
</dependencies>

View File

@ -103,26 +103,30 @@ public class BungeeServerInfo implements ServerInfo
sendData( channel, data, true );
}
// TODO: Don't like this method
@Override
public boolean sendData(String channel, byte[] data, boolean queue)
{
Preconditions.checkNotNull( channel, "channel" );
Preconditions.checkNotNull( data, "data" );
synchronized ( packetQueue )
Server server;
synchronized ( players )
{
Server server = ( players.isEmpty() ) ? null : players.iterator().next().getServer();
server = ( players.isEmpty() ) ? null : players.iterator().next().getServer();
}
if ( server != null )
{
server.sendData( channel, data );
return true;
} else if ( queue )
{
synchronized ( packetQueue )
{
packetQueue.add( new PluginMessage( channel, data, false ) );
}
return false;
}
return false;
}
private long lastPing;

View File

@ -43,6 +43,7 @@ import net.md_5.bungee.protocol.packet.GameState;
import net.md_5.bungee.protocol.packet.Handshake;
import net.md_5.bungee.protocol.packet.Kick;
import net.md_5.bungee.protocol.packet.Login;
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;
@ -52,6 +53,7 @@ import net.md_5.bungee.protocol.packet.Respawn;
import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.SetCompression;
import net.md_5.bungee.protocol.packet.StartConfiguration;
import net.md_5.bungee.protocol.packet.ViewDistance;
import net.md_5.bungee.util.AddressUtil;
import net.md_5.bungee.util.BufUtil;
@ -73,7 +75,7 @@ public class ServerConnector extends PacketHandler
private enum State
{
LOGIN_SUCCESS, ENCRYPT_RESPONSE, LOGIN, FINISHED;
LOGIN_SUCCESS, LOGIN, FINISHED;
}
@Override
@ -84,13 +86,13 @@ public class ServerConnector extends PacketHandler
return;
}
String message = "Exception Connecting:" + Util.exception( t );
String message = ChatColor.RED + "Exception Connecting: " + Util.exception( t );
if ( user.getServer() == null )
{
user.disconnect( message );
} else
{
user.sendMessage( ChatColor.RED + message );
user.sendMessage( message );
}
}
@ -145,8 +147,15 @@ public class ServerConnector extends PacketHandler
public void handle(LoginSuccess loginSuccess) throws Exception
{
Preconditions.checkState( thisState == State.LOGIN_SUCCESS, "Not expecting LOGIN_SUCCESS" );
if ( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_20_2 )
{
ServerConnection server = new ServerConnection( ch, target );
cutThrough( server );
} else
{
ch.setProtocol( Protocol.GAME );
thisState = State.LOGIN;
}
// Only reset the Forge client when:
// 1) The user is switching servers (so has a current server)
@ -182,6 +191,12 @@ public class ServerConnector extends PacketHandler
Preconditions.checkState( thisState == State.LOGIN, "Not expecting LOGIN" );
ServerConnection server = new ServerConnection( ch, target );
handleLogin( bungee, ch, user, target, handshakeHandler, server, login );
cutThrough( server );
}
public static void handleLogin(ProxyServer bungee, ChannelWrapper ch, UserConnection user, BungeeServerInfo target, ForgeServerHandler handshakeHandler, ServerConnection server, Login login) throws Exception
{
ServerConnectedEvent event = new ServerConnectedEvent( user, server );
bungee.getPluginManager().callEvent( event );
@ -225,14 +240,13 @@ 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.isDebug(), login.isFlat(), login.getDeathLocation(),
(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() );
user.unsafe().sendPacket( modLogin );
if ( user.getServer() != null )
if ( user.getDimension() != null )
{
user.getServer().setObsolete( true );
user.getTabListHandler().onServerChange();
user.getServerSentScoreboard().clear();
@ -244,14 +258,15 @@ 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(), false, login.getDeathLocation(),
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() ) );
user.getServer().disconnect( "Quitting" );
} else
{
user.unsafe().sendPacket( BungeeCord.getInstance().registerChannels( user.getPendingConnection().getVersion() ) );
ByteBuf brand = ByteBufAllocator.DEFAULT.heapBuffer();
DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")", brand );
user.unsafe().sendPacket( new PluginMessage( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_13 ? "minecraft:brand" : "MC|Brand", DefinedPacket.toArray( brand ), handshakeHandler.isServerForge() ) );
user.unsafe().sendPacket( new PluginMessage( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_13 ? "minecraft:brand" : "MC|Brand", DefinedPacket.toArray( brand ), handshakeHandler != null && handshakeHandler.isServerForge() ) );
brand.release();
}
@ -295,19 +310,40 @@ 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(),
false, login.getDeathLocation(), login.getPortalCooldown() ) );
(byte) 0, login.getDeathLocation(), login.getPortalCooldown() ) );
}
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(),
false, login.getDeathLocation(), login.getPortalCooldown() ) );
(byte) 0, login.getDeathLocation(), login.getPortalCooldown() ) );
if ( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_14 )
{
user.unsafe().sendPacket( new ViewDistance( login.getViewDistance() ) );
}
user.setDimension( login.getDimension() );
}
}
private void cutThrough(ServerConnection server)
{
if ( user.getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_20_2 )
{
if ( user.getServer() != null )
{
// Begin config mode
user.unsafe().sendPacket( new StartConfiguration() );
} else
{
ch.setDecodeProtocol( Protocol.CONFIGURATION );
ch.write( new LoginAcknowledged() );
ch.setEncodeProtocol( Protocol.CONFIGURATION );
}
}
// Remove from old servers
if ( user.getServer() != null )
{
user.getServer().setObsolete( true );
user.getServer().disconnect( "Quitting" );
}

View File

@ -72,6 +72,7 @@ public final class UserConnection implements ProxiedPlayer
/*========================================================================*/
@NonNull
private final ProxyServer bungee;
@Getter
@NonNull
private final ChannelWrapper ch;
@Getter
@ -124,6 +125,9 @@ public final class UserConnection implements ProxiedPlayer
private final Scoreboard serverSentScoreboard = new Scoreboard();
@Getter
private final Collection<UUID> sentBossBars = new HashSet<>();
@Getter
@Setter
private String lastCommandTabbed;
/*========================================================================*/
@Getter
private String displayName;

View File

@ -23,11 +23,14 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.logging.Level;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.ServerConnection;
import net.md_5.bungee.ServerConnection.KeepAliveData;
import net.md_5.bungee.ServerConnector;
import net.md_5.bungee.UserConnection;
import net.md_5.bungee.Util;
import net.md_5.bungee.api.ProxyServer;
@ -35,6 +38,7 @@ import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.api.event.CommandsDeclareEvent;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.ServerConnectEvent;
@ -53,11 +57,13 @@ import net.md_5.bungee.netty.ChannelWrapper;
import net.md_5.bungee.netty.PacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.PacketWrapper;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
import net.md_5.bungee.protocol.packet.BossBar;
import net.md_5.bungee.protocol.packet.Commands;
import net.md_5.bungee.protocol.packet.KeepAlive;
import net.md_5.bungee.protocol.packet.Kick;
import net.md_5.bungee.protocol.packet.Login;
import net.md_5.bungee.protocol.packet.PlayerListItem;
import net.md_5.bungee.protocol.packet.PlayerListItemRemove;
import net.md_5.bungee.protocol.packet.PlayerListItemUpdate;
@ -85,6 +91,7 @@ public class DownstreamBridge extends PacketHandler
private final ProxyServer bungee;
private final UserConnection con;
private final ServerConnection server;
private boolean receivedLogin;
@Override
public void exception(Throwable t) throws Exception
@ -136,7 +143,7 @@ public class DownstreamBridge extends PacketHandler
public void handle(PacketWrapper packet) throws Exception
{
EntityMap rewrite = con.getEntityRewrite();
if ( rewrite != null )
if ( rewrite != null && con.getCh().getEncodeProtocol() == Protocol.GAME )
{
rewrite.rewriteClientbound( packet.buf, con.getServerEntityId(), con.getClientEntityId(), con.getPendingConnection().getVersion() );
}
@ -406,6 +413,27 @@ public class DownstreamBridge extends PacketHandler
}
break;
}
case "GetPlayerServer":
{
String name = in.readUTF();
ProxiedPlayer player = bungee.getPlayer( name );
out.writeUTF( "GetPlayerServer" );
out.writeUTF( name );
if ( player == null )
{
out.writeUTF( "" );
break;
}
Server srv = player.getServer();
if ( srv == null )
{
out.writeUTF( "" );
} else
{
out.writeUTF( srv.getInfo().getName() );
}
break;
}
case "IP":
out.writeUTF( "IP" );
if ( con.getSocketAddress() instanceof InetSocketAddress )
@ -567,6 +595,16 @@ public class DownstreamBridge extends PacketHandler
}
break;
}
case "KickPlayerRaw":
{
ProxiedPlayer player = bungee.getPlayer( in.readUTF() );
if ( player != null )
{
BaseComponent[] kickReason = ComponentSerializer.parse( in.readUTF() );
player.disconnect( kickReason );
}
break;
}
}
// Check we haven't set out to null, and we have written data, if so reply back back along the BungeeCord channel
@ -619,6 +657,23 @@ public class DownstreamBridge extends PacketHandler
return input.getText();
}
} );
} else
{
String last = con.getLastCommandTabbed();
if ( last != null )
{
String commandName = last.toLowerCase( Locale.ROOT );
commands.addAll( bungee.getPluginManager().getCommands().stream()
.filter( (entry) ->
{
String lowerCase = entry.getKey().toLowerCase( Locale.ROOT );
return lowerCase.startsWith( commandName ) && entry.getValue().hasPermission( con ) && !bungee.getDisabledCommands().contains( lowerCase );
} )
.map( (stringCommandEntry) -> '/' + stringCommandEntry.getKey() )
.collect( Collectors.toList() ) );
commands.sort( null );
con.setLastCommandTabbed( null );
}
}
TabCompleteResponseEvent tabCompleteResponseEvent = new TabCompleteResponseEvent( server, con, new ArrayList<>( commands ) );
@ -769,6 +824,17 @@ public class DownstreamBridge extends PacketHandler
throw CancelSendSignal.INSTANCE;
}
@Override
public void handle(Login login) throws Exception
{
Preconditions.checkState( !receivedLogin, "Not expecting login" );
receivedLogin = true;
ServerConnector.handleLogin( bungee, server.getCh(), con, server.getInfo(), null, server, login );
throw CancelSendSignal.INSTANCE;
}
@Override
public String toString()
{

View File

@ -59,6 +59,7 @@ 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.LoginPayloadResponse;
import net.md_5.bungee.protocol.packet.LoginRequest;
import net.md_5.bungee.protocol.packet.LoginSuccess;
@ -111,6 +112,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private boolean legacy;
@Getter
private String extraDataInHandshake = "";
private UserConnection userCon;
@Getter
private boolean duplication = false;
@ -130,12 +132,12 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private enum State
{
HANDSHAKE, STATUS, PING, USERNAME, ENCRYPT, FINISHING;
HANDSHAKE, STATUS, PING, USERNAME, ENCRYPT, FINISHING, CONFIGURING;
}
private boolean canSendKickMessage()
{
return thisState == State.USERNAME || thisState == State.ENCRYPT || thisState == State.FINISHING;
return thisState == State.USERNAME || thisState == State.ENCRYPT || thisState == State.FINISHING || thisState == State.CONFIGURING;
}
@Override
@ -620,12 +622,40 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{
if ( !ch.isClosing() )
{
UserConnection userCon = new UserConnection( bungee, ch, getName(), InitialHandler.this );
userCon = new UserConnection( bungee, ch, getName(), InitialHandler.this );
userCon.setCompressionThreshold( BungeeCord.getInstance().config.getCompressionThreshold() );
userCon.init();
unsafe.sendPacket( new LoginSuccess( getUniqueId(), getName(), ( loginProfile == null ) ? null : loginProfile.getProperties() ) );
if ( getVersion() >= ProtocolConstants.MINECRAFT_1_20_2 )
{
thisState = State.CONFIGURING;
} else
{
ch.setProtocol( Protocol.GAME );
finish2();
}
}
}
} );
}
};
// fire login event
bungee.getPluginManager().callEvent( new LoginEvent( InitialHandler.this, complete ) );
}
@Override
public void handle(LoginAcknowledged loginAcknowledged) throws Exception
{
Preconditions.checkState( thisState == State.CONFIGURING, "Not expecting CONFIGURING" );
finish2();
ch.setEncodeProtocol( Protocol.CONFIGURATION );
}
private void finish2()
{
userCon.init();
ch.getHandle().pipeline().get( HandlerBoss.class ).setHandler( new UpstreamBridge( bungee, userCon ) );
bungee.getPluginManager().callEvent( new PostLoginEvent( userCon ) );
@ -644,14 +674,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection
userCon.connect( server, null, true, ServerConnectEvent.Reason.JOIN_PROXY );
}
}
} );
}
};
// fire login event
bungee.getPluginManager().callEvent( new LoginEvent( InitialHandler.this, complete ) );
}
@Override
public void handle(LoginPayloadResponse response) throws Exception

View File

@ -25,15 +25,18 @@ import net.md_5.bungee.forge.ForgeConstants;
import net.md_5.bungee.netty.ChannelWrapper;
import net.md_5.bungee.netty.PacketHandler;
import net.md_5.bungee.protocol.PacketWrapper;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.ProtocolConstants;
import net.md_5.bungee.protocol.packet.Chat;
import net.md_5.bungee.protocol.packet.ClientChat;
import net.md_5.bungee.protocol.packet.ClientCommand;
import net.md_5.bungee.protocol.packet.ClientSettings;
import net.md_5.bungee.protocol.packet.KeepAlive;
import net.md_5.bungee.protocol.packet.LoginAcknowledged;
import net.md_5.bungee.protocol.packet.PlayerListItem;
import net.md_5.bungee.protocol.packet.PlayerListItemRemove;
import net.md_5.bungee.protocol.packet.PluginMessage;
import net.md_5.bungee.protocol.packet.StartConfiguration;
import net.md_5.bungee.protocol.packet.TabCompleteRequest;
import net.md_5.bungee.protocol.packet.TabCompleteResponse;
import net.md_5.bungee.util.AllowedCharacters;
@ -51,7 +54,6 @@ public class UpstreamBridge extends PacketHandler
BungeeCord.getInstance().addConnection( con );
con.getTabListHandler().onConnect();
con.unsafe().sendPacket( BungeeCord.getInstance().registerChannels( con.getPendingConnection().getVersion() ) );
}
@Override
@ -134,7 +136,7 @@ public class UpstreamBridge extends PacketHandler
if ( con.getServer() != null )
{
EntityMap rewrite = con.getEntityRewrite();
if ( rewrite != null )
if ( rewrite != null && con.getServer().getCh().getEncodeProtocol() == Protocol.GAME )
{
rewrite.rewriteServerbound( packet.buf, con.getClientEntityId(), con.getServerEntityId(), con.getPendingConnection().getVersion() );
}
@ -213,8 +215,9 @@ public class UpstreamBridge extends PacketHandler
{
List<String> suggestions = new ArrayList<>();
boolean isRegisteredCommand = false;
boolean isCommand = tabComplete.getCursor().startsWith( "/" );
if ( tabComplete.getCursor().startsWith( "/" ) )
if ( isCommand )
{
isRegisteredCommand = bungee.getPluginManager().dispatchCommand( con, tabComplete.getCursor().substring( 1 ), suggestions );
}
@ -267,6 +270,15 @@ public class UpstreamBridge extends PacketHandler
{
throw CancelSendSignal.INSTANCE;
}
if ( isCommand && con.getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_13 )
{
int lastSpace = tabComplete.getCursor().lastIndexOf( ' ' );
if ( lastSpace == -1 )
{
con.setLastCommandTabbed( tabComplete.getCursor().substring( 1 ) );
}
}
}
@Override
@ -319,6 +331,19 @@ public class UpstreamBridge extends PacketHandler
con.getPendingConnection().relayMessage( pluginMessage );
}
@Override
public void handle(StartConfiguration startConfiguration) throws Exception
{
ChannelWrapper ch = con.getServer().getCh();
if ( ch.getDecodeProtocol() == Protocol.LOGIN )
{
ch.setDecodeProtocol( Protocol.CONFIGURATION );
ch.write( new LoginAcknowledged() );
ch.setEncodeProtocol( Protocol.CONFIGURATION );
throw CancelSendSignal.INSTANCE;
}
}
@Override
public String toString()
{

View File

@ -82,6 +82,8 @@ public abstract class EntityMap
case ProtocolConstants.MINECRAFT_1_19_4:
case ProtocolConstants.MINECRAFT_1_20:
return EntityMap_1_16_2.INSTANCE_1_19_4;
case ProtocolConstants.MINECRAFT_1_20_2:
return EntityMap_1_16_2.INSTANCE_1_20_2;
}
throw new RuntimeException( "Version " + version + " has no entity map" );
}

View File

@ -20,6 +20,7 @@ class EntityMap_1_16_2 extends EntityMap
static final EntityMap_1_16_2 INSTANCE_1_19 = new EntityMap_1_16_2( 0x02, 0x2F );
static final EntityMap_1_16_2 INSTANCE_1_19_1 = new EntityMap_1_16_2( 0x02, 0x30 );
static final EntityMap_1_16_2 INSTANCE_1_19_4 = new EntityMap_1_16_2( 0x03, 0x30 );
static final EntityMap_1_16_2 INSTANCE_1_20_2 = new EntityMap_1_16_2( -1, 0x33 );
//
private final int spawnPlayerId;
private final int spectateId;

View File

@ -11,6 +11,7 @@ import lombok.Getter;
import lombok.Setter;
import net.md_5.bungee.compress.PacketCompressor;
import net.md_5.bungee.compress.PacketDecompressor;
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;
@ -35,12 +36,33 @@ public class ChannelWrapper
this.remoteAddress = ( this.ch.remoteAddress() == null ) ? this.ch.parent().localAddress() : this.ch.remoteAddress();
}
public void setProtocol(Protocol protocol)
public Protocol getDecodeProtocol()
{
return ch.pipeline().get( MinecraftDecoder.class ).getProtocol();
}
public void setDecodeProtocol(Protocol protocol)
{
ch.pipeline().get( MinecraftDecoder.class ).setProtocol( protocol );
}
public Protocol getEncodeProtocol()
{
return ch.pipeline().get( MinecraftEncoder.class ).getProtocol();
}
public void setEncodeProtocol(Protocol protocol)
{
ch.pipeline().get( MinecraftEncoder.class ).setProtocol( protocol );
}
public void setProtocol(Protocol protocol)
{
setDecodeProtocol( protocol );
setEncodeProtocol( protocol );
}
public void setVersion(int protocol)
{
ch.pipeline().get( MinecraftDecoder.class ).setProtocolVersion( protocol );
@ -51,13 +73,29 @@ public class ChannelWrapper
{
if ( !closed )
{
DefinedPacket defined = null;
if ( packet instanceof PacketWrapper )
{
( (PacketWrapper) packet ).setReleased( true );
ch.writeAndFlush( ( (PacketWrapper) packet ).buf, ch.voidPromise() );
PacketWrapper wrapper = (PacketWrapper) packet;
wrapper.setReleased( true );
ch.writeAndFlush( wrapper.buf, ch.voidPromise() );
defined = wrapper.packet;
} else
{
ch.writeAndFlush( packet, ch.voidPromise() );
if ( packet instanceof DefinedPacket )
{
defined = (DefinedPacket) packet;
}
}
if ( defined != null )
{
Protocol nextProtocol = defined.nextProtocol();
if ( nextProtocol != null )
{
setEncodeProtocol( nextProtocol );
}
}
}
}
@ -124,11 +162,11 @@ public class ChannelWrapper
public void setCompressionThreshold(int compressionThreshold)
{
if ( ch.pipeline().get( PacketCompressor.class ) == null && compressionThreshold != -1 )
if ( ch.pipeline().get( PacketCompressor.class ) == null && compressionThreshold >= 0 )
{
addBefore( PipelineUtils.PACKET_ENCODER, "compress", new PacketCompressor() );
}
if ( compressionThreshold != -1 )
if ( compressionThreshold >= 0 )
{
ch.pipeline().get( PacketCompressor.class ).setThreshold( compressionThreshold );
} else
@ -136,11 +174,11 @@ public class ChannelWrapper
ch.pipeline().remove( "compress" );
}
if ( ch.pipeline().get( PacketDecompressor.class ) == null && compressionThreshold != -1 )
if ( ch.pipeline().get( PacketDecompressor.class ) == null && compressionThreshold >= 0 )
{
addBefore( PipelineUtils.PACKET_DECODER, "decompress", new PacketDecompressor() );
}
if ( compressionThreshold == -1 )
if ( compressionThreshold < 0 )
{
ch.pipeline().remove( "decompress" );
}

View File

@ -17,6 +17,7 @@ import net.md_5.bungee.connection.PingHandler;
import net.md_5.bungee.protocol.BadPacketException;
import net.md_5.bungee.protocol.OverflowPacketException;
import net.md_5.bungee.protocol.PacketWrapper;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.util.QuietException;
/**
@ -101,9 +102,18 @@ public class HandlerBoss extends ChannelInboundHandlerAdapter
return;
}
PacketWrapper packet = (PacketWrapper) msg;
if ( packet.packet != null )
{
Protocol nextProtocol = packet.packet.nextProtocol();
if ( nextProtocol != null )
{
channel.setDecodeProtocol( nextProtocol );
}
}
if ( handler != null )
{
PacketWrapper packet = (PacketWrapper) msg;
boolean sendPacket = handler.shouldHandle( packet );
try
{

View File

@ -6,12 +6,12 @@
<parent>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>bungeecord-query</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-Query</name>

View File

@ -6,12 +6,12 @@
<parent>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>bungeecord-slf4j</artifactId>
<version>1.20-R0.1-SNAPSHOT</version>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>BungeeCord-SLF4J</name>