From e2a2e19489ff1981299f5837d2dad3440091dfff Mon Sep 17 00:00:00 2001 From: mrapple Date: Sat, 6 Sep 2014 19:38:31 -0500 Subject: [PATCH 01/39] Change groupId to tc.oc and add our deployment info --- api/pom.xml | 11 +++++------ bootstrap/pom.xml | 5 ++--- chat/pom.xml | 3 +-- config/pom.xml | 3 +-- event/pom.xml | 3 +-- log/pom.xml | 6 +++--- module/cmd-alert/pom.xml | 3 +-- module/cmd-find/pom.xml | 3 +-- module/cmd-list/pom.xml | 3 +-- module/cmd-send/pom.xml | 3 +-- module/cmd-server/pom.xml | 3 +-- module/pom.xml | 5 ++--- module/reconnect-yaml/pom.xml | 3 +-- native/pom.xml | 3 +-- pom.xml | 37 +++++++++++------------------------ protocol/pom.xml | 5 ++--- proxy/pom.xml | 13 ++++++------ query/pom.xml | 5 ++--- 18 files changed, 43 insertions(+), 74 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 43a4dd9432..1b87f5d86e 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-parent 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-api 1.11-SNAPSHOT jar @@ -20,25 +19,25 @@ - net.md-5 + tc.oc bungeecord-chat ${project.version} compile - net.md-5 + tc.oc bungeecord-config ${project.version} compile - net.md-5 + tc.oc bungeecord-event ${project.version} compile - net.md-5 + tc.oc bungeecord-protocol ${project.version} compile diff --git a/bootstrap/pom.xml b/bootstrap/pom.xml index 5c42c6fada..c7dd2775be 100644 --- a/bootstrap/pom.xml +++ b/bootstrap/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-parent 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-bootstrap 1.11-SNAPSHOT jar @@ -26,7 +25,7 @@ - net.md-5 + tc.oc bungeecord-proxy ${project.version} compile diff --git a/chat/pom.xml b/chat/pom.xml index e8f3fd6c59..239c40f753 100644 --- a/chat/pom.xml +++ b/chat/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-parent 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-chat 1.11-SNAPSHOT jar diff --git a/config/pom.xml b/config/pom.xml index 5d32d0e842..7d2fd9a5e5 100644 --- a/config/pom.xml +++ b/config/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-parent 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-config 1.11-SNAPSHOT jar diff --git a/event/pom.xml b/event/pom.xml index 65a642244e..bf8b306550 100644 --- a/event/pom.xml +++ b/event/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-parent 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-event 1.11-SNAPSHOT jar diff --git a/log/pom.xml b/log/pom.xml index 22a933f273..56528a4bc9 100644 --- a/log/pom.xml +++ b/log/pom.xml @@ -4,13 +4,13 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-parent 1.11-SNAPSHOT ../pom.xml - net.md-5 + tc.oc bungeecord-log 1.11-SNAPSHOT jar @@ -26,7 +26,7 @@ compile - net.md-5 + tc.oc bungeecord-chat ${project.version} compile diff --git a/module/cmd-alert/pom.xml b/module/cmd-alert/pom.xml index 223d0f6ff1..4339668bb3 100644 --- a/module/cmd-alert/pom.xml +++ b/module/cmd-alert/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-module 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-module-cmd-alert 1.11-SNAPSHOT jar diff --git a/module/cmd-find/pom.xml b/module/cmd-find/pom.xml index 7635889da4..7a420ba846 100644 --- a/module/cmd-find/pom.xml +++ b/module/cmd-find/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-module 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-module-cmd-find 1.11-SNAPSHOT jar diff --git a/module/cmd-list/pom.xml b/module/cmd-list/pom.xml index 76158bcb54..90ebd4f5dd 100644 --- a/module/cmd-list/pom.xml +++ b/module/cmd-list/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-module 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-module-cmd-list 1.11-SNAPSHOT jar diff --git a/module/cmd-send/pom.xml b/module/cmd-send/pom.xml index 8737541900..37d2df285f 100644 --- a/module/cmd-send/pom.xml +++ b/module/cmd-send/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-module 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-module-cmd-send 1.11-SNAPSHOT jar diff --git a/module/cmd-server/pom.xml b/module/cmd-server/pom.xml index 8a0ed9de39..f197d3a0ce 100644 --- a/module/cmd-server/pom.xml +++ b/module/cmd-server/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-module 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-module-cmd-server 1.11-SNAPSHOT jar diff --git a/module/pom.xml b/module/pom.xml index 2d517465b9..a70727e38b 100644 --- a/module/pom.xml +++ b/module/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-parent 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-module 1.11-SNAPSHOT pom @@ -33,7 +32,7 @@ - net.md-5 + tc.oc bungeecord-api ${project.version} compile diff --git a/module/reconnect-yaml/pom.xml b/module/reconnect-yaml/pom.xml index c08ad70d47..11cf9d51ff 100644 --- a/module/reconnect-yaml/pom.xml +++ b/module/reconnect-yaml/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-module 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-module-reconnect-yaml 1.11-SNAPSHOT jar diff --git a/native/pom.xml b/native/pom.xml index 940d257e1e..7a2dadce14 100644 --- a/native/pom.xml +++ b/native/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-parent 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-native 1.11-SNAPSHOT jar diff --git a/pom.xml b/pom.xml index 7f9564c6d7..4a17e53301 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ 9 - net.md-5 + tc.oc bungeecord-parent 1.11-SNAPSHOT pom @@ -29,6 +29,16 @@ repo + + + overcast-deployment + https://repo.oc.tc/content/repositories/releases + + + overcast-deployment + https://repo.oc.tc/content/repositories/snapshots + + @@ -117,31 +127,6 @@ - - org.codehaus.mojo - animal-sniffer-maven-plugin - 1.13 - - - process-classes - - check - - - - - - java.lang.ClassLoader - java.lang.Throwable - java.util.Locale - - - org.codehaus.mojo.signature - java16 - 1.1 - - - org.apache.maven.plugins diff --git a/protocol/pom.xml b/protocol/pom.xml index 63d04980a9..d73892d9a4 100644 --- a/protocol/pom.xml +++ b/protocol/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-parent 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-protocol 1.11-SNAPSHOT jar @@ -20,7 +19,7 @@ - net.md-5 + tc.oc bungeecord-chat ${project.version} compile diff --git a/proxy/pom.xml b/proxy/pom.xml index 703fbda3fe..68776775a1 100644 --- a/proxy/pom.xml +++ b/proxy/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-parent 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-proxy 1.11-SNAPSHOT jar @@ -39,31 +38,31 @@ compile - net.md-5 + tc.oc bungeecord-api ${project.version} compile - net.md-5 + tc.oc bungeecord-log ${project.version} compile - net.md-5 + tc.oc bungeecord-native ${project.version} compile - net.md-5 + tc.oc bungeecord-protocol ${project.version} compile - net.md-5 + tc.oc bungeecord-query ${project.version} compile diff --git a/query/pom.xml b/query/pom.xml index fbadb18910..65f7684dd2 100644 --- a/query/pom.xml +++ b/query/pom.xml @@ -4,13 +4,12 @@ 4.0.0 - net.md-5 + tc.oc bungeecord-parent 1.11-SNAPSHOT ../pom.xml - net.md-5 bungeecord-query 1.11-SNAPSHOT jar @@ -26,7 +25,7 @@ compile - net.md-5 + tc.oc bungeecord-api ${project.version} compile From 114e9b7918e19136be899c63651c45462a303b7c Mon Sep 17 00:00:00 2001 From: mrapple Date: Thu, 11 Sep 2014 23:33:52 -0500 Subject: [PATCH 02/39] Disable security manager --- proxy/src/main/java/net/md_5/bungee/BungeeCord.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 159dab671a..68d3386475 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -179,7 +179,8 @@ public BungeeCord() throws IOException // Java uses ! to indicate a resource inside of a jar/zip/other container. Running Bungee from within a directory that has a ! will cause this to muck up. Preconditions.checkState( new File( "." ).getAbsolutePath().indexOf( '!' ) == -1, "Cannot use BungeeCord in directory with ! in path." ); - System.setSecurityManager( new BungeeSecurityManager() ); + // Overcast - disable security manager + // System.setSecurityManager( new BungeeSecurityManager() ); try { From d23b68801e6e151ebb0d1f6e814f8cb1af0f70c3 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Wed, 19 Nov 2014 04:07:51 -0500 Subject: [PATCH 03/39] Log stderr at WARNING instead of SEVERE --- proxy/src/main/java/net/md_5/bungee/BungeeCord.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 68d3386475..2312c9a7cc 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -213,7 +213,9 @@ public BungeeCord() throws IOException consoleReader.setExpandEvents( false ); logger = new BungeeLogger( "BungeeCord", "proxy.log", consoleReader ); - System.setErr( new PrintStream( new LoggingOutputStream( logger, Level.SEVERE ), true ) ); + + // Overcast - stderr gets a lot of non-error output, so log it at WARNING level instead of SEVERE + System.setErr( new PrintStream( new LoggingOutputStream( logger, Level.WARNING ), true ) ); System.setOut( new PrintStream( new LoggingOutputStream( logger, Level.INFO ), true ) ); if ( !Boolean.getBoolean( "net.md_5.bungee.native.disable" ) ) From b58f1c0e33bc86bcc0742655e430c66a47b9adf8 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Thu, 27 Nov 2014 17:40:43 -0500 Subject: [PATCH 04/39] Postpone PluginManager creation so that EventBus gets the right logger --- .../main/java/net/md_5/bungee/BungeeCord.java | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 2312c9a7cc..4a5ee55c12 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -130,7 +130,7 @@ public class BungeeCord extends ProxyServer * Plugin manager. */ @Getter - public final PluginManager pluginManager = new PluginManager( this ); + public final PluginManager pluginManager; @Getter @Setter private ReconnectHandler reconnectHandler; @@ -156,18 +156,6 @@ public class BungeeCord extends ProxyServer private ConnectionThrottle connectionThrottle; private final ModuleManager moduleManager = new ModuleManager(); - - { - // TODO: Proper fallback when we interface the manager - getPluginManager().registerCommand( null, new CommandReload() ); - getPluginManager().registerCommand( null, new CommandEnd() ); - getPluginManager().registerCommand( null, new CommandIP() ); - getPluginManager().registerCommand( null, new CommandBungee() ); - getPluginManager().registerCommand( null, new CommandPerms() ); - - registerChannel( "BungeeCord" ); - } - public static BungeeCord getInstance() { return (BungeeCord) ProxyServer.getInstance(); @@ -235,6 +223,17 @@ public BungeeCord() throws IOException logger.info( "Using standard Java compressor. To enable zero copy compression, run on 64 bit Linux" ); } } + + pluginManager = new PluginManager( this ); + + // TODO: Proper fallback when we interface the manager + getPluginManager().registerCommand( null, new CommandReload() ); + getPluginManager().registerCommand( null, new CommandEnd() ); + getPluginManager().registerCommand( null, new CommandIP() ); + getPluginManager().registerCommand( null, new CommandBungee() ); + getPluginManager().registerCommand( null, new CommandPerms() ); + + registerChannel( "BungeeCord" ); } /** From 83008edaf28ba468c4a14ebd204b775032a0245a Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Thu, 27 Nov 2014 17:41:15 -0500 Subject: [PATCH 05/39] Log event exceptions at SEVERE level --- event/src/main/java/net/md_5/bungee/event/EventBus.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/event/src/main/java/net/md_5/bungee/event/EventBus.java b/event/src/main/java/net/md_5/bungee/event/EventBus.java index 5b5d42010b..080349d2b9 100644 --- a/event/src/main/java/net/md_5/bungee/event/EventBus.java +++ b/event/src/main/java/net/md_5/bungee/event/EventBus.java @@ -52,7 +52,7 @@ public void post(Object event) throw new Error( "Method rejected target/argument: " + event, ex ); } catch ( InvocationTargetException ex ) { - logger.log( Level.WARNING, MessageFormat.format( "Error dispatching event {0} to listener {1}", event, method.getListener() ), ex.getCause() ); + logger.log( Level.SEVERE, MessageFormat.format( "Error dispatching event {0} to listener {1}", event, method.getListener() ), ex.getCause() ); } } } From d2d4c55b491185db52ea8cea9b136e83569e4e2b Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Thu, 27 Nov 2014 21:18:59 -0500 Subject: [PATCH 06/39] Improve logging of packet decoding errors --- .../java/net/md_5/bungee/protocol/BadPacketException.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/BadPacketException.java b/protocol/src/main/java/net/md_5/bungee/protocol/BadPacketException.java index 6c0ef4dfa0..d3ee377d8b 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/BadPacketException.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/BadPacketException.java @@ -1,6 +1,8 @@ package net.md_5.bungee.protocol; -public class BadPacketException extends RuntimeException +import io.netty.handler.codec.DecoderException; + +public class BadPacketException extends DecoderException { public BadPacketException(String message) From 12a61c1d22de33b81df05ef00775f6519a48c037 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sun, 30 Nov 2014 15:02:58 -0500 Subject: [PATCH 07/39] A few more packet ID range checks --- .../java/net/md_5/bungee/protocol/Protocol.java | 2 +- .../java/net/md_5/bungee/entitymap/EntityMap.java | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java b/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java index 01f23441d6..80c0b7ab63 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java @@ -287,7 +287,7 @@ public final DefinedPacket createPacket(int id, int version) { throw new BadPacketException( "Unsupported protocol version" ); } - if ( id > MAX_PACKET_ID ) + if ( id < 0 || id > MAX_PACKET_ID ) { throw new BadPacketException( "Packet with id " + id + " outside of range " ); } diff --git a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java index 34ddc19f5e..6ce1078385 100644 --- a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java +++ b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap.java @@ -5,6 +5,7 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; import net.md_5.bungee.protocol.DefinedPacket; +import net.md_5.bungee.protocol.Protocol; import net.md_5.bungee.protocol.ProtocolConstants; /** @@ -107,12 +108,15 @@ private static void rewrite(ByteBuf packet, int oldId, int newId, boolean[] ints int packetId = DefinedPacket.readVarInt( packet ); int packetIdLength = packet.readerIndex() - readerIndex; - if ( ints[packetId] ) + if ( 0 <= packetId && packetId < Protocol.MAX_PACKET_ID) { - rewriteInt( packet, oldId, newId, readerIndex + packetIdLength ); - } else if ( varints[packetId] ) - { - rewriteVarInt( packet, oldId, newId, readerIndex + packetIdLength ); + if ( ints[packetId] ) + { + rewriteInt( packet, oldId, newId, readerIndex + packetIdLength ); + } else if ( varints[packetId] ) + { + rewriteVarInt(packet, oldId, newId, readerIndex + packetIdLength); + } } packet.readerIndex( readerIndex ); } From 0287453095de11b3e9e7dda23a8da22557c39d30 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sat, 13 Dec 2014 15:16:04 -0500 Subject: [PATCH 08/39] Ignore a common exception that appears to be harmless --- .../main/java/net/md_5/bungee/netty/ChannelWrapper.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java b/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java index 0b0dd736e5..831b207213 100644 --- a/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java +++ b/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java @@ -13,6 +13,8 @@ import net.md_5.bungee.protocol.PacketWrapper; import net.md_5.bungee.protocol.Protocol; +import java.util.NoSuchElementException; + public class ChannelWrapper { @@ -110,7 +112,11 @@ public void setCompressionThreshold(int compressionThreshold) { if ( ch.pipeline().get( PacketCompressor.class ) == null && compressionThreshold != -1 ) { - addBefore( PipelineUtils.PACKET_ENCODER, "compress", new PacketCompressor() ); + try { + addBefore(PipelineUtils.PACKET_ENCODER, "compress", new PacketCompressor()); + } catch(NoSuchElementException ignored) { + // Sometimes packet-encoder is not in the pipeline, probably when the client disconnects soon after connecting + } } if ( compressionThreshold != -1 ) { From aca76c185b25b7ddeb8e85c21c8a81e4b3d338b5 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sun, 14 Dec 2014 02:58:43 -0500 Subject: [PATCH 09/39] Fix NPE caused by the other fix --- proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java b/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java index 831b207213..a2bc0831dc 100644 --- a/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java +++ b/proxy/src/main/java/net/md_5/bungee/netty/ChannelWrapper.java @@ -114,8 +114,9 @@ public void setCompressionThreshold(int compressionThreshold) { try { addBefore(PipelineUtils.PACKET_ENCODER, "compress", new PacketCompressor()); - } catch(NoSuchElementException ignored) { + } catch(NoSuchElementException ex) { // Sometimes packet-encoder is not in the pipeline, probably when the client disconnects soon after connecting + return; } } if ( compressionThreshold != -1 ) From dfbefc1fdac3bbda07321026c61be797b85d936d Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Mon, 22 Dec 2014 12:37:59 -0500 Subject: [PATCH 10/39] Remove startup delay for outdated build --- bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java b/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java index 3c1bbe9360..d811ea162c 100644 --- a/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java +++ b/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java @@ -44,8 +44,6 @@ public static void main(String[] args) throws Exception 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 ) ); } } From 637b5e9eba915d16c965a455918d6d5a9e59aeb3 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Tue, 6 Jan 2015 11:24:09 -0500 Subject: [PATCH 11/39] Add the capability to simulate username changes --- .../java/net/md_5/bungee/api/event/ServerConnectEvent.java | 1 + proxy/src/main/java/net/md_5/bungee/ServerConnector.java | 4 +++- proxy/src/main/java/net/md_5/bungee/UserConnection.java | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/net/md_5/bungee/api/event/ServerConnectEvent.java b/api/src/main/java/net/md_5/bungee/api/event/ServerConnectEvent.java index 17cfccd0a0..51824022bd 100644 --- a/api/src/main/java/net/md_5/bungee/api/event/ServerConnectEvent.java +++ b/api/src/main/java/net/md_5/bungee/api/event/ServerConnectEvent.java @@ -34,6 +34,7 @@ public class ServerConnectEvent extends Event implements Cancellable * Cancelled state. */ private boolean cancelled; + private String fakeUsername; public ServerConnectEvent(ProxiedPlayer player, ServerInfo target) { diff --git a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java index 2014b0c492..90d91d7d2d 100644 --- a/proxy/src/main/java/net/md_5/bungee/ServerConnector.java +++ b/proxy/src/main/java/net/md_5/bungee/ServerConnector.java @@ -33,6 +33,7 @@ import net.md_5.bungee.protocol.packet.Handshake; import net.md_5.bungee.protocol.packet.Kick; import net.md_5.bungee.protocol.packet.Login; +import net.md_5.bungee.protocol.packet.LoginRequest; import net.md_5.bungee.protocol.packet.LoginSuccess; import net.md_5.bungee.protocol.packet.PluginMessage; import net.md_5.bungee.protocol.packet.Respawn; @@ -48,6 +49,7 @@ public class ServerConnector extends PacketHandler private final UserConnection user; private final BungeeServerInfo target; private State thisState = State.LOGIN_SUCCESS; + private final String fakeUsername; @Getter private ForgeServerHandler handshakeHandler; private boolean obsolete; @@ -105,7 +107,7 @@ public void connected(ChannelWrapper channel) throws Exception channel.write( copiedHandshake ); channel.setProtocol( Protocol.LOGIN ); - channel.write( user.getPendingConnection().getLoginRequest() ); + channel.write(new LoginRequest(fakeUsername != null ? fakeUsername : user.getPendingConnection().getName())); } @Override diff --git a/proxy/src/main/java/net/md_5/bungee/UserConnection.java b/proxy/src/main/java/net/md_5/bungee/UserConnection.java index d620fbf598..49732ae7c8 100644 --- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java +++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java @@ -256,6 +256,7 @@ public void connect(ServerInfo info, final Callback callback, final boo } final BungeeServerInfo target = (BungeeServerInfo) event.getTarget(); // Update in case the event changed target + final String fakeUsername = event.getFakeUsername(); if ( getServer() != null && Objects.equal( getServer().getInfo(), target ) ) { @@ -288,7 +289,7 @@ protected void initChannel(Channel ch) throws Exception PipelineUtils.BASE.initChannel( ch ); ch.pipeline().addAfter( PipelineUtils.FRAME_DECODER, PipelineUtils.PACKET_DECODER, new MinecraftDecoder( Protocol.HANDSHAKE, false, getPendingConnection().getVersion() ) ); ch.pipeline().addAfter( PipelineUtils.FRAME_PREPENDER, PipelineUtils.PACKET_ENCODER, new MinecraftEncoder( Protocol.HANDSHAKE, false, getPendingConnection().getVersion() ) ); - ch.pipeline().get( HandlerBoss.class ).setHandler( new ServerConnector( bungee, UserConnection.this, target ) ); + ch.pipeline().get( HandlerBoss.class ).setHandler( new ServerConnector( bungee, UserConnection.this, target, fakeUsername ) ); } }; ChannelFutureListener listener = new ChannelFutureListener() From 11939a92be7d4cee1c16de55279dcee77f1a286c Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Fri, 13 Feb 2015 02:28:52 -0500 Subject: [PATCH 12/39] Properly serialize all BaseComponent subclasses --- .../main/java/net/md_5/bungee/chat/ComponentSerializer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java index 5756fc4afd..8fbd4bcfdc 100644 --- a/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java +++ b/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java @@ -18,9 +18,9 @@ public class ComponentSerializer implements JsonDeserializer { private final static Gson gson = new GsonBuilder(). - registerTypeAdapter( BaseComponent.class, new ComponentSerializer() ). - registerTypeAdapter( TextComponent.class, new TextComponentSerializer() ). - registerTypeAdapter( TranslatableComponent.class, new TranslatableComponentSerializer() ). + registerTypeHierarchyAdapter( BaseComponent.class, new ComponentSerializer() ). + registerTypeHierarchyAdapter( TextComponent.class, new TextComponentSerializer() ). + registerTypeHierarchyAdapter( TranslatableComponent.class, new TranslatableComponentSerializer() ). create(); public final static ThreadLocal> serializedComponents = new ThreadLocal>(); From 790fcc0c6c07284670113b1b484dc9caa20020ed Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Mon, 31 Aug 2015 03:28:07 -0400 Subject: [PATCH 13/39] Don't set the default log level to ALL --- log/src/main/java/net/md_5/bungee/log/BungeeLogger.java | 1 - 1 file changed, 1 deletion(-) diff --git a/log/src/main/java/net/md_5/bungee/log/BungeeLogger.java b/log/src/main/java/net/md_5/bungee/log/BungeeLogger.java index 9598fff324..75e71c4c12 100644 --- a/log/src/main/java/net/md_5/bungee/log/BungeeLogger.java +++ b/log/src/main/java/net/md_5/bungee/log/BungeeLogger.java @@ -23,7 +23,6 @@ public class BungeeLogger extends Logger public BungeeLogger(String loggerName, String filePattern, ConsoleReader reader) { super( loggerName, null ); - setLevel( Level.ALL ); try { From c9091cabc0d6f3f8fc15ab2d7dd5402d9a493d46 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sat, 5 Sep 2015 09:12:04 -0400 Subject: [PATCH 14/39] Allow commands to dynamically decide if they should be handled or passed upstream --- .../md_5/bungee/api/plugin/CommandBypassException.java | 8 ++++++++ .../java/net/md_5/bungee/api/plugin/PluginManager.java | 2 ++ 2 files changed, 10 insertions(+) create mode 100644 api/src/main/java/net/md_5/bungee/api/plugin/CommandBypassException.java diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/CommandBypassException.java b/api/src/main/java/net/md_5/bungee/api/plugin/CommandBypassException.java new file mode 100644 index 0000000000..0c3419c825 --- /dev/null +++ b/api/src/main/java/net/md_5/bungee/api/plugin/CommandBypassException.java @@ -0,0 +1,8 @@ +package net.md_5.bungee.api.plugin; + +/** + * Thrown from inside a command to tell the proxy to pass the command upstream + */ +public class CommandBypassException extends RuntimeException { + +} diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java index 71a5a15829..ed8d0f6eb2 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java @@ -174,6 +174,8 @@ public boolean dispatchCommand(CommandSender sender, String commandLine, List Date: Sat, 3 Oct 2015 06:26:47 -0400 Subject: [PATCH 15/39] Improve component cycle detection --- .../md_5/bungee/api/chat/BaseComponent.java | 96 ++++++++++++++++++- .../md_5/bungee/api/chat/TextComponent.java | 9 +- .../api/chat/TranslatableComponent.java | 17 +++- .../bungee/chat/BaseComponentSerializer.java | 14 +-- .../md_5/bungee/chat/ComponentSerializer.java | 6 +- .../chat/TranslatableComponentSerializer.java | 8 +- 6 files changed, 127 insertions(+), 23 deletions(-) diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java index cbb48b082e..0baf53e12f 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java @@ -1,5 +1,6 @@ package net.md_5.bungee.api.chat; +import com.google.common.base.Joiner; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @@ -7,11 +8,13 @@ import net.md_5.bungee.api.ChatColor; import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashSet; import java.util.List; -import lombok.ToString; +import java.util.Map; +import java.util.Set; @Setter -@ToString(exclude = "parent") @NoArgsConstructor public abstract class BaseComponent { @@ -395,4 +398,93 @@ void toLegacyText(StringBuilder builder) } } } + + protected static final ChatColor[] DECORATIONS = { + ChatColor.BOLD, + ChatColor.ITALIC, + ChatColor.UNDERLINE, + ChatColor.STRIKETHROUGH, + ChatColor.MAGIC + }; + + protected static final Joiner JOINER = Joiner.on(", "); + + public Boolean hasFormatRaw(ChatColor format) { + switch(format) { + case BOLD: return isBoldRaw(); + case ITALIC: return isItalicRaw(); + case UNDERLINE: return isUnderlinedRaw(); + case STRIKETHROUGH: return isStrikethroughRaw(); + case MAGIC: return isObfuscatedRaw(); + case RESET: return null; + } + + if(getColorRaw() == null) { + return null; + } else { + return getColorRaw() == format; + } + } + + public Map getFormatsRaw() { + EnumMap formats = new EnumMap(ChatColor.class); + + if(getColorRaw() != null) formats.put(getColorRaw(), true); + + for(ChatColor format : DECORATIONS) { + final Boolean flag = hasFormatRaw(format); + if(flag != null) formats.put(format, flag); + } + + return formats; + } + + protected void toStringTerminal(List fields) { + if(getColorRaw() != null) { + fields.add("color=\"" + getColorRaw().name().toLowerCase() + "\""); + } + + for(ChatColor format : DECORATIONS) { + final Boolean flag = hasFormatRaw(format); + if(flag != null) { + fields.add(format.name().toLowerCase() + "=" + flag); + } + } + + if(getClickEvent() != null) { + fields.add("clickEvent=" + getClickEvent()); + } + } + + protected void toStringRecursive(List fields) { + if(getHoverEvent() != null) { + fields.add("hoverEvent=" + getHoverEvent()); + } + + if(getExtra() != null && !getExtra().isEmpty()) { + fields.add("extra=[" + Joiner.on(", ").join(getExtra()) + "]"); + } + } + + private static final ThreadLocal> visited = new ThreadLocal>() { + @Override protected Set initialValue() { + return new HashSet(); + } + }; + + @Override + public String toString() { + List fields = new ArrayList(); + toStringTerminal(fields); + try { + if(visited.get().add(this)) { + toStringRecursive(fields); + } else { + fields.add("... (cycle)"); + } + } finally { + visited.get().remove(this); + } + return getClass().getSimpleName() + "{" + JOINER.join(fields) + "}"; + } } diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java index 15a26785e0..9e21ee9879 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java @@ -5,9 +5,11 @@ import lombok.NoArgsConstructor; import lombok.Setter; import net.md_5.bungee.api.ChatColor; +import org.apache.commons.lang.StringEscapeUtils; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -212,9 +214,8 @@ protected void toLegacyText(StringBuilder builder) super.toLegacyText( builder ); } - @Override - public String toString() - { - return String.format( "TextComponent{text=%s, %s}", text, super.toString() ); + @Override protected void toStringTerminal(List fields) { + fields.add("text=\"" + StringEscapeUtils.escapeJava(getText()) + "\""); + super.toStringTerminal(fields); } } diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java index 79c2e32e65..231ed9127f 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java @@ -10,11 +10,10 @@ import java.util.ResourceBundle; import java.util.regex.Matcher; import java.util.regex.Pattern; -import lombok.ToString; +import org.apache.commons.lang.StringEscapeUtils; @Getter @Setter -@ToString @NoArgsConstructor public class TranslatableComponent extends BaseComponent { @@ -249,4 +248,18 @@ private void addFormat(StringBuilder builder) builder.append( ChatColor.MAGIC ); } } + + @Override + protected void toStringTerminal(List fields) { + fields.add("translate=\"" + StringEscapeUtils.escapeJava(getTranslate()) + "\""); + super.toStringTerminal(fields); + } + + @Override + protected void toStringRecursive(List fields) { + if(getWith() != null && !getWith().isEmpty()) { + fields.add("with=[" + JOINER.join(getWith()) + "]"); + } + super.toStringRecursive(fields); + } } diff --git a/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java index 9aed9c564b..77f678ede7 100644 --- a/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java +++ b/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java @@ -10,7 +10,6 @@ import net.md_5.bungee.api.chat.HoverEvent; import java.util.Arrays; -import java.util.HashSet; public class BaseComponentSerializer { @@ -78,16 +77,9 @@ protected void deserialize(JsonObject object, BaseComponent component, JsonDeser protected void serialize(JsonObject object, BaseComponent component, JsonSerializationContext context) { - boolean first = false; - if ( ComponentSerializer.serializedComponents.get() == null ) - { - first = true; - ComponentSerializer.serializedComponents.set( new HashSet() ); - } try { - Preconditions.checkArgument( !ComponentSerializer.serializedComponents.get().contains( component ), "Component loop" ); - ComponentSerializer.serializedComponents.get().add( component ); + Preconditions.checkArgument( ComponentSerializer.serializedComponents.get().add( component ), "Component loop: " + component ); if ( component.getColorRaw() != null ) { object.addProperty( "color", component.getColorRaw().getName() ); @@ -140,10 +132,6 @@ protected void serialize(JsonObject object, BaseComponent component, JsonSeriali } finally { ComponentSerializer.serializedComponents.get().remove( component ); - if ( first ) - { - ComponentSerializer.serializedComponents.set( null ); - } } } } diff --git a/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java index 8fbd4bcfdc..4acb09b7d5 100644 --- a/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java +++ b/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java @@ -23,7 +23,11 @@ public class ComponentSerializer implements JsonDeserializer registerTypeHierarchyAdapter( TranslatableComponent.class, new TranslatableComponentSerializer() ). create(); - public final static ThreadLocal> serializedComponents = new ThreadLocal>(); + public final static ThreadLocal> serializedComponents = new ThreadLocal>() { + @Override protected HashSet initialValue() { + return new HashSet(); + } + }; public static BaseComponent[] parse(String json) { diff --git a/chat/src/main/java/net/md_5/bungee/chat/TranslatableComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/TranslatableComponentSerializer.java index c01af26864..213fb574d0 100644 --- a/chat/src/main/java/net/md_5/bungee/chat/TranslatableComponentSerializer.java +++ b/chat/src/main/java/net/md_5/bungee/chat/TranslatableComponentSerializer.java @@ -38,7 +38,13 @@ public JsonElement serialize(TranslatableComponent src, Type typeOfSrc, JsonSeri object.addProperty( "translate", src.getTranslate() ); if ( src.getWith() != null ) { - object.add( "with", context.serialize( src.getWith() ) ); + try { + ComponentSerializer.serializedComponents.get().add( src ); + object.add( "with", context.serialize( src.getWith() ) ); + } + finally { + ComponentSerializer.serializedComponents.get().remove( src ); + } } return object; } From 1d109a8306a3da05493d2ea6cd8ada10c07d14fc Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sun, 4 Oct 2015 01:53:42 -0400 Subject: [PATCH 16/39] Remove parent field from BaseComponent --- .../java/net/md_5/bungee/api/ChatColor.java | 9 + .../md_5/bungee/api/ChatStringBuilder.java | 106 ++++++++++++ .../md_5/bungee/api/chat/BaseComponent.java | 155 ++++++++++-------- .../md_5/bungee/api/chat/TextComponent.java | 27 +-- .../api/chat/TranslatableComponent.java | 47 ++---- .../api/chat/TranslatableComponentTest.java | 2 +- .../net/md_5/bungee/chat/ComponentsTest.java | 4 +- 7 files changed, 218 insertions(+), 132 deletions(-) create mode 100644 chat/src/main/java/net/md_5/bungee/api/ChatStringBuilder.java diff --git a/chat/src/main/java/net/md_5/bungee/api/ChatColor.java b/chat/src/main/java/net/md_5/bungee/api/ChatColor.java index cd88bd4700..85291a8806 100644 --- a/chat/src/main/java/net/md_5/bungee/api/ChatColor.java +++ b/chat/src/main/java/net/md_5/bungee/api/ChatColor.java @@ -105,6 +105,15 @@ public enum ChatColor */ public static final char COLOR_CHAR = '\u00A7'; public static final String ALL_CODES = "0123456789AaBbCcDdEeFfKkLlMmNnOoRr"; + + public static final ChatColor[] DECORATIONS = { + BOLD, + ITALIC, + UNDERLINE, + STRIKETHROUGH, + MAGIC + }; + /** * Pattern to remove all colour codes. */ diff --git a/chat/src/main/java/net/md_5/bungee/api/ChatStringBuilder.java b/chat/src/main/java/net/md_5/bungee/api/ChatStringBuilder.java new file mode 100644 index 0000000000..a3b0a2be53 --- /dev/null +++ b/chat/src/main/java/net/md_5/bungee/api/ChatStringBuilder.java @@ -0,0 +1,106 @@ +package net.md_5.bungee.api; + +import java.util.EnumSet; +import java.util.Set; + +public class ChatStringBuilder { + + private final StringBuilder builder; + private ChatColor oldColor, newColor; + private final Set oldDecorations, newDecorations; + private boolean formatChanged = true; + + public ChatStringBuilder(String initial, ChatColor color, Set decorations) { + builder = initial != null ? new StringBuilder(initial) : new StringBuilder(); + + oldColor = newColor = color; + + oldDecorations = decorations != null ? EnumSet.copyOf(decorations) : EnumSet.noneOf(ChatColor.class); + newDecorations = EnumSet.noneOf(ChatColor.class); + } + + public ChatStringBuilder() { + this(null, ChatColor.RESET, null); + } + + @Override + public String toString() { + return builder.toString(); + } + + private void refreshComplete() { + builder.append(oldColor = newColor); + + oldDecorations.clear(); + for(ChatColor deco : newDecorations) { + oldDecorations.add(deco); + builder.append(deco); + } + } + + private void refreshIfChanged() { + if(!formatChanged) return; + + // If color changed, a complete refresh is required + if(oldColor != newColor) { + refreshComplete(); + return; + } + + // If any decorations were removed, a complete refresh is required + for(ChatColor deco : oldDecorations) { + if(!newDecorations.contains(deco)) { + refreshComplete(); + return; + } + } + + // If the only change is added decorations, they can just be appended + for(ChatColor deco : newDecorations) { + if(oldDecorations.add(deco)) { + builder.append(deco); + } + } + } + + public void append(String text) { + if(!text.isEmpty()) { + refreshIfChanged(); + builder.append(text); + } + } + + public void append(Object thing) { + append(String.valueOf(thing)); + } + + public void color(ChatColor color) { + if(newColor != color) { + formatChanged = true; + newColor = color; + } + } + + public void decoration(ChatColor decoration, boolean on) { + if(on) { + if(newDecorations.add(decoration)) { + formatChanged = true; + } + } else { + if(newDecorations.remove(decoration)) { + formatChanged = true; + } + } + } + + public void decorations(Set decorations) { + for(ChatColor deco : ChatColor.DECORATIONS) { + decoration(deco, decorations.contains(deco)); + } + } + + public void format(ChatColor color, Set decorations) { + color(color); + decorations(decorations); + } +} diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java index 0baf53e12f..119c330079 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java @@ -1,14 +1,16 @@ package net.md_5.bungee.api.chat; import com.google.common.base.Joiner; -import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.ChatStringBuilder; import java.util.ArrayList; +import java.util.Collections; import java.util.EnumMap; +import java.util.EnumSet; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -19,9 +21,6 @@ public abstract class BaseComponent { - @Setter(AccessLevel.NONE) - BaseComponent parent; - /** * The color of this component and any child components (unless overridden) */ @@ -146,15 +145,7 @@ public static String toPlainText(BaseComponent... components) */ public ChatColor getColor() { - if ( color == null ) - { - if ( parent == null ) - { - return ChatColor.WHITE; - } - return parent.getColor(); - } - return color; + return color != null ? color : ChatColor.WHITE; } /** @@ -168,6 +159,10 @@ public ChatColor getColorRaw() return color; } + public ChatColor getColor(ChatColor def) { + return color != null ? color : def; + } + /** * Returns whether this component is bold. This uses the parent's setting if * this component hasn't been set. false is returned if none of the parent @@ -177,11 +172,7 @@ public ChatColor getColorRaw() */ public boolean isBold() { - if ( bold == null ) - { - return parent != null && parent.isBold(); - } - return bold; + return bold != null && bold; } /** @@ -204,11 +195,7 @@ public Boolean isBoldRaw() */ public boolean isItalic() { - if ( italic == null ) - { - return parent != null && parent.isItalic(); - } - return italic; + return italic != null && italic; } /** @@ -231,11 +218,7 @@ public Boolean isItalicRaw() */ public boolean isUnderlined() { - if ( underlined == null ) - { - return parent != null && parent.isUnderlined(); - } - return underlined; + return underlined != null && underlined; } /** @@ -258,11 +241,7 @@ public Boolean isUnderlinedRaw() */ public boolean isStrikethrough() { - if ( strikethrough == null ) - { - return parent != null && parent.isStrikethrough(); - } - return strikethrough; + return strikethrough != null && strikethrough; } /** @@ -285,11 +264,7 @@ public Boolean isStrikethroughRaw() */ public boolean isObfuscated() { - if ( obfuscated == null ) - { - return parent != null && parent.isObfuscated(); - } - return obfuscated; + return obfuscated != null && obfuscated; } /** @@ -305,10 +280,6 @@ public Boolean isObfuscatedRaw() public void setExtra(List components) { - for ( BaseComponent component : components ) - { - component.parent = this; - } extra = components; } @@ -335,7 +306,6 @@ public void addExtra(BaseComponent component) { extra = new ArrayList(); } - component.parent = this; extra.add( component ); } @@ -383,60 +353,107 @@ void toPlainText(StringBuilder builder) */ public String toLegacyText() { - StringBuilder builder = new StringBuilder(); - toLegacyText( builder ); + ChatStringBuilder builder = new ChatStringBuilder(); + toLegacyText(builder, ChatColor.WHITE, Collections.emptySet()); return builder.toString(); } - void toLegacyText(StringBuilder builder) + protected void toLegacyText(ChatStringBuilder builder, ChatColor color, Set decorations) { + color = getColor(color); + decorations = getDecorations(decorations); + + toLegacyTextContent(builder, color, decorations); + if ( extra != null ) { for ( BaseComponent e : extra ) { - e.toLegacyText( builder ); + e.toLegacyText( builder, color, decorations ); } } } - protected static final ChatColor[] DECORATIONS = { - ChatColor.BOLD, - ChatColor.ITALIC, - ChatColor.UNDERLINE, - ChatColor.STRIKETHROUGH, - ChatColor.MAGIC - }; + protected void toLegacyTextContent(ChatStringBuilder builder, ChatColor color, Set decorations) { + } protected static final Joiner JOINER = Joiner.on(", "); - public Boolean hasFormatRaw(ChatColor format) { - switch(format) { + public Boolean getDecoration(ChatColor decoration) { + switch(decoration) { case BOLD: return isBoldRaw(); case ITALIC: return isItalicRaw(); case UNDERLINE: return isUnderlinedRaw(); case STRIKETHROUGH: return isStrikethroughRaw(); case MAGIC: return isObfuscatedRaw(); - case RESET: return null; + default: return null; } + } - if(getColorRaw() == null) { - return null; + public boolean getDecoration(ChatColor decoration, boolean def) { + Boolean flag = getDecoration(decoration); + if(flag != null) { + return flag; } else { - return getColorRaw() == format; + return def; } } - public Map getFormatsRaw() { - EnumMap formats = new EnumMap(ChatColor.class); + public void setDecoration(ChatColor decoration, Boolean flag) { + switch(decoration) { + case BOLD: setBold(flag); return; + case ITALIC: setItalic(flag); return; + case UNDERLINE: setUnderlined(flag); return; + case STRIKETHROUGH: setStrikethrough(flag); return; + case MAGIC: setObfuscated(flag); return; + } + } - if(getColorRaw() != null) formats.put(getColorRaw(), true); + public Map getDecorations() { + EnumMap decos = new EnumMap(ChatColor.class); + for(ChatColor deco : ChatColor.DECORATIONS) { + final Boolean flag = getDecoration(deco); + if(flag != null) decos.put(deco, flag); + } + return decos; + } - for(ChatColor format : DECORATIONS) { - final Boolean flag = hasFormatRaw(format); - if(flag != null) formats.put(format, flag); + public Set getDecorations(Set def) { + EnumSet decos = EnumSet.noneOf(ChatColor.class); + for(ChatColor deco : ChatColor.DECORATIONS) { + if(getDecoration(deco, def.contains(deco))) { + decos.add(deco); + } } + return decos; + } + + public void mergeDecorations(BaseComponent from) { + for(ChatColor deco : ChatColor.DECORATIONS) { + Boolean flag = from.getDecoration(deco); + if(flag != null) setDecoration(deco, flag); + } + } + + public void mergeColor(BaseComponent from) { + if(from.getColorRaw() != null) { + setColor(from.getColorRaw()); + } + } + + public void mergeEvents(BaseComponent from) { + if(from.getClickEvent() != null) { + setClickEvent(from.getClickEvent()); + } + if(from.getHoverEvent() != null) { + setHoverEvent(from.getHoverEvent()); + } + } - return formats; + public void mergeFormatting(BaseComponent from) { + mergeDecorations(from); + mergeColor(from); + mergeEvents(from); } protected void toStringTerminal(List fields) { @@ -444,8 +461,8 @@ protected void toStringTerminal(List fields) { fields.add("color=\"" + getColorRaw().name().toLowerCase() + "\""); } - for(ChatColor format : DECORATIONS) { - final Boolean flag = hasFormatRaw(format); + for(ChatColor format : ChatColor.DECORATIONS) { + final Boolean flag = getDecoration(format); if(flag != null) { fields.add(format.name().toLowerCase() + "=" + flag); } diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java index 9e21ee9879..c8ef9791b2 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java @@ -5,11 +5,13 @@ import lombok.NoArgsConstructor; import lombok.Setter; import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.ChatStringBuilder; import org.apache.commons.lang.StringEscapeUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -187,31 +189,10 @@ protected void toPlainText(StringBuilder builder) } @Override - protected void toLegacyText(StringBuilder builder) + protected void toLegacyTextContent(ChatStringBuilder builder, ChatColor color, Set decorations) { - builder.append( getColor() ); - if ( isBold() ) - { - builder.append( ChatColor.BOLD ); - } - if ( isItalic() ) - { - builder.append( ChatColor.ITALIC ); - } - if ( isUnderlined() ) - { - builder.append( ChatColor.UNDERLINE ); - } - if ( isStrikethrough() ) - { - builder.append( ChatColor.STRIKETHROUGH ); - } - if ( isObfuscated() ) - { - builder.append( ChatColor.MAGIC ); - } + builder.format(color, decorations); builder.append( text ); - super.toLegacyText( builder ); } @Override protected void toStringTerminal(List fields) { diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java index 231ed9127f..7725ba0cb6 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java @@ -3,13 +3,17 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import net.md_5.bungee.api.ChatColor; + import java.util.ArrayList; import java.util.List; import java.util.MissingResourceException; import java.util.ResourceBundle; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.ChatStringBuilder; import org.apache.commons.lang.StringEscapeUtils; @Getter @@ -98,10 +102,6 @@ public BaseComponent duplicate() */ public void setWith(List components) { - for ( BaseComponent component : components ) - { - component.parent = this; - } with = components; } @@ -128,7 +128,6 @@ public void addWith(BaseComponent component) { with = new ArrayList(); } - component.parent = this; with.add( component ); } @@ -178,7 +177,7 @@ protected void toPlainText(StringBuilder builder) } @Override - protected void toLegacyText(StringBuilder builder) + protected void toLegacyTextContent(ChatStringBuilder builder, ChatColor color, Set decorations) { String trans; try @@ -197,7 +196,7 @@ protected void toLegacyText(StringBuilder builder) int pos = matcher.start(); if ( pos != position ) { - addFormat( builder ); + builder.format( color, decorations ); builder.append( trans.substring( position, pos ) ); } position = matcher.end(); @@ -208,45 +207,19 @@ protected void toLegacyText(StringBuilder builder) case 's': case 'd': String withIndex = matcher.group( 1 ); - with.get( withIndex != null ? Integer.parseInt( withIndex ) - 1 : i++ ).toLegacyText( builder ); + with.get( withIndex != null ? Integer.parseInt( withIndex ) - 1 : i++ ).toLegacyText( builder, color, decorations ); break; case '%': - addFormat( builder ); + builder.format( color, decorations ); builder.append( '%' ); break; } } if ( trans.length() != position ) { - addFormat( builder ); + builder.format( color, decorations ); builder.append( trans.substring( position, trans.length() ) ); } - super.toLegacyText( builder ); - } - - private void addFormat(StringBuilder builder) - { - builder.append( getColor() ); - if ( isBold() ) - { - builder.append( ChatColor.BOLD ); - } - if ( isItalic() ) - { - builder.append( ChatColor.ITALIC ); - } - if ( isUnderlined() ) - { - builder.append( ChatColor.UNDERLINE ); - } - if ( isStrikethrough() ) - { - builder.append( ChatColor.STRIKETHROUGH ); - } - if ( isObfuscated() ) - { - builder.append( ChatColor.MAGIC ); - } } @Override diff --git a/chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java b/chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java index 453d375d15..53e49d555e 100644 --- a/chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java +++ b/chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java @@ -13,6 +13,6 @@ public void testMissingPlaceholdersAdded() { TranslatableComponent testComponent = new TranslatableComponent( "Test string with %s placeholders: %s", "2", "aoeu" ); assertEquals( "Test string with 2 placeholders: aoeu", testComponent.toPlainText() ); - assertEquals( "§fTest string with §f2§f placeholders: §faoeu", testComponent.toLegacyText() ); + assertEquals( "§fTest string with 2 placeholders: aoeu", testComponent.toLegacyText() ); } } diff --git a/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java b/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java index 004a2b7a88..5f8dced76a 100644 --- a/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java +++ b/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java @@ -60,13 +60,13 @@ public void testTranslateComponent() Assert.assertEquals( "Given Golden Sword * 5 to thinkofdeath", translatableComponent.toPlainText() ); Assert.assertEquals( ChatColor.WHITE + "Given " + ChatColor.AQUA + "Golden Sword" + ChatColor.WHITE - + " * " + ChatColor.WHITE + "5" + ChatColor.WHITE + " to " + ChatColor.WHITE + "thinkofdeath", + + " * 5 to 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() ); + Assert.assertEquals( ChatColor.WHITE + "Page 5 of 50", positional.toLegacyText() ); } @Test From 2b8be1189baf653bc35fdbae0b97fc4381a821d5 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sun, 4 Oct 2015 09:40:12 -0400 Subject: [PATCH 17/39] Seems Apache Commons is not available at runtime --- chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java | 3 +-- .../java/net/md_5/bungee/api/chat/TranslatableComponent.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java index c8ef9791b2..3472237377 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java @@ -6,7 +6,6 @@ import lombok.Setter; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatStringBuilder; -import org.apache.commons.lang.StringEscapeUtils; import java.util.ArrayList; import java.util.Arrays; @@ -196,7 +195,7 @@ protected void toLegacyTextContent(ChatStringBuilder builder, ChatColor color, S } @Override protected void toStringTerminal(List fields) { - fields.add("text=\"" + StringEscapeUtils.escapeJava(getText()) + "\""); + fields.add("text=\"" + getText() + "\""); super.toStringTerminal(fields); } } diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java index 7725ba0cb6..a828b6494b 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java @@ -14,7 +14,6 @@ import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatStringBuilder; -import org.apache.commons.lang.StringEscapeUtils; @Getter @Setter @@ -224,7 +223,7 @@ protected void toLegacyTextContent(ChatStringBuilder builder, ChatColor color, S @Override protected void toStringTerminal(List fields) { - fields.add("translate=\"" + StringEscapeUtils.escapeJava(getTranslate()) + "\""); + fields.add("translate=\"" + getTranslate() + "\""); super.toStringTerminal(fields); } From fd8e6fe277676da0ac42b3e2c77ef08ee86683d1 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sat, 10 Oct 2015 18:38:52 -0400 Subject: [PATCH 18/39] Register PluginLoggers with the LogManager --- .../net/md_5/bungee/api/plugin/Plugin.java | 2 +- .../md_5/bungee/api/plugin/PluginLogger.java | 19 +++++++++++++++++++ .../net/md_5/bungee/log/BungeeLogger.java | 1 - 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/Plugin.java b/api/src/main/java/net/md_5/bungee/api/plugin/Plugin.java index bc91208a7d..d9cc587033 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/Plugin.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/Plugin.java @@ -85,7 +85,7 @@ final void init(ProxyServer proxy, PluginDescription description) this.proxy = proxy; this.description = description; this.file = description.getFile(); - this.logger = new PluginLogger( this ); + this.logger = PluginLogger.get( this ); } // diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginLogger.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginLogger.java index b304ec0d66..8b52dd8d42 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginLogger.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginLogger.java @@ -1,10 +1,29 @@ package net.md_5.bungee.api.plugin; +import java.util.logging.LogManager; import java.util.logging.LogRecord; import java.util.logging.Logger; public class PluginLogger extends Logger { + public static PluginLogger get(Plugin context) { + LogManager lm = LogManager.getLogManager(); + Logger logger = lm.getLogger(context.getClass().getCanonicalName()); + + if(logger instanceof PluginLogger) { + return (PluginLogger) logger; + } else { + PluginLogger pluginLogger = new PluginLogger(context); + + // Register the logger under the plugin's name, unless some other logger is already using the name + if(logger == null) { + lm.addLogger(pluginLogger); + pluginLogger.setParent(context.getProxy().getLogger()); // addLogger changes this, change it back + } + + return pluginLogger; + } + } private final String pluginName; diff --git a/log/src/main/java/net/md_5/bungee/log/BungeeLogger.java b/log/src/main/java/net/md_5/bungee/log/BungeeLogger.java index 75e71c4c12..3647747ab1 100644 --- a/log/src/main/java/net/md_5/bungee/log/BungeeLogger.java +++ b/log/src/main/java/net/md_5/bungee/log/BungeeLogger.java @@ -31,7 +31,6 @@ public BungeeLogger(String loggerName, String filePattern, ConsoleReader reader) addHandler( fileHandler ); ColouredWriter consoleHandler = new ColouredWriter( reader ); - consoleHandler.setLevel( Level.INFO ); consoleHandler.setFormatter( formatter ); addHandler( consoleHandler ); } catch ( IOException ex ) From f56d94a4bac6b51e12fda17b147888d0c85f9d3c Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sun, 11 Oct 2015 04:45:26 -0400 Subject: [PATCH 19/39] Register root logger with LogManager as well --- .../java/net/md_5/bungee/log/BungeeLogger.java | 15 +++++++++++++-- .../src/main/java/net/md_5/bungee/BungeeCord.java | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/log/src/main/java/net/md_5/bungee/log/BungeeLogger.java b/log/src/main/java/net/md_5/bungee/log/BungeeLogger.java index 3647747ab1..ea042038c5 100644 --- a/log/src/main/java/net/md_5/bungee/log/BungeeLogger.java +++ b/log/src/main/java/net/md_5/bungee/log/BungeeLogger.java @@ -4,13 +4,22 @@ import java.io.IOException; import java.util.logging.FileHandler; import java.util.logging.Formatter; -import java.util.logging.Level; +import java.util.logging.LogManager; import java.util.logging.LogRecord; import java.util.logging.Logger; import jline.console.ConsoleReader; public class BungeeLogger extends Logger { + public static BungeeLogger get(String loggerName, String filePattern, ConsoleReader reader) { + final LogManager lm = LogManager.getLogManager(); + Logger logger = lm.getLogger(loggerName); + if(!(logger instanceof BungeeLogger)) { + logger = new BungeeLogger(loggerName, filePattern, reader); + lm.addLogger(logger); + } + return (BungeeLogger) logger; + } private final Formatter formatter = new ConciseFormatter(); private final LogDispatcher dispatcher = new LogDispatcher( this ); @@ -20,9 +29,11 @@ public class BungeeLogger extends Logger "CallToPrintStackTrace", "CallToThreadStartDuringObjectConstruction" }) @SuppressFBWarnings("SC_START_IN_CTOR") - public BungeeLogger(String loggerName, String filePattern, ConsoleReader reader) + private BungeeLogger(String loggerName, String filePattern, ConsoleReader reader) { super( loggerName, null ); + setParent(Logger.getLogger("")); + setUseParentHandlers(false); try { diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 4a5ee55c12..e45fb7ddb6 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -200,7 +200,7 @@ public BungeeCord() throws IOException consoleReader = new ConsoleReader(); consoleReader.setExpandEvents( false ); - logger = new BungeeLogger( "BungeeCord", "proxy.log", consoleReader ); + logger = BungeeLogger.get( "BungeeCord", "proxy.log", consoleReader ); // Overcast - stderr gets a lot of non-error output, so log it at WARNING level instead of SEVERE System.setErr( new PrintStream( new LoggingOutputStream( logger, Level.WARNING ), true ) ); From 132e8d79efbc2d6be61cdef313dc89147a443f6c Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sat, 16 Jan 2016 06:59:23 -0500 Subject: [PATCH 20/39] Allow Configuration objects to be cloned --- .../src/main/java/net/md_5/bungee/config/Configuration.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/config/src/main/java/net/md_5/bungee/config/Configuration.java b/config/src/main/java/net/md_5/bungee/config/Configuration.java index 967a1b2acd..78822dc5c7 100644 --- a/config/src/main/java/net/md_5/bungee/config/Configuration.java +++ b/config/src/main/java/net/md_5/bungee/config/Configuration.java @@ -25,6 +25,11 @@ public Configuration(Configuration defaults) this( new LinkedHashMap(), defaults ); } + public Configuration(Configuration values, Configuration defaults) + { + this( values.self, defaults ); + } + Configuration(Map map, Configuration defaults) { this.self = new LinkedHashMap<>(); From 56c9497492477eba46c02c064f6f08eeaef467ec Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sun, 24 Jan 2016 18:52:29 -0500 Subject: [PATCH 21/39] Safe dynamic modification of the server list --- .../java/net/md_5/bungee/api/ProxyConfig.java | 66 ++++++++++++++++++ .../java/net/md_5/bungee/api/ProxyServer.java | 14 ++++ .../main/java/net/md_5/bungee/BungeeCord.java | 8 ++- .../net/md_5/bungee/conf/Configuration.java | 67 +++++++++++++++++++ 4 files changed, 154 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java b/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java index edd82c1e0e..7f405b91db 100644 --- a/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java +++ b/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java @@ -32,9 +32,75 @@ public interface ProxyConfig /** * Set of all servers. + * + * @deprecated The returned map may be modified concurrently by the proxy. + * The safe alternative is {@link #getServersCopy()}. */ + @Deprecated Map getServers(); + /** + * Return all servers registered to this proxy, keyed by name. The returned map + * is an immutable snapshot of the actual server collection. It cannot be modified, + * and it will not change. + * + * @return all registered remote server destinations + */ + Map getServersCopy(); + + /** + * Gets the server info of a server. + * + * @param name the name of the configured server + * @return the server info belonging to the specified server + */ + ServerInfo getServerInfo(String name); + + /** + * Register the given server to the proxy. + * Any currently registered server with the same name will be replaced. + * + * @return the previously registered server with the same name, or null if there was no such server. + */ + ServerInfo addServer(ServerInfo server); + + /** + * Register all of the given servers to the proxy. + * + * @return true if any servers were added or replaced. + */ + boolean addServers(Collection servers); + + /** + * Un-register the server with the given name from the proxy. + * + * @return the server that was removed, or null if there is no server with the given name. + */ + ServerInfo removeServerNamed(String name); + + /** + * Un-register the given server from the proxy. + * The server is matched by name only, other fields in the given {@link ServerInfo} are ignored. + * + * @return the server that was removed, or null if there is no server with a matching name. + */ + ServerInfo removeServer(ServerInfo server); + + /** + * Un-register servers with any of the given names from the proxy. + * + * @return true if any servers were removed. + */ + boolean removeServersNamed(Collection names); + + /** + * Un-register all of the given servers from the proxy. + * The servers are matched by name only, other fields in the given {@link ServerInfo} are ignored. + * + * @return true if any servers were removed. + */ + boolean removeServers(Collection servers); + /** * Does the server authenticate with mojang */ diff --git a/api/src/main/java/net/md_5/bungee/api/ProxyServer.java b/api/src/main/java/net/md_5/bungee/api/ProxyServer.java index 11c5b68576..20e2045d8e 100644 --- a/api/src/main/java/net/md_5/bungee/api/ProxyServer.java +++ b/api/src/main/java/net/md_5/bungee/api/ProxyServer.java @@ -93,9 +93,23 @@ public static void setInstance(ProxyServer instance) * return a fresh map each time. * * @return all registered remote server destinations + * + * @deprecated The returned map is part of the proxy's internal state, + * and may be modified concurrently by the proxy. + * The safe alternative is {@link #getServersCopy()}. */ + @Deprecated public abstract Map getServers(); + /** + * Return all servers registered to this proxy, keyed by name. The returned map + * is an immutable snapshot of the actual server collection. It cannot be modified, + * and it will not change. + * + * @return all registered remote server destinations + */ + public abstract Map getServersCopy(); + /** * Gets the server info of a server. * diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index e45fb7ddb6..4ed748a902 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -558,10 +558,16 @@ public Map getServers() return config.getServers(); } + @Override + public Map getServersCopy() + { + return config.getServersCopy(); + } + @Override public ServerInfo getServerInfo(String name) { - return getServers().get( name ); + return config.getServerInfo( name ); } @Override diff --git a/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java b/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java index 25d87d97d6..90f68527d2 100644 --- a/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java +++ b/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java @@ -1,6 +1,7 @@ package net.md_5.bungee.conf; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableMap; import gnu.trove.map.TMap; import java.io.File; import java.io.IOException; @@ -11,6 +12,7 @@ import java.util.logging.Level; import javax.imageio.ImageIO; import lombok.Getter; +import lombok.Synchronized; import net.md_5.bungee.api.Favicon; import net.md_5.bungee.api.ProxyConfig; import net.md_5.bungee.api.ProxyServer; @@ -142,4 +144,69 @@ public Favicon getFaviconObject() { return favicon; } + + @Override + @Synchronized("servers") + public Map getServersCopy() { + return ImmutableMap.copyOf( servers ); + } + + @Override + @Synchronized("servers") + public ServerInfo getServerInfo(String name) + { + return this.servers.get( name ); + } + + @Override + @Synchronized("servers") + public ServerInfo addServer(ServerInfo server) + { + return this.servers.put( server.getName(), server ); + } + + @Override + @Synchronized("servers") + public boolean addServers(Collection servers) + { + boolean changed = false; + for ( ServerInfo server : servers ) + { + if ( server != this.servers.put( server.getName(), server ) ) changed = true; + } + return changed; + } + + @Override + @Synchronized("servers") + public ServerInfo removeServerNamed(String name) + { + return this.servers.remove( name ); + } + + @Override + @Synchronized("servers") + public ServerInfo removeServer(ServerInfo server) + { + return this.servers.remove( server.getName() ); + } + + @Override + @Synchronized("servers") + public boolean removeServersNamed(Collection names) + { + return this.servers.keySet().removeAll( names ); + } + + @Override + @Synchronized("servers") + public boolean removeServers(Collection servers) + { + boolean changed = false; + for ( ServerInfo server : servers ) + { + if ( null != this.servers.remove( server.getName() ) ) changed = true; + } + return changed; + } } From 1dfbed80075ebd88b58b4bb398aa2ba36a7db522 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Wed, 27 Jan 2016 00:51:22 -0500 Subject: [PATCH 22/39] Don't complain about completely irrelevant annotation --- .../java/net/md_5/bungee/api/plugin/PluginManager.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java index ed8d0f6eb2..bb285b1bc4 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java @@ -3,10 +3,8 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; -import com.google.common.eventbus.Subscribe; import java.io.File; import java.io.InputStream; -import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.Arrays; @@ -400,11 +398,6 @@ public T callEvent(T event) */ public void registerListener(Plugin plugin, Listener listener) { - for ( Method method : listener.getClass().getDeclaredMethods() ) - { - Preconditions.checkArgument( !method.isAnnotationPresent( Subscribe.class ), - "Listener %s has registered using deprecated subscribe annotation! Please update to @EventHandler.", listener ); - } eventBus.register( listener ); listenersByPlugin.put( plugin, listener ); } From c26aa8c97a1a8c8933de5b5e7f467d11f76b2268 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Mon, 1 Feb 2016 22:40:25 -0500 Subject: [PATCH 23/39] Store remote IP in error log records --- proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java b/proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java index 3efeff8178..bf504a110c 100644 --- a/proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java +++ b/proxy/src/main/java/net/md_5/bungee/netty/HandlerBoss.java @@ -7,6 +7,8 @@ import io.netty.handler.timeout.ReadTimeoutException; import java.io.IOException; import java.util.logging.Level; +import java.util.logging.LogRecord; + import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.connection.CancelSendSignal; import net.md_5.bungee.connection.InitialHandler; @@ -119,7 +121,10 @@ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws E } ); } else { - ProxyServer.getInstance().getLogger().log( Level.SEVERE, handler + " - encountered exception", cause ); + final LogRecord record = new LogRecord( Level.SEVERE, handler + " - encountered exception" ); + record.setThrown( cause ); + record.setParameters( new Object[]{ ctx.channel().remoteAddress() } ); + ProxyServer.getInstance().getLogger().log( record ); } if ( handler != null ) From eda0ca7bccb1b53a648ade77c83ca9e094112116 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Wed, 3 Feb 2016 05:52:12 -0500 Subject: [PATCH 24/39] Handle Ping packets in Status state --- .../java/net/md_5/bungee/connection/InitialHandler.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java index bdcbdb7ad1..adab8fa9ba 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/InitialHandler.java @@ -111,7 +111,7 @@ public boolean shouldHandle(PacketWrapper packet) throws Exception private enum State { - HANDSHAKE, STATUS, PING, USERNAME, ENCRYPT, FINISHED; + HANDSHAKE, STATUS, USERNAME, ENCRYPT, FINISHED; } @Override @@ -243,14 +243,12 @@ public void done(ProxyPingEvent pingResult, Throwable error) motd, BungeeCord.getInstance().config.getFaviconObject() ), null ); } - - thisState = State.PING; } @Override public void handle(PingPacket ping) throws Exception { - Preconditions.checkState( thisState == State.PING, "Not expecting PING" ); + Preconditions.checkState( thisState == State.STATUS, "Not expecting PING" ); unsafe.sendPacket( ping ); disconnect( "" ); } @@ -544,7 +542,7 @@ public void disconnect(final BaseComponent... reason) @Override public void run() { - if ( thisState != State.STATUS && thisState != State.PING ) + if ( thisState != State.STATUS ) { unsafe().sendPacket( new Kick( ComponentSerializer.toString( reason ) ) ); } From 045198a76de9a743a74d840be443cc3e16c8f98e Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Wed, 3 Feb 2016 06:26:20 -0500 Subject: [PATCH 25/39] Detect more things as bad packets --- .../net/md_5/bungee/protocol/MinecraftDecoder.java | 10 ++++++++-- .../net/md_5/bungee/protocol/Varint21FrameDecoder.java | 5 ++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftDecoder.java b/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftDecoder.java index e7cb380342..f7566f625c 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftDecoder.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/MinecraftDecoder.java @@ -30,8 +30,14 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) t DefinedPacket packet = prot.createPacket( packetId, protocolVersion ); if ( packet != null ) { - packet.read( in, prot.getDirection(), protocolVersion ); - + try + { + packet.read( in, prot.getDirection(), protocolVersion ); + } + catch( IndexOutOfBoundsException e ) + { + throw new BadPacketException( "Unexpected end of packet " + packet.getClass(), e ); + } if ( in.isReadable() ) { throw new BadPacketException( "Did not read all bytes from packet " + packet.getClass() + " " + packetId + " Protocol " + protocol + " Direction " + prot ); diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/Varint21FrameDecoder.java b/protocol/src/main/java/net/md_5/bungee/protocol/Varint21FrameDecoder.java index 29e54dba06..f5f8d863a3 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/Varint21FrameDecoder.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/Varint21FrameDecoder.java @@ -4,7 +4,6 @@ import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; -import io.netty.handler.codec.CorruptedFrameException; import java.util.List; @@ -33,7 +32,7 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) t int length = DefinedPacket.readVarInt( Unpooled.wrappedBuffer( buf ) ); if ( length == 0 ) { - throw new CorruptedFrameException( "Empty Packet!" ); + throw new BadPacketException( "Empty Packet!" ); } if ( in.readableBytes() < length ) @@ -64,6 +63,6 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) t } } - throw new CorruptedFrameException( "length wider than 21-bit" ); + throw new BadPacketException( "length wider than 21-bit" ); } } From d55b5023caafb488396382d258327d36a7932389 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Thu, 4 Feb 2016 04:59:17 -0500 Subject: [PATCH 26/39] Implement minecraft-api --- api/pom.xml | 5 +++ .../net/md_5/bungee/api/CommandSender.java | 41 +------------------ .../java/net/md_5/bungee/api/ProxyServer.java | 14 ++++++- .../md_5/bungee/api/config/ServerInfo.java | 2 +- .../bungee/api/connection/ProxiedPlayer.java | 26 +----------- .../net/md_5/bungee/api/plugin/Listener.java | 2 +- .../net/md_5/bungee/api/plugin/Plugin.java | 14 ++++++- .../bungee/api/plugin/PluginDescription.java | 24 ++++++++++- .../md_5/bungee/api/plugin/PluginManager.java | 26 +++++++++++- config/pom.xml | 6 +++ .../net/md_5/bungee/config/Configuration.java | 4 +- .../main/java/net/md_5/bungee/BungeeCord.java | 5 +++ .../net/md_5/bungee/BungeeServerInfo.java | 28 +++++++++++++ .../java/net/md_5/bungee/UserConnection.java | 6 +++ .../bungee/command/ConsoleCommandSender.java | 2 +- 15 files changed, 133 insertions(+), 72 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 1b87f5d86e..9ef2b0da29 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -18,6 +18,11 @@ API implemented by the Elastic Portal Suite + + tc.oc + minecraft-api + 1.11-SNAPSHOT + tc.oc bungeecord-chat diff --git a/api/src/main/java/net/md_5/bungee/api/CommandSender.java b/api/src/main/java/net/md_5/bungee/api/CommandSender.java index a35b3fd0c9..798ca60dda 100644 --- a/api/src/main/java/net/md_5/bungee/api/CommandSender.java +++ b/api/src/main/java/net/md_5/bungee/api/CommandSender.java @@ -1,27 +1,10 @@ package net.md_5.bungee.api; -import net.md_5.bungee.api.chat.BaseComponent; - import java.util.Collection; -public interface CommandSender +public interface CommandSender extends tc.oc.minecraft.api.command.CommandSender { - /** - * Get the unique name of this command sender. - * - * @return the senders username - */ - public String getName(); - - /** - * Send a message to this sender. - * - * @param message the message to send - */ - @Deprecated - public void sendMessage(String message); - /** * Send several messages to this sender. Each message will be sent * separately. @@ -31,20 +14,6 @@ public interface CommandSender @Deprecated public void sendMessages(String... messages); - /** - * Send a message to this sender. - * - * @param message the message to send - */ - public void sendMessage(BaseComponent... message); - - /** - * Send a message to this sender. - * - * @param message the message to send - */ - public void sendMessage(BaseComponent message); - /** * Get all groups this user is part of. This returns an unmodifiable * collection. @@ -67,14 +36,6 @@ public interface CommandSender */ public void removeGroups(String... groups); - /** - * Checks if this user has the specified permission node. - * - * @param permission the node to check - * @return whether they have this node - */ - public boolean hasPermission(String permission); - /** * Set a permission node for this user. * diff --git a/api/src/main/java/net/md_5/bungee/api/ProxyServer.java b/api/src/main/java/net/md_5/bungee/api/ProxyServer.java index 20e2045d8e..8b02ebab75 100644 --- a/api/src/main/java/net/md_5/bungee/api/ProxyServer.java +++ b/api/src/main/java/net/md_5/bungee/api/ProxyServer.java @@ -16,7 +16,7 @@ import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.scheduler.TaskScheduler; -public abstract class ProxyServer +public abstract class ProxyServer implements tc.oc.minecraft.api.server.LocalServer { @Getter @@ -87,6 +87,18 @@ public static void setInstance(ProxyServer instance) */ public abstract ProxiedPlayer getPlayer(UUID uuid); + @Override + public ProxiedPlayer getPlayerExact(String name) + { + return getPlayer( name ); + } + + @Override + public Collection getOnlinePlayers() + { + return getPlayers(); + } + /** * Return all servers registered to this proxy, keyed by name. Unlike the * methods in {@link ConfigurationAdapter#getServers()}, this will not diff --git a/api/src/main/java/net/md_5/bungee/api/config/ServerInfo.java b/api/src/main/java/net/md_5/bungee/api/config/ServerInfo.java index e9f1ff6696..74b2791d78 100644 --- a/api/src/main/java/net/md_5/bungee/api/config/ServerInfo.java +++ b/api/src/main/java/net/md_5/bungee/api/config/ServerInfo.java @@ -10,7 +10,7 @@ /** * Class used to represent a server to connect to. */ -public interface ServerInfo +public interface ServerInfo extends tc.oc.minecraft.api.server.Server { /** diff --git a/api/src/main/java/net/md_5/bungee/api/connection/ProxiedPlayer.java b/api/src/main/java/net/md_5/bungee/api/connection/ProxiedPlayer.java index 375815c446..204d452b30 100644 --- a/api/src/main/java/net/md_5/bungee/api/connection/ProxiedPlayer.java +++ b/api/src/main/java/net/md_5/bungee/api/connection/ProxiedPlayer.java @@ -2,7 +2,7 @@ import java.util.Locale; import java.util.Map; -import java.util.UUID; + import net.md_5.bungee.api.Callback; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.CommandSender; @@ -14,24 +14,9 @@ * Represents a player who's connection is being connected to somewhere else, * whether it be a remote or embedded server. */ -public interface ProxiedPlayer extends Connection, CommandSender +public interface ProxiedPlayer extends Connection, CommandSender, tc.oc.minecraft.api.entity.Player { - /** - * Gets this player's display name. - * - * @return the players current display name - */ - String getDisplayName(); - - /** - * Sets this players display name to be used as their nametag and tab list - * name. - * - * @param name the name to set - */ - void setDisplayName(String name); - /** * Send a message to the specified screen position of this player. * @@ -128,13 +113,6 @@ public interface ProxiedPlayer extends Connection, CommandSender @Deprecated String getUUID(); - /** - * Get this connection's UUID, if set. - * - * @return the UUID - */ - UUID getUniqueId(); - /** * Gets this player's locale. * diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/Listener.java b/api/src/main/java/net/md_5/bungee/api/plugin/Listener.java index 31ed4eea7f..a4797ad72f 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/Listener.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/Listener.java @@ -3,6 +3,6 @@ /** * Dummy interface which all event subscribers and listeners must implement. */ -public interface Listener +public interface Listener extends tc.oc.minecraft.api.event.Listener { } diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/Plugin.java b/api/src/main/java/net/md_5/bungee/api/plugin/Plugin.java index d9cc587033..5bc19f7294 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/Plugin.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/Plugin.java @@ -15,7 +15,7 @@ * Represents any Plugin that may be loaded at runtime to enhance existing * functionality. */ -public class Plugin +public class Plugin implements tc.oc.minecraft.api.plugin.Plugin { @Getter @@ -50,6 +50,12 @@ public void onDisable() { } + @Override + public ProxyServer getServer() + { + return getProxy(); + } + /** * Gets the data folder where this plugin may store arbitrary data. It will * be a child of {@link ProxyServer#getPluginsFolder()}. @@ -61,6 +67,12 @@ public final File getDataFolder() return new File( getProxy().getPluginsFolder(), getDescription().getName() ); } + @Override + public InputStream getResource(String name) + { + return getResourceAsStream( name ); + } + /** * Get a resource from within this plugins jar or container. Care must be * taken to close the returned stream. diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginDescription.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginDescription.java index ef12ae9037..2568203b4e 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginDescription.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginDescription.java @@ -1,8 +1,12 @@ package net.md_5.bungee.api.plugin; import java.io.File; +import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; + +import com.google.common.collect.ImmutableList; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -13,7 +17,7 @@ @Data @NoArgsConstructor @AllArgsConstructor -public class PluginDescription +public class PluginDescription implements tc.oc.minecraft.api.plugin.PluginDescription { /** @@ -48,4 +52,22 @@ public class PluginDescription * Optional description. */ private String description = null; + + @Override + public List getAuthors() + { + return Collections.singletonList( author ); + } + + @Override + public List getDepend() + { + return ImmutableList.copyOf( getDepends() ); + } + + @Override + public List getSoftDepend() + { + return ImmutableList.copyOf( getSoftDepends() ); + } } diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java index bb285b1bc4..4beedefa8b 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java @@ -37,7 +37,7 @@ * example event handling and plugin management. */ @RequiredArgsConstructor -public class PluginManager +public class PluginManager implements tc.oc.minecraft.api.plugin.PluginManager { private static final Pattern argsSplit = Pattern.compile( " " ); @@ -192,6 +192,12 @@ public Collection getPlugins() return plugins.values(); } + @Override + public Collection getAllPlugins() + { + return getPlugins(); + } + /** * Returns a loaded plugin identified by the specified name. * @@ -388,6 +394,24 @@ public T callEvent(T event) return event; } + @Override + public void registerListener(tc.oc.minecraft.api.plugin.Plugin plugin, tc.oc.minecraft.api.event.Listener listener) + { + registerListener( (Plugin) plugin, (Listener) listener ); + } + + @Override + public void unregisterListener(tc.oc.minecraft.api.event.Listener listener) + { + unregisterListener( (Listener) listener ); + } + + @Override + public void unregisterListeners(tc.oc.minecraft.api.plugin.Plugin plugin) + { + unregisterListeners( (Plugin) plugin ); + } + /** * Register a {@link Listener} for receiving called events. Methods in this * Object which wish to receive events must be annotated with the diff --git a/config/pom.xml b/config/pom.xml index 7d2fd9a5e5..e731d711e5 100644 --- a/config/pom.xml +++ b/config/pom.xml @@ -18,6 +18,12 @@ Generic java configuration API intended for use with BungeeCord + + tc.oc + minecraft-api + 1.11-SNAPSHOT + compile + org.yaml snakeyaml diff --git a/config/src/main/java/net/md_5/bungee/config/Configuration.java b/config/src/main/java/net/md_5/bungee/config/Configuration.java index 78822dc5c7..a36cc0f46d 100644 --- a/config/src/main/java/net/md_5/bungee/config/Configuration.java +++ b/config/src/main/java/net/md_5/bungee/config/Configuration.java @@ -7,12 +7,14 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import lombok.Getter; -public final class Configuration +public final class Configuration implements tc.oc.minecraft.api.configuration.Configuration { private static final char SEPARATOR = '.'; final Map self; + @Getter private final Configuration defaults; public Configuration() diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 4ed748a902..e1b33e82e3 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -614,6 +614,11 @@ public ServerInfo constructServerInfo(String name, InetSocketAddress address, St return new BungeeServerInfo( name, address, motd, restricted ); } + @Override + public tc.oc.minecraft.api.command.ConsoleCommandSender getConsoleSender() { + return ConsoleCommandSender.getInstance(); + } + @Override public CommandSender getConsole() { diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java b/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java index 1dd0aeba8a..f8699d26ad 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeServerInfo.java @@ -13,6 +13,8 @@ import java.util.HashSet; import java.util.LinkedList; import java.util.Queue; +import java.util.UUID; + import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.Synchronized; @@ -69,6 +71,32 @@ public Collection getPlayers() return Collections.unmodifiableCollection( new HashSet( players ) ); } + @Override + public Collection getOnlinePlayers() + { + return getPlayers(); + } + + @Override + public ProxiedPlayer getPlayerExact(String name) + { + for(ProxiedPlayer player : getPlayers()) + { + if(name.equalsIgnoreCase(player.getName())) return player; + } + return null; + } + + @Override + public ProxiedPlayer getPlayer(UUID id) + { + for(ProxiedPlayer player : getPlayers()) + { + if(id.equals(player.getUniqueId())) return player; + } + return null; + } + @Override public boolean canAccess(CommandSender player) { diff --git a/proxy/src/main/java/net/md_5/bungee/UserConnection.java b/proxy/src/main/java/net/md_5/bungee/UserConnection.java index 49732ae7c8..4ce806bd19 100644 --- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java +++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java @@ -551,6 +551,12 @@ public Locale getLocale() return ( locale == null && settings != null ) ? locale = Locale.forLanguageTag( settings.getLocale().replaceAll( "_", "-" ) ) : locale; } + @Override + public Locale getCurrentLocale() + { + return getLocale(); + } + @Override public boolean isForgeUser() { diff --git a/proxy/src/main/java/net/md_5/bungee/command/ConsoleCommandSender.java b/proxy/src/main/java/net/md_5/bungee/command/ConsoleCommandSender.java index 49dde16ffe..326e89abf9 100644 --- a/proxy/src/main/java/net/md_5/bungee/command/ConsoleCommandSender.java +++ b/proxy/src/main/java/net/md_5/bungee/command/ConsoleCommandSender.java @@ -10,7 +10,7 @@ /** * Command sender representing the proxy console. */ -public class ConsoleCommandSender implements CommandSender +public class ConsoleCommandSender implements CommandSender, tc.oc.minecraft.api.command.ConsoleCommandSender { @Getter From ddac4bb5541e3c9f835b5f806ec815d602413e41 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sat, 5 Mar 2016 02:09:59 -0500 Subject: [PATCH 27/39] Add selector and score components to chat API --- .../md_5/bungee/api/ChatStringBuilder.java | 24 +++++++- .../md_5/bungee/api/chat/ScoreComponent.java | 55 +++++++++++++++++++ .../bungee/api/chat/SelectorComponent.java | 45 +++++++++++++++ .../md_5/bungee/chat/ComponentSerializer.java | 12 ++++ .../bungee/chat/ScoreComponentSerializer.java | 38 +++++++++++++ .../chat/SelectorComponentSerializer.java | 31 +++++++++++ .../main/java/net/md_5/bungee/BungeeCord.java | 6 ++ 7 files changed, 208 insertions(+), 3 deletions(-) create mode 100644 chat/src/main/java/net/md_5/bungee/api/chat/ScoreComponent.java create mode 100644 chat/src/main/java/net/md_5/bungee/api/chat/SelectorComponent.java create mode 100644 chat/src/main/java/net/md_5/bungee/chat/ScoreComponentSerializer.java create mode 100644 chat/src/main/java/net/md_5/bungee/chat/SelectorComponentSerializer.java diff --git a/chat/src/main/java/net/md_5/bungee/api/ChatStringBuilder.java b/chat/src/main/java/net/md_5/bungee/api/ChatStringBuilder.java index a3b0a2be53..bcd53d3131 100644 --- a/chat/src/main/java/net/md_5/bungee/api/ChatStringBuilder.java +++ b/chat/src/main/java/net/md_5/bungee/api/ChatStringBuilder.java @@ -3,7 +3,7 @@ import java.util.EnumSet; import java.util.Set; -public class ChatStringBuilder { +public class ChatStringBuilder implements Appendable { private final StringBuilder builder; private ChatColor oldColor, newColor; @@ -63,11 +63,29 @@ private void refreshIfChanged() { } } - public void append(String text) { - if(!text.isEmpty()) { + @Override + public ChatStringBuilder append(CharSequence text) { + if(text.length() != 0) { refreshIfChanged(); builder.append(text); } + return this; + } + + @Override + public ChatStringBuilder append(CharSequence text, int start, int end) { + if(start < end) { + refreshIfChanged(); + builder.append(text, start, end); + } + return this; + } + + @Override + public Appendable append(char c) { + refreshIfChanged(); + builder.append(c); + return this; } public void append(Object thing) { diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/ScoreComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/ScoreComponent.java new file mode 100644 index 0000000000..0d943ad61b --- /dev/null +++ b/chat/src/main/java/net/md_5/bungee/api/chat/ScoreComponent.java @@ -0,0 +1,55 @@ +package net.md_5.bungee.api.chat; + +import java.util.List; +import java.util.Set; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.ChatStringBuilder; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class ScoreComponent extends BaseComponent { + + private final String name, objective; + + public ScoreComponent(String name, String objective) { + this.name = checkNotNull(name); + this.objective = checkNotNull(objective); + } + + public String getName() { + return name; + } + + public String getObjective() { + return objective; + } + + @Override + public ScoreComponent duplicate() { + return new ScoreComponent(getName(), getObjective()); + } + + private String plainTextContent() { + return getName() + ':' + getObjective(); + } + + @Override + void toPlainText(StringBuilder builder) { + builder.append(plainTextContent()); + super.toPlainText(builder); + } + + @Override + protected void toLegacyTextContent(ChatStringBuilder builder, ChatColor color, Set decorations) { + builder.format(color, decorations); + builder.append(plainTextContent()); + } + + @Override + protected void toStringTerminal(List fields) { + fields.add("name=\"" + getName() + '"'); + fields.add("objective=\"" + getObjective() + '"'); + super.toStringTerminal(fields); + } +} diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/SelectorComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/SelectorComponent.java new file mode 100644 index 0000000000..53cc35be83 --- /dev/null +++ b/chat/src/main/java/net/md_5/bungee/api/chat/SelectorComponent.java @@ -0,0 +1,45 @@ +package net.md_5.bungee.api.chat; + +import java.util.List; +import java.util.Set; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.ChatStringBuilder; + +import static com.google.common.base.Preconditions.checkNotNull; + +public class SelectorComponent extends BaseComponent { + + private final String selector; + + public SelectorComponent(String selector) { + this.selector = checkNotNull(selector); + } + + public String getSelector() { + return selector; + } + + @Override + public SelectorComponent duplicate() { + return new SelectorComponent(getSelector()); + } + + @Override + void toPlainText(StringBuilder builder) { + builder.append(selector); + super.toPlainText(builder); + } + + @Override + protected void toLegacyTextContent(ChatStringBuilder builder, ChatColor color, Set decorations) { + builder.format(color, decorations); + builder.append(getSelector()); + } + + @Override + protected void toStringTerminal(List fields) { + fields.add("selector=\"" + getSelector() + '"'); + super.toStringTerminal(fields); + } +} diff --git a/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java index 4acb09b7d5..a3e777664a 100644 --- a/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java +++ b/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java @@ -8,6 +8,8 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ScoreComponent; +import net.md_5.bungee.api.chat.SelectorComponent; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.chat.TranslatableComponent; @@ -21,6 +23,8 @@ public class ComponentSerializer implements JsonDeserializer registerTypeHierarchyAdapter( BaseComponent.class, new ComponentSerializer() ). registerTypeHierarchyAdapter( TextComponent.class, new TextComponentSerializer() ). registerTypeHierarchyAdapter( TranslatableComponent.class, new TranslatableComponentSerializer() ). + registerTypeHierarchyAdapter( SelectorComponent.class, new SelectorComponentSerializer() ). + registerTypeHierarchyAdapter( ScoreComponent.class, new ScoreComponentSerializer() ). create(); public final static ThreadLocal> serializedComponents = new ThreadLocal>() { @@ -63,6 +67,14 @@ public BaseComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializa { return context.deserialize( json, TranslatableComponent.class ); } + if ( object.has( "selector" ) ) + { + return context.deserialize( json, SelectorComponent.class ); + } + if ( object.has( "score" ) ) + { + return context.deserialize( json, ScoreComponent.class ); + } return context.deserialize( json, TextComponent.class ); } } diff --git a/chat/src/main/java/net/md_5/bungee/chat/ScoreComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/ScoreComponentSerializer.java new file mode 100644 index 0000000000..07f3576d11 --- /dev/null +++ b/chat/src/main/java/net/md_5/bungee/chat/ScoreComponentSerializer.java @@ -0,0 +1,38 @@ +package net.md_5.bungee.chat; + +import java.lang.reflect.Type; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import net.md_5.bungee.api.chat.ScoreComponent; + +public class ScoreComponentSerializer extends BaseComponentSerializer implements JsonSerializer, JsonDeserializer { + + @Override + public ScoreComponent deserialize(JsonElement jsonElement, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + final JsonObject json = jsonElement.getAsJsonObject(); + final JsonObject score = json.getAsJsonObject("score"); + final ScoreComponent component = new ScoreComponent(score.get("name").getAsString(), + score.get("objective").getAsString()); + deserialize(json, component, context); + return component; + } + + @Override + public JsonElement serialize(ScoreComponent src, Type typeOfSrc, JsonSerializationContext context) { + final JsonObject score = new JsonObject(); + score.addProperty("name", src.getName()); + score.addProperty("objective", src.getObjective()); + + final JsonObject json = new JsonObject(); + serialize(json, src, context); + json.add("score", score); + + return json; + } +} diff --git a/chat/src/main/java/net/md_5/bungee/chat/SelectorComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/SelectorComponentSerializer.java new file mode 100644 index 0000000000..c5fbf641a5 --- /dev/null +++ b/chat/src/main/java/net/md_5/bungee/chat/SelectorComponentSerializer.java @@ -0,0 +1,31 @@ +package net.md_5.bungee.chat; + +import java.lang.reflect.Type; + +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import net.md_5.bungee.api.chat.SelectorComponent; + +public class SelectorComponentSerializer extends BaseComponentSerializer implements JsonSerializer, JsonDeserializer { + + @Override + public SelectorComponent deserialize(JsonElement jsonElement, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + final JsonObject json = jsonElement.getAsJsonObject(); + final SelectorComponent component = new SelectorComponent(json.get("selector").getAsString()); + deserialize(json, component, context); + return component; + } + + @Override + public JsonElement serialize(SelectorComponent src, Type typeOfSrc, JsonSerializationContext context) { + final JsonObject json = new JsonObject(); + serialize(json, src, context); + json.addProperty("selector", src.getSelector()); + return json; + } +} diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index e1b33e82e3..84b9d5eb3e 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -55,6 +55,8 @@ import net.md_5.bungee.api.ServerPing; import net.md_5.bungee.api.Title; import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ScoreComponent; +import net.md_5.bungee.api.chat.SelectorComponent; import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.chat.TranslatableComponent; import net.md_5.bungee.api.config.ConfigurationAdapter; @@ -64,6 +66,8 @@ import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.PluginManager; import net.md_5.bungee.chat.ComponentSerializer; +import net.md_5.bungee.chat.ScoreComponentSerializer; +import net.md_5.bungee.chat.SelectorComponentSerializer; import net.md_5.bungee.chat.TextComponentSerializer; import net.md_5.bungee.chat.TranslatableComponentSerializer; import net.md_5.bungee.command.CommandBungee; @@ -150,6 +154,8 @@ public class BungeeCord extends ProxyServer .registerTypeAdapter( BaseComponent.class, new ComponentSerializer() ) .registerTypeAdapter( TextComponent.class, new TextComponentSerializer() ) .registerTypeAdapter( TranslatableComponent.class, new TranslatableComponentSerializer() ) + .registerTypeAdapter( SelectorComponent.class, new SelectorComponentSerializer() ) + .registerTypeAdapter( ScoreComponent.class, new ScoreComponentSerializer() ) .registerTypeAdapter( ServerPing.PlayerInfo.class, new PlayerInfoSerializer() ) .registerTypeAdapter( Favicon.class, Favicon.getFaviconTypeAdapter() ).create(); @Getter From 71bf876bc641103387d72b6d54c17533a8cd11c2 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sun, 6 Mar 2016 02:33:45 -0500 Subject: [PATCH 28/39] Various improvements to chat components * Move cycle detection to where the cycles are created, which is more robust and easier to debug * Implement equals and hashCode for all components * Make several fields non-null * Don't allow external collections into the extra/with fields * Don't create a resource bundle and regex object for every TranslatableComponent --- .../md_5/bungee/api/chat/BaseComponent.java | 180 +++++++++++++++--- .../net/md_5/bungee/api/chat/ClickEvent.java | 2 + .../net/md_5/bungee/api/chat/HoverEvent.java | 2 + .../md_5/bungee/api/chat/ScoreComponent.java | 41 ++-- .../bungee/api/chat/SelectorComponent.java | 34 ++-- .../md_5/bungee/api/chat/TextComponent.java | 31 ++- .../api/chat/TranslatableComponent.java | 74 +++++-- .../bungee/chat/BaseComponentSerializer.java | 96 +++++----- .../md_5/bungee/chat/ComponentSerializer.java | 7 - .../chat/TranslatableComponentSerializer.java | 11 +- .../net/md_5/bungee/chat/ComponentsTest.java | 53 +++--- 11 files changed, 356 insertions(+), 175 deletions(-) diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java index 119c330079..cf76837400 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java @@ -1,6 +1,9 @@ package net.md_5.bungee.api.chat; import com.google.common.base.Joiner; +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -11,7 +14,6 @@ import java.util.Collections; import java.util.EnumMap; import java.util.EnumSet; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -20,6 +22,11 @@ @NoArgsConstructor public abstract class BaseComponent { + /** + * An immutable, empty component list. {@link BaseComponent#extra} is always set to this when empty. + * Subclasses can use this for their own fields as well. + */ + protected static final List EMPTY_COMPONENT_LIST = Collections.emptyList(); /** * The color of this component and any child components (unless overridden) @@ -61,7 +68,7 @@ public abstract class BaseComponent * Appended components that inherit this component's formatting and events */ @Getter - private List extra; + private List extra = EMPTY_COMPONENT_LIST; /** * The action to preform when this component (and child components) are @@ -87,12 +94,9 @@ public abstract class BaseComponent setInsertion( old.getInsertion() ); setClickEvent( old.getClickEvent() ); setHoverEvent( old.getHoverEvent() ); - if ( old.getExtra() != null ) + for ( BaseComponent component : old.getExtra() ) { - for ( BaseComponent component : old.getExtra() ) - { - addExtra( component.duplicate() ); - } + addValidExtra( component.duplicate() ); } } @@ -278,9 +282,30 @@ public Boolean isObfuscatedRaw() return obfuscated; } + public void setHoverEvent(HoverEvent hoverEvent) { + if(hoverEvent != null) { + for(BaseComponent child : hoverEvent.getValue()) validateChild(child); + } + this.hoverEvent = hoverEvent; + } + public void setExtra(List components) { - extra = components; + if(components == null || components.isEmpty()) { + extra = EMPTY_COMPONENT_LIST; + } else { + for(BaseComponent child : components) validateChild(child); + extra = new ArrayList(components); + } + } + + public void setExtra(BaseComponent... components) { + if(components == null || components.length == 0) { + extra = EMPTY_COMPONENT_LIST; + } else { + for(BaseComponent child : components) validateChild(child); + extra = Lists.newArrayList(components); + } } /** @@ -291,7 +316,7 @@ public void setExtra(List components) */ public void addExtra(String text) { - addExtra( new TextComponent( text ) ); + addValidExtra( new TextComponent( text ) ); } /** @@ -299,10 +324,21 @@ public void addExtra(String text) * component's formatting * * @param component the component to append + * @throws IllegalArgumentException if a component cycle is detected */ public void addExtra(BaseComponent component) { - if ( extra == null ) + validateChild( component ); + addValidExtra(component); + } + + /** + * Append a component without validating it. This method should only be called when + * it is certain not to create a component cycle i.e. when the given component is + * known not to contain this one. + */ + private void addValidExtra(BaseComponent component) { + if (extra == EMPTY_COMPONENT_LIST) { extra = new ArrayList(); } @@ -456,7 +492,58 @@ public void mergeFormatting(BaseComponent from) { mergeEvents(from); } - protected void toStringTerminal(List fields) { + /** + * Verify that the given component can become a part of this component + * by checking that they do not already have the inverse relationship. + * + * This method should be called BEFORE making the given component a child + * of this one, so that this component's state remains valid. + * + * @throws IllegalArgumentException if the given component contains this component + */ + public void validateChild(BaseComponent child) { + Preconditions.checkNotNull(child); + if(child.contains(this)) { + throw new IllegalArgumentException("Component cycle detected between " + this + " and " + child); + } + } + + /** + * Is the given component contained, in whole or in part, by this one? + * + * This method is used to detect containment cycles. Unlike with collections, + * equality is tested with == rather than {@link #equals(Object)}. + * + * Subclasses with recursive fields of their own should override this method + * to include those fields in the search. + * + * @return true if the given component is the same instance as this component, + * or is a child of this component. + */ + public boolean contains(BaseComponent child) { + if(this == child) return true; + + for(BaseComponent extra : getExtra()) { + if(extra.contains(child)) return true; + } + + if(getHoverEvent() != null) { + for(BaseComponent value : getHoverEvent().getValue()) { + if(value.contains(child)) return true; + } + } + + return false; + } + + /** + * Contribute leading fields to the output of {@link #toString()}. + * + * These fields should be relatively short i.e. not recursive. They will appear before + * any fields contributed by {@link #toStringLast(List)}, which can make the output + * easier to read. + */ + protected void toStringFirst(List fields) { if(getColorRaw() != null) { fields.add("color=\"" + getColorRaw().name().toLowerCase() + "\""); } @@ -473,7 +560,12 @@ protected void toStringTerminal(List fields) { } } - protected void toStringRecursive(List fields) { + /** + * Contribute trailing fields to the output of {@link #toString()}. + * + * Particularly long fields, i.e. recursive ones, should be added here. + */ + protected void toStringLast(List fields) { if(getHoverEvent() != null) { fields.add("hoverEvent=" + getHoverEvent()); } @@ -483,25 +575,53 @@ protected void toStringRecursive(List fields) { } } - private static final ThreadLocal> visited = new ThreadLocal>() { - @Override protected Set initialValue() { - return new HashSet(); - } - }; - + /** + * Delegates to {@link #toStringFirst(List)} and {@link #toStringLast(List)}. + */ @Override - public String toString() { - List fields = new ArrayList(); - toStringTerminal(fields); - try { - if(visited.get().add(this)) { - toStringRecursive(fields); - } else { - fields.add("... (cycle)"); - } - } finally { - visited.get().remove(this); - } + public final String toString() { + final List fields = new ArrayList(); + toStringFirst(fields); + toStringLast(fields); return getClass().getSimpleName() + "{" + JOINER.join(fields) + "}"; } + + /** + * {@link #equals(Object)} delegates to this method when its argument is a {@link BaseComponent}, + * and is not null or this. + * + * Overrides of this method must call the supermethod in order to compare the base properties. + * This should be done after performing any quick comparisons, and before any expensive ones, + * as the base method contains both. + */ + protected boolean equals(BaseComponent that) { + return Objects.equal(this.color, that.color) && + Objects.equal(this.bold, that.bold) && + Objects.equal(this.italic, that.italic) && + Objects.equal(this.underlined, that.underlined) && + Objects.equal(this.strikethrough, that.strikethrough) && + Objects.equal(this.obfuscated, that.obfuscated) && + Objects.equal(this.insertion, that.insertion) && + Objects.equal(this.clickEvent, that.clickEvent) && + Objects.equal(this.hoverEvent, that.hoverEvent) && + Objects.equal(this.extra, that.extra); + } + + /** + * Delegates to {@link #equals(BaseComponent)}. + */ + @Override + public final boolean equals(Object that) { + return that != null && ( + that == this || ( + that instanceof BaseComponent && + equals((BaseComponent) that) + ) + ); + } + + @Override + public int hashCode() { + return Objects.hashCode(color, bold, italic, underlined, strikethrough, obfuscated, insertion, clickEvent, hoverEvent, extra); + } } diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/ClickEvent.java b/chat/src/main/java/net/md_5/bungee/api/chat/ClickEvent.java index 1ced284f0e..4ab9f7a38c 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/ClickEvent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/ClickEvent.java @@ -1,5 +1,6 @@ package net.md_5.bungee.api.chat; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; @@ -8,6 +9,7 @@ @Getter @ToString @RequiredArgsConstructor +@EqualsAndHashCode public final class ClickEvent { diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java b/chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java index 1b76956aac..06d0d8dd59 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/HoverEvent.java @@ -1,5 +1,6 @@ package net.md_5.bungee.api.chat; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; import lombok.ToString; @@ -7,6 +8,7 @@ @Getter @ToString @RequiredArgsConstructor +@EqualsAndHashCode final public class HoverEvent { diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/ScoreComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/ScoreComponent.java index 0d943ad61b..f0e9e983c9 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/ScoreComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/ScoreComponent.java @@ -3,27 +3,19 @@ import java.util.List; import java.util.Set; +import com.google.common.base.Objects; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NonNull; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatStringBuilder; -import static com.google.common.base.Preconditions.checkNotNull; - +@Getter +@AllArgsConstructor public class ScoreComponent extends BaseComponent { - private final String name, objective; - - public ScoreComponent(String name, String objective) { - this.name = checkNotNull(name); - this.objective = checkNotNull(objective); - } - - public String getName() { - return name; - } - - public String getObjective() { - return objective; - } + @NonNull private final String name; + @NonNull private final String objective; @Override public ScoreComponent duplicate() { @@ -47,9 +39,22 @@ protected void toLegacyTextContent(ChatStringBuilder builder, ChatColor color, S } @Override - protected void toStringTerminal(List fields) { + protected void toStringFirst(List fields) { fields.add("name=\"" + getName() + '"'); fields.add("objective=\"" + getObjective() + '"'); - super.toStringTerminal(fields); + super.toStringFirst(fields); + } + + @Override + public int hashCode() { + return Objects.hashCode(super.hashCode(), name, objective); + } + + @Override + protected boolean equals(BaseComponent that) { + return that instanceof ScoreComponent && + name.equals(((ScoreComponent) that).getName()) && + objective.equals(((ScoreComponent) that).getObjective()) && + super.equals(that); } } diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/SelectorComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/SelectorComponent.java index 53cc35be83..6f35b3e1ab 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/SelectorComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/SelectorComponent.java @@ -3,22 +3,18 @@ import java.util.List; import java.util.Set; +import com.google.common.base.Objects; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NonNull; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatStringBuilder; -import static com.google.common.base.Preconditions.checkNotNull; - +@Getter +@AllArgsConstructor public class SelectorComponent extends BaseComponent { - private final String selector; - - public SelectorComponent(String selector) { - this.selector = checkNotNull(selector); - } - - public String getSelector() { - return selector; - } + @NonNull private final String selector; @Override public SelectorComponent duplicate() { @@ -38,8 +34,20 @@ protected void toLegacyTextContent(ChatStringBuilder builder, ChatColor color, S } @Override - protected void toStringTerminal(List fields) { + protected void toStringFirst(List fields) { fields.add("selector=\"" + getSelector() + '"'); - super.toStringTerminal(fields); + super.toStringFirst(fields); + } + + @Override + public int hashCode() { + return Objects.hashCode(super.hashCode(), selector); + } + + @Override + protected boolean equals(BaseComponent that) { + return that instanceof SelectorComponent && + selector.equals(((SelectorComponent) that).getSelector()) && + super.equals(that); } } diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java index 3472237377..2609b00ecf 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java @@ -1,14 +1,14 @@ package net.md_5.bungee.api.chat; +import com.google.common.base.Objects; import lombok.AllArgsConstructor; import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.NonNull; import lombok.Setter; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatStringBuilder; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.regex.Matcher; @@ -135,14 +135,13 @@ public static BaseComponent[] fromLegacyText(String message) /** * The text of the component that will be displayed to the client */ - private String text; + @NonNull private String text; /** - * Creates a TextComponent with blank text. + * Creates a blank component */ - public TextComponent() - { - this.text = ""; + public TextComponent() { + this(""); } /** @@ -166,7 +165,7 @@ public TextComponent(TextComponent textComponent) public TextComponent(BaseComponent... extras) { setText( "" ); - setExtra( new ArrayList( Arrays.asList( extras ) ) ); + setExtra( extras ); } /** @@ -194,8 +193,20 @@ protected void toLegacyTextContent(ChatStringBuilder builder, ChatColor color, S builder.append( text ); } - @Override protected void toStringTerminal(List fields) { + @Override protected void toStringFirst(List fields) { fields.add("text=\"" + getText() + "\""); - super.toStringTerminal(fields); + super.toStringFirst(fields); + } + + @Override + public int hashCode() { + return Objects.hashCode(super.hashCode(), text); + } + + @Override + protected boolean equals(BaseComponent that) { + return that instanceof TextComponent && + text.equals(((TextComponent) that).getText()) && + super.equals(that); } } diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java index a828b6494b..34d2ed167d 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/TranslatableComponent.java @@ -1,10 +1,13 @@ package net.md_5.bungee.api.chat; +import com.google.common.base.Objects; +import com.google.common.collect.Lists; import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.NonNull; import lombok.Setter; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.MissingResourceException; import java.util.ResourceBundle; @@ -17,22 +20,22 @@ @Getter @Setter -@NoArgsConstructor public class TranslatableComponent extends BaseComponent { - private final ResourceBundle locales = ResourceBundle.getBundle( "mojang-translations/en_US" ); - private final Pattern format = Pattern.compile( "%(?:(\\d+)\\$)?([A-Za-z%]|$)" ); + private static final ResourceBundle locales = ResourceBundle.getBundle( "mojang-translations/en_US" ); + private static final Pattern format = Pattern.compile( "%(?:(\\d+)\\$)?([A-Za-z%]|$)" ); /** * The key into the Minecraft locale files to use for the translation. The * text depends on the client's locale setting. The console is always en_US */ - private String translate; + @NonNull private String translate; + /** * The components to substitute into the translation */ - private List with; + private List with = EMPTY_COMPONENT_LIST; /** * Creates a translatable component from the original to clone it. @@ -51,7 +54,7 @@ public TranslatableComponent(TranslatableComponent original) { temp.add( baseComponent.duplicate() ); } - setWith( temp ); + setWithInternal( temp ); } } @@ -79,7 +82,7 @@ public TranslatableComponent(String translate, Object... with) temp.add( (BaseComponent) w ); } } - setWith( temp ); + setWithInternal( temp ); } /** @@ -101,7 +104,27 @@ public BaseComponent duplicate() */ public void setWith(List components) { - with = components; + if(components == null) { + setWithInternal(null); + } else { + for(BaseComponent child : components) validateChild(child); + setWithInternal(new ArrayList(components)); + } + } + + /** + * Sets the translation substitutions to be used in this component. Removes + * any previously set substitutions + * + * @param components the components to substitute + */ + public void setWith(BaseComponent... components) + { + setWith(components == null ? EMPTY_COMPONENT_LIST : Arrays.asList(components)); + } + + private void setWithInternal(List components) { + with = components == null || components.isEmpty() ? EMPTY_COMPONENT_LIST : components; } /** @@ -123,7 +146,8 @@ public void addWith(String text) */ public void addWith(BaseComponent component) { - if ( with == null ) + validateChild(component); + if ( with == EMPTY_COMPONENT_LIST ) { with = new ArrayList(); } @@ -222,16 +246,38 @@ protected void toLegacyTextContent(ChatStringBuilder builder, ChatColor color, S } @Override - protected void toStringTerminal(List fields) { + public boolean contains(BaseComponent child) { + if(super.contains(child)) return true; + for(BaseComponent with : getWith()) { + if(with.contains(child)) return true; + } + return false; + } + + @Override + protected void toStringFirst(List fields) { fields.add("translate=\"" + getTranslate() + "\""); - super.toStringTerminal(fields); + super.toStringFirst(fields); } @Override - protected void toStringRecursive(List fields) { + protected void toStringLast(List fields) { if(getWith() != null && !getWith().isEmpty()) { fields.add("with=[" + JOINER.join(getWith()) + "]"); } - super.toStringRecursive(fields); + super.toStringLast(fields); + } + + @Override + public int hashCode() { + return Objects.hashCode(super.hashCode(), translate, with); + } + + @Override + protected boolean equals(BaseComponent that) { + return that instanceof TranslatableComponent && + translate.equals(((TranslatableComponent) that).getTranslate()) && + super.equals(that) && + with.equals(((TranslatableComponent) that).getWith()); } } diff --git a/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java index 77f678ede7..284490155e 100644 --- a/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java +++ b/chat/src/main/java/net/md_5/bungee/chat/BaseComponentSerializer.java @@ -1,6 +1,5 @@ package net.md_5.bungee.chat; -import com.google.common.base.Preconditions; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; @@ -77,61 +76,54 @@ protected void deserialize(JsonObject object, BaseComponent component, JsonDeser protected void serialize(JsonObject object, BaseComponent component, JsonSerializationContext context) { - try + if ( component.getColorRaw() != null ) { - Preconditions.checkArgument( ComponentSerializer.serializedComponents.get().add( component ), "Component loop: " + component ); - if ( component.getColorRaw() != null ) - { - object.addProperty( "color", component.getColorRaw().getName() ); - } - if ( component.isBoldRaw() != null ) - { - object.addProperty( "bold", component.isBoldRaw() ); - } - if ( component.isItalicRaw() != null ) - { - object.addProperty( "italic", component.isItalicRaw() ); - } - if ( component.isUnderlinedRaw() != null ) - { - object.addProperty( "underlined", component.isUnderlinedRaw() ); - } - if ( component.isStrikethroughRaw() != null ) - { - object.addProperty( "strikethrough", component.isStrikethroughRaw() ); - } - if ( component.isObfuscatedRaw() != null ) - { - object.addProperty( "obfuscated", component.isObfuscatedRaw() ); - } - if ( component.getInsertion() != null ) - { - object.addProperty( "insertion", component.getInsertion() ); - } + object.addProperty( "color", component.getColorRaw().getName() ); + } + if ( component.isBoldRaw() != null ) + { + object.addProperty( "bold", component.isBoldRaw() ); + } + if ( component.isItalicRaw() != null ) + { + object.addProperty( "italic", component.isItalicRaw() ); + } + if ( component.isUnderlinedRaw() != null ) + { + object.addProperty( "underlined", component.isUnderlinedRaw() ); + } + if ( component.isStrikethroughRaw() != null ) + { + object.addProperty( "strikethrough", component.isStrikethroughRaw() ); + } + if ( component.isObfuscatedRaw() != null ) + { + object.addProperty( "obfuscated", component.isObfuscatedRaw() ); + } + if ( component.getInsertion() != null ) + { + object.addProperty( "insertion", component.getInsertion() ); + } - if ( component.getExtra() != null ) - { - object.add( "extra", context.serialize( component.getExtra() ) ); - } + if ( component.getExtra() != null && !component.getExtra().isEmpty() ) + { + object.add( "extra", context.serialize( component.getExtra() ) ); + } - //Events - if ( component.getClickEvent() != null ) - { - JsonObject clickEvent = new JsonObject(); - clickEvent.addProperty( "action", component.getClickEvent().getAction().toString().toLowerCase() ); - clickEvent.addProperty( "value", component.getClickEvent().getValue() ); - object.add( "clickEvent", clickEvent ); - } - if ( component.getHoverEvent() != null ) - { - JsonObject hoverEvent = new JsonObject(); - hoverEvent.addProperty( "action", component.getHoverEvent().getAction().toString().toLowerCase() ); - hoverEvent.add( "value", context.serialize( component.getHoverEvent().getValue() ) ); - object.add( "hoverEvent", hoverEvent ); - } - } finally + //Events + if ( component.getClickEvent() != null ) + { + JsonObject clickEvent = new JsonObject(); + clickEvent.addProperty( "action", component.getClickEvent().getAction().toString().toLowerCase() ); + clickEvent.addProperty( "value", component.getClickEvent().getValue() ); + object.add( "clickEvent", clickEvent ); + } + if ( component.getHoverEvent() != null ) { - ComponentSerializer.serializedComponents.get().remove( component ); + JsonObject hoverEvent = new JsonObject(); + hoverEvent.addProperty( "action", component.getHoverEvent().getAction().toString().toLowerCase() ); + hoverEvent.add( "value", context.serialize( component.getHoverEvent().getValue() ) ); + object.add( "hoverEvent", hoverEvent ); } } } diff --git a/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java index a3e777664a..b9d795d2a5 100644 --- a/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java +++ b/chat/src/main/java/net/md_5/bungee/chat/ComponentSerializer.java @@ -14,7 +14,6 @@ import net.md_5.bungee.api.chat.TranslatableComponent; import java.lang.reflect.Type; -import java.util.HashSet; public class ComponentSerializer implements JsonDeserializer { @@ -27,12 +26,6 @@ public class ComponentSerializer implements JsonDeserializer registerTypeHierarchyAdapter( ScoreComponent.class, new ScoreComponentSerializer() ). create(); - public final static ThreadLocal> serializedComponents = new ThreadLocal>() { - @Override protected HashSet initialValue() { - return new HashSet(); - } - }; - public static BaseComponent[] parse(String json) { if ( json.startsWith( "[" ) ) diff --git a/chat/src/main/java/net/md_5/bungee/chat/TranslatableComponentSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/TranslatableComponentSerializer.java index 213fb574d0..a6019d6211 100644 --- a/chat/src/main/java/net/md_5/bungee/chat/TranslatableComponentSerializer.java +++ b/chat/src/main/java/net/md_5/bungee/chat/TranslatableComponentSerializer.java @@ -19,10 +19,9 @@ public class TranslatableComponentSerializer extends BaseComponentSerializer imp @Override public TranslatableComponent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { - TranslatableComponent component = new TranslatableComponent(); JsonObject object = json.getAsJsonObject(); + TranslatableComponent component = new TranslatableComponent(object.get( "translate" ).getAsString()); deserialize( object, component, context ); - component.setTranslate( object.get( "translate" ).getAsString() ); if ( object.has( "with" ) ) { component.setWith( Arrays.asList( (BaseComponent[]) context.deserialize( object.get( "with" ), BaseComponent[].class ) ) ); @@ -38,13 +37,7 @@ public JsonElement serialize(TranslatableComponent src, Type typeOfSrc, JsonSeri object.addProperty( "translate", src.getTranslate() ); if ( src.getWith() != null ) { - try { - ComponentSerializer.serializedComponents.get().add( src ); - object.add( "with", context.serialize( src.getWith() ) ); - } - finally { - ComponentSerializer.serializedComponents.get().remove( src ); - } + object.add( "with", context.serialize( src.getWith() ) ); } return object; } diff --git a/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java b/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java index 5f8dced76a..62147cb353 100644 --- a/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java +++ b/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java @@ -1,5 +1,6 @@ package net.md_5.bungee.chat; +import com.google.common.collect.ImmutableList; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ClickEvent; @@ -123,50 +124,58 @@ public void testBuilderFormatRetention() Assert.assertEquals( eventRetention[1].getClickEvent(), testClickEvent ); } - @Test(expected = IllegalArgumentException.class) + @Test public void testLoopSimple() { TextComponent component = new TextComponent( "Testing" ); - component.addExtra( component ); - ComponentSerializer.toString( component ); + + try { + component.addExtra( component ); + Assert.fail(); + } catch(IllegalArgumentException ignored) {} + + try { + component.setExtra( component ); + Assert.fail(); + } catch(IllegalArgumentException ignored) {} + + try { + component.setExtra(ImmutableList.of(component)); + Assert.fail(); + } catch(IllegalArgumentException ignored) {} } - @Test(expected = IllegalArgumentException.class) + @Test public void testLoopComplex() { TextComponent a = new TextComponent( "A" ); TextComponent b = new TextComponent( "B" ); - b.setColor( ChatColor.AQUA ); TextComponent c = new TextComponent( "C" ); - c.setColor( ChatColor.RED ); a.addExtra( b ); b.addExtra( c ); - c.addExtra( a ); - ComponentSerializer.toString( a ); + + try { + c.addExtra( a ); + Assert.fail(); + } catch(IllegalArgumentException ignored) {} } @Test - public void testRepeated() - { - TextComponent a = new TextComponent( "A" ); - TextComponent b = new TextComponent( "B" ); - b.setColor( ChatColor.AQUA ); - a.addExtra( b ); - a.addExtra( b ); - ComponentSerializer.toString( a ); + public void testLoopInTranslatable() { + TranslatableComponent c = new TranslatableComponent("hi"); + try { + c.addWith(c); + Assert.fail(); + } catch(IllegalArgumentException ignored) {} } - @Test(expected = IllegalArgumentException.class) - public void testRepeatedError() + @Test + public void testRepeated() { TextComponent a = new TextComponent( "A" ); TextComponent b = new TextComponent( "B" ); b.setColor( ChatColor.AQUA ); - TextComponent c = new TextComponent( "C" ); - c.setColor( ChatColor.RED ); a.addExtra( b ); - a.addExtra( c ); - c.addExtra( a ); a.addExtra( b ); ComponentSerializer.toString( a ); } From 73111be52ab1f7806b0720abe9c14d3285a4aba3 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sun, 6 Mar 2016 03:08:58 -0500 Subject: [PATCH 29/39] Don't autolink the MOTD --- .../java/net/md_5/bungee/api/ServerPing.java | 2 +- .../md_5/bungee/api/chat/TextComponent.java | 58 +++++++++++-------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/api/src/main/java/net/md_5/bungee/api/ServerPing.java b/api/src/main/java/net/md_5/bungee/api/ServerPing.java index 27b51849ba..3adfbd1363 100644 --- a/api/src/main/java/net/md_5/bungee/api/ServerPing.java +++ b/api/src/main/java/net/md_5/bungee/api/ServerPing.java @@ -140,7 +140,7 @@ public void setFavicon(Favicon favicon) @Deprecated public void setDescription(String description) { - this.description = new TextComponent( TextComponent.fromLegacyText( description ) ); + this.description = new TextComponent( TextComponent.fromLegacyText( description, false ) ); } @Deprecated diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java index 2609b00ecf..b96bb2eb96 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java @@ -22,15 +22,23 @@ public class TextComponent extends BaseComponent private static final Pattern url = Pattern.compile( "^(?:(https?)://)?([-\\w_\\.]{2,}\\.[a-z]{2,4})(/\\S*)?$" ); + /** + * Calls {@link #fromLegacyText(String, boolean)} with autolink true + */ + public static BaseComponent[] fromLegacyText(String message) { + return fromLegacyText(message, true); + } + /** * Converts the old formatting system that used * {@link net.md_5.bungee.api.ChatColor#COLOR_CHAR} into the new json based * system. * * @param message the text to convert + * @param autolink detect links and make them clickable * @return the components needed to print the message to the client */ - public static BaseComponent[] fromLegacyText(String message) + public static BaseComponent[] fromLegacyText(String message, boolean autolink) { ArrayList components = new ArrayList(); StringBuilder builder = new StringBuilder(); @@ -87,34 +95,38 @@ public static BaseComponent[] fromLegacyText(String message) } continue; } - int pos = message.indexOf( ' ', i ); - if ( pos == -1 ) - { - pos = message.length(); - } - if ( matcher.region( i, pos ).find() ) - { //Web link handling - if ( builder.length() > 0 ) + if(autolink) { + int pos = message.indexOf( ' ', i ); + if ( pos == -1 ) { + pos = message.length(); + } + if ( matcher.region( i, pos ).find() ) + { //Web link handling + + if ( builder.length() > 0 ) + { + TextComponent old = component; + component = new TextComponent( old ); + old.setText( builder.toString() ); + builder = new StringBuilder(); + components.add( old ); + } + TextComponent old = component; component = new TextComponent( old ); - old.setText( builder.toString() ); - builder = new StringBuilder(); - components.add( old ); + String urlString = message.substring( i, pos ); + component.setText( urlString ); + component.setClickEvent( new ClickEvent( ClickEvent.Action.OPEN_URL, + urlString.startsWith( "http" ) ? urlString : "http://" + urlString ) ); + components.add( component ); + i += pos - i - 1; + component = old; + continue; } - - TextComponent old = component; - component = new TextComponent( old ); - String urlString = message.substring( i, pos ); - component.setText( urlString ); - component.setClickEvent( new ClickEvent( ClickEvent.Action.OPEN_URL, - urlString.startsWith( "http" ) ? urlString : "http://" + urlString ) ); - components.add( component ); - i += pos - i - 1; - component = old; - continue; } + builder.append( c ); } if ( builder.length() > 0 ) From efc912b697d3307aad03277f5b4f3348e12715bf Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Thu, 24 Mar 2016 15:29:23 -0400 Subject: [PATCH 30/39] Protocol version API --- proxy/src/main/java/net/md_5/bungee/BungeeCord.java | 7 +++++++ proxy/src/main/java/net/md_5/bungee/UserConnection.java | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 84b9d5eb3e..38a507fc4a 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -4,6 +4,7 @@ import com.google.common.base.Joiner; import com.google.common.base.Preconditions; import com.google.common.base.Predicate; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -35,6 +36,7 @@ import java.util.MissingResourceException; import java.util.PropertyResourceBundle; import java.util.ResourceBundle; +import java.util.Set; import java.util.Timer; import java.util.TimerTask; import java.util.UUID; @@ -714,4 +716,9 @@ public Title createTitle() { return new BungeeTitle(); } + + @Override + public Set getProtocolVersions() { + return ImmutableSet.copyOf(ProtocolConstants.SUPPORTED_VERSION_IDS); + } } diff --git a/proxy/src/main/java/net/md_5/bungee/UserConnection.java b/proxy/src/main/java/net/md_5/bungee/UserConnection.java index 4ce806bd19..8357c59e47 100644 --- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java +++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java @@ -629,4 +629,9 @@ public boolean isConnected() { return !ch.isClosed(); } + + @Override + public int getProtocolVersion() { + return getPendingConnection().getVersion(); + } } From fbdfd0cc46f2e6da6b85393733896e536cdecb11 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Thu, 2 Jun 2016 22:05:10 -0400 Subject: [PATCH 31/39] Plugins always load classes from their own JAR if present --- .../bungee/api/plugin/PluginClassloader.java | 60 +++++++++---------- .../md_5/bungee/api/plugin/PluginManager.java | 22 ++++--- 2 files changed, 45 insertions(+), 37 deletions(-) diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginClassloader.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginClassloader.java index 85203fb8ad..f21d1ceb58 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginClassloader.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginClassloader.java @@ -2,54 +2,54 @@ import java.net.URL; import java.net.URLClassLoader; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; +import java.util.List; public class PluginClassloader extends URLClassLoader { - - private static final Set allLoaders = new CopyOnWriteArraySet<>(); - static { ClassLoader.registerAsParallelCapable(); } - public PluginClassloader(URL[] urls) + private final List dependencies; + + public PluginClassloader(List dependencies, URL[] urls) { super( urls ); - allLoaders.add( this ); + this.dependencies = dependencies; } @Override protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { - return loadClass0( name, resolve, true ); + synchronized(getClassLoadingLock(name)) { + try { + return loadLocalClass(name, resolve); + } catch(ClassNotFoundException e1) { + try { + return loadDependencyClass(name, resolve); + } catch(ClassNotFoundException e2) { + return super.loadClass(name, resolve); + } + } + } } - private Class loadClass0(String name, boolean resolve, boolean checkOther) throws ClassNotFoundException - { - try - { - return super.loadClass( name, resolve ); - } catch ( ClassNotFoundException ex ) - { - } - if ( checkOther ) - { - for ( PluginClassloader loader : allLoaders ) - { - if ( loader != this ) - { - try - { - return loader.loadClass0( name, resolve, false ); - } catch ( ClassNotFoundException ex ) - { - } - } + private Class loadLocalClass(String name, boolean resolve) throws ClassNotFoundException { + Class cls = findLoadedClass(name); + if(cls == null) cls = findClass(name); + if(resolve) resolveClass(cls); + return cls; + } + + private Class loadDependencyClass(String name, boolean resolve) throws ClassNotFoundException { + for(PluginClassloader loader : dependencies) { + try { + return loader.loadLocalClass(name, resolve); + } catch(ClassNotFoundException e) { + // continue } } - throw new ClassNotFoundException( name ); + throw new ClassNotFoundException(name); } } diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java index 4beedefa8b..a4c59cadac 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java @@ -6,13 +6,13 @@ import java.io.File; import java.io.InputStream; import java.net.URL; -import java.net.URLClassLoader; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -49,6 +49,7 @@ public class PluginManager implements tc.oc.minecraft.api.plugin.PluginManager private final Map plugins = new LinkedHashMap<>(); private final Map commandMap = new HashMap<>(); private Map toLoad = new HashMap<>(); + private final Map classLoaders = new HashMap<>(); private final Multimap commandsByPlugin = ArrayListMultimap.create(); private final Multimap listenersByPlugin = ArrayListMultimap.create(); @@ -212,10 +213,11 @@ public Plugin getPlugin(String name) public void loadPlugins() { Map pluginStatuses = new HashMap<>(); + Map pluginLoaders = new HashMap<>(); for ( Map.Entry entry : toLoad.entrySet() ) { PluginDescription plugin = entry.getValue(); - if ( !enablePlugin( pluginStatuses, new Stack(), plugin ) ) + if ( !enablePlugin( pluginStatuses, pluginLoaders, new Stack(), plugin ) ) { ProxyServer.getInstance().getLogger().log( Level.WARNING, "Failed to enable {0}", entry.getKey() ); } @@ -242,7 +244,7 @@ public void enablePlugins() } } - private boolean enablePlugin(Map pluginStatuses, Stack dependStack, PluginDescription plugin) + private boolean enablePlugin(Map pluginStatuses, Map pluginLoaders, Stack dependStack, PluginDescription plugin) { if ( pluginStatuses.containsKey( plugin ) ) { @@ -250,12 +252,13 @@ private boolean enablePlugin(Map pluginStatuses, Sta } // combine all dependencies for 'for loop' - Set dependencies = new HashSet<>(); + Set dependencies = new LinkedHashSet<>(); dependencies.addAll( plugin.getDepends() ); dependencies.addAll( plugin.getSoftDepends() ); // success status boolean status = true; + final List dependLoaders = new ArrayList<>(); // try to load dependencies first for ( String dependName : dependencies ) @@ -278,11 +281,15 @@ private boolean enablePlugin(Map pluginStatuses, Sta } else { dependStack.push( plugin ); - dependStatus = this.enablePlugin( pluginStatuses, dependStack, depend ); + dependStatus = this.enablePlugin( pluginStatuses, pluginLoaders, dependStack, depend ); dependStack.pop(); } } + if(Boolean.TRUE.equals(dependStatus)) { + dependLoaders.add(Preconditions.checkNotNull(pluginLoaders.get(depend))); + } + if ( dependStatus == Boolean.FALSE && plugin.getDepends().contains( dependName ) ) // only fail if this wasn't a soft dependency { ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} (required by {1}) is unavailable", new Object[] @@ -303,10 +310,11 @@ private boolean enablePlugin(Map pluginStatuses, Sta { try { - URLClassLoader loader = new PluginClassloader( new URL[] + PluginClassloader loader = new PluginClassloader(dependLoaders, new URL[] { plugin.getFile().toURI().toURL() } ); + pluginLoaders.put(plugin, loader); Class main = loader.loadClass( plugin.getMain() ); Plugin clazz = (Plugin) main.getDeclaredConstructor().newInstance(); From 48c2528298c09e68088fde7159ddcfba1d75ba0c Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Thu, 2 Jun 2016 22:05:37 -0400 Subject: [PATCH 32/39] Add quiet connect plugin channel message --- .../java/net/md_5/bungee/UserConnection.java | 21 +++++++++++++------ .../bungee/connection/DownstreamBridge.java | 8 +++++++ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/proxy/src/main/java/net/md_5/bungee/UserConnection.java b/proxy/src/main/java/net/md_5/bungee/UserConnection.java index 8357c59e47..b534aaee9c 100644 --- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java +++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java @@ -241,7 +241,11 @@ public ServerInfo updateAndGetNextServer(ServerInfo currentTarget) return next; } - public void connect(ServerInfo info, final Callback callback, final boolean retry) + public void connect(ServerInfo info, final Callback callback, final boolean retry) { + connect(info, callback, retry, false); + } + + public void connect(ServerInfo info, final Callback callback, final boolean retry, final boolean quiet) { Preconditions.checkNotNull( info, "info" ); @@ -265,7 +269,9 @@ public void connect(ServerInfo info, final Callback callback, final boo callback.done( false, null ); } - sendMessage( bungee.getTranslation( "already_connected" ) ); + if(!quiet) { + sendMessage( bungee.getTranslation( "already_connected" ) ); + } return; } if ( pendingConnects.contains( target ) ) @@ -275,7 +281,9 @@ public void connect(ServerInfo info, final Callback callback, final boo callback.done( false, null ); } - sendMessage( bungee.getTranslation( "already_connecting" ) ); + if(!quiet) { + sendMessage( bungee.getTranslation( "already_connecting" ) ); + } return; } @@ -311,13 +319,14 @@ public void operationComplete(ChannelFuture future) throws Exception ServerInfo def = updateAndGetNextServer( target ); if ( retry && def != null && ( getServer() == null || def != getServer().getInfo() ) ) { - sendMessage( bungee.getTranslation( "fallback_lobby" ) ); + if(!quiet) { + sendMessage( bungee.getTranslation( "fallback_lobby" ) ); + } connect( def, null, false ); } else if ( dimensionChange ) { disconnect( bungee.getTranslation( "fallback_kick", future.cause().getClass().getName() ) ); - } else - { + } else if(!quiet) { sendMessage( bungee.getTranslation( "fallback_kick", future.cause().getClass().getName() ) ); } } diff --git a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java index c2dd942ff3..4e82c90403 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java @@ -328,6 +328,14 @@ public void handle(PluginMessage pluginMessage) throws Exception con.connect( server ); } } + if ( subChannel.equals( "ConnectQuiet" ) ) + { + ServerInfo server = bungee.getServerInfo( in.readUTF() ); + if ( server != null ) + { + con.connect( server, null, false, true ); + } + } if ( subChannel.equals( "ConnectOther" ) ) { ProxiedPlayer player = bungee.getPlayer( in.readUTF() ); From 2b4016ce966448d61036815d95b3fdf4488941bf Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Fri, 3 Jun 2016 01:50:15 -0400 Subject: [PATCH 33/39] A few helpful methods for converting between components and legacy text --- .../md_5/bungee/api/chat/BaseComponent.java | 8 +++++ .../md_5/bungee/api/chat/TextComponent.java | 34 ++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java index cf76837400..e764caa42a 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java @@ -107,6 +107,14 @@ public abstract class BaseComponent */ public abstract BaseComponent duplicate(); + public static String[] toLegacyArray(BaseComponent... components) { + final String[] legacies = new String[components.length]; + for(int i = 0; i < components.length; i++) { + legacies[i] = components[i].toLegacyText(); + } + return legacies; + } + /** * Converts the components to a string that uses the old formatting codes * ({@link net.md_5.bungee.api.ChatColor#COLOR_CHAR} diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java index b96bb2eb96..185fb7628d 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java @@ -22,6 +22,14 @@ public class TextComponent extends BaseComponent private static final Pattern url = Pattern.compile( "^(?:(https?)://)?([-\\w_\\.]{2,}\\.[a-z]{2,4})(/\\S*)?$" ); + public static BaseComponent[] fromLegacyArray(String[] legacies, boolean autolink) { + final BaseComponent[] components = new BaseComponent[legacies.length]; + for(int i = 0; i < legacies.length; i++) { + components[i] = fromLegacyToComponent(legacies[i], autolink); + } + return components; + } + /** * Calls {@link #fromLegacyText(String, boolean)} with autolink true */ @@ -38,7 +46,7 @@ public static BaseComponent[] fromLegacyText(String message) { * @param autolink detect links and make them clickable * @return the components needed to print the message to the client */ - public static BaseComponent[] fromLegacyText(String message, boolean autolink) + public static List fromLegacyToList(String message, boolean autolink) { ArrayList components = new ArrayList(); StringBuilder builder = new StringBuilder(); @@ -135,6 +143,12 @@ public static BaseComponent[] fromLegacyText(String message, boolean autolink) components.add( component ); } + return components; + } + + public static BaseComponent[] fromLegacyText(String message, boolean autolink) { + final List components = fromLegacyToList(message, autolink); + // The client will crash if the array is empty if ( components.isEmpty() ) { @@ -144,6 +158,15 @@ public static BaseComponent[] fromLegacyText(String message, boolean autolink) return components.toArray( new BaseComponent[ components.size() ] ); } + public static BaseComponent fromLegacyToComponent(String message, boolean autolink) { + final List components = fromLegacyToList(message, autolink); + switch(components.size()) { + case 0: return new TextComponent(); + case 1: return components.get(0); + default: return new TextComponent(components); + } + } + /** * The text of the component that will be displayed to the client */ @@ -180,6 +203,15 @@ public TextComponent(BaseComponent... extras) setExtra( extras ); } + public TextComponent(List extra) { + this("", extra); + } + + public TextComponent(String text, List extra) { + setText(text); + setExtra(extra); + } + /** * Creates a duplicate of this TextComponent. * From 1b94bde0cb321ad54d8ea7e88286dcea79f513fa Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Wed, 8 Jun 2016 23:40:31 -0400 Subject: [PATCH 34/39] Don't throw an exception for unsupported protocols --- protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java b/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java index 80c0b7ab63..685b7db179 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/Protocol.java @@ -285,7 +285,7 @@ public final DefinedPacket createPacket(int id, int version) ProtocolData protocolData = getProtocolData( version ); if (protocolData == null) { - throw new BadPacketException( "Unsupported protocol version" ); + return null; // Unsupported protocol version } if ( id < 0 || id > MAX_PACKET_ID ) { From b99a1e67bf7cd2eeb3f5802a9d8f5b5fa8bf23c4 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sun, 26 Jun 2016 21:28:53 -0400 Subject: [PATCH 35/39] Implement minecraft-api strict config getters --- .../net/md_5/bungee/config/Configuration.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/config/src/main/java/net/md_5/bungee/config/Configuration.java b/config/src/main/java/net/md_5/bungee/config/Configuration.java index a36cc0f46d..38e2d6a17a 100644 --- a/config/src/main/java/net/md_5/bungee/config/Configuration.java +++ b/config/src/main/java/net/md_5/bungee/config/Configuration.java @@ -1,5 +1,6 @@ package net.md_5.bungee.config; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collection; @@ -8,11 +9,14 @@ import java.util.List; import java.util.Map; import lombok.Getter; +import tc.oc.minecraft.api.configuration.AbstractConfigurationSection; +import tc.oc.minecraft.api.configuration.InvalidConfigurationException; -public final class Configuration implements tc.oc.minecraft.api.configuration.Configuration +public final class Configuration extends AbstractConfigurationSection implements tc.oc.minecraft.api.configuration.Configuration { private static final char SEPARATOR = '.'; + final String absolutePath; final Map self; @Getter private final Configuration defaults; @@ -34,6 +38,12 @@ public Configuration(Configuration values, Configuration defaults) Configuration(Map map, Configuration defaults) { + this("", map, defaults); + } + + Configuration(String absolutePath, Map map, Configuration defaults) + { + this.absolutePath = absolutePath; this.self = new LinkedHashMap<>(); this.defaults = defaults; @@ -63,7 +73,7 @@ private Configuration getSectionFor(String path) Object section = self.get( root ); if ( section == null ) { - section = new Configuration( ( defaults == null ) ? null : defaults.getSection( path ) ); + section = new Configuration( resolvePath(path), ImmutableMap.of(), (defaults == null ) ? null : defaults.getSection(path ) ); self.put( root, section ); } @@ -143,6 +153,11 @@ public Configuration getSection(String path) return (Configuration) get( path, ( def instanceof Configuration ) ? def : new Configuration( ( defaults == null ) ? null : defaults.getSection( path ) ) ); } + @Override + public Configuration needSection(String path) throws InvalidConfigurationException { + return needType(path, Configuration.class); + } + /** * Gets keys, not deep by default. * @@ -418,4 +433,9 @@ public List getList(String path, List def) Object val = get( path, def ); return ( val instanceof List ) ? (List) val : def; } + + @Override + public String getCurrentPath() { + return absolutePath; + } } From ef44e691e2dea93c25dadbf437e581395266c378 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Wed, 6 Jul 2016 02:31:22 -0400 Subject: [PATCH 36/39] Handle default colors better when converting to/from legacy text --- .../java/net/md_5/bungee/api/ChatColor.java | 15 +- .../md_5/bungee/api/ChatStringBuilder.java | 22 ++- .../md_5/bungee/api/chat/BaseComponent.java | 59 +++++-- .../md_5/bungee/api/chat/TextComponent.java | 132 +++++++-------- .../bungee/api/chat/TextComponentTest.java | 152 ++++++++++++++++++ .../api/chat/TranslatableComponentTest.java | 2 +- .../net/md_5/bungee/chat/ComponentsTest.java | 9 +- 7 files changed, 294 insertions(+), 97 deletions(-) create mode 100644 chat/src/test/java/net/md_5/bungee/api/chat/TextComponentTest.java diff --git a/chat/src/main/java/net/md_5/bungee/api/ChatColor.java b/chat/src/main/java/net/md_5/bungee/api/ChatColor.java index 85291a8806..e216abf859 100644 --- a/chat/src/main/java/net/md_5/bungee/api/ChatColor.java +++ b/chat/src/main/java/net/md_5/bungee/api/ChatColor.java @@ -2,7 +2,10 @@ import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.regex.Pattern; + +import com.google.common.collect.ImmutableSet; import lombok.Getter; /** @@ -106,13 +109,13 @@ public enum ChatColor public static final char COLOR_CHAR = '\u00A7'; public static final String ALL_CODES = "0123456789AaBbCcDdEeFfKkLlMmNnOoRr"; - public static final ChatColor[] DECORATIONS = { + public static final Set DECORATIONS = ImmutableSet.of( BOLD, ITALIC, UNDERLINE, STRIKETHROUGH, MAGIC - }; + ); /** * Pattern to remove all colour codes. @@ -157,6 +160,14 @@ public String toString() return toString; } + public boolean isColor() { + return this == RESET || (code >= '0' && code <= 'f'); + } + + public boolean isDecoration() { + return DECORATIONS.contains(this); + } + /** * Strips the given message of all color codes * diff --git a/chat/src/main/java/net/md_5/bungee/api/ChatStringBuilder.java b/chat/src/main/java/net/md_5/bungee/api/ChatStringBuilder.java index bcd53d3131..ac7990b3c8 100644 --- a/chat/src/main/java/net/md_5/bungee/api/ChatStringBuilder.java +++ b/chat/src/main/java/net/md_5/bungee/api/ChatStringBuilder.java @@ -2,15 +2,17 @@ import java.util.EnumSet; import java.util.Set; +import javax.annotation.Nullable; public class ChatStringBuilder implements Appendable { private final StringBuilder builder; - private ChatColor oldColor, newColor; + private @Nullable ChatColor oldColor, newColor; private final Set oldDecorations, newDecorations; private boolean formatChanged = true; + private boolean colored = false; - public ChatStringBuilder(String initial, ChatColor color, Set decorations) { + public ChatStringBuilder(String initial, @Nullable ChatColor color, Set decorations) { builder = initial != null ? new StringBuilder(initial) : new StringBuilder(); oldColor = newColor = color; @@ -20,7 +22,7 @@ public ChatStringBuilder(String initial, ChatColor color, Set decorat } public ChatStringBuilder() { - this(null, ChatColor.RESET, null); + this(null, null, null); } @Override @@ -29,6 +31,11 @@ public String toString() { } private void refreshComplete() { + if(newColor == null) { + newColor = ChatColor.RESET; + } + + colored = true; builder.append(oldColor = newColor); oldDecorations.clear(); @@ -92,7 +99,12 @@ public void append(Object thing) { append(String.valueOf(thing)); } - public void color(ChatColor color) { + public void color(@Nullable ChatColor color) { + if(colored && color == null) { + // Cannot un-color a legacy string + color = ChatColor.RESET; + } + if(newColor != color) { formatChanged = true; newColor = color; @@ -117,7 +129,7 @@ public void decorations(Set decorations) { } } - public void format(ChatColor color, Set decorations) { + public void format(@Nullable ChatColor color, Set decorations) { color(color); decorations(decorations); } diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java index e764caa42a..15788d0108 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/BaseComponent.java @@ -3,6 +3,7 @@ import com.google.common.base.Joiner; import com.google.common.base.Objects; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import lombok.Getter; import lombok.NoArgsConstructor; @@ -17,6 +18,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import javax.annotation.Nullable; @Setter @NoArgsConstructor @@ -115,6 +117,10 @@ public static String[] toLegacyArray(BaseComponent... components) { return legacies; } + public static String toLegacyText(BaseComponent... components) { + return toLegacyText(null, ImmutableSet.of(), components); + } + /** * Converts the components to a string that uses the old formatting codes * ({@link net.md_5.bungee.api.ChatColor#COLOR_CHAR} @@ -122,12 +128,12 @@ public static String[] toLegacyArray(BaseComponent... components) { * @param components the components to convert * @return the string in the old format */ - public static String toLegacyText(BaseComponent... components) + public static String toLegacyText(@Nullable ChatColor color, Set decorations, BaseComponent... components) { StringBuilder builder = new StringBuilder(); for ( BaseComponent msg : components ) { - builder.append( msg.toLegacyText() ); + builder.append( msg.toLegacyText(color, decorations) ); } return builder.toString(); } @@ -149,9 +155,8 @@ public static String toPlainText(BaseComponent... components) } /** - * Returns the color of this component. This uses the parent's color if this - * component doesn't have one. {@link net.md_5.bungee.api.ChatColor#WHITE} - * is returned if no color is found. + * Returns the color of this component, or {@link net.md_5.bungee.api.ChatColor#WHITE} + * if this component has no color. * * @return the color of this component */ @@ -161,8 +166,7 @@ public ChatColor getColor() } /** - * Returns the color of this component without checking the parents color. - * May return null + * Returns the color of this component, or null if this component has no color. * * @return the color of this component */ @@ -175,6 +179,11 @@ public ChatColor getColor(ChatColor def) { return color != null ? color : def; } + public void setColor(@Nullable ChatColor color) { + Preconditions.checkArgument(color == null || color.isColor(), "not a color"); + this.color = color; + } + /** * Returns whether this component is bold. This uses the parent's setting if * this component hasn't been set. false is returned if none of the parent @@ -390,19 +399,43 @@ void toPlainText(StringBuilder builder) } /** - * Converts the component to a string that uses the old formatting codes - * ({@link net.md_5.bungee.api.ChatColor#COLOR_CHAR} + * Calls {@link #toLegacyText(ChatColor, Set)} with no default color or decorations. + */ + public String toLegacyText() { + return toLegacyText(null, ImmutableSet.of()); + } + + public String toLegacyText(@Nullable ChatColor color, ChatColor... decorations) { + return toLegacyText(color, ImmutableSet.copyOf(decorations)); + } + + /** + * Converts the component to a string that uses the old formatting codes {@link net.md_5.bungee.api.ChatColor#COLOR_CHAR} + * + * Any given default color or decorations will be applied as if they were inherited from a parent component. + * Any part of the string that is not formatted by some component in this tree will have the default formatting + * applied. + * + * If null is given as the default color, then no color is applied to the returned string other than from + * the components. This is only possible up to the first formatting applied by a component (because formatting + * cannot be "removed" in legacy text, only replaced). Any default-formatted text after that will be given + * the {@link ChatColor#RESET} format, which can also be the color passed to this method. + * + * @param color Default color, or {@link ChatColor#RESET}, or null for no default + * @param decorations Default decorations * * @return the string in the old format */ - public String toLegacyText() + public String toLegacyText(@Nullable ChatColor color, Set decorations) { + Preconditions.checkArgument(color == null || color.isColor(), "default color cannot be a decoration"); + ChatStringBuilder builder = new ChatStringBuilder(); - toLegacyText(builder, ChatColor.WHITE, Collections.emptySet()); + toLegacyText(builder, color, decorations); return builder.toString(); } - protected void toLegacyText(ChatStringBuilder builder, ChatColor color, Set decorations) + protected void toLegacyText(ChatStringBuilder builder, @Nullable ChatColor color, Set decorations) { color = getColor(color); decorations = getDecorations(decorations); @@ -418,7 +451,7 @@ protected void toLegacyText(ChatStringBuilder builder, ChatColor color, Set decorations) { + protected void toLegacyTextContent(ChatStringBuilder builder, @Nullable ChatColor color, Set decorations) { } protected static final Joiner JOINER = Joiner.on(", "); diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java index 185fb7628d..7cf4e5b02d 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/TextComponent.java @@ -52,69 +52,18 @@ public static List fromLegacyToList(String message, boolean autol StringBuilder builder = new StringBuilder(); TextComponent component = new TextComponent(); Matcher matcher = url.matcher( message ); + boolean formatting = false; for ( int i = 0; i < message.length(); i++ ) { - char c = message.charAt( i ); - if ( c == ChatColor.COLOR_CHAR ) - { - i++; - c = message.charAt( i ); - if ( c >= 'A' && c <= 'Z' ) - { - c += 32; - } - ChatColor format = ChatColor.getByChar( c ); - if ( format == null ) - { - continue; - } - if ( builder.length() > 0 ) - { - TextComponent old = component; - component = new TextComponent( old ); - old.setText( builder.toString() ); - builder = new StringBuilder(); - components.add( old ); - } - switch ( format ) - { - case BOLD: - component.setBold( true ); - break; - case ITALIC: - component.setItalic( true ); - break; - case UNDERLINE: - component.setUnderlined( true ); - break; - case STRIKETHROUGH: - component.setStrikethrough( true ); - break; - case MAGIC: - component.setObfuscated( true ); - break; - case RESET: - format = ChatColor.WHITE; - default: - component = new TextComponent(); - component.setColor( format ); - break; - } - continue; - } - - if(autolink) { - int pos = message.indexOf( ' ', i ); - if ( pos == -1 ) - { - pos = message.length(); - } - if ( matcher.region( i, pos ).find() ) - { //Web link handling - - if ( builder.length() > 0 ) - { + final char c = message.charAt( i ); + if(c == ChatColor.COLOR_CHAR) { + formatting = true; + } else if(formatting) { + formatting = false; + final ChatColor format = ChatColor.getByChar(Character.toLowerCase(c)); + if(format != null) { + if(builder.length() > 0) { TextComponent old = component; component = new TextComponent( old ); old.setText( builder.toString() ); @@ -122,21 +71,60 @@ public static List fromLegacyToList(String message, boolean autol components.add( old ); } - TextComponent old = component; - component = new TextComponent( old ); - String urlString = message.substring( i, pos ); - component.setText( urlString ); - component.setClickEvent( new ClickEvent( ClickEvent.Action.OPEN_URL, - urlString.startsWith( "http" ) ? urlString : "http://" + urlString ) ); - components.add( component ); - i += pos - i - 1; - component = old; - continue; + switch ( format ) + { + case BOLD: + component.setBold( true ); + break; + case ITALIC: + component.setItalic( true ); + break; + case UNDERLINE: + component.setUnderlined( true ); + break; + case STRIKETHROUGH: + component.setStrikethrough( true ); + break; + case MAGIC: + component.setObfuscated( true ); + break; + default: + component = new TextComponent(); + component.setColor( format ); + break; + } } - } + } else { + if(autolink) { + int pos = message.indexOf(' ', i); + if(pos == -1) { + pos = message.length(); + } - builder.append( c ); + if(matcher.region(i, pos).find()) { //Web link handling + if(builder.length() > 0) { + TextComponent old = component; + component = new TextComponent(old); + old.setText(builder.toString()); + builder = new StringBuilder(); + components.add(old); + } + + final String urlString = message.substring(i, pos); + final TextComponent urlComponent = new TextComponent(component); + urlComponent.setText(urlString); + urlComponent.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, + urlString.startsWith("http") ? urlString : "http://" + urlString)); + components.add(urlComponent); + i = pos - 1; + continue; + } + } + + builder.append( c ); + } } + if ( builder.length() > 0 ) { component.setText( builder.toString() ); diff --git a/chat/src/test/java/net/md_5/bungee/api/chat/TextComponentTest.java b/chat/src/test/java/net/md_5/bungee/api/chat/TextComponentTest.java new file mode 100644 index 0000000000..93f93a69ca --- /dev/null +++ b/chat/src/test/java/net/md_5/bungee/api/chat/TextComponentTest.java @@ -0,0 +1,152 @@ +package net.md_5.bungee.api.chat; + +import net.md_5.bungee.api.ChatColor; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class TextComponentTest { + + @Test + public void fromLegacyNoFormatting() throws Exception { + assertEquals(new TextComponent("woot"), + TextComponent.fromLegacyToComponent("woot", false)); + } + + @Test + public void fromLegacyWithFormatting() throws Exception { + TextComponent c = new TextComponent("woot"); + c.setColor(ChatColor.GREEN); + c.setBold(true); + + assertEquals(c, TextComponent.fromLegacyToComponent(ChatColor.GREEN.toString() + ChatColor.BOLD + "woot", false)); + } + + @Test + public void fromLegacyPartialColor() throws Exception { + TextComponent one = new TextComponent("One"); + TextComponent two = new TextComponent("Two"); two.setColor(ChatColor.GREEN); + TextComponent c = new TextComponent(one, two); + + assertEquals(c, TextComponent.fromLegacyToComponent("One" + ChatColor.GREEN + "Two", false)); + } + + @Test + public void fromLegacyAutoLinkStandalone() throws Exception { + TextComponent c = new TextComponent("https://oc.tc"); + c.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://oc.tc")); + + assertEquals(c, TextComponent.fromLegacyToComponent("https://oc.tc", true)); + } + + @Test + public void fromLegacyAutoLinkInline() throws Exception { + TextComponent one = new TextComponent("Go to "); + TextComponent two = new TextComponent("https://oc.tc"); two.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://oc.tc")); + TextComponent three = new TextComponent(" for a good time"); + TextComponent c = new TextComponent(one, two, three); + + assertEquals(c, TextComponent.fromLegacyToComponent("Go to https://oc.tc for a good time", true)); + } + + @Test + public void toLegacyNoFormatting() throws Exception { + assertEquals("woot", new TextComponent("woot").toLegacyText()); + } + + @Test + public void toLegacyWithFormatting() throws Exception { + TextComponent c = new TextComponent("woot"); + c.setColor(ChatColor.GREEN); + c.setBold(true); + + assertEquals(ChatColor.GREEN.toString() + ChatColor.BOLD + "woot", + c.toLegacyText()); + } + + @Test + public void toLegacyPartialColorNoDefault() throws Exception { + TextComponent one = new TextComponent("One"); + TextComponent two = new TextComponent("Two"); two.setColor(ChatColor.GREEN); + TextComponent three = new TextComponent("Three"); + one.addExtra(two); + one.addExtra(three); + + assertEquals("One" + ChatColor.GREEN + "Two" + ChatColor.RESET + "Three", + one.toLegacyText()); + } + + @Test + public void toLegacyPartialColorWithDefault() throws Exception { + TextComponent one = new TextComponent("One"); + TextComponent two = new TextComponent("Two"); two.setColor(ChatColor.GREEN); + TextComponent three = new TextComponent("Three"); + one.addExtra(two); + one.addExtra(three); + + assertEquals(ChatColor.RED + "One" + ChatColor.GREEN + "Two" + ChatColor.RED + "Three", + one.toLegacyText(ChatColor.RED)); + } + + @Test + public void toLegacyAddDecoration() throws Exception { + TextComponent one = new TextComponent("One"); one.setColor(ChatColor.RED); + TextComponent two = new TextComponent("Two"); two.setBold(true); + one.addExtra(two); + + assertEquals(ChatColor.RED + "One" + ChatColor.BOLD + "Two", + one.toLegacyText()); + } + + @Test + public void toLegacyRemoveDecoration() throws Exception { + TextComponent one = new TextComponent("One"); one.setColor(ChatColor.RED); + TextComponent two = new TextComponent("Two"); two.setBold(true); + TextComponent three = new TextComponent("Three"); + one.addExtra(two); + one.addExtra(three); + + assertEquals(ChatColor.RED + "One" + ChatColor.BOLD + "Two" + ChatColor.RED + "Three", + one.toLegacyText()); + } + + @Test + public void toLegacyNestedDecoration() throws Exception { + TextComponent one = new TextComponent("One"); one.setColor(ChatColor.RED); + TextComponent two = new TextComponent("Two"); two.setBold(true); + TextComponent three = new TextComponent("Three"); three.setItalic(true); + one.addExtra(two); + two.addExtra(three); + two.addExtra(new TextComponent("Two")); + one.addExtra(new TextComponent("One")); + + assertEquals(ChatColor.RED + "One" + ChatColor.BOLD + "Two" + ChatColor.ITALIC + "Three" + ChatColor.RED + ChatColor.BOLD + "Two" + ChatColor.RED + "One", + one.toLegacyText()); + } + + @Test + public void toLegacyCollapseFormatting() throws Exception { + TextComponent one = new TextComponent(""); one.setColor(ChatColor.RED); + TextComponent two = new TextComponent(""); two.setColor(ChatColor.GREEN); + TextComponent three = new TextComponent("Hi"); three.setColor(ChatColor.BLUE); + TextComponent four = new TextComponent(""); four.setColor(ChatColor.YELLOW); + TextComponent five = new TextComponent("There"); five.setColor(ChatColor.BLUE); + one.addExtra(two); + one.addExtra(three); + one.addExtra(four); + one.addExtra(five); + + assertEquals(ChatColor.BLUE + "HiThere", + one.toLegacyText()); + } + + @Test + public void toLegacyWithClickEvent() throws Exception { + TextComponent one = new TextComponent("Go to "); + TextComponent two = new TextComponent("https://oc.tc"); two.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, "https://oc.tc")); + TextComponent three = new TextComponent(" for a good time"); + TextComponent c = new TextComponent(one, two, three); + + assertEquals("Go to https://oc.tc for a good time", c.toLegacyText()); + } +} diff --git a/chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java b/chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java index 53e49d555e..70be2889c6 100644 --- a/chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java +++ b/chat/src/test/java/net/md_5/bungee/api/chat/TranslatableComponentTest.java @@ -13,6 +13,6 @@ public void testMissingPlaceholdersAdded() { TranslatableComponent testComponent = new TranslatableComponent( "Test string with %s placeholders: %s", "2", "aoeu" ); assertEquals( "Test string with 2 placeholders: aoeu", testComponent.toPlainText() ); - assertEquals( "§fTest string with 2 placeholders: aoeu", testComponent.toLegacyText() ); + assertEquals( "Test string with 2 placeholders: aoeu", testComponent.toLegacyText() ); } } diff --git a/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java b/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java index 62147cb353..e9985eac40 100644 --- a/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java +++ b/proxy/src/test/java/net/md_5/bungee/chat/ComponentsTest.java @@ -1,6 +1,7 @@ package net.md_5.bungee.chat; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.ClickEvent; @@ -36,8 +37,8 @@ public void testLegacyConverter() Assert.assertEquals( "Text http://spigotmc.org google.com/test", BaseComponent.toPlainText( test2 ) ); //The extra ChatColor.WHITEs 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 - + " " + ChatColor.GREEN + "google.com/test", BaseComponent.toLegacyText( test2 ) ); + Assert.assertEquals( ChatColor.WHITE + "Text " + ChatColor.WHITE + "http://spigotmc.org" + ChatColor.WHITE + " " + ChatColor.GREEN + "google.com/test", + BaseComponent.toLegacyText( ChatColor.WHITE, ImmutableSet.of(), test2 ) ); ClickEvent url1 = test2[1].getClickEvent(); Assert.assertNotNull( url1 ); @@ -62,12 +63,12 @@ public void testTranslateComponent() Assert.assertEquals( "Given Golden Sword * 5 to thinkofdeath", translatableComponent.toPlainText() ); Assert.assertEquals( ChatColor.WHITE + "Given " + ChatColor.AQUA + "Golden Sword" + ChatColor.WHITE + " * 5 to thinkofdeath", - translatableComponent.toLegacyText() ); + translatableComponent.toLegacyText(ChatColor.WHITE) ); TranslatableComponent positional = new TranslatableComponent( "book.pageIndicator", "5", "50" ); Assert.assertEquals( "Page 5 of 50", positional.toPlainText() ); - Assert.assertEquals( ChatColor.WHITE + "Page 5 of 50", positional.toLegacyText() ); + Assert.assertEquals( ChatColor.WHITE + "Page 5 of 50", positional.toLegacyText(ChatColor.WHITE) ); } @Test From 951af28a9d066fa7a7430c2f6f6fe740ce6ccc68 Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sat, 23 Jul 2016 23:57:17 -0400 Subject: [PATCH 37/39] Optionally shutdown if any plugins fail to load --- .../java/net/md_5/bungee/api/ProxyConfig.java | 5 +++ .../md_5/bungee/api/plugin/PluginManager.java | 36 +++++++++++++------ .../net/md_5/bungee/BungeeCordLauncher.java | 7 +++- .../main/java/net/md_5/bungee/BungeeCord.java | 2 +- .../net/md_5/bungee/conf/Configuration.java | 2 ++ 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java b/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java index 7f405b91db..9147e7388d 100644 --- a/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java +++ b/api/src/main/java/net/md_5/bungee/api/ProxyConfig.java @@ -145,4 +145,9 @@ public interface ProxyConfig * The favicon used for the server ping list. */ Favicon getFaviconObject(); + + /** + * Shutdown immediately if any plugins fail to load + */ + boolean isRequireAllPlugins(); } diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java index a4c59cadac..f5e30a5161 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java @@ -21,6 +21,8 @@ import java.util.jar.JarFile; import java.util.logging.Level; import java.util.regex.Pattern; + +import lombok.Getter; import lombok.RequiredArgsConstructor; import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.CommandSender; @@ -49,6 +51,8 @@ public class PluginManager implements tc.oc.minecraft.api.plugin.PluginManager private final Map plugins = new LinkedHashMap<>(); private final Map commandMap = new HashMap<>(); private Map toLoad = new HashMap<>(); + private final @Getter List loadedPlugins = new ArrayList<>(); + private final @Getter List enabledPlugins = new ArrayList<>(); private final Map classLoaders = new HashMap<>(); private final Multimap commandsByPlugin = ArrayListMultimap.create(); private final Multimap listenersByPlugin = ArrayListMultimap.create(); @@ -210,16 +214,16 @@ public Plugin getPlugin(String name) return plugins.get( name ); } - public void loadPlugins() + public void loadPlugins() throws Exception { Map pluginStatuses = new HashMap<>(); Map pluginLoaders = new HashMap<>(); for ( Map.Entry entry : toLoad.entrySet() ) { PluginDescription plugin = entry.getValue(); - if ( !enablePlugin( pluginStatuses, pluginLoaders, new Stack(), plugin ) ) + if ( !loadPlugin(pluginStatuses, pluginLoaders, new Stack(), plugin ) ) { - ProxyServer.getInstance().getLogger().log( Level.WARNING, "Failed to enable {0}", entry.getKey() ); + ProxyServer.getInstance().getLogger().log( Level.SEVERE, "Failed to load {0}", entry.getKey() ); } } toLoad.clear(); @@ -228,23 +232,27 @@ public void loadPlugins() public void enablePlugins() { - for ( Plugin plugin : plugins.values() ) + for ( Plugin plugin : loadedPlugins ) { try { plugin.onEnable(); + enabledPlugins.add(plugin); ProxyServer.getInstance().getLogger().log( Level.INFO, "Enabled plugin {0} version {1} by {2}", new Object[] { plugin.getDescription().getName(), plugin.getDescription().getVersion(), plugin.getDescription().getAuthor() } ); } catch ( Throwable t ) { - ProxyServer.getInstance().getLogger().log( Level.WARNING, "Exception encountered when loading plugin: " + plugin.getDescription().getName(), t ); + ProxyServer.getInstance().getLogger().log( Level.SEVERE, "Exception encountered when enabling plugin: " + plugin.getDescription().getName(), t ); + if(proxy.getConfig().isRequireAllPlugins()) { + throw t; + } } } } - private boolean enablePlugin(Map pluginStatuses, Map pluginLoaders, Stack dependStack, PluginDescription plugin) + private boolean loadPlugin(Map pluginStatuses, Map pluginLoaders, Stack dependStack, PluginDescription plugin) throws Exception { if ( pluginStatuses.containsKey( plugin ) ) { @@ -276,12 +284,12 @@ private boolean enablePlugin(Map pluginStatuses, Map dependencyGraph.append( element.getName() ).append( " -> " ); } dependencyGraph.append( plugin.getName() ).append( " -> " ).append( dependName ); - ProxyServer.getInstance().getLogger().log( Level.WARNING, "Circular dependency detected: {0}", dependencyGraph ); + ProxyServer.getInstance().getLogger().log( Level.SEVERE, "Circular dependency detected: {0}", dependencyGraph ); status = false; } else { dependStack.push( plugin ); - dependStatus = this.enablePlugin( pluginStatuses, pluginLoaders, dependStack, depend ); + dependStatus = this.loadPlugin(pluginStatuses, pluginLoaders, dependStack, depend ); dependStack.pop(); } } @@ -292,7 +300,7 @@ private boolean enablePlugin(Map pluginStatuses, Map if ( dependStatus == Boolean.FALSE && plugin.getDepends().contains( dependName ) ) // only fail if this wasn't a soft dependency { - ProxyServer.getInstance().getLogger().log( Level.WARNING, "{0} (required by {1}) is unavailable", new Object[] + ProxyServer.getInstance().getLogger().log( Level.SEVERE, "{0} (required by {1}) is unavailable", new Object[] { String.valueOf( dependName ), plugin.getName() } ); @@ -321,16 +329,24 @@ private boolean enablePlugin(Map pluginStatuses, Map clazz.init( proxy, plugin ); plugins.put( plugin.getName(), clazz ); clazz.onLoad(); + loadedPlugins.add(clazz); ProxyServer.getInstance().getLogger().log( Level.INFO, "Loaded plugin {0} version {1} by {2}", new Object[] { plugin.getName(), plugin.getVersion(), plugin.getAuthor() } ); } catch ( Throwable t ) { - proxy.getLogger().log( Level.WARNING, "Error enabling plugin " + plugin.getName(), t ); + proxy.getLogger().log( Level.SEVERE, "Error loading plugin " + plugin.getName(), t ); + if(proxy.getConfig().isRequireAllPlugins()) { + throw t; + } } } + if(!status && proxy.getConfig().isRequireAllPlugins()) { + throw new IllegalStateException("Failed to load required plugin " + plugin.getName()); + } + pluginStatuses.put( plugin, status ); return status; } diff --git a/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java b/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java index d811ea162c..6991d024b6 100644 --- a/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java +++ b/bootstrap/src/main/java/net/md_5/bungee/BungeeCordLauncher.java @@ -50,7 +50,12 @@ public static void main(String[] args) throws Exception BungeeCord bungee = new BungeeCord(); ProxyServer.setInstance( bungee ); bungee.getLogger().info( "Enabled BungeeCord version " + bungee.getVersion() ); - bungee.start(); + try { + bungee.start(); + } catch(Exception e) { + bungee.stop("Internal error"); + throw e; + } if ( !options.has( "noconsole" ) ) { diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 38a507fc4a..9addc80975 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -421,7 +421,7 @@ public void run() // TODO: Fix this shit getLogger().info( "Disabling plugins" ); - for ( Plugin plugin : Lists.reverse( new ArrayList<>( pluginManager.getPlugins() ) ) ) + for ( Plugin plugin : Lists.reverse( new ArrayList<>( pluginManager.getEnabledPlugins() ) ) ) { try { diff --git a/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java b/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java index 90f68527d2..cacb30af22 100644 --- a/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java +++ b/proxy/src/main/java/net/md_5/bungee/conf/Configuration.java @@ -59,6 +59,7 @@ public class Configuration implements ProxyConfig private boolean ipForward; private Favicon favicon; private int compressionThreshold = 256; + private boolean requireAllPlugins; public void load() { @@ -86,6 +87,7 @@ public void load() throttle = adapter.getInt( "connection_throttle", throttle ); ipForward = adapter.getBoolean( "ip_forward", ipForward ); compressionThreshold = adapter.getInt( "network_compression_threshold", compressionThreshold ); + requireAllPlugins = adapter.getBoolean( "require_all_plugins", requireAllPlugins ); disabledCommands = new CaseInsensitiveSet( (Collection) adapter.getList( "disabled_commands", Arrays.asList( "disabledcommandhere" ) ) ); From 93660d09aee5d218da715ece91ba23a824f3799a Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Thu, 22 Sep 2016 22:39:31 -0400 Subject: [PATCH 38/39] Sync with minecraft-api --- .../main/java/net/md_5/bungee/api/plugin/PluginManager.java | 3 ++- proxy/src/main/java/net/md_5/bungee/BungeeCord.java | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java index f5e30a5161..5ced80faf2 100644 --- a/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java +++ b/api/src/main/java/net/md_5/bungee/api/plugin/PluginManager.java @@ -33,13 +33,14 @@ import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.introspector.PropertyUtils; +import tc.oc.minecraft.api.plugin.PluginFinder; /** * Class to manage bridging between plugin duties and implementation duties, for * example event handling and plugin management. */ @RequiredArgsConstructor -public class PluginManager implements tc.oc.minecraft.api.plugin.PluginManager +public class PluginManager implements PluginFinder, tc.oc.minecraft.api.event.EventBus { private static final Pattern argsSplit = Pattern.compile( " " ); diff --git a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java index 9addc80975..b1a71344c0 100644 --- a/proxy/src/main/java/net/md_5/bungee/BungeeCord.java +++ b/proxy/src/main/java/net/md_5/bungee/BungeeCord.java @@ -94,6 +94,7 @@ import net.md_5.bungee.scheduler.BungeeScheduler; import net.md_5.bungee.util.CaseInsensitiveMap; import org.fusesource.jansi.AnsiConsole; +import tc.oc.minecraft.api.plugin.PluginFinder; /** * Main BungeeCord proxy class. @@ -721,4 +722,9 @@ public Title createTitle() public Set getProtocolVersions() { return ImmutableSet.copyOf(ProtocolConstants.SUPPORTED_VERSION_IDS); } + + @Override + public PluginFinder getPluginFinder() { + return pluginManager; + } } From 38fb4adb575d2ac9139df1820e8042e89015977f Mon Sep 17 00:00:00 2001 From: Jedediah Smith Date: Sun, 6 Nov 2016 02:14:59 -0500 Subject: [PATCH 39/39] Provide access to exceptions that cause disconnects --- .../net/md_5/bungee/api/connection/ProxiedPlayer.java | 2 ++ .../src/main/java/net/md_5/bungee/UserConnection.java | 10 ++++++++++ .../net/md_5/bungee/connection/DownstreamBridge.java | 2 +- .../net/md_5/bungee/connection/UpstreamBridge.java | 2 +- 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/api/src/main/java/net/md_5/bungee/api/connection/ProxiedPlayer.java b/api/src/main/java/net/md_5/bungee/api/connection/ProxiedPlayer.java index 204d452b30..891a24b018 100644 --- a/api/src/main/java/net/md_5/bungee/api/connection/ProxiedPlayer.java +++ b/api/src/main/java/net/md_5/bungee/api/connection/ProxiedPlayer.java @@ -189,4 +189,6 @@ public interface ProxiedPlayer extends Connection, CommandSender, tc.oc.minecraf * not occurred for this {@link ProxiedPlayer} yet. */ Map getModList(); + + Throwable getDisconnectException(); } diff --git a/proxy/src/main/java/net/md_5/bungee/UserConnection.java b/proxy/src/main/java/net/md_5/bungee/UserConnection.java index b534aaee9c..652224bc71 100644 --- a/proxy/src/main/java/net/md_5/bungee/UserConnection.java +++ b/proxy/src/main/java/net/md_5/bungee/UserConnection.java @@ -149,6 +149,9 @@ public void sendPacket(DefinedPacket packet) } }; + @Getter + private Throwable disconnectException; + public void init() { this.entityRewrite = EntityMap.getEntityMap( getPendingConnection().getVersion() ); @@ -346,6 +349,13 @@ public void operationComplete(ChannelFuture future) throws Exception b.connect().addListener( listener ); } + public void disconnect(Throwable exception) { + if(disconnectException == null) { + disconnectException = exception; + } + disconnect(Util.exception(exception)); + } + @Override public void disconnect(String reason) { diff --git a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java index 4e82c90403..28f50bc6a5 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/DownstreamBridge.java @@ -68,7 +68,7 @@ public void exception(Throwable t) throws Exception con.sendMessage( bungee.getTranslation( "server_went_down" ) ); } else { - con.disconnect( Util.exception( t ) ); + con.disconnect( t ); } } diff --git a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java index 92d1da05b8..bf74eb1d11 100644 --- a/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java +++ b/proxy/src/main/java/net/md_5/bungee/connection/UpstreamBridge.java @@ -44,7 +44,7 @@ public UpstreamBridge(ProxyServer bungee, UserConnection con) @Override public void exception(Throwable t) throws Exception { - con.disconnect( Util.exception( t ) ); + con.disconnect( t ); } @Override