1
0
Fork 0

Compare commits

...

11 Commits

Author SHA1 Message Date
Marc Baloup cf36174de7 new event TabCompleteRequestEvent and deprecate TabCompleteEvent 2023-09-24 00:59:54 +02:00
Marc Baloup b7f0cc4217 Add CommandsDeclareEvent to declare commands with brigadier API 2023-09-24 00:59:54 +02:00
Marc Baloup a0f6d000ec Server branding now includes the backend server name 2023-09-24 00:59:54 +02:00
Marc Baloup 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
Marc Baloup f52180c385 Change projet configuration and POM for Pandacube 2023-09-24 00:59:54 +02:00
Marc Baloup 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>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-api</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
@ -20,25 +19,25 @@
<dependencies>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-chat</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-config</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-event</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-protocol</artifactId>
<version>${project.version}</version>
<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.
* @deprecated please use {@link TabCompleteRequestEvent} to support 1.13+ suggestions.
*/
@Deprecated
@Data
@ToString(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;
import static org.junit.jupiter.api.Assertions.*;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Collection;
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 org.junit.Test;
import org.junit.jupiter.api.Test;
public class ServerConnectRequestTest
{
@ -78,15 +79,15 @@ public class ServerConnectRequestTest
}
};
@Test(expected = NullPointerException.class)
@Test
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()
{
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;
import static org.junit.jupiter.api.Assertions.*;
import io.netty.channel.unix.DomainSocketAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import net.md_5.bungee.Util;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@RequiredArgsConstructor
@RunWith(Parameterized.class)
public class AddressParseTest
{
@Parameters
public static Collection<Object[]> data()
public static Stream<Arguments> data()
{
return Arrays.asList( new Object[][]
{
{
"127.0.0.1", "127.0.0.1", Util.DEFAULT_PORT
},
{
"127.0.0.1:1337", "127.0.0.1", 1337
},
{
"[::1]", "0:0:0:0:0:0:0:1", Util.DEFAULT_PORT
},
{
"[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
}
} );
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 ),
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 ),
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 ),
Arguments.of( "unix:///var/run/bungee.sock", "/var/run/bungee.sock", -1 )
);
}
private final String line;
private final String host;
private final int port;
@Test
public void test()
@ParameterizedTest
@MethodSource("data")
public void test(String line, String host, int port)
{
SocketAddress parsed = Util.getAddr( line );
@ -65,14 +40,14 @@ public class AddressParseTest
{
InetSocketAddress tcp = (InetSocketAddress) parsed;
Assert.assertEquals( host, tcp.getHostString() );
Assert.assertEquals( port, tcp.getPort() );
assertEquals( host, tcp.getHostString() );
assertEquals( port, tcp.getPort() );
} else if ( parsed instanceof DomainSocketAddress )
{
DomainSocketAddress unix = (DomainSocketAddress) parsed;
Assert.assertEquals( host, unix.path() );
Assert.assertEquals( -1, port );
assertEquals( host, unix.path() );
assertEquals( -1, port );
} else
{
throw new AssertionError( "Unknown socket " + parsed );

View File

@ -1,7 +1,7 @@
package net.md_5.bungee.util;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
public class CaseInsensitiveTest
{
@ -13,12 +13,12 @@ public class CaseInsensitiveTest
CaseInsensitiveMap<Object> map = new CaseInsensitiveMap<>();
map.put( "FOO", obj );
Assert.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.contains( "foo" ) ); // Assert that contains is case insensitive
assertTrue( map.entrySet().iterator().next().getKey().equals( "FOO" ) ); // Assert that case is preserved
// Assert that remove is case insensitive
map.remove( "FoO" );
Assert.assertFalse( map.contains( "foo" ) );
assertFalse( map.contains( "foo" ) );
}
@Test
@ -27,8 +27,8 @@ public class CaseInsensitiveTest
CaseInsensitiveSet set = new CaseInsensitiveSet();
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" );
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;
import static org.junit.jupiter.api.Assertions.*;
import java.util.UUID;
import net.md_5.bungee.Util;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Test;
public class UUIDTest
{
@ -13,7 +13,7 @@ public class UUIDTest
{
UUID uuid = UUID.fromString( "af74a02d-19cb-445b-b07f-6866a861f783" );
UUID uuid1 = Util.getUUID( "af74a02d19cb445bb07f6866a861f783" );
Assert.assertEquals( uuid, uuid1 );
assertEquals( uuid, uuid1 );
}
@Test
@ -23,7 +23,7 @@ public class UUIDTest
{
UUID expected = UUID.randomUUID();
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>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-bootstrap</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
@ -21,14 +20,12 @@
<properties>
<maven.deploy.skip>true</maven.deploy.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>
</properties>
<dependencies>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-proxy</artifactId>
<version>${project.version}</version>
<scope>compile</scope>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,148 +1,138 @@
package net.md_5.bungee.config;
import static org.junit.jupiter.api.Assertions.*;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import lombok.RequiredArgsConstructor;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
@RequiredArgsConstructor
@RunWith(Parameterized.class)
public class CompoundConfigurationTest
{
@Parameters(name = "{0}")
public static Iterable<Object[]> data()
public static Stream<Arguments> data()
{
// CHECKSTYLE:OFF
return Arrays.asList( new Object[][]
{
{
// provider
YamlConfiguration.class,
// testDocument
""
+ "receipt: Oz-Ware Purchase Invoice\n"
+ "date: 2012-08-06\n"
+ "customer:\n"
+ " given: Dorothy\n"
+ " family: Gale\n"
+ "\n"
+ "items:\n"
+ " - part_no: A4786\n"
+ " descrip: Water Bucket (Filled)\n"
+ " price: 1.47\n"
+ " quantity: 4\n"
+ "\n"
+ " - part_no: E1628\n"
+ " descrip: High Heeled \"Ruby\" Slippers\n"
+ " size: 8\n"
+ " price: 100.27\n"
+ " quantity: 1\n"
+ "\n"
+ "bill-to: &id001\n"
+ " street: |\n"
+ " 123 Tornado Alley\n"
+ " Suite 16\n"
+ " city: East Centerville\n"
+ " state: KS\n"
+ "\n"
+ "ship-to: *id001\n"
+ "\n"
+ "specialDelivery: >\n"
+ " Follow the Yellow Brick\n"
+ " Road to the Emerald City.\n"
+ " Pay no attention to the\n"
+ " man behind the curtain.",
// numberTest
""
+ "someKey:\n"
+ " 1: 1\n"
+ " 2: 2\n"
+ " 3: 3\n"
+ " 4: 4",
// nullTest
""
+ "null:\n"
+ " null: object\n"
+ " object: null\n"
},
{
// provider
JsonConfiguration.class,
// testDocument
""
+ "{\n"
+ " \"customer\": {\n"
+ " \"given\": \"Dorothy\", \n"
+ " \"family\": \"Gale\"\n"
+ " }, \n"
+ " \"ship-to\": {\n"
+ " \"city\": \"East Centerville\", \n"
+ " \"state\": \"KS\", \n"
+ " \"street\": \"123 Tornado Alley\\nSuite 16\\n\"\n"
+ " }, \n"
+ " \"bill-to\": {\n"
+ " \"city\": \"East Centerville\", \n"
+ " \"state\": \"KS\", \n"
+ " \"street\": \"123 Tornado Alley\\nSuite 16\\n\"\n"
+ " }, \n"
+ " \"date\": \"2012-08-06\", \n"
+ " \"items\": [\n"
+ " {\n"
+ " \"part_no\": \"A4786\", \n"
+ " \"price\": 1.47, \n"
+ " \"descrip\": \"Water Bucket (Filled)\", \n"
+ " \"quantity\": 4\n"
+ " }, \n"
+ " {\n"
+ " \"part_no\": \"E1628\", \n"
+ " \"descrip\": \"High Heeled \\\"Ruby\\\" Slippers\", \n"
+ " \"price\": 100.27, \n"
+ " \"quantity\": 1, \n"
+ " \"size\": 8\n"
+ " }\n"
+ " ], \n"
+ " \"receipt\": \"Oz-Ware Purchase Invoice\", \n"
+ " \"specialDelivery\": \"Follow the Yellow Brick Road to the Emerald City. Pay no attention to the man behind the curtain.\"\n"
+ "}",
// numberTest
""
+ "{\n"
+ " \"someKey\": {\n"
+ " \"1\": 1, \n"
+ " \"2\": 2, \n"
+ " \"3\": 3, \n"
+ " \"4\": 4\n"
+ " }\n"
+ "}",
// nullTest
""
+ "{\n"
+ " \"null\": {\n"
+ " \"null\": \"object\", \n"
+ " \"object\": null\n"
+ " }\n"
+ "}"
}
} );
// CHECKSTYLE:ON
return Stream.of(
Arguments.of(
// provider
YamlConfiguration.class,
// testDocument
""
+ "receipt: Oz-Ware Purchase Invoice\n"
+ "date: 2012-08-06\n"
+ "customer:\n"
+ " given: Dorothy\n"
+ " family: Gale\n"
+ "\n"
+ "items:\n"
+ " - part_no: A4786\n"
+ " descrip: Water Bucket (Filled)\n"
+ " price: 1.47\n"
+ " quantity: 4\n"
+ "\n"
+ " - part_no: E1628\n"
+ " descrip: High Heeled \"Ruby\" Slippers\n"
+ " size: 8\n"
+ " price: 100.27\n"
+ " quantity: 1\n"
+ "\n"
+ "bill-to: &id001\n"
+ " street: |\n"
+ " 123 Tornado Alley\n"
+ " Suite 16\n"
+ " city: East Centerville\n"
+ " state: KS\n"
+ "\n"
+ "ship-to: *id001\n"
+ "\n"
+ "specialDelivery: >\n"
+ " Follow the Yellow Brick\n"
+ " Road to the Emerald City.\n"
+ " Pay no attention to the\n"
+ " man behind the curtain.",
// numberTest
""
+ "someKey:\n"
+ " 1: 1\n"
+ " 2: 2\n"
+ " 3: 3\n"
+ " 4: 4",
// nullTest
""
+ "null:\n"
+ " null: object\n"
+ " object: null\n"
),
Arguments.of(
// provider
JsonConfiguration.class,
// testDocument
""
+ "{\n"
+ " \"customer\": {\n"
+ " \"given\": \"Dorothy\", \n"
+ " \"family\": \"Gale\"\n"
+ " }, \n"
+ " \"ship-to\": {\n"
+ " \"city\": \"East Centerville\", \n"
+ " \"state\": \"KS\", \n"
+ " \"street\": \"123 Tornado Alley\\nSuite 16\\n\"\n"
+ " }, \n"
+ " \"bill-to\": {\n"
+ " \"city\": \"East Centerville\", \n"
+ " \"state\": \"KS\", \n"
+ " \"street\": \"123 Tornado Alley\\nSuite 16\\n\"\n"
+ " }, \n"
+ " \"date\": \"2012-08-06\", \n"
+ " \"items\": [\n"
+ " {\n"
+ " \"part_no\": \"A4786\", \n"
+ " \"price\": 1.47, \n"
+ " \"descrip\": \"Water Bucket (Filled)\", \n"
+ " \"quantity\": 4\n"
+ " }, \n"
+ " {\n"
+ " \"part_no\": \"E1628\", \n"
+ " \"descrip\": \"High Heeled \\\"Ruby\\\" Slippers\", \n"
+ " \"price\": 100.27, \n"
+ " \"quantity\": 1, \n"
+ " \"size\": 8\n"
+ " }\n"
+ " ], \n"
+ " \"receipt\": \"Oz-Ware Purchase Invoice\", \n"
+ " \"specialDelivery\": \"Follow the Yellow Brick Road to the Emerald City. Pay no attention to the man behind the curtain.\"\n"
+ "}",
// numberTest
""
+ "{\n"
+ " \"someKey\": {\n"
+ " \"1\": 1, \n"
+ " \"2\": 2, \n"
+ " \"3\": 3, \n"
+ " \"4\": 4\n"
+ " }\n"
+ "}",
// nullTest
""
+ "{\n"
+ " \"null\": {\n"
+ " \"null\": \"object\", \n"
+ " \"object\": null\n"
+ " }\n"
+ "}"
)
);
}
//
private final Class<? extends ConfigurationProvider> provider;
private final String testDocument;
private final String numberTest;
private final String nullTest;
@Test
public void testConfig() throws Exception
@ParameterizedTest
@MethodSource("data")
public void testConfig(Class<? extends ConfigurationProvider> provider, String testDocument, String numberTest, String nullTest) throws Exception
{
Configuration conf = ConfigurationProvider.getProvider( provider ).load( testDocument );
testSection( conf );
@ -151,7 +141,7 @@ public class CompoundConfigurationTest
ConfigurationProvider.getProvider( provider ).save( conf, sw );
// 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.set( "receipt", "Oz-Ware Purchase Invoice" ); // Add it back
@ -160,37 +150,38 @@ public class CompoundConfigurationTest
private void testSection(Configuration conf)
{
Assert.assertEquals( "receipt", "Oz-Ware Purchase Invoice", conf.getString( "receipt" ) );
// Assert.assertEquals( "date", "2012-08-06", conf.get( "date" ).toString() );
assertEquals( "Oz-Ware Purchase Invoice", conf.getString( "receipt" ), "receipt" );
// assertEquals( "2012-08-06", conf.get( "date" ).toString(), "date" );
Configuration customer = conf.getSection( "customer" );
Assert.assertEquals( "customer.given", "Dorothy", customer.getString( "given" ) );
Assert.assertEquals( "customer.given", "Dorothy", conf.getString( "customer.given" ) );
assertEquals( "Dorothy", customer.getString( "given" ), "customer.given" );
assertEquals( "Dorothy", conf.getString( "customer.given" ), "customer.given" );
List items = conf.getList( "items" );
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 );
Assert.assertEquals( null, conf.get( "receipt" ) );
Assert.assertEquals( "foo", conf.get( "receipt", "foo" ) );
assertEquals( null, conf.get( "receipt" ) );
assertEquals( "foo", conf.get( "receipt", "foo" ) );
Configuration newSection = conf.getSection( "new.section" );
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" );
Assert.assertEquals( "bar", conf.get( "other.new.section" ) );
assertEquals( "bar", conf.get( "other.new.section" ) );
Assert.assertTrue( conf.contains( "customer.given" ) );
Assert.assertTrue( customer.contains( "given" ) );
assertTrue( conf.contains( "customer.given" ) );
assertTrue( customer.contains( "given" ) );
Assert.assertFalse( conf.contains( "customer.foo" ) );
Assert.assertFalse( customer.contains( "foo" ) );
assertFalse( conf.contains( "customer.foo" ) );
assertFalse( customer.contains( "foo" ) );
}
@Test
public void testNumberedKeys()
@ParameterizedTest
@MethodSource("data")
public void testNumberedKeys(Class<? extends ConfigurationProvider> provider, String testDocument, String numberTest, String nullTest)
{
Configuration conf = ConfigurationProvider.getProvider( provider ).load( numberTest );
@ -201,29 +192,31 @@ public class CompoundConfigurationTest
}
}
@Test
public void testNull()
@ParameterizedTest
@MethodSource("data")
public void testNull(Class<? extends ConfigurationProvider> provider, String testDocument, String numberTest, String nullTest)
{
Configuration conf = ConfigurationProvider.getProvider( provider ).load( nullTest );
Assert.assertEquals( "object", conf.get( "null.null" ) );
Assert.assertEquals( "object", conf.getSection( "null" ).get( "null" ) );
assertEquals( "object", conf.get( "null.null" ) );
assertEquals( "object", conf.getSection( "null" ).get( "null" ) );
Assert.assertEquals( null, conf.get( "null.object" ) );
Assert.assertEquals( "", conf.getString( "null.object" ) );
assertEquals( null, conf.get( "null.object" ) );
assertEquals( "", conf.getString( "null.object" ) );
}
@Test
public void testMapAddition()
@ParameterizedTest
@MethodSource("data")
public void testMapAddition(Class<? extends ConfigurationProvider> provider, String testDocument, String numberTest, String nullTest)
{
Configuration conf = ConfigurationProvider.getProvider( provider ).load( testDocument );
conf.set( "addition", Collections.singletonMap( "foo", "bar" ) );
// Order matters
Assert.assertEquals( "bar", conf.getSection( "addition" ).getString( "foo" ) );
Assert.assertEquals( "bar", conf.getString( "addition.foo" ) );
assertEquals( "bar", conf.getSection( "addition" ).getString( "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;
import org.junit.Assert;
import org.junit.Test;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
public class DefaultConfigurationTest
{
@ -16,8 +16,8 @@ public class DefaultConfigurationTest
Configuration actualConfig = new Configuration( defaultConfig );
Assert.assertEquals( 10, actualConfig.getInt( "setting" ) );
Assert.assertEquals( 11, actualConfig.getInt( "nested.setting" ) );
Assert.assertEquals( 12, actualConfig.getInt( "double.nested.setting" ) );
assertEquals( 10, actualConfig.getInt( "setting" ) );
assertEquals( 11, actualConfig.getInt( "nested.setting" ) );
assertEquals( 12, actualConfig.getInt( "double.nested.setting" ) );
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
package net.md_5.bungee;
import static org.junit.jupiter.api.Assertions.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
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.JavaZlib;
import net.md_5.bungee.jni.zlib.NativeZlib;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Test;
public class NativeZlibTest
{
@ -22,7 +22,7 @@ public class NativeZlibTest
{
if ( NativeCode.isSupported() )
{
Assert.assertTrue( "Native code failed to load!", factory.load() );
assertTrue( factory.load(), "Native code failed to load!" );
test( factory.newInstance() );
}
test( new JavaZlib() );
@ -64,6 +64,6 @@ public class NativeZlibTest
long elapsed = System.currentTimeMillis() - start;
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">
<modelVersion>4.0.0</modelVersion>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>pom</packaging>
@ -37,7 +37,6 @@
<module>config</module>
<module>event</module>
<module>log</module>
<module>module</module>
<module>protocol</module>
<module>proxy</module>
<module>query</module>
@ -91,9 +90,9 @@
</dependencyManagement>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.0</version>
<scope>test</scope>
</dependency>
<dependency>
@ -132,7 +131,7 @@
<artifactId>scriptus</artifactId>
<version>0.5.0</version>
<configuration>
<format>git:${project.name}:${project.version}:%s:${build.number}</format>
<format>git:${project.name}-Pandacube:${project.version}:%s:${build.number}</format>
</configuration>
<executions>
<execution>

View File

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

View File

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

View File

@ -658,8 +658,8 @@ public enum Protocol
/*========================================================================*/
public static final int MAX_PACKET_ID = 0xFF;
/*========================================================================*/
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_SERVER = new DirectionData( this, ProtocolConstants.Direction.TO_SERVER );
public final DirectionData TO_CLIENT = new DirectionData( this, ProtocolConstants.Direction.TO_CLIENT );
public static void main(String[] args)
{
@ -719,7 +719,7 @@ public enum Protocol
return new ProtocolMapping( protocol, id );
}
static final class DirectionData
public static final class DirectionData
{
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)
{

View File

@ -4,6 +4,7 @@ import com.google.common.base.Preconditions;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.arguments.BoolArgumentType;
import com.mojang.brigadier.arguments.DoubleArgumentType;
import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType;
@ -303,7 +304,7 @@ public class Commands extends DefinedPacket
}
@Data
private static class ArgumentRegistry
public static class ArgumentRegistry
{
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
protected Boolean read(ByteBuf buf)
protected BoolArgumentType read(ByteBuf buf)
{
return buf.readBoolean();
return BoolArgumentType.bool();
}
@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>()
@ -353,7 +365,7 @@ public class Commands extends DefinedPacket
buf.writeByte( t );
}
};
private static final ArgumentSerializer<FloatArgumentType> FLOAT_RANGE = new ArgumentSerializer<FloatArgumentType>()
private static final ProperArgumentSerializer<FloatArgumentType> FLOAT_RANGE = new ProperArgumentSerializer<FloatArgumentType>()
{
@Override
protected FloatArgumentType read(ByteBuf buf)
@ -381,8 +393,20 @@ public class Commands extends DefinedPacket
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
protected DoubleArgumentType read(ByteBuf buf)
@ -410,8 +434,20 @@ public class Commands extends DefinedPacket
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
protected IntegerArgumentType read(ByteBuf buf)
@ -439,6 +475,18 @@ public class Commands extends DefinedPacket
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>()
{
@ -454,7 +502,7 @@ public class Commands extends DefinedPacket
buf.writeInt( t );
}
};
private static final ArgumentSerializer<LongArgumentType> LONG_RANGE = new ArgumentSerializer<LongArgumentType>()
private static final ProperArgumentSerializer<LongArgumentType> LONG_RANGE = new ProperArgumentSerializer<LongArgumentType>()
{
@Override
protected LongArgumentType read(ByteBuf buf)
@ -482,6 +530,18 @@ public class Commands extends DefinedPacket
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>()
{
@ -537,11 +597,20 @@ public class Commands extends DefinedPacket
static
{
register( "brigadier:bool", VOID );
register( "brigadier:bool", BOOLEAN );
PROPER_PROVIDERS.put( BoolArgumentType.class, BOOLEAN );
register( "brigadier:float", FLOAT_RANGE );
PROPER_PROVIDERS.put( FloatArgumentType.class, FLOAT_RANGE );
register( "brigadier:double", DOUBLE_RANGE );
PROPER_PROVIDERS.put( DoubleArgumentType.class, DOUBLE_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 );
PROPER_PROVIDERS.put( StringArgumentType.class, STRING );
@ -756,6 +825,404 @@ public class Commands extends DefinedPacket
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)
{
Object key;
@ -879,9 +1346,13 @@ public class Commands extends DefinedPacket
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

View File

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

View File

@ -4,13 +4,12 @@
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-proxy</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
@ -52,37 +51,37 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-api</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-log</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-native</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-protocol</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-query</artifactId>
<version>${project.version}</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-slf4j</artifactId>
<version>${project.version}</version>
<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.LoggingForwardHandler;
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.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
@ -173,7 +172,6 @@ public class BungeeCord extends ProxyServer
.registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create();
@Getter
private ConnectionThrottle connectionThrottle;
private final ModuleManager moduleManager = new ModuleManager();
{
// 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() );
File moduleDirectory = new File( "modules" );
moduleManager.load( this, moduleDirectory );
pluginManager.detectPlugins( moduleDirectory );
pluginsFolder.mkdir();
pluginManager.detectPlugins( pluginsFolder );

View File

@ -5,7 +5,6 @@ import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import joptsimple.OptionParser;
import joptsimple.OptionSet;
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( "*** 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( "*** 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.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import lombok.Data;
import lombok.Getter;
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.netty.ChannelWrapper;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.Protocol;
import net.md_5.bungee.protocol.packet.PluginMessage;
@RequiredArgsConstructor
@ -30,6 +32,7 @@ public class ServerConnection implements Server
private final boolean forgeServer = false;
@Getter
private final Queue<KeepAliveData> keepAlives = new ArrayDeque<>();
private final Queue<DefinedPacket> packetQueue = new ConcurrentLinkedQueue<>();
private final 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
public void sendData(String channel, byte[] data)
{
unsafe().sendPacket( new PluginMessage( channel, data, forgeServer ) );
sendPacketQueued( new PluginMessage( channel, data, forgeServer ) );
}
@Override

View File

@ -20,6 +20,7 @@ import java.util.Map;
import java.util.Objects;
import java.util.Queue;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;
import lombok.Getter;
import lombok.NonNull;
@ -142,6 +143,7 @@ public final class UserConnection implements ProxiedPlayer
@Setter
private ForgeServerHandler forgeServerHandler;
/*========================================================================*/
private final Queue<DefinedPacket> packetQueue = new ConcurrentLinkedQueue<>();
private final Unsafe unsafe = new Unsafe()
{
@Override
@ -177,6 +179,27 @@ public final class UserConnection implements ProxiedPlayer
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
public boolean isActive()
{
@ -489,10 +512,10 @@ public final class UserConnection implements ProxiedPlayer
position = ChatMessageType.SYSTEM;
}
unsafe().sendPacket( new SystemChat( message, position.ordinal() ) );
sendPacketQueued( new SystemChat( message, position.ordinal() ) );
} 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();
title.setAction( net.md_5.bungee.protocol.packet.Title.Action.ACTIONBAR );
title.setText( ComponentSerializer.toString( message ) );
unsafe.sendPacket( title );
sendPacketQueued( title );
}
} else
{
@ -524,7 +547,7 @@ public final class UserConnection implements ProxiedPlayer
@Override
public void sendData(String channel, byte[] data)
{
unsafe().sendPacket( new PluginMessage( channel, data, forgeClientHandler.isForgeUser() ) );
sendPacketQueued( new PluginMessage( channel, data, forgeClientHandler.isForgeUser() ) );
}
@Override
@ -700,7 +723,7 @@ public final class UserConnection implements ProxiedPlayer
header = ChatComponentTransformer.getInstance().transform( this, true, header )[0];
footer = ChatComponentTransformer.getInstance().transform( this, true, footer )[0];
unsafe().sendPacket( new PlayerListHeaderFooter(
sendPacketQueued( new PlayerListHeaderFooter(
ComponentSerializer.toString( header ),
ComponentSerializer.toString( footer )
) );
@ -712,7 +735,7 @@ public final class UserConnection implements ProxiedPlayer
header = ChatComponentTransformer.getInstance().transform( this, true, header );
footer = ChatComponentTransformer.getInstance().transform( this, true, footer );
unsafe().sendPacket( new PlayerListHeaderFooter(
sendPacketQueued( new PlayerListHeaderFooter(
ComponentSerializer.toString( header ),
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.ByteStreams;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.ArgumentBuilder;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import com.mojang.brigadier.context.StringRange;
@ -19,9 +20,12 @@ import io.netty.channel.unix.DomainSocketAddress;
import java.io.DataInput;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.logging.Level;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
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.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.api.event.CommandsDeclareEvent;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.ServerConnectEvent;
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!" );
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 ) );
brand.release();
// 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;
CommandsDeclareEvent commandsDeclareEvent = new CommandsDeclareEvent( server, con, commands.getRoot() );
bungee.getPluginManager().callEvent( commandsDeclareEvent );
modified = commandsDeclareEvent.isModified();
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 ) )
@ -745,11 +755,65 @@ public class DownstreamBridge extends PacketHandler
if ( modified )
{
commands.setRoot( (com.mojang.brigadier.tree.RootCommandNode) filterCommandNode( commands.getRoot(), new IdentityHashMap<>() ) );
con.unsafe().sendPacket( commands );
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
public void handle(ServerData serverData) throws Exception
{

View File

@ -114,6 +114,15 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private String extraDataInHandshake = "";
private UserConnection userCon;
@Getter
private boolean duplication = false;
@Getter
private String realName = null;
@Getter
private UUID realId = null;
@Override
public boolean shouldHandle(PacketWrapper packet) throws Exception
{
@ -411,6 +420,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
}
this.loginRequest = loginRequest;
setName( realName = loginRequest.getData() );
int limit = BungeeCord.getInstance().config.getPlayerLimit();
if ( limit > 0 && bungee.getOnlineCount() >= limit )
@ -419,14 +429,6 @@ public class InitialHandler extends PacketHandler implements PendingConnection
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>()
{
@ -443,6 +445,16 @@ public class InitialHandler extends PacketHandler implements PendingConnection
{
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 )
{
thisState = State.ENCRYPT;
@ -497,8 +509,8 @@ public class InitialHandler extends PacketHandler implements PendingConnection
if ( obj != null && obj.getId() != null )
{
loginProfile = obj;
name = obj.getName();
uniqueId = Util.getUUID( obj.getId() );
setName( realName = obj.getName() );
uniqueId = realId = Util.getUUID( obj.getId() );
finish();
return;
}
@ -516,10 +528,25 @@ public class InitialHandler extends PacketHandler implements PendingConnection
private void finish()
{
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( Charsets.UTF_8 ) );
if ( uniqueId == null )
if ( uniqueId == null ) // offline mode and no plugin used setUniqueId()
{
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() )
@ -693,6 +720,54 @@ public class InitialHandler extends PacketHandler implements PendingConnection
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
public int getVersion()
{
@ -732,6 +807,11 @@ public class InitialHandler extends PacketHandler implements PendingConnection
this.uniqueId = uuid;
}
private void updateOfflineId()
{
offlineId = UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + getName() ).getBytes( Charsets.UTF_8 ) );
}
@Override
public String getUUID()
{

View File

@ -6,7 +6,6 @@ import com.mojang.brigadier.suggestion.Suggestion;
import com.mojang.brigadier.suggestion.Suggestions;
import io.netty.channel.Channel;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
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.SettingsChangedEvent;
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.forge.ForgeConstants;
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.ClientCommand;
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.LoginAcknowledged;
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 );
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;
}
List<String> results = tabCompleteEvent.getSuggestions();
if ( !results.isEmpty() )
Suggestions brigadierResults = tabCompleteRequestEvent.getSuggestions();
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 )
{
List<String> results = new ArrayList<>( brigadierResults.getList().size() );
for ( Suggestion s : brigadierResults.getList() )
{
results.add( s.getText() );
}
con.unsafe().sendPacket( new TabCompleteResponse( results ) );
} else
{
int start = tabComplete.getCursor().lastIndexOf( ' ' ) + 1;
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 ) ) );
con.unsafe().sendPacket( new TabCompleteResponse( tabComplete.getTransactionId(), brigadierResults ) );
}
throw CancelSendSignal.INSTANCE;
}
@ -330,10 +341,21 @@ public class UpstreamBridge extends PacketHandler
ch.setDecodeProtocol( Protocol.CONFIGURATION );
ch.write( new LoginAcknowledged() );
ch.setEncodeProtocol( Protocol.CONFIGURATION );
con.getServer().sendQueuedPackets();
throw CancelSendSignal.INSTANCE;
}
}
@Override
public void handle(FinishConfiguration finishConfiguration) throws Exception
{
con.sendQueuedPackets();
super.handle( finishConfiguration );
}
@Override
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 );
}
public int getEncodeVersion()
{
return ch.pipeline().get( MinecraftEncoder.class ).getProtocolVersion();
}
public void write(Object packet)
{
if ( !closed )

View File

@ -1,12 +1,12 @@
package net.md_5.bungee;
import static org.junit.jupiter.api.Assertions.*;
import com.google.common.base.Ticker;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Test;
public class ThrottleTest
{
@ -38,18 +38,18 @@ public class ThrottleTest
address = new InetSocketAddress( InetAddress.getByName( null ), 0 );
}
Assert.assertFalse( "Address should not be throttled", throttle.throttle( address ) ); // 1
Assert.assertFalse( "Address should not be throttled", throttle.throttle( address ) ); // 2
Assert.assertFalse( "Address should not be throttled", throttle.throttle( address ) ); // 3
Assert.assertTrue( "Address should be throttled", throttle.throttle( address ) ); // The 3rd one must be throttled, but also increased the count to 4
assertFalse( throttle.throttle( address ), "Address should not be throttled" ); // 1
assertFalse( throttle.throttle( address ), "Address should not be throttled" ); // 2
assertFalse( throttle.throttle( address ), "Address should not be throttled" ); // 3
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 ); // Now we are at 2, will not be throttled
Assert.assertFalse( "Address should not be throttled", throttle.throttle( address ) ); // 3
Assert.assertTrue( "Address should be throttled", throttle.throttle( address ) ); // 4
assertFalse( throttle.throttle( address ), "Address should not be throttled" ); // 3
assertTrue( throttle.throttle( address ), "Address should be throttled" ); // 4
// Now test expiration
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;
import static org.junit.jupiter.api.Assertions.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import net.md_5.bungee.api.plugin.DummyPlugin;
import net.md_5.bungee.api.scheduler.ScheduledTask;
import net.md_5.bungee.api.scheduler.TaskScheduler;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Test;
public class SchedulerTest
{
@ -31,7 +31,7 @@ public class SchedulerTest
latch.await( 5, TimeUnit.SECONDS );
Assert.assertEquals( 0, latch.getCount() );
assertEquals( 0, latch.getCount() );
}
@Test
@ -43,17 +43,17 @@ public class SchedulerTest
ScheduledTask task = setup( scheduler, b );
scheduler.cancel( task.getId() );
Thread.sleep( 250 );
Assert.assertFalse( b.get() );
assertFalse( b.get() );
task = setup( scheduler, b );
scheduler.cancel( task );
Thread.sleep( 250 );
Assert.assertFalse( b.get() );
assertFalse( b.get() );
task = setup( scheduler, b );
scheduler.cancel( task.getOwner() );
Thread.sleep( 250 );
Assert.assertFalse( b.get() );
assertFalse( b.get() );
}
@Test
@ -64,11 +64,11 @@ public class SchedulerTest
setup( scheduler, b );
Thread.sleep( 250 );
Assert.assertTrue( b.get() );
assertTrue( b.get() );
b.set( false );
Thread.sleep( 250 );
Assert.assertTrue( b.get() );
assertTrue( b.get() );
}
private ScheduledTask setup(TaskScheduler scheduler, final AtomicBoolean hasRun)

View File

@ -1,8 +1,8 @@
package net.md_5.bungee.util;
import static org.junit.jupiter.api.Assertions.*;
import java.net.InetSocketAddress;
import org.junit.Assert;
import org.junit.Test;
import org.junit.jupiter.api.Test;
public class AddressUtilTest
{
@ -11,9 +11,9 @@ public class AddressUtilTest
public void testScope()
{
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 );
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>
<parent>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-parent</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-query</artifactId>
<version>1.20-R0.2-SNAPSHOT</version>
<packaging>jar</packaging>
@ -25,7 +24,7 @@
<scope>compile</scope>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<groupId>fr.pandacube.bungeecord</groupId>
<artifactId>bungeecord-api</artifactId>
<version>${project.version}</version>
<scope>compile</scope>

View File

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