--- a/net/minecraft/world/level/block/entity/BannerBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BannerBlockEntity.java
@@ -24,8 +_,8 @@
     private static final String TAG_PATTERNS = "patterns";
     private static final Component DEFAULT_NAME = Component.translatable("block.minecraft.banner");
     @Nullable
-    private Component name;
-    private final DyeColor baseColor;
+    public Component name;
+    public DyeColor baseColor;
     private BannerPatternLayers patterns = BannerPatternLayers.EMPTY;
 
     public BannerBlockEntity(BlockPos pos, BlockState blockState) {
@@ -51,7 +_,7 @@
     @Override
     protected void saveAdditional(ValueOutput output) {
         super.saveAdditional(output);
-        if (!this.patterns.equals(BannerPatternLayers.EMPTY)) {
+        if (!this.patterns.equals(BannerPatternLayers.EMPTY) || serialisingForNetwork.get()) { // Paper - always send patterns to client
             output.store("patterns", BannerPatternLayers.CODEC, this.patterns);
         }
 
@@ -62,7 +_,7 @@
     protected void loadAdditional(ValueInput input) {
         super.loadAdditional(input);
         this.name = parseCustomNameSafe(input, "CustomName");
-        this.patterns = input.read("patterns", BannerPatternLayers.CODEC).orElse(BannerPatternLayers.EMPTY);
+        this.setPatterns(input.read("patterns", BannerPatternLayers.CODEC).orElse(BannerPatternLayers.EMPTY)); // CraftBukkit - apply limits
     }
 
     @Override
@@ -70,9 +_,18 @@
         return ClientboundBlockEntityDataPacket.create(this);
     }
 
+    // Paper start - always send patterns to client
+    ThreadLocal<Boolean> serialisingForNetwork = ThreadLocal.withInitial(() -> Boolean.FALSE);
     @Override
     public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
+        final Boolean wasSerialisingForNetwork = serialisingForNetwork.get();
+        try {
+            serialisingForNetwork.set(Boolean.TRUE);
         return this.saveWithoutMetadata(registries);
+        } finally {
+            serialisingForNetwork.set(wasSerialisingForNetwork);
+        }
+        // Paper end - always send patterns to client
     }
 
     public BannerPatternLayers getPatterns() {
@@ -92,7 +_,7 @@
     @Override
     protected void applyImplicitComponents(DataComponentGetter componentGetter) {
         super.applyImplicitComponents(componentGetter);
-        this.patterns = componentGetter.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY);
+        this.setPatterns(componentGetter.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY)); // CraftBukkit - apply limits
         this.name = componentGetter.get(DataComponents.CUSTOM_NAME);
     }
 
@@ -108,4 +_,13 @@
         output.discard("patterns");
         output.discard("CustomName");
     }
+
+    // CraftBukkit start
+    public void setPatterns(BannerPatternLayers bannerPatternLayers) {
+        if (bannerPatternLayers.layers().size() > 20) {
+            bannerPatternLayers = new BannerPatternLayers(java.util.List.copyOf(bannerPatternLayers.layers().subList(0, 20)));
+        }
+        this.patterns = bannerPatternLayers;
+    }
+    // CraftBukkit end
 }
