Skip to content

Commit fc3f2f3

Browse files
committed
more wrappers, more fixes
1 parent 0b6249a commit fc3f2f3

520 files changed

Lines changed: 20006 additions & 2730 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import com.comphenix.protocol.wrappers.WrappedPositionMoveRotation;
6767
import com.comphenix.protocol.wrappers.WrappedTeamParameters;
6868
import com.comphenix.protocol.wrappers.WrappedWatchableObject;
69+
import com.comphenix.protocol.wrappers.WrappedWeightedList;
6970
import com.comphenix.protocol.wrappers.nbt.NbtBase;
7071
import com.comphenix.protocol.wrappers.nbt.NbtCompound;
7172
import com.comphenix.protocol.wrappers.nbt.NbtFactory;
@@ -815,6 +816,20 @@ public StructureModifier<WrappedParticle> getNewParticles() {
815816
);
816817
}
817818

819+
/**
820+
* Retrieve a read/write structure for WeightedList fields.
821+
*
822+
* @param elementConverter converter for the element type inside each weighted entry
823+
* @param <T> the Bukkit-side element type
824+
* @return A modifier for WeightedList fields.
825+
*/
826+
public <T> StructureModifier<WrappedWeightedList<T>> getWeightedLists(
827+
EquivalentConverter<T> elementConverter) {
828+
return structureModifier.withType(
829+
WrappedWeightedList.getNmsClass(),
830+
WrappedWeightedList.getConverter(elementConverter));
831+
}
832+
818833
/**
819834
* Retrieve a read/write structure for the MobEffectList class in 1.9.
820835
* @return A modifier for MobEffectList fields.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.comphenix.protocol.injector;
2+
3+
import com.comphenix.protocol.PacketType;
4+
import com.comphenix.protocol.reflect.EquivalentConverter;
5+
import com.comphenix.protocol.reflect.accessors.Accessors;
6+
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
7+
import com.comphenix.protocol.utility.Tuple;
8+
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
12+
public class EquivalentConstructor {
13+
private final PacketType packetType;
14+
private final List<Tuple<Class<?>, EquivalentConverter<?>>> converters = new ArrayList<>();
15+
16+
private ConstructorAccessor constructorAccessor;
17+
18+
public EquivalentConstructor(PacketType packetType) {
19+
this.packetType = packetType;
20+
}
21+
22+
public EquivalentConstructor withParam(Class<?> param, EquivalentConverter<?> converter) {
23+
converters.add(new Tuple<>(param, converter));
24+
return this;
25+
}
26+
27+
public EquivalentConstructor withParam(Class<?> param) {
28+
converters.add(new Tuple<>(param, null));
29+
return this;
30+
}
31+
32+
@SuppressWarnings({"unchecked", "rawtypes"})
33+
public Object create(Object... args) {
34+
if (constructorAccessor == null) {
35+
Class<?>[] params = new Class<?>[converters.size()];
36+
for (int i = 0; i < converters.size(); i++) {
37+
params[i] = converters.get(i).first();
38+
}
39+
constructorAccessor = Accessors.getConstructorAccessor(packetType.getPacketClass(), params);
40+
}
41+
42+
Object[] convertedArgs = new Object[args.length];
43+
44+
int i = 0;
45+
for (Tuple<Class<?>, EquivalentConverter<?>> entry : converters) {
46+
EquivalentConverter converter = (EquivalentConverter) entry.second();
47+
convertedArgs[i] = converter != null ? converter.getGeneric(args[i]) : args[i];
48+
i++;
49+
}
50+
51+
return constructorAccessor.invoke(convertedArgs);
52+
}
53+
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.comphenix.protocol.error.RethrowErrorReporter;
2222
import com.comphenix.protocol.events.PacketContainer;
2323
import com.comphenix.protocol.injector.packet.PacketRegistry;
24+
import com.comphenix.protocol.reflect.EquivalentConverter;
2425
import com.comphenix.protocol.reflect.FieldAccessException;
2526
import com.comphenix.protocol.wrappers.BukkitConverters;
2627
import com.google.common.collect.ImmutableList;
@@ -29,7 +30,10 @@
2930

3031
import java.lang.reflect.Constructor;
3132
import java.lang.reflect.InvocationTargetException;
33+
import java.util.HashMap;
34+
import java.util.LinkedHashMap;
3235
import java.util.List;
36+
import java.util.Map;
3337

3438
/**
3539
* A packet constructor that uses an internal Minecraft.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package com.comphenix.protocol.utility;
2+
3+
public record Tuple<A, B>(A first, B second) {}

src/main/java/com/comphenix/protocol/wrappers/CustomPacketPayloadWrapper.java

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,29 +48,61 @@ public final class CustomPacketPayloadWrapper {
4848
private static final MethodAccessor GET_ID_PAYLOAD_METHOD;
4949
private static final MethodAccessor SERIALIZE_PAYLOAD_METHOD;
5050

51+
/** True when running on MC 1.21.5+ where DiscardedPayload is used instead of the ByteBuddy proxy. */
52+
private static final boolean USE_DISCARDED_PAYLOAD;
53+
5154
private static final EquivalentConverter<CustomPacketPayloadWrapper> CONVERTER;
5255

5356
static {
5457
try {
5558
MINECRAFT_KEY_CLASS = MinecraftReflection.getMinecraftKeyClass();
5659
CUSTOM_PACKET_PAYLOAD_CLASS = MinecraftReflection.getMinecraftClass("network.protocol.common.custom.CustomPacketPayload");
5760

58-
Method getPayloadId = FuzzyReflection.fromClass(CUSTOM_PACKET_PAYLOAD_CLASS).getMethod(FuzzyMethodContract.newBuilder()
59-
.banModifier(Modifier.STATIC)
60-
.returnTypeExact(MINECRAFT_KEY_CLASS)
61-
.parameterCount(0)
62-
.build());
61+
// MC 1.21.5+: CustomPacketPayload no longer has id(); DiscardedPayload is the fallback payload
62+
// MC < 1.21.5: CustomPacketPayload.id() returns Identifier directly
63+
Method getPayloadId = null;
64+
boolean useDiscardedPayload = false;
65+
try {
66+
getPayloadId = FuzzyReflection.fromClass(CUSTOM_PACKET_PAYLOAD_CLASS).getMethod(FuzzyMethodContract.newBuilder()
67+
.banModifier(Modifier.STATIC)
68+
.returnTypeExact(MINECRAFT_KEY_CLASS)
69+
.parameterCount(0)
70+
.build());
71+
} catch (IllegalArgumentException ignored) {
72+
// New API: id() lives on DiscardedPayload, not on CustomPacketPayload
73+
Class<?> discardedPayloadClass = MinecraftReflection.getMinecraftClass(
74+
"network.protocol.common.custom.DiscardedPayload");
75+
getPayloadId = discardedPayloadClass.getMethod("id");
76+
useDiscardedPayload = true;
77+
}
6378
GET_ID_PAYLOAD_METHOD = Accessors.getMethodAccessor(getPayloadId);
79+
USE_DISCARDED_PAYLOAD = useDiscardedPayload;
6480

65-
Method serializePayloadData = FuzzyReflection.fromClass(CUSTOM_PACKET_PAYLOAD_CLASS).getMethod(FuzzyMethodContract.newBuilder()
66-
.banModifier(Modifier.STATIC)
67-
.returnTypeVoid()
68-
.parameterCount(1)
69-
.parameterDerivedOf(ByteBuf.class, 0)
70-
.build());
71-
SERIALIZE_PAYLOAD_METHOD = Accessors.getMethodAccessor(serializePayloadData);
81+
// serialize method may not exist in new API
82+
Method serializePayloadData = null;
83+
try {
84+
serializePayloadData = FuzzyReflection.fromClass(CUSTOM_PACKET_PAYLOAD_CLASS).getMethod(FuzzyMethodContract.newBuilder()
85+
.banModifier(Modifier.STATIC)
86+
.returnTypeVoid()
87+
.parameterCount(1)
88+
.parameterDerivedOf(ByteBuf.class, 0)
89+
.build());
90+
} catch (IllegalArgumentException ignored) {
91+
// Not present in new API
92+
}
93+
SERIALIZE_PAYLOAD_METHOD = serializePayloadData != null
94+
? Accessors.getMethodAccessor(serializePayloadData) : null;
7295

73-
Constructor<?> payloadWrapperConstructor = makePayloadWrapper();
96+
Constructor<?> payloadWrapperConstructor;
97+
if (useDiscardedPayload) {
98+
// New API: use DiscardedPayload(Identifier, ByteBuf) as the payload handle
99+
Class<?> discardedPayloadClass = MinecraftReflection.getMinecraftClass(
100+
"network.protocol.common.custom.DiscardedPayload");
101+
payloadWrapperConstructor = discardedPayloadClass.getConstructor(
102+
MINECRAFT_KEY_CLASS, ByteBuf.class);
103+
} else {
104+
payloadWrapperConstructor = makePayloadWrapper();
105+
}
74106
PAYLOAD_WRAPPER_CONSTRUCTOR = Accessors.getConstructorAccessor(payloadWrapperConstructor);
75107

76108
CONVERTER = new EquivalentConverter<CustomPacketPayloadWrapper>() {
@@ -185,6 +217,9 @@ public static CustomPacketPayloadWrapper fromUnknownPayload(Object payload) {
185217
return data;
186218
})
187219
.orElseGet(() -> {
220+
if (SERIALIZE_PAYLOAD_METHOD == null) {
221+
return new byte[0];
222+
}
188223
ByteBuf buffer = Unpooled.buffer();
189224
Object serializer = MinecraftReflection.getPacketDataSerializer(buffer);
190225
SERIALIZE_PAYLOAD_METHOD.invoke(payload, serializer);
@@ -230,6 +265,11 @@ public MinecraftKey getId() {
230265
* @return a new payload wrapper instance using the provided message id and payload.
231266
*/
232267
public Object newHandle() {
268+
if (USE_DISCARDED_PAYLOAD) {
269+
// New API: DiscardedPayload(Identifier, ByteBuf)
270+
ByteBuf buf = Unpooled.copiedBuffer(this.payload);
271+
return PAYLOAD_WRAPPER_CONSTRUCTOR.invoke(this.getGenericId(), buf);
272+
}
233273
return PAYLOAD_WRAPPER_CONSTRUCTOR.invoke(this.getGenericId(), this.payload);
234274
}
235275

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package com.comphenix.protocol.wrappers;
2+
3+
import java.util.Objects;
4+
5+
import com.comphenix.protocol.events.InternalStructure;
6+
import com.comphenix.protocol.reflect.EquivalentConverter;
7+
import com.comphenix.protocol.reflect.accessors.Accessors;
8+
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
9+
import com.comphenix.protocol.utility.MinecraftReflection;
10+
11+
/**
12+
* Wraps the NMS {@code ExplosionParticleInfo} record, which pairs a
13+
* {@link WrappedParticle} with scaling and speed float values.
14+
*
15+
* <p>NMS record: {@code ExplosionParticleInfo(ParticleOptions particle, float scaling, float speed)}
16+
*/
17+
public class WrappedExplosionParticleInfo {
18+
19+
private static Class<?> NMS_CLASS;
20+
private static ConstructorAccessor NMS_CTOR;
21+
22+
private static synchronized void ensureReflection() {
23+
if (NMS_CLASS != null) {
24+
return;
25+
}
26+
NMS_CLASS = MinecraftReflection.getMinecraftClass("core.particles.ExplosionParticleInfo");
27+
NMS_CTOR = Accessors.getConstructorAccessor(
28+
NMS_CLASS,
29+
MinecraftReflection.getParticleParam(),
30+
float.class,
31+
float.class);
32+
}
33+
34+
/**
35+
* Returns the NMS {@code ExplosionParticleInfo} class.
36+
*/
37+
public static Class<?> getNmsClass() {
38+
ensureReflection();
39+
return NMS_CLASS;
40+
}
41+
42+
// ── Instance data ────────────────────────────────────────────────────
43+
44+
private WrappedParticle<?> particle;
45+
private float scaling;
46+
private float speed;
47+
48+
public WrappedExplosionParticleInfo() {
49+
this.scaling = 1.0f;
50+
this.speed = 1.0f;
51+
}
52+
53+
public WrappedExplosionParticleInfo(WrappedParticle<?> particle, float scaling, float speed) {
54+
this.particle = particle;
55+
this.scaling = scaling;
56+
this.speed = speed;
57+
}
58+
59+
public WrappedParticle<?> getParticle() {
60+
return particle;
61+
}
62+
63+
public void setParticle(WrappedParticle<?> particle) {
64+
this.particle = particle;
65+
}
66+
67+
public float getScaling() {
68+
return scaling;
69+
}
70+
71+
public void setScaling(float scaling) {
72+
this.scaling = scaling;
73+
}
74+
75+
public float getSpeed() {
76+
return speed;
77+
}
78+
79+
public void setSpeed(float speed) {
80+
this.speed = speed;
81+
}
82+
83+
// ── Converter ────────────────────────────────────────────────────────
84+
85+
/**
86+
* Reads an NMS {@code ExplosionParticleInfo} into this wrapper via
87+
* {@link InternalStructure} typed getters.
88+
*/
89+
public static WrappedExplosionParticleInfo fromHandle(InternalStructure handle) {
90+
WrappedParticle<?> particle = handle.getNewParticles().read(0);
91+
float scaling = handle.getFloat().read(0);
92+
float speed = handle.getFloat().read(1);
93+
return new WrappedExplosionParticleInfo(particle, scaling, speed);
94+
}
95+
96+
/**
97+
* Returns an {@link EquivalentConverter} between {@code WrappedExplosionParticleInfo}
98+
* and the NMS {@code ExplosionParticleInfo} record.
99+
*/
100+
@SuppressWarnings({"unchecked", "rawtypes"})
101+
public static EquivalentConverter<WrappedExplosionParticleInfo> getConverter() {
102+
return new EquivalentConverter<>() {
103+
104+
@Override
105+
public WrappedExplosionParticleInfo getSpecific(Object generic) {
106+
InternalStructure structure = InternalStructure.getConverter().getSpecific(generic);
107+
return fromHandle(structure);
108+
}
109+
110+
@Override
111+
public Object getGeneric(WrappedExplosionParticleInfo specific) {
112+
ensureReflection();
113+
EquivalentConverter particleConverter = BukkitConverters.getParticleConverter();
114+
Object nmsParticle = particleConverter.getGeneric(specific.particle);
115+
return NMS_CTOR.invoke(nmsParticle, specific.scaling, specific.speed);
116+
}
117+
118+
@Override
119+
public Class<WrappedExplosionParticleInfo> getSpecificType() {
120+
return WrappedExplosionParticleInfo.class;
121+
}
122+
};
123+
}
124+
125+
// ── Object methods ───────────────────────────────────────────────────
126+
127+
@Override
128+
public boolean equals(Object o) {
129+
if (this == o) return true;
130+
if (!(o instanceof WrappedExplosionParticleInfo that)) return false;
131+
return Float.compare(scaling, that.scaling) == 0
132+
&& Float.compare(speed, that.speed) == 0
133+
&& Objects.equals(particle, that.particle);
134+
}
135+
136+
@Override
137+
public int hashCode() {
138+
return Objects.hash(particle, scaling, speed);
139+
}
140+
141+
@Override
142+
public String toString() {
143+
return "WrappedExplosionParticleInfo{particle=" + particle
144+
+ ", scaling=" + scaling + ", speed=" + speed + "}";
145+
}
146+
}
147+

src/main/java/com/comphenix/protocol/wrappers/WrappedPositionMoveRotation.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,23 @@ public Class<WrappedPositionMoveRotation> getSpecificType() {
113113
public float getPitch() { return pitch; }
114114
public void setPitch(float pitch) { this.pitch = pitch; }
115115

116+
@Override
117+
public boolean equals(Object o) {
118+
if (this == o) return true;
119+
if (!(o instanceof WrappedPositionMoveRotation other)) return false;
120+
return Double.compare(x, other.x) == 0 && Double.compare(y, other.y) == 0
121+
&& Double.compare(z, other.z) == 0
122+
&& Double.compare(deltaX, other.deltaX) == 0
123+
&& Double.compare(deltaY, other.deltaY) == 0
124+
&& Double.compare(deltaZ, other.deltaZ) == 0
125+
&& Float.compare(yaw, other.yaw) == 0 && Float.compare(pitch, other.pitch) == 0;
126+
}
127+
128+
@Override
129+
public int hashCode() {
130+
return java.util.Objects.hash(x, y, z, deltaX, deltaY, deltaZ, yaw, pitch);
131+
}
132+
116133
@Override
117134
public String toString() {
118135
return "WrappedPositionMoveRotation{pos=(" + x + ", " + y + ", " + z + ")"

0 commit comments

Comments
 (0)