Compare commits

..

19 Commits

Author SHA1 Message Date
fcb01544e9
new event TabCompleteRequestEvent and deprecate TabCompleteEvent 2022-11-26 16:07:38 +01:00
e10fb5fa02
Add CommandsDeclareEvent to declare commands with brigadier API 2022-11-26 16:07:38 +01:00
b45d4a1467
Server branding now includes the backend server name 2022-11-26 16:07:38 +01:00
9d08220c15
Multi-session with same Minecraft account with specific permission
Players with permission bungeecord.multiple_connect can have multiple connections with the same Minecraft account.
The UUID and player name is altered to avoid collision with other player:
UUID : xxxxxxxx-xxxx-VIxx-xxxx-xxxxxxxxxxxx
- The UUID version (V above) is now the provided version + 8 (for online player, it is 4, so it becomes C).
- The I digit will follow the index of the duplicated player : first duplicated player is 1, second one is 2.
- The name of the player will be the real player name, followed by the character "." (dot) followed by the duplication index.

Bedrock accounts connected using the Floodgate plugin will not be able to connect multiple times due to the risk of xUID collision.
2022-11-26 16:07:37 +01:00
fc6d924f90
Change projet configuration and POM for Pandacube 2022-11-26 16:07:37 +01:00
4caf2d1451
Remove modules and startup delay
We don’t need them for Pandacube
2022-11-26 16:07:37 +01:00
Ismael Hanbel
511017ab35
#3396: Update Netty version 2022-11-12 11:52:30 +11:00
floge07
c3e8cfac79
#3374, #3389: Improve log handling of normal java.util Logger usage by forwarding the LogRecords directly to the BungeeLogger instead of the fallback err stream. 2022-11-12 11:51:14 +11:00
rgnter
bf2b3c68f8
#3384: Update documentation of ProxyPingEvent 2022-11-12 11:43:29 +11:00
Outfluencer
68e74a8c03
#3378: Remove KickStringWriter from the pipeline after handshake arrives 2022-11-12 11:41:10 +11:00
Outfluencer
5b4a540440
#3361: Cache MessageFormats for translations 2022-11-12 11:39:31 +11:00
osfanbuff63
88da5c05c7
#3353: Update GitHub actions
Updates `actions/checkout` and `actions/setup-java` to v3.
2022-11-12 11:34:17 +11:00
md_5
2d369e8945
Update SnakeYAML version 2022-10-02 09:18:42 +11:00
md_5
02548c4b9b
Update Netty/SnakeYAML version 2022-09-22 10:16:27 +10:00
Outfluencer
71990e3ccc
#3387: Use the correct write method for ChatChain in ClientCommand 2022-08-27 07:40:18 +10:00
Outfluencer
5e7dcc48b9
#3382: Use the correct write method for ChatChain in ClientChat packet 2022-08-20 16:22:14 +10:00
Outfluencer
5cdba87b87
#3377: Add additional checks for protocol length limits 2022-08-16 19:26:33 +10:00
Outfluencer
696315615d
#3366: Improve consistency and appearance of default translations 2022-08-14 11:34:00 +10:00
Outfluencer
dd3f820040
#3363, #3369: Implement new ServerData packet to stop MOTD data from servers 2022-08-14 11:32:35 +10:00
19 changed files with 220 additions and 52 deletions

View File

@ -14,9 +14,10 @@ jobs:
name: Java ${{ matrix.java }}
steps:
- uses: actions/checkout@v2
- uses: actions/setup-java@v1
- uses: actions/checkout@v3
- uses: actions/setup-java@v3
with:
distribution: zulu
java-version: ${{ matrix.java }}
- run: java -version && mvn --version
- run: mvn --activate-profiles dist --no-transfer-progress package

View File

@ -72,7 +72,7 @@
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.30</version>
<version>1.33</version>
<scope>compile</scope>
</dependency>
</dependencies>

View File

@ -8,7 +8,7 @@ import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.connection.PendingConnection;
/**
* Called when the proxy is pinged with packet 0xFE from the server list.
* Called when the proxy is queried for status from the server list.
*/
@Data
@ToString(callSuper = false)

View File

@ -28,7 +28,7 @@
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.30</version>
<version>1.33</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>

View File

@ -24,6 +24,7 @@ public class BungeeLogger extends Logger
{
super( loggerName, null );
setLevel( Level.ALL );
setUseParentHandlers( false );
try
{

View File

@ -0,0 +1,29 @@
package net.md_5.bungee.log;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class LoggingForwardHandler extends Handler
{
private final Logger logger;
@Override
public void publish(LogRecord record)
{
logger.log( record );
}
@Override
public void flush()
{
}
@Override
public void close() throws SecurityException
{
}
}

View File

@ -72,7 +72,7 @@
<properties>
<build.number>unknown</build.number>
<lombok.version>1.18.22</lombok.version>
<netty.version>4.1.77.Final</netty.version>
<netty.version>4.1.85.Final</netty.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

View File

@ -30,6 +30,7 @@ import net.md_5.bungee.protocol.packet.Respawn;
import net.md_5.bungee.protocol.packet.ScoreboardDisplay;
import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.ServerData;
import net.md_5.bungee.protocol.packet.SetCompression;
import net.md_5.bungee.protocol.packet.StatusRequest;
import net.md_5.bungee.protocol.packet.StatusResponse;
@ -208,4 +209,8 @@ public abstract class AbstractPacketHandler
public void handle(GameState gameState) throws Exception
{
}
public void handle(ServerData serverData) throws Exception
{
}
}

View File

@ -21,12 +21,22 @@ public abstract class DefinedPacket
public static void writeString(String s, ByteBuf buf)
{
if ( s.length() > Short.MAX_VALUE )
writeString( s, buf, Short.MAX_VALUE );
}
public static void writeString(String s, ByteBuf buf, int maxLength)
{
throw new OverflowPacketException( "Cannot send string longer than Short.MAX_VALUE (got " + s.length() + " characters)" );
if ( s.length() > maxLength )
{
throw new OverflowPacketException( "Cannot send string longer than " + maxLength + " (got " + s.length() + " characters)" );
}
byte[] b = s.getBytes( Charsets.UTF_8 );
if ( b.length > maxLength * 3 )
{
throw new OverflowPacketException( "Cannot send string longer than " + ( maxLength * 3 ) + " (got " + b.length + " bytes)" );
}
writeVarInt( b.length, buf );
buf.writeBytes( b );
}
@ -39,15 +49,14 @@ public abstract class DefinedPacket
public static String readString(ByteBuf buf, int maxLen)
{
int len = readVarInt( buf );
if ( len > maxLen * 4 )
if ( len > maxLen * 3 )
{
throw new OverflowPacketException( "Cannot receive string longer than " + maxLen * 4 + " (got " + len + " bytes)" );
throw new OverflowPacketException( "Cannot receive string longer than " + maxLen * 3 + " (got " + len + " bytes)" );
}
byte[] b = new byte[ len ];
buf.readBytes( b );
String s = buf.toString( buf.readerIndex(), len, Charsets.UTF_8 );
buf.readerIndex( buf.readerIndex() + len );
String s = new String( b, Charsets.UTF_8 );
if ( s.length() > maxLen )
{
throw new OverflowPacketException( "Cannot receive string longer than " + maxLen + " (got " + s.length() + " characters)" );
@ -275,7 +284,7 @@ public abstract class DefinedPacket
{
if ( buf.readBoolean() )
{
return new PlayerPublicKey( buf.readLong(), readArray( buf ), readArray( buf ) );
return new PlayerPublicKey( buf.readLong(), readArray( buf, 512 ), readArray( buf, 4096 ) );
}
return null;

View File

@ -36,6 +36,7 @@ import net.md_5.bungee.protocol.packet.Respawn;
import net.md_5.bungee.protocol.packet.ScoreboardDisplay;
import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.ServerData;
import net.md_5.bungee.protocol.packet.SetCompression;
import net.md_5.bungee.protocol.packet.StatusRequest;
import net.md_5.bungee.protocol.packet.StatusResponse;
@ -338,6 +339,12 @@ public enum Protocol
map( ProtocolConstants.MINECRAFT_1_19, 0x49 ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x4C )
);
TO_CLIENT.registerPacket(
ServerData.class,
ServerData::new,
map( ProtocolConstants.MINECRAFT_1_19, 0x3F ),
map( ProtocolConstants.MINECRAFT_1_19_1, 0x42 )
);
TO_SERVER.registerPacket(
KeepAlive.class,

View File

@ -54,7 +54,7 @@ public class Chat extends DefinedPacket
@Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
writeString( message, buf );
writeString( message, buf, ( direction == ProtocolConstants.Direction.TO_CLIENT ) ? 262144 : ( protocolVersion >= ProtocolConstants.MINECRAFT_1_11 ? 256 : 100 ) );
if ( direction == ProtocolConstants.Direction.TO_CLIENT )
{
buf.writeByte( position );

View File

@ -49,7 +49,7 @@ public class ClientChat extends DefinedPacket
buf.writeBoolean( signedPreview );
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 )
{
chain.write( buf );
chain.write( buf, direction, protocolVersion );
}
}

View File

@ -67,7 +67,7 @@ public class ClientCommand extends DefinedPacket
buf.writeBoolean( signedPreview );
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 )
{
chain.write( buf );
chain.write( buf, direction, protocolVersion );
}
}

View File

@ -0,0 +1,78 @@
package net.md_5.bungee.protocol.packet;
import io.netty.buffer.ByteBuf;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class ServerData extends DefinedPacket
{
private String motd;
private String icon;
private boolean preview;
private boolean enforceSecure;
@Override
public void read(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
if ( buf.readBoolean() )
{
motd = readString( buf, 262144 );
}
if ( buf.readBoolean() )
{
icon = readString( buf );
}
preview = buf.readBoolean();
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 )
{
enforceSecure = buf.readBoolean();
}
}
@Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
if ( motd != null )
{
buf.writeBoolean( true );
writeString( motd, buf, 262144 );
} else
{
buf.writeBoolean( false );
}
if ( icon != null )
{
buf.writeBoolean( true );
writeString( icon, buf );
} else
{
buf.writeBoolean( false );
}
buf.writeBoolean( preview );
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 )
{
buf.writeBoolean( enforceSecure );
}
}
@Override
public void handle(AbstractPacketHandler handler) throws Exception
{
handler.handle( this );
}
}

View File

@ -30,7 +30,7 @@ public class SystemChat extends DefinedPacket
@Override
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
writeString( message, buf );
writeString( message, buf, 262144 );
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_19_1 )
{
buf.writeBoolean( position == ChatMessageType.ACTION_BAR.ordinal() );

View File

@ -24,10 +24,12 @@ import java.io.IOException;
import java.io.PrintStream;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.text.Format;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
@ -85,6 +87,7 @@ import net.md_5.bungee.conf.Configuration;
import net.md_5.bungee.conf.YamlConfig;
import net.md_5.bungee.forge.ForgeConstants;
import net.md_5.bungee.log.BungeeLogger;
import net.md_5.bungee.log.LoggingForwardHandler;
import net.md_5.bungee.log.LoggingOutputStream;
import net.md_5.bungee.netty.PipelineUtils;
import net.md_5.bungee.protocol.DefinedPacket;
@ -112,10 +115,9 @@ public class BungeeCord extends ProxyServer
@Getter
public final Configuration config = new Configuration();
/**
* Localization bundle.
* Localization formats.
*/
private ResourceBundle baseBundle;
private ResourceBundle customBundle;
private Map<String, Format> messageFormats;
public EventLoopGroup eventLoops;
/**
* locations.yml save thread.
@ -187,13 +189,6 @@ public class BungeeCord extends ProxyServer
// 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." );
try
{
baseBundle = ResourceBundle.getBundle( "messages" );
} catch ( MissingResourceException ex )
{
baseBundle = ResourceBundle.getBundle( "messages", Locale.ENGLISH );
}
reloadMessages();
// This is a workaround for quite possibly the weirdest bug I have ever encountered in my life!
@ -213,6 +208,21 @@ public class BungeeCord extends ProxyServer
logger = new BungeeLogger( "BungeeCord", "proxy.log", consoleReader );
JDK14LoggerFactory.LOGGER = logger;
// Before we can set the Err and Out streams to our LoggingOutputStream we also have to remove
// the default ConsoleHandler from the root logger, which writes to the err stream.
// But we still want to log these records, so we add our own handler which forwards the LogRecord to the BungeeLogger.
// This way we skip the err stream and the problem of only getting a string without context, and can handle the LogRecord itself.
// Thus improving the default bahavior for projects that log on other Logger instances not created by BungeeCord.
Logger rootLogger = Logger.getLogger( "" );
for ( Handler handler : rootLogger.getHandlers() )
{
rootLogger.removeHandler( handler );
}
rootLogger.addHandler( new LoggingForwardHandler( logger ) );
// We want everything that reaches these output streams to be handled by our logger
// since it applies a nice looking format and also writes to the logfile.
System.setErr( new PrintStream( new LoggingOutputStream( logger, Level.SEVERE ), true ) );
System.setOut( new PrintStream( new LoggingOutputStream( logger, Level.INFO ), true ) );
@ -531,32 +541,49 @@ public class BungeeCord extends ProxyServer
return ( BungeeCord.class.getPackage().getImplementationVersion() == null ) ? "unknown" : BungeeCord.class.getPackage().getImplementationVersion();
}
public void reloadMessages()
public final void reloadMessages()
{
Map<String, Format> cachedFormats = new HashMap<>();
File file = new File( "messages.properties" );
if ( file.isFile() )
{
try ( FileReader rd = new FileReader( file ) )
{
customBundle = new PropertyResourceBundle( rd );
cacheResourceBundle( cachedFormats, new PropertyResourceBundle( rd ) );
} catch ( IOException ex )
{
getLogger().log( Level.SEVERE, "Could not load custom messages.properties", ex );
}
}
ResourceBundle baseBundle;
try
{
baseBundle = ResourceBundle.getBundle( "messages" );
} catch ( MissingResourceException ex )
{
baseBundle = ResourceBundle.getBundle( "messages", Locale.ENGLISH );
}
cacheResourceBundle( cachedFormats, baseBundle );
messageFormats = Collections.unmodifiableMap( cachedFormats );
}
private void cacheResourceBundle(Map<String, Format> map, ResourceBundle resourceBundle)
{
Enumeration<String> keys = resourceBundle.getKeys();
while ( keys.hasMoreElements() )
{
map.computeIfAbsent( keys.nextElement(), (key) -> new MessageFormat( resourceBundle.getString( key ) ) );
}
}
@Override
public String getTranslation(String name, Object... args)
{
String translation = "<translation '" + name + "' missing>";
try
{
translation = MessageFormat.format( customBundle != null && customBundle.containsKey( name ) ? customBundle.getString( name ) : baseBundle.getString( name ), args );
} catch ( MissingResourceException ex )
{
}
return translation;
Format format = messageFormats.get( name );
return ( format != null ) ? format.format( args ) : "<translation '" + name + "' missing>";
}
@Override

View File

@ -64,6 +64,7 @@ import net.md_5.bungee.protocol.packet.Respawn;
import net.md_5.bungee.protocol.packet.ScoreboardDisplay;
import net.md_5.bungee.protocol.packet.ScoreboardObjective;
import net.md_5.bungee.protocol.packet.ScoreboardScore;
import net.md_5.bungee.protocol.packet.ServerData;
import net.md_5.bungee.protocol.packet.SetCompression;
import net.md_5.bungee.protocol.packet.TabCompleteResponse;
import net.md_5.bungee.tab.TabList;
@ -742,6 +743,15 @@ public class DownstreamBridge extends PacketHandler
return dest;
}
@Override
public void handle(ServerData serverData) throws Exception
{
serverData.setMotd( null );
serverData.setIcon( null );
con.unsafe().sendPacket( serverData );
throw CancelSendSignal.INSTANCE;
}
@Override
public String toString()
{

View File

@ -323,6 +323,7 @@ public class InitialHandler extends PacketHandler implements PendingConnection
Preconditions.checkState( thisState == State.HANDSHAKE, "Not expecting HANDSHAKE" );
this.handshake = handshake;
ch.setVersion( handshake.getProtocolVersion() );
ch.getHandle().pipeline().remove( PipelineUtils.LEGACY_KICKER );
// Starting with FML 1.8, a "\0FML\0" token is appended to the handshake. This interferes
// with Bungee's IP forwarding, so we detect it, and remove it from the host string, for now.

View File

@ -7,29 +7,29 @@ connect_kick=\u00a7cKicked whilst connecting to {0}: {1}
current_server=\u00a76You are currently connected to {0}.
fallback_kick=\u00a7cCould not connect to a default or fallback server. Incorrectly configured address/port/firewall? {0}
fallback_lobby=\u00a7cCould not connect to target server, you have been moved to a fallback server.
lost_connection=[Proxy] Lost connection to server.
mojang_fail=Error occurred while contacting login servers, are they down?
lost_connection=\u00a7cProxy lost connection to server.
mojang_fail=\u00a7cError occurred while contacting login servers, are they down?
no_permission=\u00a7cYou do not have permission to execute this command!
no_server=\u00a7cThe specified server does not exist.
no_server_permission=\u00a7cYou don''t have permission to access this server.
outdated_client=Outdated client! Please use {0}
outdated_server=Outdated server! I''m still on {0}
proxy_full=Server is full!
restart=[Proxy] Proxy restarting.
outdated_client=\u00a7cOutdated client! Please use {0}
outdated_server=\u00a7cOutdated server! I''m still on {0}
proxy_full=\u00a7cServer is full!
restart=\u00a7cThe proxy server is restarting
server_list=\u00a76You may connect to the following servers at this time:
server_went_down=\u00a7cThe server you were previously on went down, you have been connected to a fallback server
total_players=Total players online: {0}
name_invalid=Username contains invalid characters.
ping_cannot_connect=\u00a7c[Bungee] Can''t connect to server.
offline_mode_player=Not authenticated with Minecraft.net
secure_profile_required=A secure profile is required to join this server.
secure_profile_expired=Secure profile expired.
secure_profile_invalid=Secure profile invalid.
name_invalid=\u00a7cUsername contains invalid characters.
ping_cannot_connect=\u00a7cCould not request status from target server.
offline_mode_player=\u00a7cNot authenticated with Minecraft.net
secure_profile_required=\u00a7cA secure profile is required to join this server.
secure_profile_expired=\u00a7cSecure profile expired.
secure_profile_invalid=\u00a7cSecure profile invalid.
message_needed=\u00a7cYou must supply a message.
error_occurred_player=\u00a7cAn error occurred while parsing your message. (Hover for details)
error_occurred_console=\u00a7cAn error occurred while parsing your message: {0}
click_to_connect=Click to connect to the server
username_needed=\u00a7cPlease follow this command by a user name.
username_needed=\u00a7cPlease follow this command by a username.
user_not_online=\u00a7cThat user is not online.
user_online_at=\u00a7a{0} \u00a7ris online at {1}
send_cmd_usage=\u00a7cNot enough arguments, usage: /send <server|player|all|current> <target>
@ -38,5 +38,5 @@ you_got_summoned=\u00a76Summoned to {0} by {1}
command_perms_groups=\u00a76You have the following groups: {0}
command_perms_permission=\u00a79- {0}
command_ip=\u00a79IP of {0} is {1}
illegal_chat_characters=\u00a7cillegal characters in chat ({0})
illegal_chat_characters=\u00a7cIllegal characters in chat ({0})
kick_message=\u00a7cYou have been kicked off the proxy.