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 558343c3..005c7c49 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 java.awt.Color; import java.util.ArrayList; import java.util.List; import lombok.AccessLevel; @@ -129,6 +130,10 @@ public abstract class BaseComponent { setColor( component.getColorRaw() ); } + if ( replace || !style.hasShadowColor() ) + { + setShadowColor( component.getShadowColorRaw() ); + } if ( replace || !style.hasFont() ) { setFont( component.getFontRaw() ); @@ -175,6 +180,7 @@ public abstract class BaseComponent if ( retention == FormatRetention.EVENTS || retention == FormatRetention.NONE ) { setColor( null ); + setShadowColor( null ); setBold( null ); setItalic( null ); setUnderlined( null ); @@ -295,6 +301,46 @@ public abstract class BaseComponent return style.getColor(); } + /** + * Set this component's shadow color. + * + * @param color the component shadow color, or null to use the default + */ + public void setShadowColor(Color color) + { + this.style.setShadowColor( color ); + } + + /** + * Returns the shadow color of this component. This uses the parent's shadow color if this + * component doesn't have one. null is returned if no shadow color is found. + * + * @return the shadow color of this component + */ + public Color getShadowColor() + { + if ( !style.hasShadowColor() ) + { + if ( parent == null ) + { + return null; + } + return parent.getShadowColor(); + } + return style.getShadowColor(); + } + + /** + * Returns the shadow color of this component without checking the parents + * shadow color. May return null + * + * @return the shadow color of this component + */ + public Color getShadowColorRaw() + { + return style.getShadowColor(); + } + /** * Set this component's font. * @@ -536,6 +582,10 @@ public abstract class BaseComponent { setColor( style.getColor() ); } + if ( style.hasShadowColor() ) + { + setShadowColor( style.getShadowColor() ); + } if ( style.hasFont() ) { setFont( style.getFont() ); diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/ComponentStyle.java b/chat/src/main/java/net/md_5/bungee/api/chat/ComponentStyle.java index 15f44ea7..463a5597 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/ComponentStyle.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/ComponentStyle.java @@ -1,5 +1,6 @@ package net.md_5.bungee.api.chat; +import java.awt.Color; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -23,6 +24,10 @@ public final class ComponentStyle implements Cloneable * {@link ChatColor#color} should not be null). */ private ChatColor color; + /** + * The shadow color of this style. + */ + private Color shadowColor; /** * The font of this style. */ @@ -68,6 +73,26 @@ public final class ComponentStyle implements Cloneable return ( color != null ); } + /** + * Returns the shadow color of this style. May return null. + * + * @return the shadow color of this style, or null if default color + */ + public Color getShadowColor() + { + return shadowColor; + } + + /** + * Returns whether or not this style has a shadow color set. + * + * @return whether a shadow color is set + */ + public boolean hasShadowColor() + { + return ( shadowColor != null ); + } + /** * Returns the font of this style. May return null. * @@ -195,7 +220,7 @@ public final class ComponentStyle implements Cloneable */ public boolean isEmpty() { - return color == null && font == null && bold == null + return color == null && shadowColor == null && font == null && bold == null && italic == null && underlined == null && strikethrough == null && obfuscated == null; } @@ -203,7 +228,7 @@ public final class ComponentStyle implements Cloneable @Override public ComponentStyle clone() { - return new ComponentStyle( color, font, bold, italic, underlined, strikethrough, obfuscated ); + return new ComponentStyle( color, shadowColor, font, bold, italic, underlined, strikethrough, obfuscated ); } /** @@ -227,6 +252,7 @@ public final class ComponentStyle implements Cloneable { return new ComponentStyleBuilder() .color( other.color ) + .shadowColor( other.shadowColor ) .font( other.font ) .bold( other.bold ) .italic( other.italic ) diff --git a/chat/src/main/java/net/md_5/bungee/api/chat/ComponentStyleBuilder.java b/chat/src/main/java/net/md_5/bungee/api/chat/ComponentStyleBuilder.java index 6481ae81..e8ca2235 100644 --- a/chat/src/main/java/net/md_5/bungee/api/chat/ComponentStyleBuilder.java +++ b/chat/src/main/java/net/md_5/bungee/api/chat/ComponentStyleBuilder.java @@ -1,5 +1,6 @@ package net.md_5.bungee.api.chat; +import java.awt.Color; import net.md_5.bungee.api.ChatColor; /** @@ -26,6 +27,7 @@ public final class ComponentStyleBuilder { private ChatColor color; + private Color shadowColor; private String font; private Boolean bold, italic, underlined, strikethrough, obfuscated; @@ -41,6 +43,18 @@ public final class ComponentStyleBuilder return this; } + /** + * Set the style shadow color. + * + * @param shadowColor the shadow color to set, or null to use the default + * @return this ComponentStyleBuilder for chaining + */ + public ComponentStyleBuilder shadowColor(Color shadowColor) + { + this.shadowColor = shadowColor; + return this; + } + /** * Set the style font. * @@ -121,6 +135,6 @@ public final class ComponentStyleBuilder */ public ComponentStyle build() { - return new ComponentStyle( color, font, bold, italic, underlined, strikethrough, obfuscated ); + return new ComponentStyle( color, shadowColor, font, bold, italic, underlined, strikethrough, obfuscated ); } } diff --git a/chat/src/main/java/net/md_5/bungee/chat/ComponentStyleSerializer.java b/chat/src/main/java/net/md_5/bungee/chat/ComponentStyleSerializer.java index 84e63727..c3ef5775 100644 --- a/chat/src/main/java/net/md_5/bungee/chat/ComponentStyleSerializer.java +++ b/chat/src/main/java/net/md_5/bungee/chat/ComponentStyleSerializer.java @@ -1,5 +1,6 @@ package net.md_5.bungee.chat; +import com.google.gson.JsonArray; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; @@ -8,6 +9,7 @@ import com.google.gson.JsonParseException; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializationContext; import com.google.gson.JsonSerializer; +import java.awt.Color; import java.lang.reflect.Type; import java.util.Map; import net.md_5.bungee.api.ChatColor; @@ -67,6 +69,10 @@ public class ComponentStyleSerializer implements JsonSerializer, { object.addProperty( "color", style.getColor().getName() ); } + if ( style.hasShadowColor() ) + { + object.addProperty( "shadow_color", style.getShadowColor().getRGB() ); + } if ( style.hasFont() ) { object.addProperty( "font", style.getFont() ); @@ -102,6 +108,17 @@ public class ComponentStyleSerializer implements JsonSerializer, case "color": builder.color( ChatColor.of( value.getAsString() ) ); break; + case "shadow_color": + if ( value.isJsonArray() ) + { + JsonArray array = value.getAsJsonArray(); + + builder.shadowColor( new Color( array.get( 0 ).getAsFloat(), array.get( 1 ).getAsFloat(), array.get( 2 ).getAsFloat(), array.get( 3 ).getAsFloat() ) ); + } else if ( value.isJsonPrimitive() ) + { + builder.shadowColor( new Color( value.getAsNumber().intValue(), true ) ); + } + break; case "font": builder.font( value.getAsString() ); break; diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java b/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java index 6cd9e6a4..f3f690c4 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/DefinedPacket.java @@ -499,7 +499,7 @@ public abstract class DefinedPacket public static BitSet readFixedBitSet(int i, ByteBuf buf) { - byte[] bits = new byte[ ( i + 8 ) >> 3 ]; + byte[] bits = new byte[ ( i + 7 ) >> 3 ]; buf.readBytes( bits ); return BitSet.valueOf( bits ); @@ -511,7 +511,7 @@ public abstract class DefinedPacket { throw new OverflowPacketException( "BitSet too large (expected " + size + " got " + bits.size() + ")" ); } - buf.writeBytes( Arrays.copyOf( bits.toByteArray(), ( size + 8 ) >> 3 ) ); + buf.writeBytes( Arrays.copyOf( bits.toByteArray(), ( size + 7 ) >> 3 ) ); } public void read(ByteBuf buf) diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java b/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java index 86412d48..93963ca3 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/ProtocolConstants.java @@ -48,6 +48,7 @@ public class ProtocolConstants public static final int MINECRAFT_1_20_5 = 766; public static final int MINECRAFT_1_21 = 767; public static final int MINECRAFT_1_21_2 = 768; + public static final int MINECRAFT_1_21_4 = 1073742047; public static final List SUPPORTED_VERSIONS; public static final List SUPPORTED_VERSION_IDS; @@ -116,7 +117,7 @@ public class ProtocolConstants if ( SNAPSHOT_SUPPORT ) { // supportedVersions.add( "1.21.x" ); - // supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_21_2 ); + supportedVersionIds.add( ProtocolConstants.MINECRAFT_1_21_4 ); } SUPPORTED_VERSIONS = supportedVersions.build(); diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/PlayerListItem.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/PlayerListItem.java index 60f7305b..67a54ecc 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/PlayerListItem.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/PlayerListItem.java @@ -148,5 +148,7 @@ public class PlayerListItem extends DefinedPacket // UPDATE_LIST_ORDER 1.21.2 Integer listOrder; + // UPDATE_HAT 1.21.4 + Boolean showHat; } } diff --git a/protocol/src/main/java/net/md_5/bungee/protocol/packet/PlayerListItemUpdate.java b/protocol/src/main/java/net/md_5/bungee/protocol/packet/PlayerListItemUpdate.java index a45b001e..40492bd6 100644 --- a/protocol/src/main/java/net/md_5/bungee/protocol/packet/PlayerListItemUpdate.java +++ b/protocol/src/main/java/net/md_5/bungee/protocol/packet/PlayerListItemUpdate.java @@ -64,6 +64,9 @@ public class PlayerListItemUpdate extends DefinedPacket case UPDATE_LIST_ORDER: item.listOrder = DefinedPacket.readVarInt( buf ); break; + case UPDATE_HAT: + item.showHat = buf.readBoolean(); + break; } } } @@ -115,6 +118,9 @@ public class PlayerListItemUpdate extends DefinedPacket case UPDATE_LIST_ORDER: DefinedPacket.writeVarInt( item.listOrder, buf ); break; + case UPDATE_HAT: + buf.writeBoolean( item.showHat ); + break; } } } @@ -135,6 +141,7 @@ public class PlayerListItemUpdate extends DefinedPacket UPDATE_LISTED, UPDATE_LATENCY, UPDATE_DISPLAY_NAME, - UPDATE_LIST_ORDER; + UPDATE_LIST_ORDER, + UPDATE_HAT; } } 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 755b8fd6..206bc8d2 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 @@ -91,6 +91,8 @@ public abstract class EntityMap return EntityMap_1_16_2.INSTANCE_1_20_5; case ProtocolConstants.MINECRAFT_1_21_2: return EntityMap_1_16_2.INSTANCE_1_21_2; + case ProtocolConstants.MINECRAFT_1_21_4: + return EntityMap_1_16_2.INSTANCE_1_21_4; } throw new RuntimeException( "Version " + version + " has no entity map" ); } diff --git a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_16_2.java b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_16_2.java index a71932a7..66afd2f1 100644 --- a/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_16_2.java +++ b/proxy/src/main/java/net/md_5/bungee/entitymap/EntityMap_1_16_2.java @@ -24,6 +24,7 @@ class EntityMap_1_16_2 extends EntityMap static final EntityMap_1_16_2 INSTANCE_1_20_3 = new EntityMap_1_16_2( -1, 0x34 ); static final EntityMap_1_16_2 INSTANCE_1_20_5 = new EntityMap_1_16_2( -1, 0x37 ); static final EntityMap_1_16_2 INSTANCE_1_21_2 = new EntityMap_1_16_2( -1, 0x39 ); + static final EntityMap_1_16_2 INSTANCE_1_21_4 = new EntityMap_1_16_2( -1, 0x3B ); // private final int spawnPlayerId; private final int spectateId;