--- a/net/minecraft/core/component/DataComponentPatch.java
+++ b/net/minecraft/core/component/DataComponentPatch.java
@@ -106,6 +_,11 @@
                     buffer.writeVarInt(0);
                     buffer.writeVarInt(0);
                 } else {
+                    // Paper start - data sanitization for items
+                    final io.papermc.paper.util.sanitizer.ItemObfuscationSession itemObfuscationSession = value.map.isEmpty()
+                        ? null // Avoid thread local lookup of current session if it won't be needed anyway.
+                        : io.papermc.paper.util.sanitizer.ItemObfuscationSession.currentSession();
+                    // Paper end - data sanitization for items
                     int i = 0;
                     int i1 = 0;
 
@@ -113,7 +_,7 @@
                         value.map
                     )) {
                         if (entry.getValue().isPresent()) {
-                            i++;
+                            if (!io.papermc.paper.util.sanitizer.ItemComponentSanitizer.shouldDrop(itemObfuscationSession, entry.getKey())) i++; // Paper - data sanitization for items
                         } else {
                             i1++;
                         }
@@ -126,6 +_,7 @@
                         value.map
                     )) {
                         Optional<?> optional = entryx.getValue();
+                        optional = io.papermc.paper.util.sanitizer.ItemComponentSanitizer.override(itemObfuscationSession, entryx.getKey(), entryx.getValue()); // Paper - data sanitization for items
                         if (optional.isPresent()) {
                             DataComponentType<?> dataComponentType = entryx.getKey();
                             DataComponentType.STREAM_CODEC.encode(buffer, dataComponentType);
@@ -145,7 +_,13 @@
             }
 
             private <T> void encodeComponent(RegistryFriendlyByteBuf buffer, DataComponentType<T> component, Object value) {
-                codecGetter.apply(component).encode(buffer, (T)value);
+                // Paper start - codec errors of random anonymous classes are useless
+                try {
+                    codecGetter.apply(component).encode(buffer, (T)value);
+                } catch (final Exception e) {
+                    throw new RuntimeException("Error encoding component " + component, e);
+                }
+                // Paper end - codec errors of random anonymous classes are useless
             }
         };
     }
@@ -249,6 +_,42 @@
 
         Builder() {
         }
+
+        // CraftBukkit start
+        public void copy(DataComponentPatch orig) {
+            this.map.putAll(orig.map);
+        }
+
+        public void clear(DataComponentType<?> type) {
+            this.map.remove(type);
+        }
+
+        public boolean isSet(DataComponentType<?> type) {
+            return this.map.containsKey(type);
+        }
+
+        public boolean isEmpty() {
+            return this.map.isEmpty();
+        }
+
+        @Override
+        public boolean equals(Object object) {
+            if (this == object) {
+                return true;
+            }
+
+            if (object instanceof DataComponentPatch.Builder patch) {
+                return this.map.equals(patch.map);
+            }
+
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return this.map.hashCode();
+        }
+        // CraftBukkit end
 
         public <T> DataComponentPatch.Builder set(DataComponentType<T> component, T value) {
             this.map.put(component, Optional.of(value));
