--- a/net/minecraft/world/level/block/entity/BannerBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BannerBlockEntity.java
@@ -23,7 +_,7 @@
     public static final int MAX_PATTERNS = 6;
     private static final String TAG_PATTERNS = "patterns";
     @Nullable
-    private Component name;
+    public Component name; // Paper - AT public
     public DyeColor baseColor;
     private BannerPatternLayers patterns = BannerPatternLayers.EMPTY;
 
@@ -50,7 +_,7 @@
     @Override
     protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
         super.saveAdditional(tag, registries);
-        if (!this.patterns.equals(BannerPatternLayers.EMPTY)) {
+        if (!this.patterns.equals(BannerPatternLayers.EMPTY) || serialisingForNetwork.get()) { // Paper - always send patterns to client
             tag.put("patterns", BannerPatternLayers.CODEC.encodeStart(registries.createSerializationContext(NbtOps.INSTANCE), this.patterns).getOrThrow());
         }
 
@@ -70,7 +_,7 @@
             BannerPatternLayers.CODEC
                 .parse(registries.createSerializationContext(NbtOps.INSTANCE), tag.get("patterns"))
                 .resultOrPartial(string -> LOGGER.error("Failed to parse banner patterns: '{}'", string))
-                .ifPresent(bannerPatternLayers -> this.patterns = bannerPatternLayers);
+                .ifPresent(bannerPatternLayers -> this.setPatterns(bannerPatternLayers)); // CraftBukkit - apply limits
         }
     }
 
@@ -79,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() {
@@ -101,7 +_,7 @@
     @Override
     protected void applyImplicitComponents(BlockEntity.DataComponentInput componentInput) {
         super.applyImplicitComponents(componentInput);
-        this.patterns = componentInput.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY);
+        this.setPatterns(componentInput.getOrDefault(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY)); // CraftBukkit - apply limits
         this.name = componentInput.get(DataComponents.CUSTOM_NAME);
     }
 
@@ -117,4 +_,13 @@
         tag.remove("patterns");
         tag.remove("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
 }
