Skip to content

Commit e726f6e

Browse files
committed
1.21
1 parent 389233f commit e726f6e

26 files changed

+370
-212
lines changed

build.gradle

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ repositories {
3535
dependencies {
3636
implementation 'net.bytebuddy:byte-buddy:1.14.14'
3737
compileOnly 'org.spigotmc:spigot-api:1.20.6-R0.1-SNAPSHOT'
38-
compileOnly 'org.spigotmc:spigot:1.20.6-R0.1-SNAPSHOT'
38+
compileOnly 'org.spigotmc:spigot:1.21-R0.1-SNAPSHOT'
3939
compileOnly 'io.netty:netty-all:4.0.23.Final'
4040
compileOnly 'net.kyori:adventure-text-serializer-gson:4.14.0'
4141
compileOnly 'com.googlecode.json-simple:json-simple:1.1.1'
@@ -46,7 +46,7 @@ dependencies {
4646
testImplementation 'org.mockito:mockito-core:5.6.0'
4747
testImplementation 'io.netty:netty-common:4.1.97.Final'
4848
testImplementation 'io.netty:netty-transport:4.1.97.Final'
49-
testImplementation 'org.spigotmc:spigot:1.20.6-R0.1-SNAPSHOT'
49+
testImplementation 'org.spigotmc:spigot:1.21-R0.1-SNAPSHOT'
5050
testImplementation 'net.kyori:adventure-text-serializer-gson:4.14.0'
5151
testImplementation 'net.kyori:adventure-text-serializer-plain:4.14.0'
5252
}
@@ -59,6 +59,14 @@ java {
5959
withSourcesJar()
6060
}
6161

62+
jar {
63+
manifest {
64+
attributes(
65+
'paperweight-mappings-namespace': 'mojang'
66+
)
67+
}
68+
}
69+
6270
shadowJar {
6371
dependencies {
6472
include(dependency('net.bytebuddy:byte-buddy:.*'))

src/main/java/com/comphenix/protocol/PacketType.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ public static class Server extends PacketTypeEnum {
229229
public static final PacketType RECIPE_UPDATE = new PacketType(PROTOCOL, SENDER, 0x77, "UpdateRecipes", "RecipeUpdate");
230230
public static final PacketType TAGS = new PacketType(PROTOCOL, SENDER, 0x78, "UpdateTags", "Tags");
231231
public static final PacketType PROJECTILE_POWER = new PacketType(PROTOCOL, SENDER, 0x79, "ProjectilePower");
232+
public static final PacketType REPORT_DETAILS = new PacketType(PROTOCOL, SENDER, 0x7A, "CustomReportDetails");
233+
public static final PacketType SERVER_LINKS = new PacketType(PROTOCOL, SENDER, 0x7B, "ServerLinks");
232234

233235
// ---- Removed in 1.9
234236

@@ -684,6 +686,8 @@ public static class Server extends PacketTypeEnum {
684686
public static final PacketType UPDATE_ENABLED_FEATURES = new PacketType(PROTOCOL, SENDER, 0x0C, "UpdateEnabledFeatures");
685687
public static final PacketType UPDATE_TAGS = new PacketType(PROTOCOL, SENDER, 0x0D, "UpdateTags");
686688
public static final PacketType SELECT_KNOWN_PACKS = new PacketType(PROTOCOL, SENDER, 0x0E, "ClientboundSelectKnownPacks");
689+
public static final PacketType REPORT_DETAILS = new PacketType(PROTOCOL, SENDER, 0x0F, "CustomReportDetails");
690+
public static final PacketType SERVER_LINKS = new PacketType(PROTOCOL, SENDER, 0x10, "ServerLinks");
687691

688692
/**
689693
* @deprecated Removed in 1.20.4: replaced with new packets for removing and sending resource packs

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

Lines changed: 78 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,25 @@
1717

1818
package com.comphenix.protocol.injector;
1919

20+
import java.lang.reflect.Field;
21+
import java.lang.reflect.Modifier;
2022
import java.security.PublicKey;
23+
import java.util.List;
2124
import java.util.Map;
22-
import java.util.Objects;
2325
import java.util.Optional;
2426
import java.util.concurrent.ConcurrentHashMap;
27+
import java.util.function.Function;
2528
import java.util.function.Supplier;
2629

2730
import com.comphenix.protocol.PacketType;
31+
import com.comphenix.protocol.injector.packet.KnownPacketData;
2832
import com.comphenix.protocol.injector.packet.PacketRegistry;
2933
import com.comphenix.protocol.reflect.FuzzyReflection;
3034
import com.comphenix.protocol.reflect.StructureModifier;
3135
import com.comphenix.protocol.reflect.accessors.Accessors;
3236
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
37+
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
38+
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
3339
import com.comphenix.protocol.reflect.fuzzy.FuzzyMethodContract;
3440
import com.comphenix.protocol.reflect.instances.DefaultInstances;
3541
import com.comphenix.protocol.reflect.instances.InstanceCreator;
@@ -41,9 +47,10 @@
4147
import com.comphenix.protocol.utility.ZeroBuffer;
4248
import com.comphenix.protocol.wrappers.WrappedChatComponent;
4349
import com.comphenix.protocol.wrappers.WrappedStreamCodec;
44-
import com.google.common.base.Preconditions;
4550

51+
import com.google.common.base.Preconditions;
4652
import io.netty.buffer.ByteBuf;
53+
import io.netty.buffer.Unpooled;
4754
import net.bytebuddy.dynamic.DynamicType;
4855
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy.Default;
4956
import net.bytebuddy.implementation.FixedValue;
@@ -57,14 +64,14 @@
5764
public class StructureCache {
5865

5966
// Structure modifiers
60-
private static final Map<Class<?>, Supplier<Object>> CACHED_INSTANCE_CREATORS = new ConcurrentHashMap<>();
67+
private static final Map<Class<?>, Optional<Supplier<Object>>> CACHED_INSTANCE_CREATORS = new ConcurrentHashMap<>();
6168
private static final Map<PacketType, StructureModifier<Object>> STRUCTURE_MODIFIER_CACHE = new ConcurrentHashMap<>();
6269

6370
// packet data serializer which always returns an empty nbt tag compound
6471
private static final Object TRICK_INIT_LOCK = new Object();
6572
private static boolean TRICK_TRIED = false;
6673

67-
private static Supplier<Object> TRICKED_DATA_SERIALIZER_BASE;
74+
private static Function<ByteBuf, Object> TRICKED_DATA_SERIALIZER_BASE;
6875
private static Supplier<Object> TRICKED_DATA_SERIALIZER_JSON;
6976

7077
/**
@@ -75,12 +82,40 @@ public static Object newPacket(Class<?> packetClass) {
7582
return newInstance(packetClass);
7683
}
7784

85+
public static boolean canCreateInstance(Class<?> clazz) {
86+
Optional<Supplier<Object>> creator = CACHED_INSTANCE_CREATORS.computeIfAbsent(clazz, x ->
87+
Optional.ofNullable(determineBestCreator(clazz)));
88+
return creator.isPresent();
89+
}
90+
7891
public static Object newInstance(Class<?> clazz) {
79-
Supplier<Object> creator = CACHED_INSTANCE_CREATORS.computeIfAbsent(clazz, StructureCache::determineBestCreator);
80-
return creator.get();
92+
Optional<Supplier<Object>> creator = CACHED_INSTANCE_CREATORS.computeIfAbsent(clazz, x ->
93+
Optional.ofNullable(determineBestCreator(clazz)));
94+
if (!creator.isPresent()) {
95+
throw new IllegalArgumentException("Cannot create instance of " + clazz);
96+
}
97+
return creator.get().get();
8198
}
8299

83100
static Supplier<Object> determineBestCreator(Class<?> clazz) {
101+
// certain packets are singletons which can't really be created
102+
if (MinecraftReflection.isPacketClass(clazz)) {
103+
FuzzyReflection fuzzy = FuzzyReflection.fromClass(clazz, false);
104+
List<Field> singletons = fuzzy.getFieldList(FuzzyFieldContract.newBuilder()
105+
.typeExact(clazz)
106+
.requireModifier(Modifier.STATIC)
107+
.requireModifier(Modifier.PUBLIC)
108+
.build());
109+
if (singletons.size() == 1) {
110+
FieldAccessor accessor = Accessors.getFieldAccessor(singletons.get(0));
111+
try {
112+
accessor.get(null);
113+
return () -> accessor.get(null);
114+
} catch (Exception ignored) {
115+
}
116+
}
117+
}
118+
84119
try {
85120
InstanceCreator creator = InstanceCreator.forClass(clazz);
86121
if (creator.get() != null) {
@@ -95,21 +130,40 @@ static Supplier<Object> determineBestCreator(Class<?> clazz) {
95130
if (streamCodec != null && tryInitTrickDataSerializer()) {
96131
try {
97132
// first try with the base accessor
98-
Object serializer = TRICKED_DATA_SERIALIZER_BASE.get();
133+
Object serializer = TRICKED_DATA_SERIALIZER_BASE.apply(new ZeroBuffer());
99134
streamCodec.decode(serializer); // throwaway instance, for testing
100135

101136
// method is working
102137
return () -> streamCodec.decode(serializer);
103-
} catch (Exception ignored) {
138+
} catch (Exception ex) {
104139
try {
105-
// try with the json accessor
106-
Object serializer = TRICKED_DATA_SERIALIZER_JSON.get();
107-
streamCodec.decode(serializer); // throwaway instance, for testing
140+
byte[] data;
141+
if (clazz.equals(PacketType.Play.Server.MAP_CHUNK.getPacketClass())) {
142+
data = KnownPacketData.MAP_CHUNK;
143+
} else if (clazz.equals(PacketType.Play.Server.SCOREBOARD_OBJECTIVE.getPacketClass())) {
144+
data = KnownPacketData.SCOREBOARD_OBJECTIVE;
145+
} else {
146+
throw ex;
147+
}
148+
149+
Object serializer = TRICKED_DATA_SERIALIZER_BASE.apply(Unpooled.copiedBuffer(data));
150+
streamCodec.decode(serializer);
108151

109-
// method is working
110-
return () -> streamCodec.decode(serializer);
152+
return () -> {
153+
((ByteBuf) serializer).readerIndex(0);
154+
return streamCodec.decode(serializer);
155+
};
111156
} catch (Exception ignored1) {
112-
// shrug, fall back to default behaviour
157+
try {
158+
// try with the json accessor
159+
Object serializer = TRICKED_DATA_SERIALIZER_JSON.get();
160+
streamCodec.decode(serializer); // throwaway instance, for testing
161+
162+
// method is working
163+
return () -> streamCodec.decode(serializer);
164+
} catch (Exception ignored2) {
165+
// shrug, fall back to default behaviour
166+
}
113167
}
114168
}
115169
}
@@ -124,7 +178,7 @@ static Supplier<Object> determineBestCreator(Class<?> clazz) {
124178
if (tryInitTrickDataSerializer()) {
125179
try {
126180
// first try with the base accessor
127-
Object serializer = TRICKED_DATA_SERIALIZER_BASE.get();
181+
Object serializer = TRICKED_DATA_SERIALIZER_BASE.apply(new ZeroBuffer());
128182
serializerAccessor.invoke(serializer); // throwaway instance, for testing
129183

130184
// method is working
@@ -145,12 +199,12 @@ static Supplier<Object> determineBestCreator(Class<?> clazz) {
145199
}
146200
}
147201

148-
// try via DefaultInstances as fallback
149-
return () -> {
150-
Object packetInstance = DefaultInstances.DEFAULT.create(clazz);
151-
Objects.requireNonNull(packetInstance, "Unable to create instance for class " + clazz + " - " + tryInitTrickDataSerializer() + " - " + streamCodec);
152-
return packetInstance;
153-
};
202+
Object instance = DefaultInstances.DEFAULT.create(clazz);
203+
if (instance == null) {
204+
return null;
205+
}
206+
207+
return () -> DefaultInstances.DEFAULT.create(clazz);
154208
}
155209

156210
/**
@@ -206,7 +260,7 @@ public static StructureModifier<Object> getStructure(final PacketType packetType
206260
*/
207261
public static Object newNullDataSerializer() {
208262
tryInitTrickDataSerializer();
209-
return TRICKED_DATA_SERIALIZER_BASE.get();
263+
return TRICKED_DATA_SERIALIZER_BASE.apply(new ZeroBuffer());
210264
}
211265

212266
static void initTrickDataSerializer() {
@@ -236,10 +290,10 @@ static void initTrickDataSerializer() {
236290
.parameterDerivedOf(ByteBuf.class)
237291
.parameterDerivedOf(MinecraftReflection.getRegistryAccessClass())
238292
.build()));
239-
TRICKED_DATA_SERIALIZER_BASE = () -> accessor.invoke(new ZeroBuffer(), MinecraftRegistryAccess.get());
293+
TRICKED_DATA_SERIALIZER_BASE = (buf) -> accessor.invoke(buf, MinecraftRegistryAccess.get());
240294
} else {
241295
ConstructorAccessor accessor = Accessors.getConstructorAccessor(serializerBase, ByteBuf.class);
242-
TRICKED_DATA_SERIALIZER_BASE = () -> accessor.invoke(new ZeroBuffer());
296+
TRICKED_DATA_SERIALIZER_BASE = accessor::invoke;
243297
}
244298

245299
//xtended builder which intercepts the read string method as well
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.comphenix.protocol.injector.packet;
2+
3+
public final class KnownPacketData {
4+
public static final byte[] SCOREBOARD_OBJECTIVE = {
5+
4, 84, 101, 115, 116, 1
6+
};
7+
8+
public static final byte[] MAP_CHUNK = {
9+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
10+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11+
0x00, 0x00, 0x00
12+
};
13+
}

src/main/java/com/comphenix/protocol/injector/packet/PacketRegistry.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ private static synchronized Register createRegisterV1_20_5() {
370370
Class<?> idCodecEntryClass = MinecraftReflection.getMinecraftClass("network.codec.IdDispatchCodec$Entry", "network.codec.IdDispatchCodec$b");
371371
Class<?> protocolDirectionClass = MinecraftReflection.getPacketFlowClass();
372372

373-
Function<?, ?> emptyFunction = input -> null;
373+
Function<?, ?> emptyFunction = input -> input;
374374

375375
FuzzyReflection protocolInfoReflection = FuzzyReflection.fromClass(protocolInfoClass);
376376

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

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,6 @@
1717

1818
package com.comphenix.protocol.reflect;
1919

20-
import com.comphenix.protocol.reflect.accessors.Accessors;
21-
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
22-
import com.comphenix.protocol.reflect.instances.BannedGenerator;
23-
import com.comphenix.protocol.reflect.instances.DefaultInstances;
24-
import com.comphenix.protocol.reflect.instances.InstanceProvider;
25-
import com.comphenix.protocol.utility.MinecraftReflection;
26-
import com.google.common.collect.HashBasedTable;
27-
import com.google.common.collect.Table;
28-
2920
import java.lang.ref.Reference;
3021
import java.lang.ref.SoftReference;
3122
import java.lang.reflect.Field;
@@ -43,6 +34,17 @@
4334
import java.util.function.UnaryOperator;
4435
import java.util.stream.Collectors;
4536

37+
import com.comphenix.protocol.injector.StructureCache;
38+
import com.comphenix.protocol.reflect.accessors.Accessors;
39+
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
40+
import com.comphenix.protocol.reflect.instances.BannedGenerator;
41+
import com.comphenix.protocol.reflect.instances.DefaultInstances;
42+
import com.comphenix.protocol.reflect.instances.InstanceProvider;
43+
import com.comphenix.protocol.utility.MinecraftReflection;
44+
45+
import com.google.common.collect.HashBasedTable;
46+
import com.google.common.collect.Table;
47+
4648
/**
4749
* Provides list-oriented access to the fields of a Minecraft packet.
4850
* <p>
@@ -142,8 +144,9 @@ private static Map<FieldAccessor, Integer> generateDefaultFields(Collection<Fiel
142144

143145
for (FieldAccessor accessor : fields) {
144146
Field field = accessor.getField();
145-
if (!field.getType().isPrimitive() && !Modifier.isFinal(field.getModifiers())) {
146-
if (DEFAULT_GENERATOR.hasDefault(field.getType())) {
147+
if (!field.getType().isPrimitive()) {// && !Modifier.isFinal(field.getModifiers())) {
148+
// if (DEFAULT_GENERATOR.hasDefault(field.getType())) {
149+
if (StructureCache.canCreateInstance(field.getType())) {
147150
requireDefaults.put(accessor, currentFieldIndex);
148151
}
149152
}
@@ -395,13 +398,12 @@ public StructureModifier<T> writeDefaults() throws FieldAccessException {
395398
// They must be null or messages will be blank
396399
Field field = accessor.getField();
397400
if (field.getType().getCanonicalName().equals("net.md_5.bungee.api.chat.BaseComponent[]")) {
398-
accessor.set(this.target, null);
401+
accessor.set(target, null);
399402
continue;
400403
}
401404

402-
// get the default value and write the field
403-
Object defaultValue = DEFAULT_GENERATOR.getDefault(field.getType());
404-
accessor.set(this.target, defaultValue);
405+
Object value = StructureCache.newInstance(field.getType());
406+
accessor.set(target, value);
405407
}
406408

407409
return this;

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ private static void fromManual(Supplier<Class<?>> getClass, Function<Object, Obj
8282
fromWrapper(MinecraftReflection::getIChatBaseComponentClass, WrappedChatComponent::fromHandle);
8383
fromWrapper(WrappedVillagerData::getNmsClass, WrappedVillagerData::fromHandle);
8484
fromConverter(MinecraftReflection::getSectionPositionClass, BukkitConverters.getSectionPositionConverter());
85+
fromManual(MinecraftReflection::getAttributeSnapshotClass, source ->
86+
WrappedAttribute.fromHandle(source).shallowClone().getHandle());
8587

8688
try {
8789
fromManual(ComponentConverter::getBaseComponentArrayClass, source ->

src/main/java/com/comphenix/protocol/reflect/instances/InstanceCreator.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ public Object get() {
6464
Object result = null;
6565
int minCount = Integer.MAX_VALUE;
6666

67-
for (Constructor<?> testCtor : type.getConstructors()) {
67+
for (Constructor<?> testCtor : type.getDeclaredConstructors()) {
6868
Class<?>[] paramTypes = testCtor.getParameterTypes();
6969
if (paramTypes.length > minCount) {
7070
continue;
@@ -73,9 +73,10 @@ public Object get() {
7373
Object[] testParams = createParams(paramTypes);
7474

7575
try {
76-
result = testCtor.newInstance(testParams);
76+
ConstructorAccessor testAccessor = Accessors.getConstructorAccessor(testCtor);
77+
result = testAccessor.invoke(testParams);
7778
minCount = paramTypes.length;
78-
this.constructor = Accessors.getConstructorAccessor(testCtor);
79+
this.constructor = testAccessor;
7980
this.paramTypes = paramTypes;
8081
} catch (Exception ignored) {
8182
}
@@ -105,9 +106,10 @@ public Object get() {
105106
Object[] testParams = createParams(paramTypes);
106107

107108
try {
108-
result = testMethod.invoke(null, testParams);
109+
MethodAccessor testAccessor = Accessors.getMethodAccessor(testMethod);
110+
result = testAccessor.invoke(null, testParams);
109111
minCount = paramTypes.length;
110-
this.factoryMethod = Accessors.getMethodAccessor(testMethod);
112+
this.factoryMethod = testAccessor;
111113
this.paramTypes = paramTypes;
112114
} catch (Exception ignored) {
113115
}

src/main/java/com/comphenix/protocol/utility/MinecraftProtocolVersion.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,11 @@ private static NavigableMap<MinecraftVersion, Integer> createLookup() {
8888
map.put(new MinecraftVersion(1, 19, 4), 762);
8989

9090
map.put(new MinecraftVersion(1, 20, 0), 763);
91-
map.put(new MinecraftVersion(1, 20, 1), 763);
9291
map.put(new MinecraftVersion(1, 20, 2), 764);
92+
map.put(new MinecraftVersion(1, 20, 3), 765);
93+
map.put(new MinecraftVersion(1, 20, 5), 766);
94+
95+
map.put(new MinecraftVersion(1, 21, 0), 767);
9396
return map;
9497
}
9598

0 commit comments

Comments
 (0)