Skip to content

Commit a936183

Browse files
authored
Fix WrappedList - NBT lists may now be heterogeneous (#3394)
1 parent 804aa5d commit a936183

File tree

4 files changed

+62
-21
lines changed

4 files changed

+62
-21
lines changed

src/main/java/com/comphenix/protocol/wrappers/nbt/NbtList.java

+16-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public interface NbtList<TType> extends NbtBase<List<NbtBase<TType>>>, Iterable<
2323
String EMPTY_NAME = "";
2424

2525
/**
26-
* Get the type of each element.
26+
* Get the type of each element. For heterogeneous lists this will return {@link NbtType#TAG_COMPOUND TAG_COMPOUND}.
2727
* <p>
2828
* This will be {@link NbtType#TAG_END TAG_END} if the NBT list has just been created.
2929
* @return Element type.
@@ -32,18 +32,32 @@ public interface NbtList<TType> extends NbtBase<List<NbtBase<TType>>>, Iterable<
3232

3333
/**
3434
* Set the type of each element.
35+
* <p>
36+
* In 1.21.5 and up lists can be heterogeneous, here the type is only used to convert elements added with {@link NbtList#addClosest(Object)}
3537
* @param type - type of each element.
38+
* @deprecated since 1.21.5 lists can be heterogeneous
3639
*/
40+
@Deprecated
3741
void setElementType(NbtType type);
3842

3943
/**
4044
* Add a value to a typed list by attempting to convert it to the nearest value.
4145
* <p>
4246
* Note that the list must be typed by setting {@link #setElementType(NbtType)} before calling this function.
4347
* @param value - the value to add.
48+
* @deprecated since 1.21.5 lists can be heterogeneous. Use {@link NbtList#addClosest(Object, NbtType)}
4449
*/
50+
@Deprecated
4551
void addClosest(Object value);
46-
52+
53+
/**
54+
* Add a value to a typed list by attempting to convert it to the nearest value.
55+
* <p>
56+
* @param value - the value to add.
57+
* @param type - the resulting type of the entry
58+
*/
59+
void addClosest(Object value, NbtType type);
60+
4761
/**
4862
* Add a NBT list or NBT compound to the list.
4963
* @param element Element to add

src/main/java/com/comphenix/protocol/wrappers/nbt/WrappedList.java

+44-17
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package com.comphenix.protocol.wrappers.nbt;
1919

20+
import com.comphenix.protocol.utility.MinecraftVersion;
2021
import com.comphenix.protocol.wrappers.collection.ConvertedList;
2122
import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer;
2223
import com.google.common.base.Joiner;
@@ -103,7 +104,9 @@ public static <T> NbtList<T> fromList(String name, Collection<? extends T> eleme
103104
*/
104105
public WrappedList(Object handle) {
105106
this.container = new WrappedElement<>(handle);
106-
this.elementType = container.getSubType();
107+
if (!MinecraftVersion.v1_21_5.atOrAbove()) {
108+
this.elementType = container.getSubType();
109+
}
107110
}
108111

109112
/**
@@ -113,7 +116,9 @@ public WrappedList(Object handle) {
113116
*/
114117
public WrappedList(Object handle, String name) {
115118
this.container = new WrappedElement<>(handle, name);
116-
this.elementType = container.getSubType();
119+
if (!MinecraftVersion.v1_21_5.atOrAbove()) {
120+
this.elementType = container.getSubType();
121+
}
117122
}
118123

119124
@Override
@@ -141,13 +146,28 @@ public NbtType getType() {
141146

142147
@Override
143148
public NbtType getElementType() {
144-
return elementType;
149+
if (!MinecraftVersion.v1_21_5.atOrAbove()) {
150+
return elementType;
151+
} else {
152+
List<NbtBase<TType>> value = getValue();
153+
NbtType type = NbtType.TAG_END;
154+
for (NbtBase<TType> entry : value) {
155+
if (type == NbtType.TAG_END) {
156+
type = entry.getType();
157+
} else if (type != entry.getType()) {
158+
return NbtType.TAG_COMPOUND;
159+
}
160+
}
161+
return type;
162+
}
145163
}
146164

147165
@Override
148166
public void setElementType(NbtType type) {
149167
this.elementType = type;
150-
container.setSubType(type);
168+
if (!MinecraftVersion.v1_21_5.atOrAbove()) {
169+
container.setSubType(type);
170+
}
151171
}
152172

153173
@Override
@@ -171,14 +191,16 @@ private void verifyElement(NbtBase<TType> element) {
171191
if (!element.getName().equals(EMPTY_NAME))
172192
throw new IllegalArgumentException("Cannot add a the named NBT tag " + element + " to a list.");
173193

174-
// Check element type
175-
if (getElementType() != NbtType.TAG_END) {
176-
if (!element.getType().equals(getElementType())) {
177-
throw new IllegalArgumentException(
178-
"Cannot add " + element + " of " + element.getType() + " to a list of type " + getElementType());
194+
if (!MinecraftVersion.v1_21_5.atOrAbove()) {
195+
// Check element type
196+
if (getElementType() != NbtType.TAG_END) {
197+
if (!element.getType().equals(getElementType())) {
198+
throw new IllegalArgumentException(
199+
"Cannot add " + element + " of " + element.getType() + " to a list of type " + getElementType());
200+
}
201+
} else {
202+
container.setSubType(element.getType());
179203
}
180-
} else {
181-
container.setSubType(element.getType());
182204
}
183205
}
184206

@@ -235,16 +257,21 @@ public NbtBase<List<NbtBase<TType>>> deepClone() {
235257
}
236258

237259
@Override
238-
@SuppressWarnings("unchecked")
239260
public void addClosest(Object value) {
240-
if (getElementType() == NbtType.TAG_END)
261+
if (elementType == NbtType.TAG_END)
241262
throw new IllegalStateException("This list has not been typed yet.");
242-
263+
264+
addClosest(value, elementType);
265+
}
266+
267+
@Override
268+
@SuppressWarnings("unchecked")
269+
public void addClosest(Object value, NbtType type) {
243270
if (value instanceof Number) {
244271
Number number = (Number) value;
245272

246273
// Convert the number
247-
switch (getElementType()) {
274+
switch (type) {
248275
case TAG_BYTE: add(number.byteValue()); break;
249276
case TAG_SHORT: add(number.shortValue()); break;
250277
case TAG_INT: add(number.intValue()); break;
@@ -262,7 +289,7 @@ public void addClosest(Object value) {
262289

263290
} else {
264291
// Just add it
265-
add((NbtBase<TType>) NbtFactory.ofWrapper(getElementType(), EMPTY_NAME, value));
292+
add((NbtBase<TType>) NbtFactory.ofWrapper(type, EMPTY_NAME, value));
266293
}
267294
}
268295

@@ -355,7 +382,7 @@ public void setValue(List<NbtBase<TType>> newValue) {
355382
}
356383

357384
// Update the sub type as well
358-
if (lastElement != null) {
385+
if (lastElement != null && !MinecraftVersion.v1_21_5.atOrAbove()) {
359386
container.setSubType(lastElement.getType());
360387
}
361388
}

src/main/java/com/comphenix/protocol/wrappers/nbt/io/NbtConfigurationSerializer.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,9 @@ private NbtWrapper<?> readNode(ConfigurationSection parent, String name) {
261261

262262
if (node instanceof List) {
263263
NbtList<Object> list = NbtFactory.ofList(decoded[0]);
264-
list.setElementType(type);
265264

266265
for (Object value : (List<Object>) node) {
267-
list.addClosest(toNodeValue(value, type));
266+
list.addClosest(toNodeValue(value, type), type);
268267
}
269268

270269
// Add the list

src/test/java/com/comphenix/protocol/wrappers/nbt/io/NbtConfigurationSerializerTest.java

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public void testSerialization() {
2424
compound.put("name", "test");
2525
compound.put("values", new int[]{1, 2, 3});
2626
compound.put(NbtFactory.ofList("telephone", "12345678", "81549300"));
27+
compound.put(NbtFactory.ofList("heterogeneous", "somestring", 12345, 1.0));
2728

2829
compound.put(NbtFactory.ofList("lists", NbtFactory.ofList("", "a", "a", "b", "c")));
2930

0 commit comments

Comments
 (0)