Skip to content

Commit 9b54794

Browse files
committed
Fix cloning in 1.17
Addresses #1222
1 parent 42bec5a commit 9b54794

File tree

6 files changed

+85
-70
lines changed

6 files changed

+85
-70
lines changed

.travis.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
language: java
2+
os: linux
3+
dist: focal
24
jdk:
3-
- openjdk8
5+
- openjdk16
46
script: mvn clean test
57
install: true
68
notifications:

src/main/java/com/comphenix/protocol/events/PacketContainer.java

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import com.comphenix.protocol.reflect.cloning.AggregateCloner.BuilderParameters;
3636
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
3737
import com.comphenix.protocol.reflect.instances.DefaultInstances;
38+
import com.comphenix.protocol.reflect.instances.InstanceProvider;
3839
import com.comphenix.protocol.utility.MinecraftMethods;
3940
import com.comphenix.protocol.utility.MinecraftReflection;
4041
import com.comphenix.protocol.utility.MinecraftVersion;
@@ -82,11 +83,11 @@ public class PacketContainer implements Serializable {
8283
// Support for serialization
8384
private static ConcurrentMap<Class<?>, Method> writeMethods = Maps.newConcurrentMap();
8485
private static ConcurrentMap<Class<?>, Method> readMethods = Maps.newConcurrentMap();
85-
86+
8687
// Used to clone packets
8788
private static final AggregateCloner DEEP_CLONER = AggregateCloner
8889
.newBuilder()
89-
.instanceProvider(DefaultInstances.DEFAULT)
90+
.instanceProvider(StructureCache::newPacket)
9091
.andThen(BukkitCloner.class)
9192
.andThen(ImmutableDetector.class)
9293
.andThen(JavaOptionalCloner.class)
@@ -97,7 +98,7 @@ public class PacketContainer implements Serializable {
9798

9899
private static final AggregateCloner SHALLOW_CLONER = AggregateCloner
99100
.newBuilder()
100-
.instanceProvider(DefaultInstances.DEFAULT)
101+
.instanceProvider(StructureCache::newPacket)
101102
.andThen(param -> {
102103
if (param == null)
103104
throw new IllegalArgumentException("Cannot be NULL.");
@@ -110,8 +111,12 @@ public class PacketContainer implements Serializable {
110111
.build();
111112

112113
// Packets that cannot be cloned by our default deep cloner
113-
private static final Set<PacketType> CLONING_UNSUPPORTED = Sets.newHashSet(
114-
PacketType.Play.Server.UPDATE_ATTRIBUTES, PacketType.Status.Server.SERVER_INFO);
114+
private static final Set<PacketType> FAST_CLONE_UNSUPPORTED = Sets.newHashSet(
115+
PacketType.Play.Server.BOSS,
116+
PacketType.Play.Server.ADVANCEMENTS,
117+
PacketType.Play.Client.USE_ENTITY,
118+
PacketType.Status.Server.SERVER_INFO
119+
);
115120

116121
/**
117122
* Creates a packet container for a new packet.
@@ -1155,14 +1160,16 @@ public PacketContainer shallowClone() {
11551160
*/
11561161
public PacketContainer deepClone() {
11571162
Object clonedPacket = null;
1158-
1159-
// Fall back on the alternative (but slower) method of reading and writing back the packet
1160-
if (!CLONING_UNSUPPORTED.contains(type)) {
1163+
1164+
if (!FAST_CLONE_UNSUPPORTED.contains(type)) {
11611165
try {
11621166
clonedPacket = DEEP_CLONER.clone(getHandle());
1163-
} catch (Exception ignored) {}
1167+
} catch (Exception ex) {
1168+
FAST_CLONE_UNSUPPORTED.add(type);
1169+
}
11641170
}
11651171

1172+
// Fall back on the slower alternative method of reading and writing back the packet
11661173
if (clonedPacket == null) {
11671174
clonedPacket = SerializableCloner.clone(this).getHandle();
11681175
}

src/main/java/com/comphenix/protocol/injector/StructureCache.java

Lines changed: 26 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import com.comphenix.protocol.injector.packet.PacketRegistry;
2727
import com.comphenix.protocol.reflect.StructureModifier;
2828
import com.comphenix.protocol.reflect.compiler.BackgroundCompiler;
29-
import com.comphenix.protocol.reflect.compiler.CompileListener;
3029
import com.comphenix.protocol.reflect.compiler.CompiledStructureModifier;
3130
import com.comphenix.protocol.reflect.instances.DefaultInstances;
3231
import com.comphenix.protocol.utility.MinecraftReflection;
@@ -41,9 +40,28 @@
4140
*/
4241
public class StructureCache {
4342
// Structure modifiers
44-
private static ConcurrentMap<PacketType, StructureModifier<Object>> structureModifiers = new ConcurrentHashMap<>();
43+
private static final ConcurrentMap<PacketType, StructureModifier<Object>> structureModifiers = new ConcurrentHashMap<>();
4544

46-
private static Set<PacketType> compiling = new HashSet<>();
45+
private static final Set<PacketType> compiling = new HashSet<>();
46+
47+
public static Object newPacket(Class<?> clazz) {
48+
Object result = DefaultInstances.DEFAULT.create(clazz);
49+
50+
// TODO make these generic
51+
if (result == null) {
52+
try {
53+
return clazz.getConstructor(PacketDataSerializer.class).newInstance(new PacketDataSerializer(new ZeroBuffer()));
54+
} catch (ReflectiveOperationException ex) {
55+
try {
56+
return clazz.getConstructor(PacketDataSerializer.class).newInstance(new ZeroPacketDataSerializer());
57+
} catch (ReflectiveOperationException ex1) {
58+
throw new IllegalArgumentException("Failed to create packet: " + clazz, ex);
59+
}
60+
}
61+
}
62+
63+
return result;
64+
}
4765

4866
/**
4967
* Creates an empty Minecraft packet of the given type.
@@ -52,25 +70,8 @@ public class StructureCache {
5270
*/
5371
public static Object newPacket(PacketType type) {
5472
Class<?> clazz = PacketRegistry.getPacketClassFromType(type, true);
55-
56-
// Check the return value
5773
if (clazz != null) {
58-
// TODO: Optimize DefaultInstances
59-
Object result = DefaultInstances.DEFAULT.create(clazz);
60-
61-
if (result == null) {
62-
try {
63-
return clazz.getConstructor(PacketDataSerializer.class).newInstance(new PacketDataSerializer(new ZeroBuffer()));
64-
} catch (ReflectiveOperationException ex) {
65-
try {
66-
return clazz.getConstructor(PacketDataSerializer.class).newInstance(new ZeroPacketDataSerializer());
67-
} catch (ReflectiveOperationException ex1) {
68-
throw new IllegalArgumentException("Failed to create packet for type: " + type, ex);
69-
}
70-
}
71-
}
72-
73-
return result;
74+
return newPacket(clazz);
7475
}
7576
throw new IllegalArgumentException("Cannot find associated packet class: " + type);
7677
}
@@ -115,13 +116,13 @@ public static StructureModifier<Object> getStructure(Class<?> packetType, boolea
115116
* @return A structure modifier.
116117
*/
117118
public static StructureModifier<Object> getStructure(final PacketType type, boolean compile) {
118-
Preconditions.checkNotNull(type);
119+
Preconditions.checkNotNull(type, "type cannot be null");
119120
StructureModifier<Object> result = structureModifiers.get(type);
120121

121122
// We don't want to create this for every lookup
122123
if (result == null) {
123124
// Use the vanilla class definition
124-
final StructureModifier<Object> value = new StructureModifier<Object>(
125+
final StructureModifier<Object> value = new StructureModifier<>(
125126
PacketRegistry.getPacketClassFromType(type, true), MinecraftReflection.getPacketClass(), true);
126127

127128
result = structureModifiers.putIfAbsent(type, value);
@@ -139,12 +140,8 @@ public static StructureModifier<Object> getStructure(final PacketType type, bool
139140
final BackgroundCompiler compiler = BackgroundCompiler.getInstance();
140141

141142
if (!compiling.contains(type) && compiler != null) {
142-
compiler.scheduleCompilation(result, new CompileListener<Object>() {
143-
@Override
144-
public void onCompiled(StructureModifier<Object> compiledModifier) {
145-
structureModifiers.put(type, compiledModifier);
146-
}
147-
});
143+
compiler.scheduleCompilation(result,
144+
compiledModifier -> structureModifiers.put(type, compiledModifier));
148145
compiling.add(type);
149146
}
150147
}

src/main/java/com/comphenix/protocol/reflect/ObjectWriter.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,11 @@ private void copyToInternal(Object source, Object destination, Class<?> commonTy
117117
}
118118

119119
// Copy private fields underneath
120-
Class<?> superclass = commonType.getSuperclass();
121-
122-
if (superclass != null && !superclass.equals(Object.class)) {
123-
copyToInternal(source, destination, superclass, false);
124-
}
125-
120+
// Class<?> superclass = commonType.getSuperclass();
121+
//
122+
// if (superclass != null && !superclass.equals(Object.class)) {
123+
// copyToInternal(source, destination, superclass, false);
124+
// }
126125
} catch (FieldAccessException e) {
127126
throw new RuntimeException("Unable to copy fields from " + commonType.getName(), e);
128127
}

src/main/java/com/comphenix/protocol/reflect/cloning/AggregateCloner.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,11 @@ public Object clone(Object source) {
256256
if (index < cloners.size()) {
257257
Cloner cloner = cloners.get(index);
258258

259-
try {
260-
return cloner.clone(source);
261-
} catch (Exception ex) {
262-
throw new RuntimeException("Failed to clone " + source + " (" + source.getClass() + ") with " + cloner, ex);
263-
}
259+
// try {
260+
return cloner.clone(source);
261+
// } catch (Exception ex) {
262+
// throw new RuntimeException("Failed to clone " + source + " (" + source.getClass() + ") with " + cloner, ex);
263+
// }
264264
}
265265

266266
// Damn - failure

src/test/java/com/comphenix/protocol/events/PacketContainerTest.java

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ public void testAttributeList() {
413413
}
414414

415415
field.setAccessible(true);
416-
assertEquals(field.get(snapshot), field.get(clonedSnapshot));
416+
testEquality(field.get(snapshot), field.get(clonedSnapshot));
417417
} catch (AssertionError e) {
418418
throw e;
419419
} catch (Throwable ex) {
@@ -611,8 +611,27 @@ public void testComponentArrays() {
611611
assertArrayEquals(components, back);
612612
}
613613

614+
private void assertPacketsEqual(PacketContainer constructed, PacketContainer cloned) {
615+
StructureModifier<Object> firstMod = constructed.getModifier(), secondMod = cloned.getModifier();
616+
assertEquals(firstMod.size(), secondMod.size());
617+
618+
if (PacketType.Status.Server.SERVER_INFO.equals(constructed.getType())) {
619+
assertArrayEquals(SerializationUtils.serialize(constructed), SerializationUtils.serialize(cloned));
620+
} else {
621+
// Make sure all the fields are equivalent
622+
for (int i = 0; i < firstMod.size(); i++) {
623+
if (firstMod.getField(i).getType().isArray())
624+
assertArrayEquals(getArray(firstMod.read(i)), getArray(secondMod.read(i)));
625+
else
626+
testEquality(firstMod.read(i), secondMod.read(i));
627+
}
628+
}
629+
}
630+
614631
@Test
615-
public void testDeepClone() {
632+
public void testCloning() {
633+
boolean failed = false;
634+
616635
// Try constructing all the packets
617636
for (PacketType type : PacketType.values()) {
618637
if (type.isDeprecated() || type.name().contains("CUSTOM_PAYLOAD") || type.name().contains("TAGS") || !type.isSupported()
@@ -644,28 +663,19 @@ public void testDeepClone() {
644663
//constructed.getModifier().write(1, TEST_COMPONENT);
645664
}
646665

647-
// Clone the packet
648-
PacketContainer cloned = constructed.deepClone();
649-
650-
// Make sure they're equivalent
651-
StructureModifier<Object> firstMod = constructed.getModifier(), secondMod = cloned.getModifier();
652-
assertEquals(firstMod.size(), secondMod.size());
653-
654-
if (PacketType.Status.Server.SERVER_INFO.equals(type)) {
655-
assertArrayEquals(SerializationUtils.serialize(constructed), SerializationUtils.serialize(cloned));
656-
} else {
657-
// Make sure all the fields are equivalent
658-
for (int i = 0; i < firstMod.size(); i++) {
659-
if (firstMod.getField(i).getType().isArray())
660-
assertArrayEquals(getArray(firstMod.read(i)), getArray(secondMod.read(i)));
661-
else
662-
testEquality(firstMod.read(i), secondMod.read(i));
663-
}
664-
}
666+
// Clone the packet both ways
667+
PacketContainer shallowCloned = constructed.shallowClone();
668+
assertPacketsEqual(constructed, shallowCloned);
669+
670+
PacketContainer deepCloned = constructed.deepClone();
671+
assertPacketsEqual(constructed, deepCloned);
665672
} catch (Exception ex) {
666673
ex.printStackTrace();
674+
failed = true;
667675
}
668676
}
677+
678+
assertFalse("Packet(s) failed to clone", failed);
669679
}
670680

671681
// Convert to objects that support equals()

0 commit comments

Comments
 (0)