Compare commits

...

11 Commits

Author SHA1 Message Date
cf36174de7 new event TabCompleteRequestEvent and deprecate TabCompleteEvent 2023-09-24 00:59:54 +02:00
b7f0cc4217 Add CommandsDeclareEvent to declare commands with brigadier API 2023-09-24 00:59:54 +02:00
a0f6d000ec Server branding now includes the backend server name 2023-09-24 00:59:54 +02:00
ca3323c00f 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-24 00:59:54 +02:00
f52180c385 Change projet configuration and POM for Pandacube 2023-09-24 00:59:54 +02:00
949cde9e2b Remove modules and startup delay
We don’t need them for Pandacube
2023-09-24 00:59:54 +02:00
md_5
497c6879e0
Add (hopefully temporary) queue for plugin messages to server 2023-09-24 06:50:46 +10:00
md_5
7b27dfaf5e
#3522: Revert "#3518: Bump io.netty:netty-bom from 4.1.97.Final to 4.1.98.Final"
This reverts commit f486a251f3.
2023-09-24 06:25:28 +10:00
md_5
f9b75c4a3a
Update tests to JUnit 5 2023-09-23 18:44:14 +10:00
md_5
0509303fd3
#3519: Queue configuration phase packets from API methods 2023-09-23 10:29:09 +10:00
dependabot[bot]
f486a251f3
#3518: Bump io.netty:netty-bom from 4.1.97.Final to 4.1.98.Final
Bumps [io.netty:netty-bom](https://github.com/netty/netty) from 4.1.97.Final to 4.1.98.Final.
- [Commits](https://github.com/netty/netty/compare/netty-4.1.97.Final...netty-4.1.98.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-09-22 08:18:54 +10:00
87 changed files with 1405 additions and 2020 deletions

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId> <artifactId>bungeecord-api</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -20,25 +19,25 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-chat</artifactId> <artifactId>bungeecord-chat</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-config</artifactId> <artifactId>bungeecord-config</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-event</artifactId> <artifactId>bungeecord-event</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-protocol</artifactId> <artifactId>bungeecord-protocol</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>

View File

@ -0,0 +1,157 @@
package net.md_5.bungee.api.event;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.suggestion.SuggestionProvider;
import com.mojang.brigadier.tree.CommandNode;
import com.mojang.brigadier.tree.RootCommandNode;
import lombok.AccessLevel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Setter;
import lombok.ToString;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.Connection;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.plugin.PluginManager;
import net.md_5.bungee.api.plugin.TabExecutor;
/**
* Event called when a downstream server (on 1.13+) sends the command structure
* to a player, but before BungeeCord adds the dummy command nodes of
* registered commands.
* <p>
* BungeeCord will not overwrite the modifications made by the listeners.
*
* <h2>Usage example</h2>
* Here is a usage example of this event, to declare a command structure.
* This illustrates the commands /server and /send of Bungee.
* <pre>
* event.getRoot().addChild( LiteralArgumentBuilder.&lt;CommandSender&gt;literal( "server" )
* .requires( sender -&gt; sender.hasPermission( "bungeecord.command.server" ) )
* .executes( a -&gt; 0 )
* .then( RequiredArgumentBuilder.argument( "serverName", StringArgumentType.greedyString() )
* .suggests( SuggestionRegistry.ASK_SERVER )
* )
* .build()
* );
* event.getRoot().addChild( LiteralArgumentBuilder.&lt;CommandSender&gt;literal( "send" )
* .requires( sender -&gt; sender.hasPermission( "bungeecord.command.send" ) )
* .then( RequiredArgumentBuilder.argument( "playerName", StringArgumentType.word() )
* .suggests( SuggestionRegistry.ASK_SERVER )
* .then( RequiredArgumentBuilder.argument( "serverName", StringArgumentType.greedyString() )
* .suggests( SuggestionRegistry.ASK_SERVER )
* )
* )
* .build()
* );
* </pre>
*
* <h2>Flag a {@link CommandNode} as executable or not</h2>
* The implementation of a {@link com.mojang.brigadier.Command Command} used in
* {@link ArgumentBuilder#executes(com.mojang.brigadier.Command)} will never be
* executed. This will only tell to the client if the current node is
* executable or not.
* <ul>
* <li>
* {@code builder.executes(null)} (default) to mark the node as not
* executable.
* </li>
* <li>
* {@code builder.executes(a -> 0)}, or any non null argument, to mark
* the node as executable (the child arguments are displayed as
* optional).
* </li>
* </ul>
*
* <h2>{@link CommandNode}s suggestions management</h2>
* The implementation of a SuggestionProvider used in
* {@link RequiredArgumentBuilder#suggests(SuggestionProvider)} will never be
* executed. This will only tell to the client how to deal with the
* auto-completion of the argument.
* <ul>
* <li>
* {@code builder.suggests(null)} (default) to disable auto-completion
* for this argument.
* </li>
* <li>
* {@code builder.suggests(SuggestionRegistry.ALL_RECIPES)} to suggest
* Minecrafts recipes.
* </li>
* <li>
* {@code builder.suggests(SuggestionRegistry.AVAILABLE_SOUNDS)} to
* suggest Minecrafts default sound identifiers.
* </li>
* <li>
* {@code builder.suggests(SuggestionRegistry.SUMMONABLE_ENTITIES)} to
* suggest Minecrafts default summonable entities identifiers.
* </li>
* <li>
* {@code builder.suggests(SuggestionRegistry.ASK_SERVER)}, or any
* other non null argument, to make the Minecraft client ask
* auto-completion to the server. Any specified implementation of
* {@link SuggestionProvider} will never be executed.
* </li>
* </ul>
*
* <h2>Argument types</h2>
* When building a new argument command node using
* {@link RequiredArgumentBuilder#argument(String, ArgumentType)}, you have to
* specify an {@link ArgumentType}. You can use all subclasses of
* {@link ArgumentType} provided with brigadier (for instance,
* {@link StringArgumentType} or {@link IntegerArgumentType}), or call any
* {@code ArgumentRegistry.minecraft*()} methods to use a {@code minecraft:*}
* argument type.
*
* <h2>Limitations with brigadier API</h2>
* This event is only used for the client to show command syntax, suggest
* sub-commands and color the arguments in the chat box. The command execution
* needs to be implemented using {@link PluginManager#registerCommand(Plugin,
* Command)} and the server-side tab-completion using {@link TabCompleteEvent}
* or {@link TabExecutor}.
*/
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class CommandsDeclareEvent extends TargetedEvent
{
/**
* Wether or not the command tree is modified by this event.
*
* If this value is set to true, BungeeCord will ensure that the
* modifications made in the command tree, will be sent to the player.
* If this is false, the modifications may not be taken into account.
*
* When calling {@link #getRoot()}, this value is automatically set
* to true.
*/
@Setter(value = AccessLevel.NONE)
private boolean modified = false;
/**
* The root command node of the command structure that will be send to the
* player.
*/
private final RootCommandNode<CommandSender> root;
public CommandsDeclareEvent(Connection sender, Connection receiver, RootCommandNode<CommandSender> root)
{
super( sender, receiver );
this.root = root;
}
/**
* The root command node of the command structure that will be send to the
* player.
* @return The root command node
*/
public RootCommandNode<CommandSender> getRoot()
{
modified = true;
return root;
}
}

View File

@ -9,7 +9,9 @@ import net.md_5.bungee.api.plugin.Cancellable;
/** /**
* Event called when a player uses tab completion. * Event called when a player uses tab completion.
* @deprecated please use {@link TabCompleteRequestEvent} to support 1.13+ suggestions.
*/ */
@Deprecated
@Data @Data
@ToString(callSuper = true) @ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)

View File

@ -0,0 +1,85 @@
package net.md_5.bungee.api.event;
import com.google.common.base.Preconditions;
import com.mojang.brigadier.context.StringRange;
import com.mojang.brigadier.suggestion.Suggestions;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import net.md_5.bungee.api.connection.Connection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Cancellable;
import net.md_5.bungee.protocol.ProtocolConstants;
/**
* Event called when a player uses tab completion.
*/
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class TabCompleteRequestEvent extends TargetedEvent implements Cancellable
{
/**
* Cancelled state.
*/
private boolean cancelled;
/**
* The message the player has already entered.
*/
private final String cursor;
/**
* Range corresponding to the last word of {@link #getCursor()}.
* If you want your suggestions to be compatible with 1.12 and older
* clients, you need to {@link #setSuggestions(Suggestions)} with
* a range equals to this one.
* For 1.13 and newer clients, any other range that cover any part of
* {@link #getCursor()} is fine.<br>
* To check if the client supports custom ranges, use
* {@link #supportsCustomRange()}.
*/
private final StringRange legacyCompatibleRange;
/**
* The suggestions that will be sent to the client. If this list is empty,
* the request will be forwarded to the server.
*/
private Suggestions suggestions;
public TabCompleteRequestEvent(Connection sender, Connection receiver, String cursor, StringRange legacyCompatibleRange, Suggestions suggestions)
{
super( sender, receiver );
this.cursor = cursor;
this.legacyCompatibleRange = legacyCompatibleRange;
this.suggestions = suggestions;
}
/**
* Sets the suggestions that will be sent to the client.
* If this list is empty, the request will be forwarded to the server.
* @param suggestions the new Suggestions. Cannot be null.
* @throws IllegalArgumentException if the client is on 1.12 or lower and
* {@code suggestions.getRange()} is not equals to {@link #legacyCompatibleRange}.
*/
public void setSuggestions(Suggestions suggestions)
{
Preconditions.checkNotNull( suggestions );
Preconditions.checkArgument( supportsCustomRange() || legacyCompatibleRange.equals( suggestions.getRange() ),
"Clients on 1.12 or lower versions don't support the provided range for tab-completion: " + suggestions.getRange()
+ ". Please use TabCompleteRequestEvent.getLegacyCompatibleRange() for legacy clients." );
this.suggestions = suggestions;
}
/**
* Convenient method to tell if the client supports custom range for
* suggestions.
* If the client is on 1.13 or above, this methods returns true, and any
* range can be used for {@link #setSuggestions(Suggestions)}. Otherwise,
* it returns false and the defined range must be equals to
* {@link #legacyCompatibleRange}.
* @return true if the client is on 1.13 or newer version, false otherwise.
*/
public boolean supportsCustomRange()
{
return ( (ProxiedPlayer) getSender() ).getPendingConnection().getVersion() >= ProtocolConstants.MINECRAFT_1_13;
}
}

View File

@ -1,12 +1,13 @@
package net.md_5.bungee.api; package net.md_5.bungee.api;
import static org.junit.jupiter.api.Assertions.*;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.Collection; import java.util.Collection;
import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerConnectEvent;
import org.junit.Test; import org.junit.jupiter.api.Test;
public class ServerConnectRequestTest public class ServerConnectRequestTest
{ {
@ -78,15 +79,15 @@ public class ServerConnectRequestTest
} }
}; };
@Test(expected = NullPointerException.class) @Test
public void testNullTarget() public void testNullTarget()
{ {
ServerConnectRequest.builder().target( null ).reason( ServerConnectEvent.Reason.JOIN_PROXY ).build(); assertThrows( NullPointerException.class, () -> ServerConnectRequest.builder().target( null ).reason( ServerConnectEvent.Reason.JOIN_PROXY ).build() );
} }
@Test(expected = NullPointerException.class) @Test
public void testNullReason() public void testNullReason()
{ {
ServerConnectRequest.builder().target( DUMMY_INFO ).reason( null ).build(); assertThrows( NullPointerException.class, () -> ServerConnectRequest.builder().target( DUMMY_INFO ).reason( null ).build() );
} }
} }

View File

@ -1,63 +1,38 @@
package net.md_5.bungee.util; package net.md_5.bungee.util;
import static org.junit.jupiter.api.Assertions.*;
import io.netty.channel.unix.DomainSocketAddress; import io.netty.channel.unix.DomainSocketAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.Arrays; import java.util.stream.Stream;
import java.util.Collection;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import net.md_5.bungee.Util; import net.md_5.bungee.Util;
import org.junit.Assert; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.Test; import org.junit.jupiter.params.provider.Arguments;
import org.junit.runner.RunWith; import org.junit.jupiter.params.provider.MethodSource;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RequiredArgsConstructor @RequiredArgsConstructor
@RunWith(Parameterized.class)
public class AddressParseTest public class AddressParseTest
{ {
@Parameters public static Stream<Arguments> data()
public static Collection<Object[]> data()
{ {
return Arrays.asList( new Object[][] return Stream.of(
{ Arguments.of( "127.0.0.1", "127.0.0.1", Util.DEFAULT_PORT ),
{ Arguments.of( "127.0.0.1:1337", "127.0.0.1", 1337 ),
"127.0.0.1", "127.0.0.1", Util.DEFAULT_PORT Arguments.of( "[::1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT ),
}, Arguments.of( "[0:0:0:0::1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT ),
{ Arguments.of( "[0:0:0:0:0:0:0:1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT ),
"127.0.0.1:1337", "127.0.0.1", 1337 Arguments.of( "[::1]:1337", "0:0:0:0:0:0:0:1", 1337 ),
}, Arguments.of( "[0:0:0:0::1]:1337", "0:0:0:0:0:0:0:1", 1337 ),
{ Arguments.of( "[0:0:0:0:0:0:0:1]:1337", "0:0:0:0:0:0:0:1", 1337 ),
"[::1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT Arguments.of( "unix:///var/run/bungee.sock", "/var/run/bungee.sock", -1 )
}, );
{
"[0:0:0:0::1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT
},
{
"[0:0:0:0:0:0:0:1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT
},
{
"[::1]:1337", "0:0:0:0:0:0:0:1", 1337
},
{
"[0:0:0:0::1]:1337", "0:0:0:0:0:0:0:1", 1337
},
{
"[0:0:0:0:0:0:0:1]:1337", "0:0:0:0:0:0:0:1", 1337
},
{
"unix:///var/run/bungee.sock", "/var/run/bungee.sock", -1
} }
} );
}
private final String line;
private final String host;
private final int port;
@Test @ParameterizedTest
public void test() @MethodSource("data")
public void test(String line, String host, int port)
{ {
SocketAddress parsed = Util.getAddr( line ); SocketAddress parsed = Util.getAddr( line );
@ -65,14 +40,14 @@ public class AddressParseTest
{ {
InetSocketAddress tcp = (InetSocketAddress) parsed; InetSocketAddress tcp = (InetSocketAddress) parsed;
Assert.assertEquals( host, tcp.getHostString() ); assertEquals( host, tcp.getHostString() );
Assert.assertEquals( port, tcp.getPort() ); assertEquals( port, tcp.getPort() );
} else if ( parsed instanceof DomainSocketAddress ) } else if ( parsed instanceof DomainSocketAddress )
{ {
DomainSocketAddress unix = (DomainSocketAddress) parsed; DomainSocketAddress unix = (DomainSocketAddress) parsed;
Assert.assertEquals( host, unix.path() ); assertEquals( host, unix.path() );
Assert.assertEquals( -1, port ); assertEquals( -1, port );
} else } else
{ {
throw new AssertionError( "Unknown socket " + parsed ); throw new AssertionError( "Unknown socket " + parsed );

View File

@ -1,7 +1,7 @@
package net.md_5.bungee.util; package net.md_5.bungee.util;
import org.junit.Assert; import static org.junit.jupiter.api.Assertions.*;
import org.junit.Test; import org.junit.jupiter.api.Test;
public class CaseInsensitiveTest public class CaseInsensitiveTest
{ {
@ -13,12 +13,12 @@ public class CaseInsensitiveTest
CaseInsensitiveMap<Object> map = new CaseInsensitiveMap<>(); CaseInsensitiveMap<Object> map = new CaseInsensitiveMap<>();
map.put( "FOO", obj ); map.put( "FOO", obj );
Assert.assertTrue( map.contains( "foo" ) ); // Assert that contains is case insensitive assertTrue( map.contains( "foo" ) ); // Assert that contains is case insensitive
Assert.assertTrue( map.entrySet().iterator().next().getKey().equals( "FOO" ) ); // Assert that case is preserved assertTrue( map.entrySet().iterator().next().getKey().equals( "FOO" ) ); // Assert that case is preserved
// Assert that remove is case insensitive // Assert that remove is case insensitive
map.remove( "FoO" ); map.remove( "FoO" );
Assert.assertFalse( map.contains( "foo" ) ); assertFalse( map.contains( "foo" ) );
} }
@Test @Test
@ -27,8 +27,8 @@ public class CaseInsensitiveTest
CaseInsensitiveSet set = new CaseInsensitiveSet(); CaseInsensitiveSet set = new CaseInsensitiveSet();
set.add( "FOO" ); set.add( "FOO" );
Assert.assertTrue( set.contains( "foo" ) ); // Assert that contains is case insensitive assertTrue( set.contains( "foo" ) ); // Assert that contains is case insensitive
set.remove( "FoO" ); set.remove( "FoO" );
Assert.assertFalse( set.contains( "foo" ) ); // Assert that remove is case insensitive assertFalse( set.contains( "foo" ) ); // Assert that remove is case insensitive
} }
} }

View File

@ -1,9 +1,9 @@
package net.md_5.bungee.util; package net.md_5.bungee.util;
import static org.junit.jupiter.api.Assertions.*;
import java.util.UUID; import java.util.UUID;
import net.md_5.bungee.Util; import net.md_5.bungee.Util;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Test;
public class UUIDTest public class UUIDTest
{ {
@ -13,7 +13,7 @@ public class UUIDTest
{ {
UUID uuid = UUID.fromString( "af74a02d-19cb-445b-b07f-6866a861f783" ); UUID uuid = UUID.fromString( "af74a02d-19cb-445b-b07f-6866a861f783" );
UUID uuid1 = Util.getUUID( "af74a02d19cb445bb07f6866a861f783" ); UUID uuid1 = Util.getUUID( "af74a02d19cb445bb07f6866a861f783" );
Assert.assertEquals( uuid, uuid1 ); assertEquals( uuid, uuid1 );
} }
@Test @Test
@ -23,7 +23,7 @@ public class UUIDTest
{ {
UUID expected = UUID.randomUUID(); UUID expected = UUID.randomUUID();
UUID actual = Util.getUUID( expected.toString().replace( "-", "" ) ); UUID actual = Util.getUUID( expected.toString().replace( "-", "" ) );
Assert.assertEquals( "Could not parse UUID " + expected, expected, actual ); assertEquals( expected, actual, "Could not parse UUID " + expected );
} }
} }
} }

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-bootstrap</artifactId> <artifactId>bungeecord-bootstrap</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -21,14 +20,12 @@
<properties> <properties>
<maven.deploy.skip>true</maven.deploy.skip> <maven.deploy.skip>true</maven.deploy.skip>
<maven.javadoc.skip>true</maven.javadoc.skip> <maven.javadoc.skip>true</maven.javadoc.skip>
<maven.compiler.source>1.6</maven.compiler.source>
<maven.compiler.target>1.6</maven.compiler.target>
<maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format> <maven.build.timestamp.format>yyyyMMdd</maven.build.timestamp.format>
</properties> </properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-proxy</artifactId> <artifactId>bungeecord-proxy</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-chat</artifactId> <artifactId>bungeecord-chat</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,5 +1,6 @@
package net.md_5.bungee.api.chat; package net.md_5.bungee.api.chat;
import static org.junit.jupiter.api.Assertions.*;
import java.awt.Color; import java.awt.Color;
import java.util.function.BiFunction; import java.util.function.BiFunction;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -10,8 +11,7 @@ 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.Item;
import net.md_5.bungee.api.chat.hover.content.Text; import net.md_5.bungee.api.chat.hover.content.Text;
import net.md_5.bungee.chat.ComponentSerializer; import net.md_5.bungee.chat.ComponentSerializer;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Test;
public class ComponentsTest public class ComponentsTest
{ {
@ -20,14 +20,14 @@ public class ComponentsTest
{ {
String json = ComponentSerializer.toString( components ); String json = ComponentSerializer.toString( components );
BaseComponent[] parsed = ComponentSerializer.parse( json ); BaseComponent[] parsed = ComponentSerializer.parse( json );
Assert.assertEquals( TextComponent.toLegacyText( parsed ), TextComponent.toLegacyText( components ) ); assertEquals( TextComponent.toLegacyText( parsed ), TextComponent.toLegacyText( components ) );
} }
public static void testDissembleReassemble(BaseComponent component) public static void testDissembleReassemble(BaseComponent component)
{ {
String json = ComponentSerializer.toString( component ); String json = ComponentSerializer.toString( component );
BaseComponent[] parsed = ComponentSerializer.parse( json ); BaseComponent[] parsed = ComponentSerializer.parse( json );
Assert.assertEquals( TextComponent.toLegacyText( parsed ), TextComponent.toLegacyText( component ) ); assertEquals( TextComponent.toLegacyText( parsed ), TextComponent.toLegacyText( component ) );
} }
public static void testAssembleDissemble(String json, boolean modern) public static void testAssembleDissemble(String json, boolean modern)
@ -35,11 +35,11 @@ public class ComponentsTest
if ( modern ) if ( modern )
{ {
BaseComponent deserialized = ComponentSerializer.deserialize( json ); BaseComponent deserialized = ComponentSerializer.deserialize( json );
Assert.assertEquals( json, ComponentSerializer.toString( deserialized ) ); assertEquals( json, ComponentSerializer.toString( deserialized ) );
} else } else
{ {
BaseComponent[] parsed = ComponentSerializer.parse( json ); BaseComponent[] parsed = ComponentSerializer.parse( json );
Assert.assertEquals( json, ComponentSerializer.toString( parsed ) ); assertEquals( json, ComponentSerializer.toString( parsed ) );
} }
} }
@ -69,7 +69,7 @@ public class ComponentsTest
json = "{\"extra\":[{\"text\":\"[\"},{\"extra\":[{\"translate\":\"block.minecraft.dirt\"}],\"text\":\"\"},{\"text\":\"]\"}],\"hoverEvent\":{\"action\":\"show_item\",\"value\":[" + hoverVal + "]},\"text\":\"\"}"; json = "{\"extra\":[{\"text\":\"[\"},{\"extra\":[{\"translate\":\"block.minecraft.dirt\"}],\"text\":\"\"},{\"text\":\"]\"}],\"hoverEvent\":{\"action\":\"show_item\",\"value\":[" + hoverVal + "]},\"text\":\"\"}";
components = ComponentSerializer.parse( json ); components = ComponentSerializer.parse( json );
Text contentText = ( (Text) components[0].getHoverEvent().getContents().get( 0 ) ); Text contentText = ( (Text) components[0].getHoverEvent().getContents().get( 0 ) );
Assert.assertEquals( hoverVal, ComponentSerializer.toString( (BaseComponent[]) contentText.getValue() ) ); assertEquals( hoverVal, ComponentSerializer.toString( (BaseComponent[]) contentText.getValue() ) );
testDissembleReassemble( components ); testDissembleReassemble( components );
////////// //////////
TextComponent component1 = new TextComponent( "HoverableText" ); TextComponent component1 = new TextComponent( "HoverableText" );
@ -80,10 +80,10 @@ public class ComponentsTest
json = ComponentSerializer.toString( component1 ); json = ComponentSerializer.toString( component1 );
components = ComponentSerializer.parse( json ); components = ComponentSerializer.parse( json );
Item parsedContentItem = ( (Item) components[0].getHoverEvent().getContents().get( 0 ) ); Item parsedContentItem = ( (Item) components[0].getHoverEvent().getContents().get( 0 ) );
Assert.assertEquals( contentItem, parsedContentItem ); assertEquals( contentItem, parsedContentItem );
Assert.assertEquals( contentItem.getCount(), parsedContentItem.getCount() ); assertEquals( contentItem.getCount(), parsedContentItem.getCount() );
Assert.assertEquals( contentItem.getId(), parsedContentItem.getId() ); assertEquals( contentItem.getId(), parsedContentItem.getId() );
Assert.assertEquals( nbt, parsedContentItem.getTag().getNbt() ); assertEquals( nbt, parsedContentItem.getTag().getNbt() );
} }
@Test @Test
@ -91,8 +91,8 @@ public class ComponentsTest
{ {
this.testEmptyComponentBuilder( this.testEmptyComponentBuilder(
ComponentBuilder::create, ComponentBuilder::create,
(components) -> Assert.assertEquals( components.length, 0 ), (components) -> assertEquals( components.length, 0 ),
(components, size) -> Assert.assertEquals( size, components.length ) (components, size) -> assertEquals( size, components.length )
); );
} }
@ -101,8 +101,8 @@ public class ComponentsTest
{ {
this.testEmptyComponentBuilder( this.testEmptyComponentBuilder(
ComponentBuilder::build, ComponentBuilder::build,
(component) -> Assert.assertNull( component.getExtra() ), (component) -> assertNull( component.getExtra() ),
(component, size) -> Assert.assertEquals( component.getExtra().size(), size ) (component, size) -> assertEquals( component.getExtra().size(), size )
); );
} }
@ -125,23 +125,23 @@ public class ComponentsTest
public void testDummyRetaining() public void testDummyRetaining()
{ {
ComponentBuilder builder = new ComponentBuilder(); ComponentBuilder builder = new ComponentBuilder();
Assert.assertNotNull( builder.getCurrentComponent() ); assertNotNull( builder.getCurrentComponent() );
builder.color( ChatColor.GREEN ); builder.color( ChatColor.GREEN );
builder.append( "test ", ComponentBuilder.FormatRetention.ALL ); builder.append( "test ", ComponentBuilder.FormatRetention.ALL );
Assert.assertEquals( builder.getCurrentComponent().getColor(), ChatColor.GREEN ); assertEquals( builder.getCurrentComponent().getColor(), ChatColor.GREEN );
} }
@Test(expected = IndexOutOfBoundsException.class) @Test
public void testComponentGettingExceptions() public void testComponentGettingExceptions()
{ {
ComponentBuilder builder = new ComponentBuilder(); ComponentBuilder builder = new ComponentBuilder();
builder.getComponent( -1 ); assertThrows( IndexOutOfBoundsException.class, () -> builder.getComponent( -1 ) );
builder.getComponent( 0 ); assertThrows( IndexOutOfBoundsException.class, () -> builder.getComponent( 0 ) );
builder.getComponent( 1 ); assertThrows( IndexOutOfBoundsException.class, () -> builder.getComponent( 1 ) );
BaseComponent component = new TextComponent( "Hello" ); BaseComponent component = new TextComponent( "Hello" );
builder.append( component ); builder.append( component );
Assert.assertEquals( builder.getComponent( 0 ), component ); assertEquals( builder.getComponent( 0 ), component );
builder.getComponent( 1 ); assertThrows( IndexOutOfBoundsException.class, () -> builder.getComponent( 1 ) );
} }
@Test @Test
@ -150,33 +150,33 @@ public class ComponentsTest
ComponentBuilder builder = new ComponentBuilder(); ComponentBuilder builder = new ComponentBuilder();
TextComponent apple = new TextComponent( "apple" ); TextComponent apple = new TextComponent( "apple" );
builder.append( apple ); builder.append( apple );
Assert.assertEquals( builder.getCurrentComponent(), apple ); assertEquals( builder.getCurrentComponent(), apple );
Assert.assertEquals( builder.getComponent( 0 ), apple ); assertEquals( builder.getComponent( 0 ), apple );
TextComponent mango = new TextComponent( "mango" ); TextComponent mango = new TextComponent( "mango" );
TextComponent orange = new TextComponent( "orange" ); TextComponent orange = new TextComponent( "orange" );
builder.append( mango ); builder.append( mango );
builder.append( orange ); builder.append( orange );
builder.removeComponent( 1 ); // Removing mango builder.removeComponent( 1 ); // Removing mango
Assert.assertEquals( builder.getComponent( 0 ), apple ); assertEquals( builder.getComponent( 0 ), apple );
Assert.assertEquals( builder.getComponent( 1 ), orange ); assertEquals( builder.getComponent( 1 ), orange );
} }
@Test @Test
public void testToLegacyFromLegacy() public void testToLegacyFromLegacy()
{ {
String text = "§a§lHello §f§kworld§7!"; String text = "§a§lHello §f§kworld§7!";
Assert.assertEquals( text, TextComponent.toLegacyText( TextComponent.fromLegacyText( text ) ) ); assertEquals( text, TextComponent.toLegacyText( TextComponent.fromLegacyText( text ) ) );
} }
@Test(expected = IndexOutOfBoundsException.class) @Test
public void testComponentBuilderCursorInvalidPos() public void testComponentBuilderCursorInvalidPos()
{ {
ComponentBuilder builder = new ComponentBuilder(); ComponentBuilder builder = new ComponentBuilder();
builder.append( new TextComponent( "Apple, " ) ); builder.append( new TextComponent( "Apple, " ) );
builder.append( new TextComponent( "Orange, " ) ); builder.append( new TextComponent( "Orange, " ) );
builder.setCursor( -1 ); assertThrows( IndexOutOfBoundsException.class, () -> builder.setCursor( -1 ) );
builder.setCursor( 2 ); assertThrows( IndexOutOfBoundsException.class, () -> builder.setCursor( 2 ) );
} }
@Test @Test
@ -184,24 +184,24 @@ public class ComponentsTest
{ {
TextComponent t1, t2, t3; TextComponent t1, t2, t3;
ComponentBuilder builder = new ComponentBuilder(); ComponentBuilder builder = new ComponentBuilder();
Assert.assertEquals( builder.getCursor(), -1 ); assertEquals( builder.getCursor(), -1 );
builder.append( t1 = new TextComponent( "Apple, " ) ); builder.append( t1 = new TextComponent( "Apple, " ) );
Assert.assertEquals( builder.getCursor(), 0 ); assertEquals( builder.getCursor(), 0 );
builder.append( t2 = new TextComponent( "Orange, " ) ); builder.append( t2 = new TextComponent( "Orange, " ) );
builder.append( t3 = new TextComponent( "Mango, " ) ); builder.append( t3 = new TextComponent( "Mango, " ) );
Assert.assertEquals( builder.getCursor(), 2 ); assertEquals( builder.getCursor(), 2 );
builder.setCursor( 0 ); builder.setCursor( 0 );
Assert.assertEquals( builder.getCurrentComponent(), t1 ); assertEquals( builder.getCurrentComponent(), t1 );
// Test that appending new components updates the position to the new list size // Test that appending new components updates the position to the new list size
// after having previously set it to 0 (first component) // after having previously set it to 0 (first component)
builder.append( new TextComponent( "and Grapefruit" ) ); builder.append( new TextComponent( "and Grapefruit" ) );
Assert.assertEquals( builder.getCursor(), 3 ); assertEquals( builder.getCursor(), 3 );
builder.setCursor( 0 ); builder.setCursor( 0 );
builder.resetCursor(); builder.resetCursor();
Assert.assertEquals( builder.getCursor(), 3 ); assertEquals( builder.getCursor(), 3 );
} }
@Test @Test
@ -210,7 +210,7 @@ public class ComponentsTest
String text = "§a§lHello §r§kworld§7!"; String text = "§a§lHello §r§kworld§7!";
BaseComponent[] components = TextComponent.fromLegacyText( text ); BaseComponent[] components = TextComponent.fromLegacyText( text );
BaseComponent[] builderComponents = new ComponentBuilder().append( components ).create(); BaseComponent[] builderComponents = new ComponentBuilder().append( components ).create();
Assert.assertArrayEquals( components, builderComponents ); assertArrayEquals( components, builderComponents );
} }
/* /*
@ -232,7 +232,7 @@ public class ComponentsTest
component.setHoverEvent( event ); component.setHoverEvent( event );
String serialised = ComponentSerializer.toString( component ); String serialised = ComponentSerializer.toString( component );
BaseComponent[] deserialised = ComponentSerializer.parse( serialised ); BaseComponent[] deserialised = ComponentSerializer.parse( serialised );
Assert.assertEquals( TextComponent.toLegacyText( deserialised ), TextComponent.toLegacyText( component ) ); assertEquals( TextComponent.toLegacyText( deserialised ), TextComponent.toLegacyText( component ) );
} }
*/ */
@ -247,9 +247,9 @@ public class ComponentsTest
); );
TextComponent component = new TextComponent( "test" ); TextComponent component = new TextComponent( "test" );
component.setHoverEvent( hoverEvent ); component.setHoverEvent( hoverEvent );
Assert.assertEquals( component.getHoverEvent().getContents().size(), 1 ); assertEquals( component.getHoverEvent().getContents().size(), 1 );
Assert.assertTrue( component.getHoverEvent().getContents().get( 0 ) instanceof Text ); assertTrue( component.getHoverEvent().getContents().get( 0 ) instanceof Text );
Assert.assertEquals( ( (Text) component.getHoverEvent().getContents().get( 0 ) ).getValue(), advancement ); assertEquals( ( (Text) component.getHoverEvent().getContents().get( 0 ) ).getValue(), advancement );
} }
@Test @Test
@ -274,11 +274,11 @@ public class ComponentsTest
TextComponent component = new TextComponent( "Sample text" ); TextComponent component = new TextComponent( "Sample text" );
component.setHoverEvent( hoverEvent ); component.setHoverEvent( hoverEvent );
Assert.assertEquals( hoverEvent.getContents().size(), 1 ); assertEquals( hoverEvent.getContents().size(), 1 );
Assert.assertTrue( hoverEvent.isLegacy() ); assertTrue( hoverEvent.isLegacy() );
String serialized = ComponentSerializer.toString( component ); String serialized = ComponentSerializer.toString( component );
BaseComponent[] deserialized = ComponentSerializer.parse( serialized ); BaseComponent[] deserialized = ComponentSerializer.parse( serialized );
Assert.assertEquals( component.getHoverEvent(), deserialized[0].getHoverEvent() ); assertEquals( component.getHoverEvent(), deserialized[0].getHoverEvent() );
} }
@Test @Test
@ -303,12 +303,12 @@ public class ComponentsTest
{ {
TextComponent component = new TextComponent( "Sample text" ); TextComponent component = new TextComponent( "Sample text" );
component.setHoverEvent( hoverEvent ); component.setHoverEvent( hoverEvent );
Assert.assertEquals( hoverEvent.getContents().size(), 2 ); assertEquals( hoverEvent.getContents().size(), 2 );
Assert.assertFalse( hoverEvent.isLegacy() ); assertFalse( hoverEvent.isLegacy() );
String serialized = ComponentSerializer.toString( component ); String serialized = ComponentSerializer.toString( component );
T deserialized = deserializer.apply( serialized ); T deserialized = deserializer.apply( serialized );
Assert.assertEquals( component.getHoverEvent(), hoverEventGetter.apply( deserialized ) ); assertEquals( component.getHoverEvent(), hoverEventGetter.apply( deserialized ) );
// Test single content: // Test single content:
String json = "{\"italic\":true,\"color\":\"gray\",\"translate\":\"chat.type.admin\",\"with\":[{\"text\":\"@\"}" String json = "{\"italic\":true,\"color\":\"gray\",\"translate\":\"chat.type.admin\",\"with\":[{\"text\":\"@\"}"
@ -345,10 +345,10 @@ public class ComponentsTest
TextComponent second = new TextComponent( " world" ); TextComponent second = new TextComponent( " world" );
second.copyFormatting( first, ComponentBuilder.FormatRetention.ALL, true ); second.copyFormatting( first, ComponentBuilder.FormatRetention.ALL, true );
Assert.assertEquals( first.isBold(), second.isBold() ); assertEquals( first.isBold(), second.isBold() );
Assert.assertEquals( first.getColor(), second.getColor() ); assertEquals( first.getColor(), second.getColor() );
Assert.assertEquals( first.getClickEvent(), second.getClickEvent() ); assertEquals( first.getClickEvent(), second.getClickEvent() );
Assert.assertEquals( first.getHoverEvent(), second.getHoverEvent() ); assertEquals( first.getHoverEvent(), second.getHoverEvent() );
} }
@Test @Test
@ -368,7 +368,7 @@ public class ComponentsTest
ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.RED ).append( "world" ).color( ChatColor.DARK_RED ); ComponentBuilder builder = new ComponentBuilder( "Hello " ).color( ChatColor.RED ).append( "world" ).color( ChatColor.DARK_RED );
ComponentBuilder cloned = new ComponentBuilder( builder ); ComponentBuilder cloned = new ComponentBuilder( builder );
Assert.assertEquals( legacyTextFunction.apply( builder ), legacyTextFunction.apply( cloned ) ); assertEquals( legacyTextFunction.apply( builder ), legacyTextFunction.apply( cloned ) );
} }
@Test @Test
@ -403,10 +403,10 @@ public class ComponentsTest
ScoreComponent scoreComponent = new ScoreComponent( "myscore", "myobjective" ); ScoreComponent scoreComponent = new ScoreComponent( "myscore", "myobjective" );
builder.append( scoreComponent ); // non array based BaseComponent append builder.append( scoreComponent ); // non array based BaseComponent append
T component = componentBuilder.apply( builder ); T component = componentBuilder.apply( builder );
Assert.assertEquals( "Hello ", extraGetter.apply( component, 0 ).toPlainText() ); assertEquals( "Hello ", extraGetter.apply( component, 0 ).toPlainText() );
Assert.assertEquals( textComponent.toPlainText(), extraGetter.apply( component, 1 ).toPlainText() ); assertEquals( textComponent.toPlainText(), extraGetter.apply( component, 1 ).toPlainText() );
Assert.assertEquals( translatableComponent.toPlainText(), extraGetter.apply( component, 2 ).toPlainText() ); assertEquals( translatableComponent.toPlainText(), extraGetter.apply( component, 2 ).toPlainText() );
Assert.assertEquals( scoreComponent.toPlainText(), extraGetter.apply( component, 3 ).toPlainText() ); assertEquals( scoreComponent.toPlainText(), extraGetter.apply( component, 3 ).toPlainText() );
} }
@Test @Test
@ -416,7 +416,7 @@ public class ComponentsTest
String text = ComponentSerializer.toString( component ); String text = ComponentSerializer.toString( component );
BaseComponent[] reparsed = ComponentSerializer.parse( text ); BaseComponent[] reparsed = ComponentSerializer.parse( text );
Assert.assertArrayEquals( component, reparsed ); assertArrayEquals( component, reparsed );
} }
@Test @Test
@ -456,10 +456,10 @@ public class ComponentsTest
T component = componentBuilder.apply( builder ); T component = componentBuilder.apply( builder );
Assert.assertEquals( extraGetter.apply( component, 1 ).getHoverEvent(), hoverEvent ); assertEquals( extraGetter.apply( component, 1 ).getHoverEvent(), hoverEvent );
Assert.assertEquals( extraGetter.apply( component, 1 ).getClickEvent(), clickEvent ); assertEquals( extraGetter.apply( component, 1 ).getClickEvent(), clickEvent );
Assert.assertEquals( "Hello world!", toPlainTextFunction.apply( component ) ); assertEquals( "Hello world!", toPlainTextFunction.apply( component ) );
Assert.assertEquals( expectedLegacyText, toLegacyTextFunction.apply( component ) ); assertEquals( expectedLegacyText, toLegacyTextFunction.apply( component ) );
} }
@Test @Test
@ -492,8 +492,8 @@ public class ComponentsTest
T component = componentBuilder.apply( builder ); T component = componentBuilder.apply( builder );
Assert.assertEquals( "Hello world!", toPlainTextFunction.apply( component ) ); assertEquals( "Hello world!", toPlainTextFunction.apply( component ) );
Assert.assertEquals( expectedLegacyString, toLegacyTextFunction.apply( component ) ); assertEquals( expectedLegacyString, toLegacyTextFunction.apply( component ) );
} }
@Test @Test
@ -502,8 +502,8 @@ public class ComponentsTest
TextComponent textComponent = new TextComponent( "Hello world" ); TextComponent textComponent = new TextComponent( "Hello world" );
textComponent.setColor( ChatColor.RED ); textComponent.setColor( ChatColor.RED );
Assert.assertEquals( "Hello world", textComponent.toPlainText() ); assertEquals( "Hello world", textComponent.toPlainText() );
Assert.assertEquals( ChatColor.RED + "Hello world", textComponent.toLegacyText() ); assertEquals( ChatColor.RED + "Hello world", textComponent.toLegacyText() );
} }
@Test @Test
@ -511,25 +511,25 @@ public class ComponentsTest
{ {
BaseComponent[] test1 = TextComponent.fromLegacyText( ChatColor.AQUA + "Aqua " + ChatColor.RED + ChatColor.BOLD + "RedBold" ); BaseComponent[] test1 = TextComponent.fromLegacyText( ChatColor.AQUA + "Aqua " + ChatColor.RED + ChatColor.BOLD + "RedBold" );
Assert.assertEquals( "Aqua RedBold", BaseComponent.toPlainText( test1 ) ); assertEquals( "Aqua RedBold", BaseComponent.toPlainText( test1 ) );
Assert.assertEquals( ChatColor.AQUA + "Aqua " + ChatColor.RED + ChatColor.BOLD + "RedBold", BaseComponent.toLegacyText( test1 ) ); assertEquals( ChatColor.AQUA + "Aqua " + ChatColor.RED + ChatColor.BOLD + "RedBold", BaseComponent.toLegacyText( test1 ) );
BaseComponent[] test2 = TextComponent.fromLegacyText( "Text http://spigotmc.org " + ChatColor.GREEN + "google.com/test" ); BaseComponent[] test2 = TextComponent.fromLegacyText( "Text http://spigotmc.org " + ChatColor.GREEN + "google.com/test" );
Assert.assertEquals( "Text http://spigotmc.org google.com/test", BaseComponent.toPlainText( test2 ) ); assertEquals( "Text http://spigotmc.org google.com/test", BaseComponent.toPlainText( test2 ) );
//The extra ChatColor instances are sometimes inserted when not needed but it doesn't change the result //The extra ChatColor instances are sometimes inserted when not needed but it doesn't change the result
Assert.assertEquals( ChatColor.WHITE + "Text " + ChatColor.WHITE + "http://spigotmc.org" + ChatColor.WHITE assertEquals( ChatColor.WHITE + "Text " + ChatColor.WHITE + "http://spigotmc.org" + ChatColor.WHITE
+ " " + ChatColor.GREEN + "google.com/test" + ChatColor.GREEN, BaseComponent.toLegacyText( test2 ) ); + " " + ChatColor.GREEN + "google.com/test" + ChatColor.GREEN, BaseComponent.toLegacyText( test2 ) );
ClickEvent url1 = test2[1].getClickEvent(); ClickEvent url1 = test2[1].getClickEvent();
Assert.assertNotNull( url1 ); assertNotNull( url1 );
Assert.assertTrue( url1.getAction() == ClickEvent.Action.OPEN_URL ); assertTrue( url1.getAction() == ClickEvent.Action.OPEN_URL );
Assert.assertEquals( "http://spigotmc.org", url1.getValue() ); assertEquals( "http://spigotmc.org", url1.getValue() );
ClickEvent url2 = test2[3].getClickEvent(); ClickEvent url2 = test2[3].getClickEvent();
Assert.assertNotNull( url2 ); assertNotNull( url2 );
Assert.assertTrue( url2.getAction() == ClickEvent.Action.OPEN_URL ); assertTrue( url2.getAction() == ClickEvent.Action.OPEN_URL );
Assert.assertEquals( "http://google.com/test", url2.getValue() ); assertEquals( "http://google.com/test", url2.getValue() );
} }
@Test @Test
@ -541,18 +541,18 @@ public class ComponentsTest
item, "5", item, "5",
"thinkofdeath" ); "thinkofdeath" );
Assert.assertEquals( "Given Golden Sword * 5 to thinkofdeath", translatableComponent.toPlainText() ); assertEquals( "Given Golden Sword * 5 to thinkofdeath", translatableComponent.toPlainText() );
Assert.assertEquals( ChatColor.WHITE + "Given " + ChatColor.AQUA + "Golden Sword" + ChatColor.WHITE assertEquals( ChatColor.WHITE + "Given " + ChatColor.AQUA + "Golden Sword" + ChatColor.WHITE
+ " * " + ChatColor.WHITE + "5" + ChatColor.WHITE + " to " + ChatColor.WHITE + "thinkofdeath", + " * " + ChatColor.WHITE + "5" + ChatColor.WHITE + " to " + ChatColor.WHITE + "thinkofdeath",
translatableComponent.toLegacyText() ); translatableComponent.toLegacyText() );
TranslatableComponent positional = new TranslatableComponent( "book.pageIndicator", "5", "50" ); TranslatableComponent positional = new TranslatableComponent( "book.pageIndicator", "5", "50" );
Assert.assertEquals( "Page 5 of 50", positional.toPlainText() ); assertEquals( "Page 5 of 50", positional.toPlainText() );
Assert.assertEquals( ChatColor.WHITE + "Page " + ChatColor.WHITE + "5" + ChatColor.WHITE + " of " + ChatColor.WHITE + "50", positional.toLegacyText() ); assertEquals( ChatColor.WHITE + "Page " + ChatColor.WHITE + "5" + ChatColor.WHITE + " of " + ChatColor.WHITE + "50", positional.toLegacyText() );
TranslatableComponent one_four_two = new TranslatableComponent( "filled_map.buried_treasure" ); TranslatableComponent one_four_two = new TranslatableComponent( "filled_map.buried_treasure" );
Assert.assertEquals( "Buried Treasure Map", one_four_two.toPlainText() ); assertEquals( "Buried Treasure Map", one_four_two.toPlainText() );
} }
@Test @Test
@ -586,8 +586,8 @@ public class ComponentsTest
append( "World" ).bold( true ).color( ChatColor.BLUE ). append( "World" ).bold( true ).color( ChatColor.BLUE ).
append( "!" ).color( ChatColor.YELLOW ) ); append( "!" ).color( ChatColor.YELLOW ) );
Assert.assertEquals( "Hello World!", toPlainTextFunction.apply( component ) ); assertEquals( "Hello World!", toPlainTextFunction.apply( component ) );
Assert.assertEquals( expectedLegacyString, toLegacyTextFunction.apply( component ) ); assertEquals( expectedLegacyString, toLegacyTextFunction.apply( component ) );
} }
@Test @Test
@ -613,8 +613,8 @@ public class ComponentsTest
T component = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED ) T component = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World" ).reset() ); .append( "World" ).reset() );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( component, 0 ).getColor() ); assertEquals( ChatColor.RED, extraGetter.apply( component, 0 ).getColor() );
Assert.assertEquals( ChatColor.WHITE, extraGetter.apply( component, 1 ).getColor() ); assertEquals( ChatColor.WHITE, extraGetter.apply( component, 1 ).getColor() );
} }
@Test @Test
@ -640,41 +640,41 @@ public class ComponentsTest
T noneRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED ) T noneRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.append( "World", ComponentBuilder.FormatRetention.NONE ) ); .append( "World", ComponentBuilder.FormatRetention.NONE ) );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( noneRetention, 0 ).getColor() ); assertEquals( ChatColor.RED, extraGetter.apply( noneRetention, 0 ).getColor() );
Assert.assertEquals( ChatColor.WHITE, extraGetter.apply( noneRetention, 1 ).getColor() ); assertEquals( ChatColor.WHITE, extraGetter.apply( noneRetention, 1 ).getColor() );
HoverEvent testEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "test" ).build() ) ); HoverEvent testEvent = new HoverEvent( HoverEvent.Action.SHOW_TEXT, new Text( new ComponentBuilder( "test" ).build() ) );
T formattingRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED ) T formattingRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).append( "World", ComponentBuilder.FormatRetention.FORMATTING ) ); .event( testEvent ).append( "World", ComponentBuilder.FormatRetention.FORMATTING ) );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( formattingRetention, 0 ).getColor() ); assertEquals( ChatColor.RED, extraGetter.apply( formattingRetention, 0 ).getColor() );
Assert.assertEquals( testEvent, extraGetter.apply( formattingRetention, 0 ).getHoverEvent() ); assertEquals( testEvent, extraGetter.apply( formattingRetention, 0 ).getHoverEvent() );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( formattingRetention, 1 ).getColor() ); assertEquals( ChatColor.RED, extraGetter.apply( formattingRetention, 1 ).getColor() );
Assert.assertNull( extraGetter.apply( formattingRetention, 1 ).getHoverEvent() ); assertNull( extraGetter.apply( formattingRetention, 1 ).getHoverEvent() );
ClickEvent testClickEvent = new ClickEvent( ClickEvent.Action.OPEN_URL, "http://www.example.com" ); ClickEvent testClickEvent = new ClickEvent( ClickEvent.Action.OPEN_URL, "http://www.example.com" );
T eventRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED ) T eventRetention = componentBuilder.apply( new ComponentBuilder( "Hello " ).color( ChatColor.RED )
.event( testEvent ).event( testClickEvent ).append( "World", ComponentBuilder.FormatRetention.EVENTS ) ); .event( testEvent ).event( testClickEvent ).append( "World", ComponentBuilder.FormatRetention.EVENTS ) );
Assert.assertEquals( ChatColor.RED, extraGetter.apply( eventRetention, 0 ).getColor() ); assertEquals( ChatColor.RED, extraGetter.apply( eventRetention, 0 ).getColor() );
Assert.assertEquals( testEvent, extraGetter.apply( eventRetention, 0 ).getHoverEvent() ); assertEquals( testEvent, extraGetter.apply( eventRetention, 0 ).getHoverEvent() );
Assert.assertEquals( testClickEvent, extraGetter.apply( eventRetention, 0 ).getClickEvent() ); assertEquals( testClickEvent, extraGetter.apply( eventRetention, 0 ).getClickEvent() );
Assert.assertEquals( ChatColor.WHITE, extraGetter.apply( eventRetention, 1 ).getColor() ); assertEquals( ChatColor.WHITE, extraGetter.apply( eventRetention, 1 ).getColor() );
Assert.assertEquals( testEvent, extraGetter.apply( eventRetention, 1 ).getHoverEvent() ); assertEquals( testEvent, extraGetter.apply( eventRetention, 1 ).getHoverEvent() );
Assert.assertEquals( testClickEvent, extraGetter.apply( eventRetention, 1 ).getClickEvent() ); assertEquals( testClickEvent, extraGetter.apply( eventRetention, 1 ).getClickEvent() );
} }
@Test(expected = IllegalArgumentException.class) @Test
public void testLoopSimple() public void testLoopSimple()
{ {
TextComponent component = new TextComponent( "Testing" ); TextComponent component = new TextComponent( "Testing" );
component.addExtra( component ); component.addExtra( component );
ComponentSerializer.toString( component ); assertThrows( IllegalArgumentException.class, () -> ComponentSerializer.toString( component ) );
} }
@Test(expected = IllegalArgumentException.class) @Test
public void testLoopComplex() public void testLoopComplex()
{ {
TextComponent a = new TextComponent( "A" ); TextComponent a = new TextComponent( "A" );
@ -685,7 +685,7 @@ public class ComponentsTest
a.addExtra( b ); a.addExtra( b );
b.addExtra( c ); b.addExtra( c );
c.addExtra( a ); c.addExtra( a );
ComponentSerializer.toString( a ); assertThrows( IllegalArgumentException.class, () -> ComponentSerializer.toString( a ) );
} }
@Test @Test
@ -699,7 +699,7 @@ public class ComponentsTest
ComponentSerializer.toString( a ); ComponentSerializer.toString( a );
} }
@Test(expected = IllegalArgumentException.class) @Test
public void testRepeatedError() public void testRepeatedError()
{ {
TextComponent a = new TextComponent( "A" ); TextComponent a = new TextComponent( "A" );
@ -711,7 +711,7 @@ public class ComponentsTest
a.addExtra( c ); a.addExtra( c );
c.addExtra( a ); c.addExtra( a );
a.addExtra( b ); a.addExtra( b );
ComponentSerializer.toString( a ); assertThrows( IllegalArgumentException.class, () -> ComponentSerializer.toString( a ) );
} }
@Test @Test
@ -736,7 +736,7 @@ public class ComponentsTest
String emptyLegacyText = fromAndToLegacyText( "" ); String emptyLegacyText = fromAndToLegacyText( "" );
// all invalid color codes and the trailing '§' should be ignored // all invalid color codes and the trailing '§' should be ignored
Assert.assertEquals( emptyLegacyText, invalidColorCodesLegacyText ); assertEquals( emptyLegacyText, invalidColorCodesLegacyText );
} }
@Test @Test
@ -745,12 +745,12 @@ public class ComponentsTest
String text = "§a"; String text = "§a";
BaseComponent[] converted = TextComponent.fromLegacyText( text ); BaseComponent[] converted = TextComponent.fromLegacyText( text );
Assert.assertEquals( ChatColor.GREEN, converted[0].getColor() ); assertEquals( ChatColor.GREEN, converted[0].getColor() );
String roundtripLegacyText = BaseComponent.toLegacyText( converted ); String roundtripLegacyText = BaseComponent.toLegacyText( converted );
// color code should not be lost during conversion // color code should not be lost during conversion
Assert.assertEquals( text, roundtripLegacyText ); assertEquals( text, roundtripLegacyText );
} }
@Test @Test
@ -762,7 +762,7 @@ public class ComponentsTest
TextComponent second = new TextComponent( "Hello, " ); TextComponent second = new TextComponent( "Hello, " );
second.addExtra( new TextComponent( "World!" ) ); second.addExtra( new TextComponent( "World!" ) );
Assert.assertEquals( first, second ); assertEquals( first, second );
} }
@Test @Test
@ -774,7 +774,7 @@ public class ComponentsTest
TextComponent second = new TextComponent( "Hello, " ); TextComponent second = new TextComponent( "Hello, " );
second.addExtra( new TextComponent( "World!" ) ); second.addExtra( new TextComponent( "World!" ) );
Assert.assertNotEquals( first, second ); assertNotEquals( first, second );
} }
@Test @Test
@ -785,7 +785,7 @@ public class ComponentsTest
BaseComponent[] reColored = TextComponent.fromLegacyText( legacy ); BaseComponent[] reColored = TextComponent.fromLegacyText( legacy );
Assert.assertArrayEquals( hexColored, reColored ); assertArrayEquals( hexColored, reColored );
} }
@Test @Test
@ -817,18 +817,18 @@ public class ComponentsTest
String expected = "{\"extra\":[{\"underlined\":true,\"color\":\"dark_red\",\"text\":\"44444\"},{\"color\":" String expected = "{\"extra\":[{\"underlined\":true,\"color\":\"dark_red\",\"text\":\"44444\"},{\"color\":"
+ "\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"}],\"text\":\"\"}"; + "\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"}],\"text\":\"\"}";
Assert.assertEquals( expected, ComponentSerializer.toString( a ) ); assertEquals( expected, ComponentSerializer.toString( a ) );
builder.append( a ); builder.append( a );
String test1 = componentSerializer.apply( componentBuilder.apply( builder ) ); String test1 = componentSerializer.apply( componentBuilder.apply( builder ) );
Assert.assertEquals( expected, test1 ); assertEquals( expected, test1 );
BaseComponent[] b = TextComponent.fromLegacyText( "§rrrrr" ); BaseComponent[] b = TextComponent.fromLegacyText( "§rrrrr" );
builder.append( b ); builder.append( b );
String test2 = componentSerializer.apply( componentBuilder.apply( builder ) ); String test2 = componentSerializer.apply( componentBuilder.apply( builder ) );
Assert.assertEquals( assertEquals(
"{\"extra\":[{\"underlined\":true,\"color\":\"dark_red\",\"text\":\"44444\"}," "{\"extra\":[{\"underlined\":true,\"color\":\"dark_red\",\"text\":\"44444\"},"
+ "{\"color\":\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"}," + "{\"color\":\"white\",\"text\":\"dd\"},{\"bold\":true,\"color\":\"gold\",\"text\":\"6666\"},"
+ "{\"color\":\"white\",\"text\":\"rrrr\"}],\"text\":\"\"}", + "{\"color\":\"white\",\"text\":\"rrrr\"}],\"text\":\"\"}",

View File

@ -1,8 +1,8 @@
package net.md_5.bungee.api.chat; package net.md_5.bungee.api.chat;
import static org.junit.jupiter.api.Assertions.*;
import net.md_5.bungee.chat.ComponentSerializer; import net.md_5.bungee.chat.ComponentSerializer;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Test;
public class TranslatableComponentTest public class TranslatableComponentTest
{ {
@ -11,8 +11,8 @@ public class TranslatableComponentTest
public void testMissingPlaceholdersAdded() public void testMissingPlaceholdersAdded()
{ {
TranslatableComponent testComponent = new TranslatableComponent( "Test string with %s placeholders: %s", 2, "aoeu" ); TranslatableComponent testComponent = new TranslatableComponent( "Test string with %s placeholders: %s", 2, "aoeu" );
Assert.assertEquals( "Test string with 2 placeholders: aoeu", testComponent.toPlainText() ); assertEquals( "Test string with 2 placeholders: aoeu", testComponent.toPlainText() );
Assert.assertEquals( "§fTest string with §f2§f placeholders: §faoeu", testComponent.toLegacyText() ); assertEquals( "§fTest string with §f2§f placeholders: §faoeu", testComponent.toLegacyText() );
} }
@Test @Test
@ -22,7 +22,7 @@ public class TranslatableComponentTest
String jsonString = ComponentSerializer.toString( testComponent ); String jsonString = ComponentSerializer.toString( testComponent );
BaseComponent[] baseComponents = ComponentSerializer.parse( jsonString ); BaseComponent[] baseComponents = ComponentSerializer.parse( jsonString );
Assert.assertEquals( "Test string with a placeholder", TextComponent.toPlainText( baseComponents ) ); assertEquals( "Test string with a placeholder", TextComponent.toPlainText( baseComponents ) );
Assert.assertEquals( "§fTest string with §fa§f placeholder", TextComponent.toLegacyText( baseComponents ) ); assertEquals( "§fTest string with §fa§f placeholder", TextComponent.toLegacyText( baseComponents ) );
} }
} }

View File

@ -36,7 +36,6 @@
<module name="SuppressWarningsHolder"/> <module name="SuppressWarningsHolder"/>
<!-- See http://checkstyle.sourceforge.net/config_imports.html --> <!-- See http://checkstyle.sourceforge.net/config_imports.html -->
<module name="AvoidStarImport"/>
<module name="ImportOrder"> <module name="ImportOrder">
<property name="option" value="above"/> <property name="option" value="above"/>
<property name="ordered" value="true"/> <property name="ordered" value="true"/>

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-config</artifactId> <artifactId>bungeecord-config</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,30 +1,25 @@
package net.md_5.bungee.config; package net.md_5.bungee.config;
import static org.junit.jupiter.api.Assertions.*;
import java.io.StringReader; import java.io.StringReader;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.junit.Assert; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.Test; import org.junit.jupiter.params.provider.Arguments;
import org.junit.runner.RunWith; import org.junit.jupiter.params.provider.MethodSource;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RequiredArgsConstructor @RequiredArgsConstructor
@RunWith(Parameterized.class)
public class CompoundConfigurationTest public class CompoundConfigurationTest
{ {
@Parameters(name = "{0}") public static Stream<Arguments> data()
public static Iterable<Object[]> data()
{
// CHECKSTYLE:OFF
return Arrays.asList( new Object[][]
{
{ {
return Stream.of(
Arguments.of(
// provider // provider
YamlConfiguration.class, YamlConfiguration.class,
// testDocument // testDocument
@ -73,8 +68,8 @@ public class CompoundConfigurationTest
+ "null:\n" + "null:\n"
+ " null: object\n" + " null: object\n"
+ " object: null\n" + " object: null\n"
}, ),
{ Arguments.of(
// provider // provider
JsonConfiguration.class, JsonConfiguration.class,
// testDocument // testDocument
@ -131,18 +126,13 @@ public class CompoundConfigurationTest
+ " \"object\": null\n" + " \"object\": null\n"
+ " }\n" + " }\n"
+ "}" + "}"
)
);
} }
} );
// CHECKSTYLE:ON
}
//
private final Class<? extends ConfigurationProvider> provider;
private final String testDocument;
private final String numberTest;
private final String nullTest;
@Test @ParameterizedTest
public void testConfig() throws Exception @MethodSource("data")
public void testConfig(Class<? extends ConfigurationProvider> provider, String testDocument, String numberTest, String nullTest) throws Exception
{ {
Configuration conf = ConfigurationProvider.getProvider( provider ).load( testDocument ); Configuration conf = ConfigurationProvider.getProvider( provider ).load( testDocument );
testSection( conf ); testSection( conf );
@ -151,7 +141,7 @@ public class CompoundConfigurationTest
ConfigurationProvider.getProvider( provider ).save( conf, sw ); ConfigurationProvider.getProvider( provider ).save( conf, sw );
// Check nulls were saved, see #1094 // Check nulls were saved, see #1094
Assert.assertFalse( "Config contains null", sw.toString().contains( "null" ) ); assertFalse( sw.toString().contains( "null" ), "Config contains null" );
conf = ConfigurationProvider.getProvider( provider ).load( new StringReader( sw.toString() ) ); conf = ConfigurationProvider.getProvider( provider ).load( new StringReader( sw.toString() ) );
conf.set( "receipt", "Oz-Ware Purchase Invoice" ); // Add it back conf.set( "receipt", "Oz-Ware Purchase Invoice" ); // Add it back
@ -160,37 +150,38 @@ public class CompoundConfigurationTest
private void testSection(Configuration conf) private void testSection(Configuration conf)
{ {
Assert.assertEquals( "receipt", "Oz-Ware Purchase Invoice", conf.getString( "receipt" ) ); assertEquals( "Oz-Ware Purchase Invoice", conf.getString( "receipt" ), "receipt" );
// Assert.assertEquals( "date", "2012-08-06", conf.get( "date" ).toString() ); // assertEquals( "2012-08-06", conf.get( "date" ).toString(), "date" );
Configuration customer = conf.getSection( "customer" ); Configuration customer = conf.getSection( "customer" );
Assert.assertEquals( "customer.given", "Dorothy", customer.getString( "given" ) ); assertEquals( "Dorothy", customer.getString( "given" ), "customer.given" );
Assert.assertEquals( "customer.given", "Dorothy", conf.getString( "customer.given" ) ); assertEquals( "Dorothy", conf.getString( "customer.given" ), "customer.given" );
List items = conf.getList( "items" ); List items = conf.getList( "items" );
Map item = (Map) items.get( 0 ); Map item = (Map) items.get( 0 );
Assert.assertEquals( "items[0].part_no", "A4786", item.get( "part_no" ) ); assertEquals( "A4786", item.get( "part_no" ), "items[0].part_no" );
conf.set( "receipt", null ); conf.set( "receipt", null );
Assert.assertEquals( null, conf.get( "receipt" ) ); assertEquals( null, conf.get( "receipt" ) );
Assert.assertEquals( "foo", conf.get( "receipt", "foo" ) ); assertEquals( "foo", conf.get( "receipt", "foo" ) );
Configuration newSection = conf.getSection( "new.section" ); Configuration newSection = conf.getSection( "new.section" );
newSection.set( "value", "foo" ); newSection.set( "value", "foo" );
Assert.assertEquals( "foo", conf.get( "new.section.value" ) ); assertEquals( "foo", conf.get( "new.section.value" ) );
conf.set( "other.new.section", "bar" ); conf.set( "other.new.section", "bar" );
Assert.assertEquals( "bar", conf.get( "other.new.section" ) ); assertEquals( "bar", conf.get( "other.new.section" ) );
Assert.assertTrue( conf.contains( "customer.given" ) ); assertTrue( conf.contains( "customer.given" ) );
Assert.assertTrue( customer.contains( "given" ) ); assertTrue( customer.contains( "given" ) );
Assert.assertFalse( conf.contains( "customer.foo" ) ); assertFalse( conf.contains( "customer.foo" ) );
Assert.assertFalse( customer.contains( "foo" ) ); assertFalse( customer.contains( "foo" ) );
} }
@Test @ParameterizedTest
public void testNumberedKeys() @MethodSource("data")
public void testNumberedKeys(Class<? extends ConfigurationProvider> provider, String testDocument, String numberTest, String nullTest)
{ {
Configuration conf = ConfigurationProvider.getProvider( provider ).load( numberTest ); Configuration conf = ConfigurationProvider.getProvider( provider ).load( numberTest );
@ -201,29 +192,31 @@ public class CompoundConfigurationTest
} }
} }
@Test @ParameterizedTest
public void testNull() @MethodSource("data")
public void testNull(Class<? extends ConfigurationProvider> provider, String testDocument, String numberTest, String nullTest)
{ {
Configuration conf = ConfigurationProvider.getProvider( provider ).load( nullTest ); Configuration conf = ConfigurationProvider.getProvider( provider ).load( nullTest );
Assert.assertEquals( "object", conf.get( "null.null" ) ); assertEquals( "object", conf.get( "null.null" ) );
Assert.assertEquals( "object", conf.getSection( "null" ).get( "null" ) ); assertEquals( "object", conf.getSection( "null" ).get( "null" ) );
Assert.assertEquals( null, conf.get( "null.object" ) ); assertEquals( null, conf.get( "null.object" ) );
Assert.assertEquals( "", conf.getString( "null.object" ) ); assertEquals( "", conf.getString( "null.object" ) );
} }
@Test @ParameterizedTest
public void testMapAddition() @MethodSource("data")
public void testMapAddition(Class<? extends ConfigurationProvider> provider, String testDocument, String numberTest, String nullTest)
{ {
Configuration conf = ConfigurationProvider.getProvider( provider ).load( testDocument ); Configuration conf = ConfigurationProvider.getProvider( provider ).load( testDocument );
conf.set( "addition", Collections.singletonMap( "foo", "bar" ) ); conf.set( "addition", Collections.singletonMap( "foo", "bar" ) );
// Order matters // Order matters
Assert.assertEquals( "bar", conf.getSection( "addition" ).getString( "foo" ) ); assertEquals( "bar", conf.getSection( "addition" ).getString( "foo" ) );
Assert.assertEquals( "bar", conf.getString( "addition.foo" ) ); assertEquals( "bar", conf.getString( "addition.foo" ) );
Assert.assertTrue( conf.get( "addition" ) instanceof Configuration ); assertTrue( conf.get( "addition" ) instanceof Configuration );
} }
} }

View File

@ -1,7 +1,7 @@
package net.md_5.bungee.config; package net.md_5.bungee.config;
import org.junit.Assert; import static org.junit.jupiter.api.Assertions.*;
import org.junit.Test; import org.junit.jupiter.api.Test;
public class DefaultConfigurationTest public class DefaultConfigurationTest
{ {
@ -16,8 +16,8 @@ public class DefaultConfigurationTest
Configuration actualConfig = new Configuration( defaultConfig ); Configuration actualConfig = new Configuration( defaultConfig );
Assert.assertEquals( 10, actualConfig.getInt( "setting" ) ); assertEquals( 10, actualConfig.getInt( "setting" ) );
Assert.assertEquals( 11, actualConfig.getInt( "nested.setting" ) ); assertEquals( 11, actualConfig.getInt( "nested.setting" ) );
Assert.assertEquals( 12, actualConfig.getInt( "double.nested.setting" ) ); assertEquals( 12, actualConfig.getInt( "double.nested.setting" ) );
} }
} }

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-event</artifactId> <artifactId>bungeecord-event</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,8 +1,8 @@
package net.md_5.bungee.event; package net.md_5.bungee.event;
import static org.junit.jupiter.api.Assertions.*;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Test;
public class EventBusTest public class EventBusTest
{ {
@ -15,14 +15,14 @@ public class EventBusTest
{ {
bus.register( this ); bus.register( this );
bus.post( new FirstEvent() ); bus.post( new FirstEvent() );
Assert.assertEquals( 0, latch.getCount() ); assertEquals( 0, latch.getCount() );
} }
@EventHandler @EventHandler
public void firstListener(FirstEvent event) public void firstListener(FirstEvent event)
{ {
bus.post( new SecondEvent() ); bus.post( new SecondEvent() );
Assert.assertEquals( 1, latch.getCount() ); assertEquals( 1, latch.getCount() );
latch.countDown(); latch.countDown();
} }

View File

@ -1,8 +1,8 @@
package net.md_5.bungee.event; package net.md_5.bungee.event;
import static org.junit.jupiter.api.Assertions.*;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Test;
public class EventPriorityTest public class EventPriorityTest
{ {
@ -16,41 +16,41 @@ public class EventPriorityTest
bus.register( this ); bus.register( this );
bus.register( new EventPriorityListenerPartner() ); bus.register( new EventPriorityListenerPartner() );
bus.post( new PriorityTestEvent() ); bus.post( new PriorityTestEvent() );
Assert.assertEquals( 0, latch.getCount() ); assertEquals( 0, latch.getCount() );
} }
@EventHandler(priority = Byte.MIN_VALUE) @EventHandler(priority = Byte.MIN_VALUE)
public void onMinPriority(PriorityTestEvent event) public void onMinPriority(PriorityTestEvent event)
{ {
Assert.assertEquals( 7, latch.getCount() ); assertEquals( 7, latch.getCount() );
latch.countDown(); latch.countDown();
} }
@EventHandler(priority = EventPriority.LOWEST) @EventHandler(priority = EventPriority.LOWEST)
public void onLowestPriority(PriorityTestEvent event) public void onLowestPriority(PriorityTestEvent event)
{ {
Assert.assertEquals( 6, latch.getCount() ); assertEquals( 6, latch.getCount() );
latch.countDown(); latch.countDown();
} }
@EventHandler @EventHandler
public void onNormalPriority(PriorityTestEvent event) public void onNormalPriority(PriorityTestEvent event)
{ {
Assert.assertEquals( 4, latch.getCount() ); assertEquals( 4, latch.getCount() );
latch.countDown(); latch.countDown();
} }
@EventHandler(priority = EventPriority.HIGHEST) @EventHandler(priority = EventPriority.HIGHEST)
public void onHighestPriority(PriorityTestEvent event) public void onHighestPriority(PriorityTestEvent event)
{ {
Assert.assertEquals( 2, latch.getCount() ); assertEquals( 2, latch.getCount() );
latch.countDown(); latch.countDown();
} }
@EventHandler(priority = Byte.MAX_VALUE) @EventHandler(priority = Byte.MAX_VALUE)
public void onMaxPriority(PriorityTestEvent event) public void onMaxPriority(PriorityTestEvent event)
{ {
Assert.assertEquals( 1, latch.getCount() ); assertEquals( 1, latch.getCount() );
latch.countDown(); latch.countDown();
} }
@ -64,14 +64,14 @@ public class EventPriorityTest
@EventHandler(priority = EventPriority.HIGH) @EventHandler(priority = EventPriority.HIGH)
public void onHighPriority(PriorityTestEvent event) public void onHighPriority(PriorityTestEvent event)
{ {
Assert.assertEquals( 3, latch.getCount() ); assertEquals( 3, latch.getCount() );
latch.countDown(); latch.countDown();
} }
@EventHandler(priority = EventPriority.LOW) @EventHandler(priority = EventPriority.LOW)
public void onLowPriority(PriorityTestEvent event) public void onLowPriority(PriorityTestEvent event)
{ {
Assert.assertEquals( 5, latch.getCount() ); assertEquals( 5, latch.getCount() );
latch.countDown(); latch.countDown();
} }
} }

View File

@ -1,8 +1,8 @@
package net.md_5.bungee.event; package net.md_5.bungee.event;
import static org.junit.jupiter.api.Assertions.*;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Test;
public class SubclassTest extends EventBusTest public class SubclassTest extends EventBusTest
{ {
@ -14,13 +14,13 @@ public class SubclassTest extends EventBusTest
public void testNestedEvents() public void testNestedEvents()
{ {
super.testNestedEvents(); super.testNestedEvents();
Assert.assertEquals( 0, latch.getCount() ); assertEquals( 0, latch.getCount() );
} }
@EventHandler @EventHandler
protected void extraListener(FirstEvent event) protected void extraListener(FirstEvent event)
{ {
Assert.assertEquals( 1, latch.getCount() ); assertEquals( 1, latch.getCount() );
latch.countDown(); latch.countDown();
} }
} }

View File

@ -1,7 +1,7 @@
package net.md_5.bungee.event; package net.md_5.bungee.event;
import org.junit.Assert; import static org.junit.jupiter.api.Assertions.fail;
import org.junit.Test; import org.junit.jupiter.api.Test;
public class UnregisteringListenerTest public class UnregisteringListenerTest
{ {
@ -19,7 +19,7 @@ public class UnregisteringListenerTest
@EventHandler @EventHandler
public void onEvent(TestEvent evt) public void onEvent(TestEvent evt)
{ {
Assert.fail( "Event listener wasn't unregistered" ); fail( "Event listener wasn't unregistered" );
} }
public static class TestEvent public static class TestEvent

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-log</artifactId> <artifactId>bungeecord-log</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -26,7 +25,7 @@
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-chat</artifactId> <artifactId>bungeecord-chat</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-alert</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_alert</name>
<description>Provides the alert and alertraw commands</description>
</project>

View File

@ -1,47 +0,0 @@
package net.md_5.bungee.module.cmd.alert;
import java.util.Locale;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.plugin.Command;
public class CommandAlert extends Command
{
public CommandAlert()
{
super( "alert", "bungeecord.command.alert" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
if ( args.length == 0 )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "message_needed" ) );
} else
{
StringBuilder builder = new StringBuilder();
if ( args[0].toLowerCase( Locale.ROOT ).startsWith( "&h" ) )
{
// Remove &h
args[0] = args[0].substring( 2 );
} else
{
builder.append( ProxyServer.getInstance().getTranslation( "alert" ) );
}
for ( String s : args )
{
builder.append( ChatColor.translateAlternateColorCodes( '&', s ) );
builder.append( " " );
}
String message = builder.substring( 0, builder.length() - 1 );
ProxyServer.getInstance().broadcast( TextComponent.fromLegacyText( message ) );
}
}
}

View File

@ -1,56 +0,0 @@
package net.md_5.bungee.module.cmd.alert;
import com.google.common.base.Joiner;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.chat.ComponentSerializer;
public class CommandAlertRaw extends Command
{
public CommandAlertRaw()
{
super( "alertraw", "bungeecord.command.alert" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
if ( args.length == 0 )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "message_needed" ) );
} else
{
String message = Joiner.on( ' ' ).join( args );
try
{
ProxyServer.getInstance().broadcast( ComponentSerializer.parse( message ) );
} catch ( Exception e )
{
Throwable error = e;
while ( error.getCause() != null )
{
error = error.getCause();
}
if ( sender instanceof ProxiedPlayer )
{
sender.sendMessage( new ComponentBuilder( ProxyServer.getInstance().getTranslation( "error_occurred_player" ) )
.event( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new ComponentBuilder( error.getMessage() )
.color( ChatColor.RED )
.create() ) )
.create()
);
} else
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "error_occurred_console", error.getMessage() ) );
}
}
}
}
}

View File

@ -1,14 +0,0 @@
package net.md_5.bungee.module.cmd.alert;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginAlert extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandAlert() );
getProxy().getPluginManager().registerCommand( this, new CommandAlertRaw() );
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.alert.PluginAlert
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-find</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_find</name>
<description>Provides the find command</description>
</project>

View File

@ -1,58 +0,0 @@
package net.md_5.bungee.module.cmd.find;
import java.util.Collections;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.command.PlayerCommand;
public class CommandFind extends PlayerCommand
{
public CommandFind()
{
super( "find", "bungeecord.command.find" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
if ( args.length != 1 )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "username_needed" ) );
} else
{
ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] );
if ( player == null || player.getServer() == null )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) );
} else
{
boolean moduleLoaded = ProxyServer.getInstance().getPluginManager().getPlugin( "cmd_server" ) != null;
ServerInfo server = player.getServer().getInfo();
ComponentBuilder componentBuilder = new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "user_online_at", player.getName(), server.getName() ) );
if ( moduleLoaded && server.canAccess( sender ) )
{
componentBuilder.event( new HoverEvent(
HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "click_to_connect" ) ).create() )
);
componentBuilder.event( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/server " + server.getName() ) );
}
sender.sendMessage( componentBuilder.create() );
}
}
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
{
return args.length == 1 ? super.onTabComplete( sender, args ) : Collections.emptyList();
}
}

View File

@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.find;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginFind extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandFind() );
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.find.PluginFind
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-kick</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_kick</name>
<description>Provides the gkick command</description>
</project>

View File

@ -1,72 +0,0 @@
package net.md_5.bungee.module.cmd.kick;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
public class CommandKick extends Command implements TabExecutor
{
public CommandKick()
{
super( "gkick", "bungeecord.command.kick" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
if ( args.length == 0 )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "username_needed" ) );
} else
{
ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] );
if ( player == null )
{
sender.sendMessage( TextComponent.fromLegacyText( ProxyServer.getInstance().getTranslation( "user_not_online" ) ) );
return;
}
if ( args.length == 1 )
{
player.disconnect( TextComponent.fromLegacyText( ProxyServer.getInstance().getTranslation( "kick_message" ) ) );
} else
{
String[] reason = new String[ args.length - 1 ];
System.arraycopy( args, 1, reason, 0, reason.length );
player.disconnect( TextComponent.fromLegacyText( ChatColor.translateAlternateColorCodes( '&', Joiner.on( ' ' ).join( reason ) ) ) );
}
}
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
{
if ( args.length == 1 )
{
Set<String> matches = new HashSet<>();
String search = args[0].toLowerCase( Locale.ROOT );
for ( ProxiedPlayer player : ProxyServer.getInstance().getPlayers() )
{
if ( player.getName().toLowerCase( Locale.ROOT ).startsWith( search ) )
{
matches.add( player.getName() );
}
}
return matches;
} else
{
return ImmutableSet.of();
}
}
}

View File

@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.kick;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginKick extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandKick() );
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.kick.PluginKick
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-list</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_list</name>
<description>Provides the glist command</description>
</project>

View File

@ -1,62 +0,0 @@
package net.md_5.bungee.module.cmd.list;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
/**
* Command to list all players connected to the proxy.
*/
public class CommandList extends Command implements TabExecutor
{
public CommandList()
{
super( "glist", "bungeecord.command.list" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
boolean hideEmptyServers = ( args.length == 0 ) || !args[0].equalsIgnoreCase( "all" );
for ( ServerInfo server : ProxyServer.getInstance().getServers().values() )
{
if ( !server.canAccess( sender ) )
{
continue;
}
Collection<ProxiedPlayer> serverPlayers = server.getPlayers();
if ( hideEmptyServers && serverPlayers.isEmpty() )
{
continue;
}
List<String> players = new ArrayList<>();
for ( ProxiedPlayer player : serverPlayers )
{
players.add( player.getDisplayName() );
}
Collections.sort( players, String.CASE_INSENSITIVE_ORDER );
sender.sendMessage( ProxyServer.getInstance().getTranslation( "command_list", server.getName(), players.size(), String.join( ChatColor.RESET + ", ", players ) ) );
}
sender.sendMessage( ProxyServer.getInstance().getTranslation( "total_players", ProxyServer.getInstance().getOnlineCount() ) );
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
{
return ( args.length > 1 ) ? Collections.emptyList() : Collections.singletonList( "all" );
}
}

View File

@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.list;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginList extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandList() );
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.list.PluginList
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-send</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_send</name>
<description>Provides the gsend command</description>
</project>

View File

@ -1,200 +0,0 @@
package net.md_5.bungee.module.cmd.send;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import net.md_5.bungee.api.Callback;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.ServerConnectRequest;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
public class CommandSend extends Command implements TabExecutor
{
protected static class SendCallback
{
private final Map<ServerConnectRequest.Result, List<String>> results = new HashMap<>();
private final CommandSender sender;
private int count = 0;
public SendCallback(CommandSender sender)
{
this.sender = sender;
for ( ServerConnectRequest.Result result : ServerConnectRequest.Result.values() )
{
results.put( result, new ArrayList<String>() );
}
}
public void lastEntryDone()
{
sender.sendMessage( ChatColor.GREEN.toString() + ChatColor.BOLD + "Send Results:" );
for ( Map.Entry<ServerConnectRequest.Result, List<String>> entry : results.entrySet() )
{
ComponentBuilder builder = new ComponentBuilder( "" );
if ( !entry.getValue().isEmpty() )
{
builder.event( new HoverEvent( HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder( Joiner.on( ", " ).join( entry.getValue() ) ).color( ChatColor.YELLOW ).create() ) );
}
builder.append( entry.getKey().name() + ": " ).color( ChatColor.GREEN );
builder.append( "" + entry.getValue().size() ).bold( true );
sender.sendMessage( builder.create() );
}
}
public static class Entry implements Callback<ServerConnectRequest.Result>
{
private final SendCallback callback;
private final ProxiedPlayer player;
private final ServerInfo target;
public Entry(SendCallback callback, ProxiedPlayer player, ServerInfo target)
{
this.callback = callback;
this.player = player;
this.target = target;
this.callback.count++;
}
@Override
public void done(ServerConnectRequest.Result result, Throwable error)
{
callback.results.get( result ).add( player.getName() );
if ( result == ServerConnectRequest.Result.SUCCESS )
{
player.sendMessage( ProxyServer.getInstance().getTranslation( "you_got_summoned", target.getName(), callback.sender.getName() ) );
}
if ( --callback.count == 0 )
{
callback.lastEntryDone();
}
}
}
}
public CommandSend()
{
super( "send", "bungeecord.command.send" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
if ( args.length != 2 )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "send_cmd_usage" ) );
return;
}
ServerInfo server = ProxyServer.getInstance().getServerInfo( args[1] );
if ( server == null )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) );
return;
}
List<ProxiedPlayer> targets;
if ( args[0].equalsIgnoreCase( "all" ) )
{
targets = new ArrayList<>( ProxyServer.getInstance().getPlayers() );
} else if ( args[0].equalsIgnoreCase( "current" ) )
{
if ( !( sender instanceof ProxiedPlayer ) )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "player_only" ) );
return;
}
ProxiedPlayer player = (ProxiedPlayer) sender;
targets = new ArrayList<>( player.getServer().getInfo().getPlayers() );
} else
{
// If we use a server name, send the entire server. This takes priority over players.
ServerInfo serverTarget = ProxyServer.getInstance().getServerInfo( args[0] );
if ( serverTarget != null )
{
targets = new ArrayList<>( serverTarget.getPlayers() );
} else
{
ProxiedPlayer player = ProxyServer.getInstance().getPlayer( args[0] );
if ( player == null )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "user_not_online" ) );
return;
}
targets = Collections.singletonList( player );
}
}
final SendCallback callback = new SendCallback( sender );
for ( ProxiedPlayer player : targets )
{
ServerConnectRequest request = ServerConnectRequest.builder()
.target( server )
.reason( ServerConnectEvent.Reason.COMMAND )
.callback( new SendCallback.Entry( callback, player, server ) )
.build();
player.connect( request );
}
sender.sendMessage( ChatColor.DARK_GREEN + "Attempting to send " + targets.size() + " players to " + server.getName() );
}
@Override
public Iterable<String> onTabComplete(CommandSender sender, String[] args)
{
if ( args.length > 2 || args.length == 0 )
{
return ImmutableSet.of();
}
Set<String> matches = new HashSet<>();
if ( args.length == 1 )
{
String search = args[0].toLowerCase( Locale.ROOT );
for ( ProxiedPlayer player : ProxyServer.getInstance().getPlayers() )
{
if ( player.getName().toLowerCase( Locale.ROOT ).startsWith( search ) )
{
matches.add( player.getName() );
}
}
if ( "all".startsWith( search ) )
{
matches.add( "all" );
}
if ( "current".startsWith( search ) )
{
matches.add( "current" );
}
} else
{
String search = args[1].toLowerCase( Locale.ROOT );
for ( String server : ProxyServer.getInstance().getServers().keySet() )
{
if ( server.toLowerCase( Locale.ROOT ).startsWith( search ) )
{
matches.add( server );
}
}
}
return matches;
}
}

View File

@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.send;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginSend extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandSend() );
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.send.PluginSend
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-cmd-server</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>cmd_server</name>
<description>Provides the server command</description>
</project>

View File

@ -1,104 +0,0 @@
package net.md_5.bungee.module.cmd.server;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.ClickEvent;
import net.md_5.bungee.api.chat.ComponentBuilder;
import net.md_5.bungee.api.chat.HoverEvent;
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.event.ServerConnectEvent;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.TabExecutor;
/**
* Command to list and switch a player between available servers.
*/
public class CommandServer extends Command implements TabExecutor
{
public CommandServer()
{
super( "server", "bungeecord.command.server" );
}
@Override
public void execute(CommandSender sender, String[] args)
{
Map<String, ServerInfo> servers = ProxyServer.getInstance().getServers();
if ( args.length == 0 )
{
if ( sender instanceof ProxiedPlayer )
{
sender.sendMessage( ProxyServer.getInstance().getTranslation( "current_server", ( (ProxiedPlayer) sender ).getServer().getInfo().getName() ) );
}
ComponentBuilder serverList = new ComponentBuilder().appendLegacy( ProxyServer.getInstance().getTranslation( "server_list" ) );
boolean first = true;
for ( ServerInfo server : servers.values() )
{
if ( server.canAccess( sender ) )
{
TextComponent serverTextComponent = new TextComponent( first ? server.getName() : ", " + server.getName() );
int count = server.getPlayers().size();
serverTextComponent.setHoverEvent( new HoverEvent(
HoverEvent.Action.SHOW_TEXT,
new ComponentBuilder( count + ( count == 1 ? " player" : " players" ) + "\n" ).appendLegacy( ProxyServer.getInstance().getTranslation( "click_to_connect" ) ).create() )
);
serverTextComponent.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, "/server " + server.getName() ) );
serverList.append( serverTextComponent );
first = false;
}
}
sender.sendMessage( serverList.create() );
} else
{
if ( !( sender instanceof ProxiedPlayer ) )
{
return;
}
ProxiedPlayer player = (ProxiedPlayer) sender;
ServerInfo server = servers.get( args[0] );
if ( server == null )
{
player.sendMessage( ProxyServer.getInstance().getTranslation( "no_server" ) );
} else if ( !server.canAccess( player ) )
{
player.sendMessage( ProxyServer.getInstance().getTranslation( "no_server_permission" ) );
} else
{
player.connect( server, ServerConnectEvent.Reason.COMMAND );
}
}
}
@Override
public Iterable<String> onTabComplete(final CommandSender sender, final String[] args)
{
return ( args.length > 1 ) ? Collections.EMPTY_LIST : Iterables.transform( Iterables.filter( ProxyServer.getInstance().getServers().values(), new Predicate<ServerInfo>()
{
private final String lower = ( args.length == 0 ) ? "" : args[0].toLowerCase( Locale.ROOT );
@Override
public boolean apply(ServerInfo input)
{
return input.getName().toLowerCase( Locale.ROOT ).startsWith( lower ) && input.canAccess( sender );
}
} ), new Function<ServerInfo, String>()
{
@Override
public String apply(ServerInfo input)
{
return input.getName();
}
} );
}
}

View File

@ -1,13 +0,0 @@
package net.md_5.bungee.module.cmd.server;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginServer extends Plugin
{
@Override
public void onEnable()
{
getProxy().getPluginManager().registerCommand( this, new CommandServer() );
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.cmd.server.PluginServer
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@ -1,55 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>pom</packaging>
<name>BungeeCord Modules</name>
<description>Parent project for all BungeeCord modules.</description>
<modules>
<module>cmd-alert</module>
<module>cmd-find</module>
<module>cmd-kick</module>
<module>cmd-list</module>
<module>cmd-send</module>
<module>cmd-server</module>
<module>reconnect-yaml</module>
</modules>
<properties>
<module.author>SpigotMC</module.author>
<maven.deploy.skip>true</maven.deploy.skip>
<maven.javadoc.skip>true</maven.javadoc.skip>
</properties>
<dependencies>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<finalName>${project.name}</finalName>
<resources>
<resource>
<filtering>true</filtering>
<directory>${basedir}/src/main/resources</directory>
</resource>
</resources>
</build>
</project>

View File

@ -1,31 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-shared-configuration>
<!--
This file contains additional configuration written by modules in the NetBeans IDE.
The configuration is intended to be shared among all the users of project and
therefore it is assumed to be part of version control checkout.
Without this configuration present, some functionality in the IDE may be limited or fail altogether.
-->
<properties xmlns="http://www.netbeans.org/ns/maven-properties-data/1">
<!--
Properties that influence various parts of the IDE, especially code formatting and the like.
You can copy and paste the single properties, into the pom.xml file and the IDE will pick them up.
That way multiple projects can share the same settings (useful for formatting rules for example).
Any value defined here will override the pom.xml file value but is only applicable to the current project.
-->
<org-netbeans-modules-editor-indent.CodeStyle.usedProfile>project</org-netbeans-modules-editor-indent.CodeStyle.usedProfile>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.classDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.otherBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>NEW_LINE</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.methodDeclBracePlacement>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinMethodCallParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSwitchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinCatchParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinTryParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinSynchronizedParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinArrayInitBrackets>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinWhileParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinIfParens>
<org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>true</org-netbeans-modules-editor-indent.text.x-java.CodeStyle.project.spaceWithinForParens>
</properties>
</project-shared-configuration>

View File

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-module-reconnect-yaml</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
<name>reconnect_yaml</name>
<description>Provides reconnect location functionality in locations.yml</description>
</project>

View File

@ -1,22 +0,0 @@
package net.md_5.bungee.module.reconnect.yaml;
import net.md_5.bungee.api.config.ListenerInfo;
import net.md_5.bungee.api.plugin.Plugin;
public class PluginYaml extends Plugin
{
@Override
public void onEnable()
{
// TODO: Abstract this for other reconnect modules
for ( ListenerInfo info : getProxy().getConfig().getListeners() )
{
if ( !info.isForceDefault() && getProxy().getReconnectHandler() == null )
{
getProxy().setReconnectHandler( new YamlReconnectHandler() );
break;
}
}
}
}

View File

@ -1,115 +0,0 @@
package net.md_5.bungee.module.reconnect.yaml;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import net.md_5.bungee.api.AbstractReconnectHandler;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.util.CaseInsensitiveMap;
import org.yaml.snakeyaml.Yaml;
public class YamlReconnectHandler extends AbstractReconnectHandler
{
private final Yaml yaml = new Yaml();
private final File file = new File( "locations.yml" );
private final ReadWriteLock lock = new ReentrantReadWriteLock();
/*========================================================================*/
private CaseInsensitiveMap<String> data;
@SuppressWarnings("unchecked")
public YamlReconnectHandler()
{
try
{
file.createNewFile();
try ( FileReader rd = new FileReader( file ) )
{
Map map = yaml.loadAs( rd, Map.class );
if ( map != null )
{
data = new CaseInsensitiveMap<>( map );
}
}
} catch ( Exception ex )
{
file.renameTo( new File( "locations.yml.old" ) );
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not load reconnect locations, resetting them" );
}
if ( data == null )
{
data = new CaseInsensitiveMap<>();
}
}
@Override
protected ServerInfo getStoredServer(ProxiedPlayer player)
{
ServerInfo server = null;
lock.readLock().lock();
try
{
server = ProxyServer.getInstance().getServerInfo( data.get( key( player ) ) );
} finally
{
lock.readLock().unlock();
}
return server;
}
@Override
public void setServer(ProxiedPlayer player)
{
lock.writeLock().lock();
try
{
data.put( key( player ), ( player.getReconnectServer() != null ) ? player.getReconnectServer().getName() : player.getServer().getInfo().getName() );
} finally
{
lock.writeLock().unlock();
}
}
private String key(ProxiedPlayer player)
{
InetSocketAddress host = player.getPendingConnection().getVirtualHost();
return player.getName() + ";" + host.getHostString() + ":" + host.getPort();
}
@Override
public void save()
{
Map<String, String> copy = new HashMap<>();
lock.readLock().lock();
try
{
copy.putAll( data );
} finally
{
lock.readLock().unlock();
}
try ( FileWriter wr = new FileWriter( file ) )
{
yaml.dump( copy, wr );
} catch ( IOException ex )
{
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not save reconnect locations", ex );
}
}
@Override
public void close()
{
}
}

View File

@ -1,5 +0,0 @@
name: ${project.name}
main: net.md_5.bungee.module.reconnect.yaml.PluginYaml
version: ${describe}
description: ${project.description}
author: ${module.author}

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-native</artifactId> <artifactId>bungeecord-native</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>

View File

@ -1,5 +1,6 @@
package net.md_5.bungee; package net.md_5.bungee;
import static org.junit.jupiter.api.Assertions.*;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import java.util.Random; import java.util.Random;
@ -9,12 +10,11 @@ import net.md_5.bungee.jni.NativeCode;
import net.md_5.bungee.jni.cipher.BungeeCipher; import net.md_5.bungee.jni.cipher.BungeeCipher;
import net.md_5.bungee.jni.cipher.JavaCipher; import net.md_5.bungee.jni.cipher.JavaCipher;
import net.md_5.bungee.jni.cipher.NativeCipher; import net.md_5.bungee.jni.cipher.NativeCipher;
import org.junit.Assert; import org.junit.jupiter.api.MethodOrderer;
import org.junit.FixMethodOrder; import org.junit.jupiter.api.Test;
import org.junit.Test; import org.junit.jupiter.api.TestMethodOrder;
import org.junit.runners.MethodSorters;
@FixMethodOrder(MethodSorters.NAME_ASCENDING) @TestMethodOrder(MethodOrderer.MethodName.class)
public class NativeCipherTest public class NativeCipherTest
{ {
@ -34,7 +34,7 @@ public class NativeCipherTest
if ( NativeCode.isSupported() ) if ( NativeCode.isSupported() )
{ {
boolean loaded = factory.load(); boolean loaded = factory.load();
Assert.assertTrue( "Native cipher failed to load!", loaded ); assertTrue( loaded, "Native cipher failed to load!" );
NativeCipher cipher = new NativeCipher(); NativeCipher cipher = new NativeCipher();
System.out.println( "Testing native cipher..." ); System.out.println( "Testing native cipher..." );
@ -48,7 +48,7 @@ public class NativeCipherTest
if ( NativeCode.isSupported() ) if ( NativeCode.isSupported() )
{ {
boolean loaded = factory.load(); boolean loaded = factory.load();
Assert.assertTrue( "Native cipher failed to load!", loaded ); assertTrue( loaded, "Native cipher failed to load!" );
NativeCipher cipher = new NativeCipher(); NativeCipher cipher = new NativeCipher();
@ -98,7 +98,7 @@ public class NativeCipherTest
// Encrypt // Encrypt
cipher.init( true, secret ); cipher.init( true, secret );
cipher.cipher( nativePlain, out ); cipher.cipher( nativePlain, out );
Assert.assertEquals( nativeCiphered, out ); assertEquals( nativeCiphered, out );
out.clear(); out.clear();
@ -106,7 +106,7 @@ public class NativeCipherTest
cipher.init( false, secret ); cipher.init( false, secret );
cipher.cipher( nativeCiphered, out ); cipher.cipher( nativeCiphered, out );
nativePlain.resetReaderIndex(); nativePlain.resetReaderIndex();
Assert.assertEquals( nativePlain, out ); assertEquals( nativePlain, out );
System.out.println( "This cipher works correctly!" ); System.out.println( "This cipher works correctly!" );
} }

View File

@ -1,5 +1,6 @@
package net.md_5.bungee; package net.md_5.bungee;
import static org.junit.jupiter.api.Assertions.*;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled; import io.netty.buffer.Unpooled;
import java.util.Arrays; import java.util.Arrays;
@ -9,8 +10,7 @@ import net.md_5.bungee.jni.NativeCode;
import net.md_5.bungee.jni.zlib.BungeeZlib; import net.md_5.bungee.jni.zlib.BungeeZlib;
import net.md_5.bungee.jni.zlib.JavaZlib; import net.md_5.bungee.jni.zlib.JavaZlib;
import net.md_5.bungee.jni.zlib.NativeZlib; import net.md_5.bungee.jni.zlib.NativeZlib;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Test;
public class NativeZlibTest public class NativeZlibTest
{ {
@ -22,7 +22,7 @@ public class NativeZlibTest
{ {
if ( NativeCode.isSupported() ) if ( NativeCode.isSupported() )
{ {
Assert.assertTrue( "Native code failed to load!", factory.load() ); assertTrue( factory.load(), "Native code failed to load!" );
test( factory.newInstance() ); test( factory.newInstance() );
} }
test( new JavaZlib() ); test( new JavaZlib() );
@ -64,6 +64,6 @@ public class NativeZlibTest
long elapsed = System.currentTimeMillis() - start; long elapsed = System.currentTimeMillis() - start;
System.out.println( "Took: " + elapsed + "ms" ); System.out.println( "Took: " + elapsed + "ms" );
Assert.assertTrue( "Results do not match", Arrays.equals( dataBuf, check ) ); assertTrue( Arrays.equals( dataBuf, check ), "Results do not match" );
} }
} }

11
pom.xml
View File

@ -3,7 +3,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
@ -37,7 +37,6 @@
<module>config</module> <module>config</module>
<module>event</module> <module>event</module>
<module>log</module> <module>log</module>
<module>module</module>
<module>protocol</module> <module>protocol</module>
<module>proxy</module> <module>proxy</module>
<module>query</module> <module>query</module>
@ -91,9 +90,9 @@
</dependencyManagement> </dependencyManagement>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>org.junit.jupiter</groupId>
<artifactId>junit</artifactId> <artifactId>junit-jupiter</artifactId>
<version>4.13.2</version> <version>5.10.0</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -132,7 +131,7 @@
<artifactId>scriptus</artifactId> <artifactId>scriptus</artifactId>
<version>0.5.0</version> <version>0.5.0</version>
<configuration> <configuration>
<format>git:${project.name}:${project.version}:%s:${build.number}</format> <format>git:${project.name}-Pandacube:${project.version}:%s:${build.number}</format>
</configuration> </configuration>
<executions> <executions>
<execution> <execution>

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-protocol</artifactId> <artifactId>bungeecord-protocol</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -41,7 +40,7 @@
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-chat</artifactId> <artifactId>bungeecord-chat</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>

View File

@ -15,6 +15,7 @@ public class MinecraftEncoder extends MessageToByteEncoder<DefinedPacket>
@Setter @Setter
private Protocol protocol; private Protocol protocol;
private boolean server; private boolean server;
@Getter
@Setter @Setter
private int protocolVersion; private int protocolVersion;

View File

@ -658,8 +658,8 @@ public enum Protocol
/*========================================================================*/ /*========================================================================*/
public static final int MAX_PACKET_ID = 0xFF; public static final int MAX_PACKET_ID = 0xFF;
/*========================================================================*/ /*========================================================================*/
final DirectionData TO_SERVER = new DirectionData( this, ProtocolConstants.Direction.TO_SERVER ); public final DirectionData TO_SERVER = new DirectionData( this, ProtocolConstants.Direction.TO_SERVER );
final DirectionData TO_CLIENT = new DirectionData( this, ProtocolConstants.Direction.TO_CLIENT ); public final DirectionData TO_CLIENT = new DirectionData( this, ProtocolConstants.Direction.TO_CLIENT );
public static void main(String[] args) public static void main(String[] args)
{ {
@ -719,7 +719,7 @@ public enum Protocol
return new ProtocolMapping( protocol, id ); return new ProtocolMapping( protocol, id );
} }
static final class DirectionData public static final class DirectionData
{ {
private final TIntObjectMap<ProtocolData> protocols = new TIntObjectHashMap<>(); private final TIntObjectMap<ProtocolData> protocols = new TIntObjectHashMap<>();
@ -802,6 +802,17 @@ public enum Protocol
} }
} }
public boolean hasPacket(Class<? extends DefinedPacket> packet, int version)
{
ProtocolData protocolData = getProtocolData( version );
if ( protocolData == null )
{
throw new BadPacketException( "Unsupported protocol version" );
}
return protocolData.packetMap.containsKey( packet );
}
final int getId(Class<? extends DefinedPacket> packet, int version) final int getId(Class<? extends DefinedPacket> packet, int version)
{ {

View File

@ -4,6 +4,7 @@ import com.google.common.base.Preconditions;
import com.mojang.brigadier.Command; import com.mojang.brigadier.Command;
import com.mojang.brigadier.StringReader; import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.arguments.BoolArgumentType;
import com.mojang.brigadier.arguments.DoubleArgumentType; import com.mojang.brigadier.arguments.DoubleArgumentType;
import com.mojang.brigadier.arguments.FloatArgumentType; import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType;
@ -303,7 +304,7 @@ public class Commands extends DefinedPacket
} }
@Data @Data
private static class ArgumentRegistry public static class ArgumentRegistry
{ {
private static final Map<String, ArgumentSerializer> PROVIDERS = new HashMap<>(); private static final Map<String, ArgumentSerializer> PROVIDERS = new HashMap<>();
@ -325,18 +326,29 @@ public class Commands extends DefinedPacket
{ {
} }
}; };
private static final ArgumentSerializer<Boolean> BOOLEAN = new ArgumentSerializer<Boolean>() private static final ProperArgumentSerializer<BoolArgumentType> BOOLEAN = new ProperArgumentSerializer<BoolArgumentType>()
{ {
@Override @Override
protected Boolean read(ByteBuf buf) protected BoolArgumentType read(ByteBuf buf)
{ {
return buf.readBoolean(); return BoolArgumentType.bool();
} }
@Override @Override
protected void write(ByteBuf buf, Boolean t) protected void write(ByteBuf buf, BoolArgumentType t)
{ {
buf.writeBoolean( t ); }
@Override
protected int getIntKey()
{
return 0;
}
@Override
protected String getKey()
{
return "brigadier:bool";
} }
}; };
private static final ArgumentSerializer<Byte> BYTE = new ArgumentSerializer<Byte>() private static final ArgumentSerializer<Byte> BYTE = new ArgumentSerializer<Byte>()
@ -353,7 +365,7 @@ public class Commands extends DefinedPacket
buf.writeByte( t ); buf.writeByte( t );
} }
}; };
private static final ArgumentSerializer<FloatArgumentType> FLOAT_RANGE = new ArgumentSerializer<FloatArgumentType>() private static final ProperArgumentSerializer<FloatArgumentType> FLOAT_RANGE = new ProperArgumentSerializer<FloatArgumentType>()
{ {
@Override @Override
protected FloatArgumentType read(ByteBuf buf) protected FloatArgumentType read(ByteBuf buf)
@ -381,8 +393,20 @@ public class Commands extends DefinedPacket
buf.writeFloat( t.getMaximum() ); buf.writeFloat( t.getMaximum() );
} }
} }
@Override
protected int getIntKey()
{
return 1;
}
@Override
protected String getKey()
{
return "brigadier:float";
}
}; };
private static final ArgumentSerializer<DoubleArgumentType> DOUBLE_RANGE = new ArgumentSerializer<DoubleArgumentType>() private static final ProperArgumentSerializer<DoubleArgumentType> DOUBLE_RANGE = new ProperArgumentSerializer<DoubleArgumentType>()
{ {
@Override @Override
protected DoubleArgumentType read(ByteBuf buf) protected DoubleArgumentType read(ByteBuf buf)
@ -410,8 +434,20 @@ public class Commands extends DefinedPacket
buf.writeDouble( t.getMaximum() ); buf.writeDouble( t.getMaximum() );
} }
} }
@Override
protected int getIntKey()
{
return 2;
}
@Override
protected String getKey()
{
return "brigadier:double";
}
}; };
private static final ArgumentSerializer<IntegerArgumentType> INTEGER_RANGE = new ArgumentSerializer<IntegerArgumentType>() private static final ProperArgumentSerializer<IntegerArgumentType> INTEGER_RANGE = new ProperArgumentSerializer<IntegerArgumentType>()
{ {
@Override @Override
protected IntegerArgumentType read(ByteBuf buf) protected IntegerArgumentType read(ByteBuf buf)
@ -439,6 +475,18 @@ public class Commands extends DefinedPacket
buf.writeInt( t.getMaximum() ); buf.writeInt( t.getMaximum() );
} }
} }
@Override
protected int getIntKey()
{
return 3;
}
@Override
protected String getKey()
{
return "brigadier:integer";
}
}; };
private static final ArgumentSerializer<Integer> INTEGER = new ArgumentSerializer<Integer>() private static final ArgumentSerializer<Integer> INTEGER = new ArgumentSerializer<Integer>()
{ {
@ -454,7 +502,7 @@ public class Commands extends DefinedPacket
buf.writeInt( t ); buf.writeInt( t );
} }
}; };
private static final ArgumentSerializer<LongArgumentType> LONG_RANGE = new ArgumentSerializer<LongArgumentType>() private static final ProperArgumentSerializer<LongArgumentType> LONG_RANGE = new ProperArgumentSerializer<LongArgumentType>()
{ {
@Override @Override
protected LongArgumentType read(ByteBuf buf) protected LongArgumentType read(ByteBuf buf)
@ -482,6 +530,18 @@ public class Commands extends DefinedPacket
buf.writeLong( t.getMaximum() ); buf.writeLong( t.getMaximum() );
} }
} }
@Override
protected int getIntKey()
{
return 4;
}
@Override
protected String getKey()
{
return "brigadier:long";
}
}; };
private static final ProperArgumentSerializer<StringArgumentType> STRING = new ProperArgumentSerializer<StringArgumentType>() private static final ProperArgumentSerializer<StringArgumentType> STRING = new ProperArgumentSerializer<StringArgumentType>()
{ {
@ -537,11 +597,20 @@ public class Commands extends DefinedPacket
static static
{ {
register( "brigadier:bool", VOID ); register( "brigadier:bool", BOOLEAN );
PROPER_PROVIDERS.put( BoolArgumentType.class, BOOLEAN );
register( "brigadier:float", FLOAT_RANGE ); register( "brigadier:float", FLOAT_RANGE );
PROPER_PROVIDERS.put( FloatArgumentType.class, FLOAT_RANGE );
register( "brigadier:double", DOUBLE_RANGE ); register( "brigadier:double", DOUBLE_RANGE );
PROPER_PROVIDERS.put( DoubleArgumentType.class, DOUBLE_RANGE );
register( "brigadier:integer", INTEGER_RANGE ); register( "brigadier:integer", INTEGER_RANGE );
register( "brigadier:long", LONG_RANGE ); PROPER_PROVIDERS.put( IntegerArgumentType.class, INTEGER_RANGE );
register( "brigadier:long", LONG_RANGE ); // 1.14+
PROPER_PROVIDERS.put( LongArgumentType.class, LONG_RANGE );
register( "brigadier:string", STRING ); register( "brigadier:string", STRING );
PROPER_PROVIDERS.put( StringArgumentType.class, STRING ); PROPER_PROVIDERS.put( StringArgumentType.class, STRING );
@ -756,6 +825,404 @@ public class Commands extends DefinedPacket
return serializer; return serializer;
} }
/**
* Returns the Minecraft ArgumentType {@code minecraft:entity}.
* @param singleEntity if the argument restrict to only one entity
* @param onlyPlayers if the argument restrict to players only
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftEntity(boolean singleEntity, boolean onlyPlayers)
{
byte flags = 0;
if ( singleEntity )
{
flags |= 1;
}
if ( onlyPlayers )
{
flags |= 2;
}
return minecraftArgumentType( "minecraft:entity", flags );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:game_profile}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftGameProfile()
{
return minecraftArgumentType( "minecraft:game_profile", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:block_pos}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftBlockPos()
{
return minecraftArgumentType( "minecraft:block_pos", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:column_pos}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftColumnPos()
{
return minecraftArgumentType( "minecraft:column_pos", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:vec3}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftVec3()
{
return minecraftArgumentType( "minecraft:vec3", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:vec2}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftVec2()
{
return minecraftArgumentType( "minecraft:vec2", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:block_state}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftBlockState()
{
return minecraftArgumentType( "minecraft:block_state", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:block_predicate}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftBlockPredicate()
{
return minecraftArgumentType( "minecraft:block_predicate", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:item_stack}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftItemStack()
{
return minecraftArgumentType( "minecraft:item_stack", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:item_predicate}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftItemPredicate()
{
return minecraftArgumentType( "minecraft:item_predicate", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:color}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftColor()
{
return minecraftArgumentType( "minecraft:color", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:component}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftComponent()
{
return minecraftArgumentType( "minecraft:component", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:message}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftMessage()
{
return minecraftArgumentType( "minecraft:message", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:nbt_compound_tag}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftNBTCompoundTag()
{
return minecraftArgumentType( "minecraft:nbt_compound_tag", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:nbt_tag}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftNBTTag()
{
return minecraftArgumentType( "minecraft:nbt_tag", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:nbt}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftNBT()
{
return minecraftArgumentType( "minecraft:nbt", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:nbt_path}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftNBTPath()
{
return minecraftArgumentType( "minecraft:nbt_path", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:objective}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftObjective()
{
return minecraftArgumentType( "minecraft:objective", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:objective_criteria}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftObjectiveCriteria()
{
return minecraftArgumentType( "minecraft:objective_criteria", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:operation}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftOperation()
{
return minecraftArgumentType( "minecraft:operation", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:particle}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftParticle()
{
return minecraftArgumentType( "minecraft:particle", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:rotation}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftRotation()
{
return minecraftArgumentType( "minecraft:rotation", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:scoreboard_slot}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftScoreboardSlot()
{
return minecraftArgumentType( "minecraft:scoreboard_slot", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:score_holder}.
* @param allowMultiple if the argument allows multiple entities
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftScoreHolder(boolean allowMultiple)
{
byte flags = 0;
if ( allowMultiple )
{
flags |= 1;
}
return minecraftArgumentType( "minecraft:score_holder", flags );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:swizzle}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftSwizzle()
{
return minecraftArgumentType( "minecraft:swizzle", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:team}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftTeam()
{
return minecraftArgumentType( "minecraft:team", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:item_slot}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftItemSlot()
{
return minecraftArgumentType( "minecraft:item_slot", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:resource_location}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftResourceLocation()
{
return minecraftArgumentType( "minecraft:resource_location", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:mob_effect}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftMobEffect()
{
return minecraftArgumentType( "minecraft:mob_effect", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:function}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftFunction()
{
return minecraftArgumentType( "minecraft:function", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:entity_anchor}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftEntityAnchor()
{
return minecraftArgumentType( "minecraft:entity_anchor", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:int_range}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftIntRange()
{
return minecraftArgumentType( "minecraft:int_range", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:float_range}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftFloatRange()
{
return minecraftArgumentType( "minecraft:float_range", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:item_enchantment}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftItemEnchantment()
{
return minecraftArgumentType( "minecraft:item_enchantment", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:entity_summon}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftEntitySummon()
{
return minecraftArgumentType( "minecraft:entity_summon", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:dimension}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftDimension()
{
return minecraftArgumentType( "minecraft:dimension", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:time}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftTime()
{
return minecraftArgumentType( "minecraft:time", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:uuid}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftUUID()
{
return minecraftArgumentType( "minecraft:uuid", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:angle}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftAngle()
{
return minecraftArgumentType( "minecraft:angle", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:resource}.
* @param rawString the raw string for the argument
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftResource(String rawString)
{
return minecraftArgumentType( "minecraft:resource", rawString );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:resource_or_tag}.
* @param rawString the raw string for the argument
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftResourceOrTag(String rawString)
{
return minecraftArgumentType( "minecraft:resource_or_tag", rawString );
}
private static ArgumentType<?> minecraftArgumentType(String key, Object rawValue)
{
ArgumentSerializer reader = PROVIDERS.get( key );
Preconditions.checkArgument( reader != null, "No provider for argument " + key );
return new DummyType( key, reader, rawValue );
}
private static ArgumentType<?> read(ByteBuf buf, int protocolVersion) private static ArgumentType<?> read(ByteBuf buf, int protocolVersion)
{ {
Object key; Object key;
@ -879,11 +1346,15 @@ public class Commands extends DefinedPacket
private static String getKey(SuggestionProvider<DummyProvider> provider) private static String getKey(SuggestionProvider<DummyProvider> provider)
{ {
Preconditions.checkArgument( provider instanceof DummyProvider, "Non dummy provider " + provider ); Preconditions.checkNotNull( provider );
if ( provider instanceof DummyProvider )
{
return ( (DummyProvider) provider ).key; return ( (DummyProvider) provider ).key;
} }
return ( (DummyProvider) ASK_SERVER ).key;
}
@Data @Data
private static final class DummyProvider implements SuggestionProvider<DummyProvider> private static final class DummyProvider implements SuggestionProvider<DummyProvider>
{ {

View File

@ -1,7 +1,7 @@
package net.md_5.bungee.protocol.packet; package net.md_5.bungee.protocol.packet;
import org.junit.Assert; import static org.junit.jupiter.api.Assertions.*;
import org.junit.Test; import org.junit.jupiter.api.Test;
public class PluginMessageTest public class PluginMessageTest
{ {
@ -9,9 +9,9 @@ public class PluginMessageTest
@Test @Test
public void testModerniseChannel() public void testModerniseChannel()
{ {
Assert.assertEquals( "bungeecord:main", PluginMessage.MODERNISE.apply( "BungeeCord" ) ); assertEquals( "bungeecord:main", PluginMessage.MODERNISE.apply( "BungeeCord" ) );
Assert.assertEquals( "BungeeCord", PluginMessage.MODERNISE.apply( "bungeecord:main" ) ); assertEquals( "BungeeCord", PluginMessage.MODERNISE.apply( "bungeecord:main" ) );
Assert.assertEquals( "legacy:foo", PluginMessage.MODERNISE.apply( "FoO" ) ); assertEquals( "legacy:foo", PluginMessage.MODERNISE.apply( "FoO" ) );
Assert.assertEquals( "foo:bar", PluginMessage.MODERNISE.apply( "foo:bar" ) ); assertEquals( "foo:bar", PluginMessage.MODERNISE.apply( "foo:bar" ) );
} }
} }

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-proxy</artifactId> <artifactId>bungeecord-proxy</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -52,37 +51,37 @@
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-api</artifactId> <artifactId>bungeecord-api</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-log</artifactId> <artifactId>bungeecord-log</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-native</artifactId> <artifactId>bungeecord-native</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-protocol</artifactId> <artifactId>bungeecord-protocol</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-query</artifactId> <artifactId>bungeecord-query</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-slf4j</artifactId> <artifactId>bungeecord-slf4j</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>

View File

@ -89,7 +89,6 @@ import net.md_5.bungee.forge.ForgeConstants;
import net.md_5.bungee.log.BungeeLogger; import net.md_5.bungee.log.BungeeLogger;
import net.md_5.bungee.log.LoggingForwardHandler; import net.md_5.bungee.log.LoggingForwardHandler;
import net.md_5.bungee.log.LoggingOutputStream; import net.md_5.bungee.log.LoggingOutputStream;
import net.md_5.bungee.module.ModuleManager;
import net.md_5.bungee.netty.PipelineUtils; import net.md_5.bungee.netty.PipelineUtils;
import net.md_5.bungee.protocol.DefinedPacket; import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants; import net.md_5.bungee.protocol.ProtocolConstants;
@ -173,7 +172,6 @@ public class BungeeCord extends ProxyServer
.registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create(); .registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create();
@Getter @Getter
private ConnectionThrottle connectionThrottle; private ConnectionThrottle connectionThrottle;
private final ModuleManager moduleManager = new ModuleManager();
{ {
// TODO: Proper fallback when we interface the manager // TODO: Proper fallback when we interface the manager
@ -271,10 +269,6 @@ public class BungeeCord extends ProxyServer
eventLoops = PipelineUtils.newEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() ); eventLoops = PipelineUtils.newEventLoopGroup( 0, new ThreadFactoryBuilder().setNameFormat( "Netty IO Thread #%1$d" ).build() );
File moduleDirectory = new File( "modules" );
moduleManager.load( this, moduleDirectory );
pluginManager.detectPlugins( moduleDirectory );
pluginsFolder.mkdir(); pluginsFolder.mkdir();
pluginManager.detectPlugins( pluginsFolder ); pluginManager.detectPlugins( pluginsFolder );

View File

@ -5,7 +5,6 @@ import java.text.SimpleDateFormat;
import java.util.Arrays; import java.util.Arrays;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.concurrent.TimeUnit;
import joptsimple.OptionParser; import joptsimple.OptionParser;
import joptsimple.OptionSet; import joptsimple.OptionSet;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
@ -56,8 +55,7 @@ public class BungeeCordLauncher
System.err.println( "*** Warning, this build is outdated ***" ); System.err.println( "*** Warning, this build is outdated ***" );
System.err.println( "*** Please download a new build from http://ci.md-5.net/job/BungeeCord ***" ); System.err.println( "*** Please download a new build from http://ci.md-5.net/job/BungeeCord ***" );
System.err.println( "*** You will get NO support regarding this build ***" ); System.err.println( "*** You will get NO support regarding this build ***" );
System.err.println( "*** Server will start in 10 seconds ***" );
Thread.sleep( TimeUnit.SECONDS.toMillis( 10 ) );
} }
} }

View File

@ -5,6 +5,7 @@ import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import lombok.Data; import lombok.Data;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -13,6 +14,7 @@ import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.netty.ChannelWrapper; import net.md_5.bungee.netty.ChannelWrapper;
import net.md_5.bungee.protocol.DefinedPacket; import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.packet.PluginMessage; import net.md_5.bungee.protocol.packet.PluginMessage;
@RequiredArgsConstructor @RequiredArgsConstructor
@ -30,6 +32,7 @@ public class ServerConnection implements Server
private final boolean forgeServer = false; private final boolean forgeServer = false;
@Getter @Getter
private final Queue<KeepAliveData> keepAlives = new ArrayDeque<>(); private final Queue<KeepAliveData> keepAlives = new ArrayDeque<>();
private final Queue<DefinedPacket> packetQueue = new ConcurrentLinkedQueue<>();
private final Unsafe unsafe = new Unsafe() private final Unsafe unsafe = new Unsafe()
{ {
@ -40,10 +43,31 @@ public class ServerConnection implements Server
} }
}; };
public void sendPacketQueued(DefinedPacket packet)
{
Protocol encodeProtocol = ch.getEncodeProtocol();
if ( !encodeProtocol.TO_SERVER.hasPacket( packet.getClass(), ch.getEncodeVersion() ) )
{
packetQueue.add( packet );
} else
{
unsafe().sendPacket( packet );
}
}
public void sendQueuedPackets()
{
DefinedPacket packet;
while ( ( packet = packetQueue.poll() ) != null )
{
unsafe().sendPacket( packet );
}
}
@Override @Override
public void sendData(String channel, byte[] data) public void sendData(String channel, byte[] data)
{ {
unsafe().sendPacket( new PluginMessage( channel, data, forgeServer ) ); sendPacketQueued( new PluginMessage( channel, data, forgeServer ) );
} }
@Override @Override

View File

@ -20,6 +20,7 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Queue; import java.util.Queue;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level; import java.util.logging.Level;
import lombok.Getter; import lombok.Getter;
import lombok.NonNull; import lombok.NonNull;
@ -142,6 +143,7 @@ public final class UserConnection implements ProxiedPlayer
@Setter @Setter
private ForgeServerHandler forgeServerHandler; private ForgeServerHandler forgeServerHandler;
/*========================================================================*/ /*========================================================================*/
private final Queue<DefinedPacket> packetQueue = new ConcurrentLinkedQueue<>();
private final Unsafe unsafe = new Unsafe() private final Unsafe unsafe = new Unsafe()
{ {
@Override @Override
@ -177,6 +179,27 @@ public final class UserConnection implements ProxiedPlayer
ch.write( packet ); ch.write( packet );
} }
public void sendPacketQueued(DefinedPacket packet)
{
Protocol encodeProtocol = ch.getEncodeProtocol();
if ( !encodeProtocol.TO_CLIENT.hasPacket( packet.getClass(), getPendingConnection().getVersion() ) )
{
packetQueue.add( packet );
} else
{
unsafe().sendPacket( packet );
}
}
public void sendQueuedPackets()
{
DefinedPacket packet;
while ( ( packet = packetQueue.poll() ) != null )
{
unsafe().sendPacket( packet );
}
}
@Deprecated @Deprecated
public boolean isActive() public boolean isActive()
{ {
@ -489,10 +512,10 @@ public final class UserConnection implements ProxiedPlayer
position = ChatMessageType.SYSTEM; position = ChatMessageType.SYSTEM;
} }
unsafe().sendPacket( new SystemChat( message, position.ordinal() ) ); sendPacketQueued( new SystemChat( message, position.ordinal() ) );
} else } else
{ {
unsafe().sendPacket( new Chat( message, (byte) position.ordinal(), sender ) ); sendPacketQueued( new Chat( message, (byte) position.ordinal(), sender ) );
} }
} }
@ -513,7 +536,7 @@ public final class UserConnection implements ProxiedPlayer
net.md_5.bungee.protocol.packet.Title title = new net.md_5.bungee.protocol.packet.Title(); net.md_5.bungee.protocol.packet.Title title = new net.md_5.bungee.protocol.packet.Title();
title.setAction( net.md_5.bungee.protocol.packet.Title.Action.ACTIONBAR ); title.setAction( net.md_5.bungee.protocol.packet.Title.Action.ACTIONBAR );
title.setText( ComponentSerializer.toString( message ) ); title.setText( ComponentSerializer.toString( message ) );
unsafe.sendPacket( title ); sendPacketQueued( title );
} }
} else } else
{ {
@ -524,7 +547,7 @@ public final class UserConnection implements ProxiedPlayer
@Override @Override
public void sendData(String channel, byte[] data) public void sendData(String channel, byte[] data)
{ {
unsafe().sendPacket( new PluginMessage( channel, data, forgeClientHandler.isForgeUser() ) ); sendPacketQueued( new PluginMessage( channel, data, forgeClientHandler.isForgeUser() ) );
} }
@Override @Override
@ -700,7 +723,7 @@ public final class UserConnection implements ProxiedPlayer
header = ChatComponentTransformer.getInstance().transform( this, true, header )[0]; header = ChatComponentTransformer.getInstance().transform( this, true, header )[0];
footer = ChatComponentTransformer.getInstance().transform( this, true, footer )[0]; footer = ChatComponentTransformer.getInstance().transform( this, true, footer )[0];
unsafe().sendPacket( new PlayerListHeaderFooter( sendPacketQueued( new PlayerListHeaderFooter(
ComponentSerializer.toString( header ), ComponentSerializer.toString( header ),
ComponentSerializer.toString( footer ) ComponentSerializer.toString( footer )
) ); ) );
@ -712,7 +735,7 @@ public final class UserConnection implements ProxiedPlayer
header = ChatComponentTransformer.getInstance().transform( this, true, header ); header = ChatComponentTransformer.getInstance().transform( this, true, header );
footer = ChatComponentTransformer.getInstance().transform( this, true, footer ); footer = ChatComponentTransformer.getInstance().transform( this, true, footer );
unsafe().sendPacket( new PlayerListHeaderFooter( sendPacketQueued( new PlayerListHeaderFooter(
ComponentSerializer.toString( header ), ComponentSerializer.toString( header ),
ComponentSerializer.toString( footer ) ComponentSerializer.toString( footer )
) ); ) );

View File

@ -6,6 +6,7 @@ import com.google.common.collect.Lists;
import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.StringRange; import com.mojang.brigadier.context.StringRange;
@ -19,9 +20,12 @@ import io.netty.channel.unix.DomainSocketAddress;
import java.io.DataInput; import java.io.DataInput;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import net.md_5.bungee.ServerConnection; import net.md_5.bungee.ServerConnection;
@ -35,6 +39,7 @@ import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server; 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.PluginMessageEvent;
import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.event.ServerDisconnectEvent; import net.md_5.bungee.api.event.ServerDisconnectEvent;
@ -299,7 +304,7 @@ public class DownstreamBridge extends PacketHandler
Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" ); Preconditions.checkState( !serverBrand.contains( bungee.getName() ), "Cannot connect proxy to itself!" );
brand = ByteBufAllocator.DEFAULT.heapBuffer(); brand = ByteBufAllocator.DEFAULT.heapBuffer();
DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + serverBrand, brand ); DefinedPacket.writeString( bungee.getName() + " (" + bungee.getVersion() + ")" + " <- " + server.getInfo().getName() + " (" + serverBrand + ")", brand );
pluginMessage.setData( DefinedPacket.toArray( brand ) ); pluginMessage.setData( DefinedPacket.toArray( brand ) );
brand.release(); brand.release();
// changes in the packet are ignored so we need to send it manually // changes in the packet are ignored so we need to send it manually
@ -729,6 +734,11 @@ public class DownstreamBridge extends PacketHandler
{ {
boolean modified = false; boolean modified = false;
CommandsDeclareEvent commandsDeclareEvent = new CommandsDeclareEvent( server, con, commands.getRoot() );
bungee.getPluginManager().callEvent( commandsDeclareEvent );
modified = commandsDeclareEvent.isModified();
for ( Map.Entry<String, Command> command : bungee.getPluginManager().getCommands() ) for ( Map.Entry<String, Command> command : bungee.getPluginManager().getCommands() )
{ {
if ( !bungee.getDisabledCommands().contains( command.getKey() ) && commands.getRoot().getChild( command.getKey() ) == null && command.getValue().hasPermission( con ) ) if ( !bungee.getDisabledCommands().contains( command.getKey() ) && commands.getRoot().getChild( command.getKey() ) == null && command.getValue().hasPermission( con ) )
@ -745,11 +755,65 @@ public class DownstreamBridge extends PacketHandler
if ( modified ) if ( modified )
{ {
commands.setRoot( (com.mojang.brigadier.tree.RootCommandNode) filterCommandNode( commands.getRoot(), new IdentityHashMap<>() ) );
con.unsafe().sendPacket( commands ); con.unsafe().sendPacket( commands );
throw CancelSendSignal.INSTANCE; throw CancelSendSignal.INSTANCE;
} }
} }
/*
* Create a deep copy of the provided command node but removes any node that are not accessible by the player
* (using {@link CommandNode#getRequirement()})
*/
private CommandNode filterCommandNode(CommandNode source, IdentityHashMap<CommandNode, CommandNode> commandNodeMapping)
{
CommandNode dest;
if ( source instanceof com.mojang.brigadier.tree.RootCommandNode )
{
dest = new com.mojang.brigadier.tree.RootCommandNode();
} else
{
if ( source.getRequirement() != null )
{
try
{
if ( !source.getRequirement().test( con ) )
{
commandNodeMapping.put( source, null );
return null;
}
} catch ( Throwable t )
{
ProxyServer.getInstance().getLogger().log( Level.SEVERE, "Requirement test for command node " + source + " encountered an exception", t );
}
}
ArgumentBuilder destChildBuilder = source.createBuilder();
destChildBuilder.requires( sender -> true );
if ( destChildBuilder.getRedirect() != null )
{
if ( commandNodeMapping.containsKey( destChildBuilder.getRedirect() ) )
destChildBuilder.redirect( commandNodeMapping.get( destChildBuilder.getRedirect() ) );
else
destChildBuilder.redirect( filterCommandNode( destChildBuilder.getRedirect(), commandNodeMapping ) );
}
dest = destChildBuilder.build();
}
commandNodeMapping.put( source, dest );
for ( CommandNode sourceChild : (Collection<CommandNode>) source.getChildren() )
{
CommandNode destChild = filterCommandNode( sourceChild, commandNodeMapping );
if ( destChild == null )
continue;
dest.addChild( destChild );
}
return dest;
}
@Override @Override
public void handle(ServerData serverData) throws Exception public void handle(ServerData serverData) throws Exception
{ {

View File

@ -114,6 +114,15 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private String extraDataInHandshake = ""; private String extraDataInHandshake = "";
private UserConnection userCon; private UserConnection userCon;
@Getter
private boolean duplication = false;
@Getter
private String realName = null;
@Getter
private UUID realId = null;
@Override @Override
public boolean shouldHandle(PacketWrapper packet) throws Exception public boolean shouldHandle(PacketWrapper packet) throws Exception
{ {
@ -411,6 +420,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
} }
this.loginRequest = loginRequest; this.loginRequest = loginRequest;
setName( realName = loginRequest.getData() );
int limit = BungeeCord.getInstance().config.getPlayerLimit(); int limit = BungeeCord.getInstance().config.getPlayerLimit();
if ( limit > 0 && bungee.getOnlineCount() >= limit ) if ( limit > 0 && bungee.getOnlineCount() >= limit )
@ -419,14 +429,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection
return; return;
} }
// If offline mode and they are already on, don't allow connect
// We can just check by UUID here as names are based on UUID
if ( !isOnlineMode() && bungee.getPlayer( getUniqueId() ) != null )
{
disconnect( bungee.getTranslation( "already_connected_proxy" ) );
return;
}
Callback<PreLoginEvent> callback = new Callback<PreLoginEvent>() Callback<PreLoginEvent> callback = new Callback<PreLoginEvent>()
{ {
@ -443,6 +445,16 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{ {
return; return;
} }
if ( !realName.equals( name ) )
{
// Floodgate changes the name attribute with reflexion
setName( realName = name );
}
if ( uniqueId != null )
{
// if plugin called setUniqueId()
realId = uniqueId;
}
if ( onlineMode ) if ( onlineMode )
{ {
thisState = State.ENCRYPT; thisState = State.ENCRYPT;
@ -497,8 +509,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
if ( obj != null && obj.getId() != null ) if ( obj != null && obj.getId() != null )
{ {
loginProfile = obj; loginProfile = obj;
name = obj.getName(); setName( realName = obj.getName() );
uniqueId = Util.getUUID( obj.getId() ); uniqueId = realId = Util.getUUID( obj.getId() );
finish(); finish();
return; return;
} }
@ -516,10 +528,25 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private void finish() private void finish()
{ {
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( Charsets.UTF_8 ) ); if ( uniqueId == null ) // offline mode and no plugin used setUniqueId()
if ( uniqueId == null )
{ {
uniqueId = offlineId; uniqueId = realId = offlineId;
}
/*
* At this point, player is either authenticated by Mojang (online mode),
* by a plugin (Floodgate ?) or the offline id is set.
*/
ProxiedPlayer existingPlayer = bungee.getPlayer( uniqueId );
if ( existingPlayer != null && existingPlayer.hasPermission( "bungeecord.multiple_connect" ) )
{
UUID newId = generateDuplicatedId( uniqueId );
if ( !uniqueId.equals( newId ) )
{
uniqueId = newId;
setName( name + "." + getDuplicationIndex( newId ) );
duplication = true;
}
} }
if ( BungeeCord.getInstance().config.isEnforceSecureProfile() ) if ( BungeeCord.getInstance().config.isEnforceSecureProfile() )
@ -693,6 +720,54 @@ public class InitialHandler extends PacketHandler implements PendingConnection
return ( name != null ) ? name : ( loginRequest == null ) ? null : loginRequest.getData(); return ( name != null ) ? name : ( loginRequest == null ) ? null : loginRequest.getData();
} }
private void setName(String name)
{
this.name = name;
if ( loginRequest != null )
{
loginRequest.setData( name ); // name transmitted to Spigot server
}
updateOfflineId();
}
private UUID generateDuplicatedId(UUID base)
{
// UUID version: offline = 3 ; Java online mode = 4 ; Floodgate xUID = 0 (and must be kept 0)
// UUID variant: offline = 0xx ; Java online mode = 10x ; Floodgate xUID = xxx
if ( base.version() == 0 )
{
/*
* Floodgates xUID converted to UUID are not supported
* because it requires the 64 MSBs to be 0 (or Floodgate API would not
* recognize a Bedrock account) and we cannot modify the 64 LSBs
* without risking a collision with the xUID of another Bedrock account
*/
return base;
}
long MSB = base.getMostSignificantBits();
long LSB = base.getLeastSignificantBits();
MSB &= 0xFFFFFFFF_FFFF_70FFL; // reset bits we need
MSB |= 0x00000000_0000_8000L; // set version to + 8 the current version
for ( int i = 1; i <= 9; i++ )
{
long newMSB = MSB | i << 8;
UUID newUUID = new UUID( newMSB, LSB );
if ( bungee.getPlayer( newUUID ) != null )
{
continue;
}
return newUUID;
}
return base; // there are too many duplicated connections for this player
}
private static int getDuplicationIndex(UUID duplicatedId)
{
return (int) ( duplicatedId.getMostSignificantBits() >> 8 ) & 0xF;
}
@Override @Override
public int getVersion() public int getVersion()
{ {
@ -732,6 +807,11 @@ public class InitialHandler extends PacketHandler implements PendingConnection
this.uniqueId = uuid; this.uniqueId = uuid;
} }
private void updateOfflineId()
{
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( Charsets.UTF_8 ) );
}
@Override @Override
public String getUUID() public String getUUID()
{ {

View File

@ -6,7 +6,6 @@ import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.Suggestions;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import net.md_5.bungee.BungeeCord; import net.md_5.bungee.BungeeCord;
@ -20,6 +19,7 @@ import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PluginMessageEvent; import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.SettingsChangedEvent; import net.md_5.bungee.api.event.SettingsChangedEvent;
import net.md_5.bungee.api.event.TabCompleteEvent; import net.md_5.bungee.api.event.TabCompleteEvent;
import net.md_5.bungee.api.event.TabCompleteRequestEvent;
import net.md_5.bungee.entitymap.EntityMap; import net.md_5.bungee.entitymap.EntityMap;
import net.md_5.bungee.forge.ForgeConstants; import net.md_5.bungee.forge.ForgeConstants;
import net.md_5.bungee.netty.ChannelWrapper; import net.md_5.bungee.netty.ChannelWrapper;
@ -31,6 +31,7 @@ import net.md_5.bungee.protocol.packet.Chat;
import net.md_5.bungee.protocol.packet.ClientChat; import net.md_5.bungee.protocol.packet.ClientChat;
import net.md_5.bungee.protocol.packet.ClientCommand; import net.md_5.bungee.protocol.packet.ClientCommand;
import net.md_5.bungee.protocol.packet.ClientSettings; import net.md_5.bungee.protocol.packet.ClientSettings;
import net.md_5.bungee.protocol.packet.FinishConfiguration;
import net.md_5.bungee.protocol.packet.KeepAlive; import net.md_5.bungee.protocol.packet.KeepAlive;
import net.md_5.bungee.protocol.packet.LoginAcknowledged; import net.md_5.bungee.protocol.packet.LoginAcknowledged;
import net.md_5.bungee.protocol.packet.PlayerListItem; import net.md_5.bungee.protocol.packet.PlayerListItem;
@ -225,32 +226,42 @@ public class UpstreamBridge extends PacketHandler
TabCompleteEvent tabCompleteEvent = new TabCompleteEvent( con, con.getServer(), tabComplete.getCursor(), suggestions ); TabCompleteEvent tabCompleteEvent = new TabCompleteEvent( con, con.getServer(), tabComplete.getCursor(), suggestions );
bungee.getPluginManager().callEvent( tabCompleteEvent ); bungee.getPluginManager().callEvent( tabCompleteEvent );
if ( tabCompleteEvent.isCancelled() ) List<String> legacyResults = tabCompleteEvent.getSuggestions();
int start = tabComplete.getCursor().lastIndexOf( ' ' ) + 1;
int end = tabComplete.getCursor().length();
StringRange lastArgumentRange = StringRange.between( start, end );
List<Suggestion> brigadier = new ArrayList<>( legacyResults.size() );
for ( String s : legacyResults )
{
brigadier.add( new Suggestion( lastArgumentRange, s ) );
}
TabCompleteRequestEvent tabCompleteRequestEvent = new TabCompleteRequestEvent( con, con.getServer(), tabComplete.getCursor(), lastArgumentRange, new Suggestions( lastArgumentRange, brigadier ) );
tabCompleteRequestEvent.setCancelled( tabCompleteEvent.isCancelled() );
bungee.getPluginManager().callEvent( tabCompleteRequestEvent );
if ( tabCompleteRequestEvent.isCancelled() )
{ {
throw CancelSendSignal.INSTANCE; throw CancelSendSignal.INSTANCE;
} }
List<String> results = tabCompleteEvent.getSuggestions(); Suggestions brigadierResults = tabCompleteRequestEvent.getSuggestions();
if ( !results.isEmpty() )
if ( !brigadierResults.isEmpty() )
{ {
// Unclear how to handle 1.13 commands at this point. Because we don't inject into the command packets we are unlikely to get this far unless
// Bungee plugins are adding results for commands they don't own anyway
if ( con.getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_13 ) if ( con.getPendingConnection().getVersion() < ProtocolConstants.MINECRAFT_1_13 )
{ {
List<String> results = new ArrayList<>( brigadierResults.getList().size() );
for ( Suggestion s : brigadierResults.getList() )
{
results.add( s.getText() );
}
con.unsafe().sendPacket( new TabCompleteResponse( results ) ); con.unsafe().sendPacket( new TabCompleteResponse( results ) );
} else } else
{ {
int start = tabComplete.getCursor().lastIndexOf( ' ' ) + 1; con.unsafe().sendPacket( new TabCompleteResponse( tabComplete.getTransactionId(), brigadierResults ) );
int end = tabComplete.getCursor().length();
StringRange range = StringRange.between( start, end );
List<Suggestion> brigadier = new LinkedList<>();
for ( String s : results )
{
brigadier.add( new Suggestion( range, s ) );
}
con.unsafe().sendPacket( new TabCompleteResponse( tabComplete.getTransactionId(), new Suggestions( range, brigadier ) ) );
} }
throw CancelSendSignal.INSTANCE; throw CancelSendSignal.INSTANCE;
} }
@ -330,10 +341,21 @@ public class UpstreamBridge extends PacketHandler
ch.setDecodeProtocol( Protocol.CONFIGURATION ); ch.setDecodeProtocol( Protocol.CONFIGURATION );
ch.write( new LoginAcknowledged() ); ch.write( new LoginAcknowledged() );
ch.setEncodeProtocol( Protocol.CONFIGURATION ); ch.setEncodeProtocol( Protocol.CONFIGURATION );
con.getServer().sendQueuedPackets();
throw CancelSendSignal.INSTANCE; throw CancelSendSignal.INSTANCE;
} }
} }
@Override
public void handle(FinishConfiguration finishConfiguration) throws Exception
{
con.sendQueuedPackets();
super.handle( finishConfiguration );
}
@Override @Override
public String toString() public String toString()
{ {

View File

@ -1,34 +0,0 @@
package net.md_5.bungee.module;
import com.google.common.io.ByteStreams;
import com.google.common.io.Files;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import lombok.Data;
import net.md_5.bungee.Util;
@Data
public class JenkinsModuleSource implements ModuleSource
{
@Override
public void retrieve(ModuleSpec module, ModuleVersion version)
{
System.out.println( "Attempting to Jenkins download module " + module.getName() + " v" + version.getBuild() );
try
{
URL website = new URL( "https://ci.md-5.net/job/BungeeCord/" + version.getBuild() + "/artifact/module/" + module.getName().replace( '_', '-' ) + "/target/" + module.getName() + ".jar" );
URLConnection con = website.openConnection();
// 15 second timeout at various stages
con.setConnectTimeout( 15000 );
con.setReadTimeout( 15000 );
Files.write( ByteStreams.toByteArray( con.getInputStream() ), module.getFile() );
System.out.println( "Download complete" );
} catch ( IOException ex )
{
System.out.println( "Failed to download: " + Util.exception( ex ) );
}
}
}

View File

@ -1,155 +0,0 @@
package net.md_5.bungee.module;
import com.google.common.base.Preconditions;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Level;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.PluginDescription;
import net.md_5.bungee.util.CaseInsensitiveMap;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
public class ModuleManager
{
private final Map<String, ModuleSource> knownSources = new HashMap<>();
public ModuleManager()
{
knownSources.put( "jenkins", new JenkinsModuleSource() );
}
// CHECKSTYLE:OFF
@SuppressFBWarnings(
{
"SF_SWITCH_FALLTHROUGH", "SF_SWITCH_NO_DEFAULT"
})
// CHECKSTYLE:ON
public void load(ProxyServer proxy, File moduleDirectory) throws Exception
{
moduleDirectory.mkdir();
ModuleVersion bungeeVersion = ModuleVersion.parse( proxy.getVersion() );
if ( bungeeVersion == null )
{
System.out.println( "Couldn't detect bungee version. Custom build?" );
return;
}
List<ModuleSpec> modules = new ArrayList<>();
File configFile = new File( "modules.yml" );
// Start Yaml
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle( DumperOptions.FlowStyle.BLOCK );
Yaml yaml = new Yaml( options );
Map<String, Object> config;
configFile.createNewFile();
try ( InputStream is = new FileInputStream( configFile ) )
{
config = (Map) yaml.load( is );
}
if ( config == null )
{
config = new CaseInsensitiveMap<>();
} else
{
config = new CaseInsensitiveMap<>( config );
}
// End yaml
List<String> defaults = new ArrayList<>();
Object readModules = config.get( "modules" );
if ( readModules != null )
{
defaults.addAll( (Collection) readModules );
}
int version = ( config.containsKey( "version" ) ) ? (int) config.get( "version" ) : 0;
switch ( version )
{
case 0:
defaults.add( "jenkins://cmd_alert" );
defaults.add( "jenkins://cmd_find" );
defaults.add( "jenkins://cmd_list" );
defaults.add( "jenkins://cmd_send" );
defaults.add( "jenkins://cmd_server" );
case 1:
defaults.add( "jenkins://reconnect_yaml" );
}
config.put( "modules", defaults );
config.put( "version", 2 );
try ( FileWriter wr = new FileWriter( configFile ) )
{
yaml.dump( config, wr );
}
for ( String s : (List<String>) config.get( "modules" ) )
{
URI uri = new URI( s );
ModuleSource source = knownSources.get( uri.getScheme() );
if ( source == null )
{
System.out.println( "Unknown module source: " + s );
continue;
}
String name = uri.getAuthority();
if ( name == null )
{
System.out.println( "Unknown module host: " + s );
continue;
}
ModuleSpec spec = new ModuleSpec( name, new File( moduleDirectory, name + ".jar" ), source );
modules.add( spec );
System.out.println( "Discovered module: " + spec );
}
for ( ModuleSpec module : modules )
{
ModuleVersion moduleVersion = ( module.getFile().exists() ) ? getVersion( module.getFile() ) : null;
if ( !bungeeVersion.equals( moduleVersion ) )
{
System.out.println( "Attempting to update plugin from " + moduleVersion + " to " + bungeeVersion );
module.getProvider().retrieve( module, bungeeVersion );
}
}
}
@SuppressFBWarnings("REC_CATCH_EXCEPTION")
private ModuleVersion getVersion(File file)
{
try ( JarFile jar = new JarFile( file ) )
{
JarEntry pdf = jar.getJarEntry( "plugin.yml" );
Preconditions.checkNotNull( pdf, "Plugin must have a plugin.yml" );
try ( InputStream in = jar.getInputStream( pdf ) )
{
PluginDescription desc = new Yaml().loadAs( in, PluginDescription.class );
return ModuleVersion.parse( desc.getVersion() );
}
} catch ( Exception ex )
{
ProxyServer.getInstance().getLogger().log( Level.WARNING, "Could not check module from file " + file, ex );
}
return null;
}
}

View File

@ -1,7 +0,0 @@
package net.md_5.bungee.module;
interface ModuleSource
{
void retrieve(ModuleSpec module, ModuleVersion version);
}

View File

@ -1,13 +0,0 @@
package net.md_5.bungee.module;
import java.io.File;
import lombok.Data;
@Data
public class ModuleSpec
{
private final String name;
private final File file;
private final ModuleSource provider;
}

View File

@ -1,35 +0,0 @@
package net.md_5.bungee.module;
import lombok.AccessLevel;
import lombok.Data;
import lombok.RequiredArgsConstructor;
@Data
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class ModuleVersion
{
private final String build;
private final String git;
public static ModuleVersion parse(String version)
{
int lastColon = version.lastIndexOf( ':' );
int secondLastColon = version.lastIndexOf( ':', lastColon - 1 );
if ( lastColon == -1 || secondLastColon == -1 )
{
return null;
}
String buildNumber = version.substring( lastColon + 1, version.length() );
String gitCommit = version.substring( secondLastColon + 1, lastColon ).replaceAll( "\"", "" );
if ( "unknown".equals( buildNumber ) || "unknown".equals( gitCommit ) )
{
return null;
}
return new ModuleVersion( buildNumber, gitCommit );
}
}

View File

@ -69,6 +69,11 @@ public class ChannelWrapper
ch.pipeline().get( MinecraftEncoder.class ).setProtocolVersion( protocol ); ch.pipeline().get( MinecraftEncoder.class ).setProtocolVersion( protocol );
} }
public int getEncodeVersion()
{
return ch.pipeline().get( MinecraftEncoder.class ).getProtocolVersion();
}
public void write(Object packet) public void write(Object packet)
{ {
if ( !closed ) if ( !closed )

View File

@ -1,12 +1,12 @@
package net.md_5.bungee; package net.md_5.bungee;
import static org.junit.jupiter.api.Assertions.*;
import com.google.common.base.Ticker; import com.google.common.base.Ticker;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Test;
public class ThrottleTest public class ThrottleTest
{ {
@ -38,18 +38,18 @@ public class ThrottleTest
address = new InetSocketAddress( InetAddress.getByName( null ), 0 ); address = new InetSocketAddress( InetAddress.getByName( null ), 0 );
} }
Assert.assertFalse( "Address should not be throttled", throttle.throttle( address ) ); // 1 assertFalse( throttle.throttle( address ), "Address should not be throttled" ); // 1
Assert.assertFalse( "Address should not be throttled", throttle.throttle( address ) ); // 2 assertFalse( throttle.throttle( address ), "Address should not be throttled" ); // 2
Assert.assertFalse( "Address should not be throttled", throttle.throttle( address ) ); // 3 assertFalse( throttle.throttle( address ), "Address should not be throttled" ); // 3
Assert.assertTrue( "Address should be throttled", throttle.throttle( address ) ); // The 3rd one must be throttled, but also increased the count to 4 assertTrue( throttle.throttle( address ), "Address should be throttled" ); // The 3rd one must be throttled, but also increased the count to 4
throttle.unthrottle( address ); // We are back at 3, next attempt will make it 4 and throttle throttle.unthrottle( address ); // We are back at 3, next attempt will make it 4 and throttle
throttle.unthrottle( address ); // Now we are at 2, will not be throttled throttle.unthrottle( address ); // Now we are at 2, will not be throttled
Assert.assertFalse( "Address should not be throttled", throttle.throttle( address ) ); // 3 assertFalse( throttle.throttle( address ), "Address should not be throttled" ); // 3
Assert.assertTrue( "Address should be throttled", throttle.throttle( address ) ); // 4 assertTrue( throttle.throttle( address ), "Address should be throttled" ); // 4
// Now test expiration // Now test expiration
ticker.value += TimeUnit.MILLISECONDS.toNanos( 50 ); ticker.value += TimeUnit.MILLISECONDS.toNanos( 50 );
Assert.assertFalse( "Address should not be throttled", throttle.throttle( address ) ); assertFalse( throttle.throttle( address ), "Address should not be throttled" );
} }
} }

View File

@ -1,13 +1,13 @@
package net.md_5.bungee.scheduler; package net.md_5.bungee.scheduler;
import static org.junit.jupiter.api.Assertions.*;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import net.md_5.bungee.api.plugin.DummyPlugin; import net.md_5.bungee.api.plugin.DummyPlugin;
import net.md_5.bungee.api.scheduler.ScheduledTask; import net.md_5.bungee.api.scheduler.ScheduledTask;
import net.md_5.bungee.api.scheduler.TaskScheduler; import net.md_5.bungee.api.scheduler.TaskScheduler;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Test;
public class SchedulerTest public class SchedulerTest
{ {
@ -31,7 +31,7 @@ public class SchedulerTest
latch.await( 5, TimeUnit.SECONDS ); latch.await( 5, TimeUnit.SECONDS );
Assert.assertEquals( 0, latch.getCount() ); assertEquals( 0, latch.getCount() );
} }
@Test @Test
@ -43,17 +43,17 @@ public class SchedulerTest
ScheduledTask task = setup( scheduler, b ); ScheduledTask task = setup( scheduler, b );
scheduler.cancel( task.getId() ); scheduler.cancel( task.getId() );
Thread.sleep( 250 ); Thread.sleep( 250 );
Assert.assertFalse( b.get() ); assertFalse( b.get() );
task = setup( scheduler, b ); task = setup( scheduler, b );
scheduler.cancel( task ); scheduler.cancel( task );
Thread.sleep( 250 ); Thread.sleep( 250 );
Assert.assertFalse( b.get() ); assertFalse( b.get() );
task = setup( scheduler, b ); task = setup( scheduler, b );
scheduler.cancel( task.getOwner() ); scheduler.cancel( task.getOwner() );
Thread.sleep( 250 ); Thread.sleep( 250 );
Assert.assertFalse( b.get() ); assertFalse( b.get() );
} }
@Test @Test
@ -64,11 +64,11 @@ public class SchedulerTest
setup( scheduler, b ); setup( scheduler, b );
Thread.sleep( 250 ); Thread.sleep( 250 );
Assert.assertTrue( b.get() ); assertTrue( b.get() );
b.set( false ); b.set( false );
Thread.sleep( 250 ); Thread.sleep( 250 );
Assert.assertTrue( b.get() ); assertTrue( b.get() );
} }
private ScheduledTask setup(TaskScheduler scheduler, final AtomicBoolean hasRun) private ScheduledTask setup(TaskScheduler scheduler, final AtomicBoolean hasRun)

View File

@ -1,8 +1,8 @@
package net.md_5.bungee.util; package net.md_5.bungee.util;
import static org.junit.jupiter.api.Assertions.*;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import org.junit.Assert; import org.junit.jupiter.api.Test;
import org.junit.Test;
public class AddressUtilTest public class AddressUtilTest
{ {
@ -11,9 +11,9 @@ public class AddressUtilTest
public void testScope() public void testScope()
{ {
InetSocketAddress addr = new InetSocketAddress( "0:0:0:0:0:0:0:1%0", 25577 ); InetSocketAddress addr = new InetSocketAddress( "0:0:0:0:0:0:0:1%0", 25577 );
Assert.assertEquals( "0:0:0:0:0:0:0:1", AddressUtil.sanitizeAddress( addr ) ); assertEquals( "0:0:0:0:0:0:0:1", AddressUtil.sanitizeAddress( addr ) );
InetSocketAddress addr2 = new InetSocketAddress( "0:0:0:0:0:0:0:1", 25577 ); InetSocketAddress addr2 = new InetSocketAddress( "0:0:0:0:0:0:0:1", 25577 );
Assert.assertEquals( "0:0:0:0:0:0:0:1", AddressUtil.sanitizeAddress( addr2 ) ); assertEquals( "0:0:0:0:0:0:0:1", AddressUtil.sanitizeAddress( addr2 ) );
} }
} }

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-query</artifactId> <artifactId>bungeecord-query</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>
@ -25,7 +24,7 @@
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-api</artifactId> <artifactId>bungeecord-api</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
<scope>compile</scope> <scope>compile</scope>

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<parent> <parent>
<groupId>net.md-5</groupId> <groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId> <artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-slf4j</artifactId> <artifactId>bungeecord-slf4j</artifactId>
<version>1.20-R0.2-SNAPSHOT</version> <version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging> <packaging>jar</packaging>