1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Sat, 27 Apr 2024 20:56:17 -0700
Subject: [PATCH] General ItemMeta fixes
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
index aa23d417272bb160bba8358a8ab0792b56bc0a01..eba5a27e452c4063567fb02d6aabdfb0446d5daf 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java
@@ -326,7 +326,14 @@ public final class CraftItemStack extends ItemStack {
// Paper end - improve handled tags on type change
// Paper start
public static void applyMetaToItem(net.minecraft.world.item.ItemStack itemStack, ItemMeta itemMeta) {
- final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator();
+ // Paper start - support updating profile after resolving it
+ final CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator() {
+ @Override
+ void skullCallback(final com.mojang.authlib.GameProfile gameProfile) {
+ itemStack.set(DataComponents.PROFILE, new net.minecraft.world.item.component.ResolvableProfile(gameProfile));
+ }
+ };
+ // Paper end - support updating profile after resolving it
((CraftMetaItem) itemMeta).applyToItem(tag);
itemStack.applyComponents(tag.build());
}
@@ -687,7 +694,14 @@ public final class CraftItemStack extends ItemStack {
}
if (!((CraftMetaItem) itemMeta).isEmpty()) {
- CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator();
+ // Paper start - support updating profile after resolving it
+ CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator() {
+ @Override
+ void skullCallback(final com.mojang.authlib.GameProfile gameProfile) {
+ item.set(DataComponents.PROFILE, new net.minecraft.world.item.component.ResolvableProfile(gameProfile));
+ }
+ };
+ // Paper end - support updating profile after resolving it
((CraftMetaItem) itemMeta).applyToItem(tag);
item.restorePatch(tag.build());
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java
index 2d6abecc94683f92da6be26b72ea829663b16d76..6a3b0c7f0cc3ffb17a231383ad103fa792d7b7ba 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBanner.java
@@ -107,6 +107,7 @@ public class CraftMetaBanner extends CraftMetaItem implements BannerMeta {
void applyToItem(CraftMetaItem.Applicator tag) {
super.applyToItem(tag);
+ if (this.patterns.isEmpty()) return; // Paper - don't write empty patterns
List<BannerPatternLayers.Layer> newPatterns = new ArrayList<>();
for (Pattern p : this.patterns) {
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java
index 7f3733c29f2e79bffa24631efb20de49fde857f2..6a6e9a1478a2ead20467bc711d0ad4a9ab3010cb 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaBookSigned.java
@@ -116,8 +116,8 @@ public class CraftMetaBookSigned extends CraftMetaItem implements BookMeta {
}
}
- this.resolved = SerializableMeta.getObject(Boolean.class, map, CraftMetaBookSigned.RESOLVED.BUKKIT, true);
- this.generation = SerializableMeta.getObject(Integer.class, map, CraftMetaBookSigned.GENERATION.BUKKIT, true);
+ this.resolved = SerializableMeta.getBoolean(map, CraftMetaBookSigned.RESOLVED.BUKKIT); // Paper - General ItemMeta fixes
+ this.generation = SerializableMeta.getObjectOptionally(Integer.class, map, CraftMetaBookSigned.GENERATION.BUKKIT, true).orElse(0); // Paper - General ItemMeta Fixes
}
@Override
@@ -129,7 +129,7 @@ public class CraftMetaBookSigned extends CraftMetaItem implements BookMeta {
for (Component page : this.pages) {
list.add(Filterable.passThrough(page));
}
- itemData.put(CraftMetaBookSigned.BOOK_CONTENT, new WrittenBookContent(Filterable.from(FilteredText.passThrough(this.title)), this.author, this.generation, list, this.resolved));
+ itemData.put(CraftMetaBookSigned.BOOK_CONTENT, new WrittenBookContent(Filterable.from(FilteredText.passThrough(this.title == null ? "" : this.title)), this.author == null ? "" : this.author, this.generation, list, this.resolved));
}
}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java
index 8e0dd4b7a7a25a8beb27b507047bc48d8227627c..cf5d27ccc2225bac3aa57912f444f95d2f37e32e 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaFirework.java
@@ -154,7 +154,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta {
}
Iterable<?> effects = SerializableMeta.getObject(Iterable.class, map, CraftMetaFirework.EXPLOSIONS.BUKKIT, true);
- this.safelyAddEffects(effects);
+ this.safelyAddEffects(effects, false); // Paper - limit firework effects
}
@Override
@@ -162,7 +162,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta {
return !(this.effects == null || this.effects.isEmpty());
}
- void safelyAddEffects(Iterable<?> collection) {
+ void safelyAddEffects(Iterable<?> collection, final boolean throwOnOversize) { // Paper
if (collection == null || (collection instanceof Collection && ((Collection<?>) collection).isEmpty())) {
return;
}
@@ -174,6 +174,15 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta {
for (Object obj : collection) {
Preconditions.checkArgument(obj instanceof FireworkEffect, "%s in %s is not a FireworkEffect", obj, collection);
+ // Paper start - limit firework effects
+ if (effects.size() + 1 > Fireworks.MAX_EXPLOSIONS) {
+ if (throwOnOversize) {
+ throw new IllegalArgumentException("Cannot have more than " + Fireworks.MAX_EXPLOSIONS + " firework effects");
+ } else {
+ continue;
+ }
+ }
+ // Paper end - limit firework effects
effects.add((FireworkEffect) obj);
}
}
@@ -186,9 +195,13 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta {
}
List<FireworkExplosion> effects = new ArrayList<>();
- for (FireworkEffect effect : this.effects) {
- effects.add(CraftMetaFirework.getExplosion(effect));
+ // Paper start - fix NPE with effects list being null
+ if (this.effects != null) {
+ for (FireworkEffect effect : this.effects) {
+ effects.add(CraftMetaFirework.getExplosion(effect));
+ }
}
+ // Paper end
itemTag.put(CraftMetaFirework.FIREWORKS, new Fireworks(this.power, effects));
}
@@ -287,6 +300,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta {
@Override
public void addEffect(FireworkEffect effect) {
Preconditions.checkArgument(effect != null, "FireworkEffect cannot be null");
+ Preconditions.checkArgument(this.effects == null || this.effects.size() + 1 <= Fireworks.MAX_EXPLOSIONS, "cannot have more than %s firework effects", Fireworks.MAX_EXPLOSIONS); // Paper - limit firework effects
if (this.effects == null) {
this.effects = new ArrayList<FireworkEffect>();
}
@@ -296,6 +310,10 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta {
@Override
public void addEffects(FireworkEffect... effects) {
Preconditions.checkArgument(effects != null, "effects cannot be null");
+ // Paper start - limit firework effects
+ final int initialSize = this.effects == null ? 0 : this.effects.size();
+ Preconditions.checkArgument(initialSize + effects.length <= Fireworks.MAX_EXPLOSIONS, "Cannot have more than %s firework effects", Fireworks.MAX_EXPLOSIONS);
+ // Paper end - limit firework effects
if (effects.length == 0) {
return;
}
@@ -314,7 +332,7 @@ class CraftMetaFirework extends CraftMetaItem implements FireworkMeta {
@Override
public void addEffects(Iterable<FireworkEffect> effects) {
Preconditions.checkArgument(effects != null, "effects cannot be null");
- this.safelyAddEffects(effects);
+ this.safelyAddEffects(effects, true); // Paper - limit firework effects
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
index 651871b4fc512747bdfa6166c2d21b4f174f5cee..ba7d2b48552b36c6519724893e4054277e7a0cdc 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
@@ -165,9 +165,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
}
}
- static final class Applicator {
+ static abstract class Applicator { // Paper - support updating profile after resolving it
final DataComponentPatch.Builder builder = DataComponentPatch.builder();
+ void skullCallback(com.mojang.authlib.GameProfile gameProfile) {} // Paper - support updating profile after resolving it
<T> Applicator put(ItemMetaKeyType<T> key, T value) {
this.builder.set(key.TYPE, value);
@@ -991,6 +992,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
@Override
public void lore(final List<? extends net.kyori.adventure.text.Component> lore) {
+ Preconditions.checkArgument(lore == null || lore.size() <= ItemLore.MAX_LINES, "lore cannot have more than %s lines", ItemLore.MAX_LINES); // Paper - limit lore lines
this.lore = lore != null ? io.papermc.paper.adventure.PaperAdventure.asVanilla(lore) : null;
}
// Paper end
@@ -1115,6 +1117,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
// Paper end
@Override
public void setLore(List<String> lore) {
+ Preconditions.checkArgument(lore == null || lore.size() <= ItemLore.MAX_LINES, "lore cannot have more than %s lines", ItemLore.MAX_LINES); // Paper - limit lore lines
if (lore == null || lore.isEmpty()) {
this.lore = null;
} else {
@@ -1130,6 +1133,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
// Paper start
@Override
public void setLoreComponents(List<net.md_5.bungee.api.chat.BaseComponent[]> lore) {
+ Preconditions.checkArgument(lore == null || lore.size() <= ItemLore.MAX_LINES, "lore cannot have more than %s lines", ItemLore.MAX_LINES); // Paper - limit lore lines
if (lore == null) {
this.lore = null;
} else {
@@ -1397,7 +1401,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
@Override
public String getAsString() {
- CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator();
+ CraftMetaItem.Applicator tag = new CraftMetaItem.Applicator() {}; // Paper - support updating profile after resolving it
this.applyToItem(tag);
DataComponentPatch patch = tag.build();
Tag nbt = DataComponentPatch.CODEC.encodeStart(MinecraftServer.getDefaultRegistryAccess().createSerializationContext(NbtOps.INSTANCE), patch).getOrThrow();
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
index c769d2a210060f6829a6cbe739d6d9ab2f602644..1feffe289a1e714084bd37b5c5ad23a37dd58325 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaSkull.java
@@ -137,10 +137,10 @@ class CraftMetaSkull extends CraftMetaItem implements SkullMeta {
// Fill in textures
PlayerProfile ownerProfile = new CraftPlayerProfile(this.profile); // getOwnerProfile may return null
if (ownerProfile.getTextures().isEmpty()) {
- ownerProfile.update().thenAccept((filledProfile) -> {
+ ownerProfile.update().thenAcceptAsync((filledProfile) -> { // Paper - run on main thread
this.setOwnerProfile(filledProfile);
- tag.put(CraftMetaSkull.SKULL_PROFILE, new ResolvableProfile(this.profile));
- });
+ tag.skullCallback(this.profile); // Paper - actually set profile on itemstack
+ }, ((org.bukkit.craftbukkit.CraftServer) org.bukkit.Bukkit.getServer()).getServer()); // Paper - run on main thread
}
}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java b/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java
index 05a4a06c0def28fc97e61b4712c45c8730fec60c..a86eb660d8f523cb99a0b668ef1130535d50ce1c 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/SerializableMeta.java
@@ -110,4 +110,21 @@ public final class SerializableMeta implements ConfigurationSerializable {
}
throw new IllegalArgumentException(field + "(" + object + ") is not a valid " + clazz);
}
+
+ // Paper start - General ItemMeta Fixes
+ public static <T> java.util.Optional<T> getObjectOptionally(Class<T> clazz, Map<?, ?> map, Object field, boolean nullable) {
+ final Object object = map.get(field);
+
+ if (clazz.isInstance(object)) {
+ return java.util.Optional.of(clazz.cast(object));
+ }
+ if (object == null) {
+ if (!nullable) {
+ throw new NoSuchElementException(map + " does not contain " + field);
+ }
+ return java.util.Optional.empty();
+ }
+ throw new IllegalArgumentException(field + "(" + object + ") is not a valid " + clazz);
+ }
+ // Paper end - General ItemMeta Fixes
}
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftFoodComponent.java b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftFoodComponent.java
index c68e85cca0f532a94545c0b7f6ed54451ce5a47e..eb08b3453738bffd1a6350dc56c18b9740be5a01 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftFoodComponent.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftFoodComponent.java
@@ -103,6 +103,7 @@ public final class CraftFoodComponent implements FoodComponent {
@Override
public void setEatSeconds(float eatSeconds) {
+ Preconditions.checkArgument(eatSeconds > 0, "Eat seconds must be positive"); // Paper - validate eat_seconds
this.handle = new FoodProperties(this.handle.nutrition(), this.handle.saturation(), this.handle.canAlwaysEat(), eatSeconds, this.handle.effects());
}
diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java
index 0b11d5ea89539decd2f6c60c5b581bbd78ff1fd6..74ebadacbbd11b5a0d8f8c6cd6409cce17cfa37d 100644
--- a/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java
+++ b/src/test/java/org/bukkit/craftbukkit/inventory/DeprecatedItemMetaCustomValueTest.java
@@ -92,7 +92,7 @@ public class DeprecatedItemMetaCustomValueTest extends AbstractTestingBase {
public void testNBTTagStoring() {
CraftMetaItem itemMeta = this.createComplexItemMeta();
- CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator();
+ CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator() {}; // Paper
itemMeta.applyToItem(compound);
assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper
diff --git a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java
index f3939074a886b20f17b00dd3c39833725f47d3f0..1123cc60671c1a48bba9b2baa1f10c6d5a6855fe 100644
--- a/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java
+++ b/src/test/java/org/bukkit/craftbukkit/inventory/PersistentDataContainerTest.java
@@ -126,7 +126,7 @@ public class PersistentDataContainerTest extends AbstractTestingBase {
public void testNBTTagStoring() {
CraftMetaItem itemMeta = this.createComplexItemMeta();
- CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator();
+ CraftMetaItem.Applicator compound = new CraftMetaItem.Applicator() {}; // Paper
itemMeta.applyToItem(compound);
assertEquals(itemMeta, new CraftMetaItem(compound.build(), null)); // Paper
@@ -472,7 +472,7 @@ public class PersistentDataContainerTest extends AbstractTestingBase {
assertEquals(List.of(), container.get(PersistentDataContainerTest.requestKey("list"), PersistentDataType.LIST.strings()));
// Write and read the entire container to NBT
- final CraftMetaItem.Applicator storage = new CraftMetaItem.Applicator();
+ final CraftMetaItem.Applicator storage = new CraftMetaItem.Applicator() {}; // Paper
craftItem.applyToItem(storage);
final CraftMetaItem readItem = new CraftMetaItem(storage.build(), null); // Paper
|