mirror of
https://github.com/dmulloy2/ProtocolLib.git
synced 2026-11-04 17:00:19 -05:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b84420b03b | ||
|
|
f84475e51a |
No files matched your search
@@ -5,6 +5,7 @@ import java.time.Instant;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -28,7 +29,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
import com.comphenix.protocol.reflect.FieldAccessException;
|
||||
import com.comphenix.protocol.reflect.StructureModifier;
|
||||
import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.utility.StreamSerializer;
|
||||
@@ -662,11 +665,88 @@ public abstract class AbstractStructure {
|
||||
* @return A modifier for EntityUseAction class fields.
|
||||
*/
|
||||
public StructureModifier<WrappedEnumEntityUseAction> getEnumEntityUseActions() {
|
||||
if (MinecraftVersion.v26_1.atOrAbove()) {
|
||||
return new EntityUseActionModifier(structureModifier);
|
||||
}
|
||||
|
||||
return structureModifier.withType(
|
||||
MinecraftReflection.getEnumEntityUseActionClass(),
|
||||
WrappedEnumEntityUseAction.CONVERTER);
|
||||
}
|
||||
|
||||
private static final class EntityUseActionModifier extends StructureModifier<WrappedEnumEntityUseAction> {
|
||||
private final StructureModifier<Object> packetModifier;
|
||||
|
||||
private EntityUseActionModifier(StructureModifier<Object> packetModifier) {
|
||||
this.packetModifier = packetModifier;
|
||||
List<FieldAccessor> fields = this.packetModifier
|
||||
.withType(MinecraftReflection.getVec3DClass())
|
||||
.getFields();
|
||||
this.initialize(
|
||||
packetModifier.getTargetType(),
|
||||
MinecraftReflection.getVec3DClass(),
|
||||
fields,
|
||||
Map.of(),
|
||||
null,
|
||||
new HashMap<>());
|
||||
this.target = packetModifier.getTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedEnumEntityUseAction read(int fieldIndex) {
|
||||
this.checkEntityUseActionIndex(fieldIndex);
|
||||
return WrappedEnumEntityUseAction.fromHandle(this.target);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrappedEnumEntityUseAction readSafely(int fieldIndex) {
|
||||
return fieldIndex == 0 && this.target != null
|
||||
? WrappedEnumEntityUseAction.fromHandle(this.target)
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureModifier<WrappedEnumEntityUseAction> write(
|
||||
int fieldIndex,
|
||||
WrappedEnumEntityUseAction value
|
||||
) {
|
||||
this.checkEntityUseActionIndex(fieldIndex);
|
||||
Preconditions.checkNotNull(value, "value cannot be null");
|
||||
|
||||
this.packetModifier
|
||||
.withType(EnumWrappers.getHandClass(), EnumWrappers.getHandConverter())
|
||||
.write(0, value.getHand());
|
||||
this.packetModifier
|
||||
.withType(MinecraftReflection.getVec3DClass(), BukkitConverters.getVectorConverter())
|
||||
.write(0, value.getPosition());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureModifier<WrappedEnumEntityUseAction> writeSafely(
|
||||
int fieldIndex,
|
||||
WrappedEnumEntityUseAction value
|
||||
) {
|
||||
return fieldIndex == 0 ? this.write(fieldIndex, value) : this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureModifier<WrappedEnumEntityUseAction> withTarget(Object target) {
|
||||
return new EntityUseActionModifier(this.packetModifier.withTarget(target));
|
||||
}
|
||||
|
||||
private void checkEntityUseActionIndex(int fieldIndex) {
|
||||
if (this.target == null) {
|
||||
throw new IllegalStateException("Cannot access a modifier with no packet handle");
|
||||
}
|
||||
if (fieldIndex != 0) {
|
||||
throw FieldAccessException.fromFormat(
|
||||
"Field index %d is out of bounds for length 1",
|
||||
fieldIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a read/write structure for the NativeGameMode enum in 1.7.2.
|
||||
* @return A modifier for NativeGameMode enum fields.
|
||||
|
||||
@@ -1235,9 +1235,13 @@ public final class MinecraftReflection {
|
||||
/**
|
||||
* Retrieves the entity use action class in 1.17.
|
||||
*
|
||||
* @return The EntityUseAction class
|
||||
* @return The EntityUseAction class, or {@code null} if it was removed in 26.1
|
||||
*/
|
||||
public static Class<?> getEnumEntityUseActionClass() {
|
||||
if (MinecraftVersion.v26_1.atOrAbove()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getOrInferMinecraftClass("ServerboundInteractPacket.Action", () -> {
|
||||
Class<?> packetClass = PacketType.Play.Client.USE_ENTITY.getPacketClass();
|
||||
FuzzyReflection fuzzyReflection = FuzzyReflection.fromClass(packetClass, true);
|
||||
@@ -1261,10 +1265,15 @@ public final class MinecraftReflection {
|
||||
/**
|
||||
* Get a method accessor to get the actual use action out of the wrapping EnumEntityUseAction in 1.17.
|
||||
*
|
||||
* @return a method accessor to get the actual use action
|
||||
* @return a method accessor to get the actual use action, or {@code null} if it was removed in 26.1
|
||||
*/
|
||||
public static MethodAccessor getEntityUseActionEnumMethodAccessor() {
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(MinecraftReflection.getEnumEntityUseActionClass(), true);
|
||||
Class<?> actionClass = MinecraftReflection.getEnumEntityUseActionClass();
|
||||
if (actionClass == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
FuzzyReflection fuzzy = FuzzyReflection.fromClass(actionClass, true);
|
||||
return Accessors.getMethodAccessor(fuzzy.getMethod(FuzzyMethodContract.newBuilder()
|
||||
.returnTypeExact(EnumWrappers.getEntityUseActionClass())
|
||||
.build()));
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.comphenix.protocol.wrappers;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import com.comphenix.protocol.PacketType;
|
||||
import com.comphenix.protocol.reflect.EquivalentConverter;
|
||||
@@ -12,6 +13,7 @@ import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.accessors.MethodAccessor;
|
||||
import com.comphenix.protocol.reflect.fuzzy.FuzzyFieldContract;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.EntityUseAction;
|
||||
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
|
||||
|
||||
@@ -28,21 +30,30 @@ public class WrappedEnumEntityUseAction extends AbstractWrapper implements Clona
|
||||
|
||||
private static final Class<?> PACKET_CLASS = PacketType.Play.Client.USE_ENTITY.getPacketClass();
|
||||
private static final Class<?>[] DECLARED_CLASSES = PACKET_CLASS.getDeclaredClasses();
|
||||
private static final boolean ACTION_CLASS_REMOVED = MinecraftVersion.v26_1.atOrAbove();
|
||||
|
||||
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getEnumEntityUseActionClass();
|
||||
private static final MethodAccessor ACTION_USE = MinecraftReflection.getEntityUseActionEnumMethodAccessor();
|
||||
private static final Class<?> HANDLE_TYPE = ACTION_CLASS_REMOVED
|
||||
? PACKET_CLASS
|
||||
: MinecraftReflection.getEnumEntityUseActionClass();
|
||||
private static final MethodAccessor ACTION_USE = ACTION_CLASS_REMOVED
|
||||
? null
|
||||
: MinecraftReflection.getEntityUseActionEnumMethodAccessor();
|
||||
|
||||
private static final ConstructorAccessor INTERACT = useAction(EnumWrappers.getHandClass());
|
||||
private static final ConstructorAccessor INTERACT_AT = useAction(EnumWrappers.getHandClass(),
|
||||
MinecraftReflection.getVec3DClass());
|
||||
private static final ConstructorAccessor PACKET_CONSTRUCTOR = ACTION_CLASS_REMOVED
|
||||
? Accessors.getConstructorAccessor(PACKET_CLASS, int.class, EnumWrappers.getHandClass(),
|
||||
MinecraftReflection.getVec3DClass(), boolean.class)
|
||||
: null;
|
||||
private static final ConstructorAccessor INTERACT = ACTION_CLASS_REMOVED
|
||||
? null
|
||||
: useAction(EnumWrappers.getHandClass());
|
||||
private static final ConstructorAccessor INTERACT_AT = ACTION_CLASS_REMOVED
|
||||
? null
|
||||
: useAction(EnumWrappers.getHandClass(), MinecraftReflection.getVec3DClass());
|
||||
|
||||
private static final Object ATTACK = Accessors.getFieldAccessor(FuzzyReflection.fromClass(PACKET_CLASS, true)
|
||||
.getField(FuzzyFieldContract.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.typeExact(MinecraftReflection.getEnumEntityUseActionClass())
|
||||
.build())
|
||||
).get(null);
|
||||
private static final WrappedEnumEntityUseAction ATTACK_WRAPPER = new WrappedEnumEntityUseAction(ATTACK);
|
||||
private static final Object ATTACK = ACTION_CLASS_REMOVED ? null : getAttackHandle();
|
||||
private static final WrappedEnumEntityUseAction ATTACK_WRAPPER = ATTACK == null
|
||||
? null
|
||||
: new WrappedEnumEntityUseAction(ATTACK);
|
||||
|
||||
private final EntityUseAction action;
|
||||
// these fields are only available for interact & interact_at
|
||||
@@ -57,7 +68,18 @@ public class WrappedEnumEntityUseAction extends AbstractWrapper implements Clona
|
||||
super(HANDLE_TYPE);
|
||||
setHandle(handle);
|
||||
|
||||
action = EnumWrappers.getEntityUseActionConverter().getSpecific(ACTION_USE.invoke(handle));
|
||||
action = ACTION_CLASS_REMOVED
|
||||
? EntityUseAction.INTERACT_AT
|
||||
: EnumWrappers.getEntityUseActionConverter().getSpecific(ACTION_USE.invoke(handle));
|
||||
}
|
||||
|
||||
private static Object getAttackHandle() {
|
||||
return Accessors.getFieldAccessor(FuzzyReflection.fromClass(PACKET_CLASS, true)
|
||||
.getField(FuzzyFieldContract.newBuilder()
|
||||
.requireModifier(Modifier.STATIC)
|
||||
.typeExact(MinecraftReflection.getEnumEntityUseActionClass())
|
||||
.build())
|
||||
).get(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,6 +113,10 @@ public class WrappedEnumEntityUseAction extends AbstractWrapper implements Clona
|
||||
* @return the action for an entity attack.
|
||||
*/
|
||||
public static WrappedEnumEntityUseAction attack() {
|
||||
if (ATTACK_WRAPPER == null) {
|
||||
throw new UnsupportedOperationException("Attack uses its own packet in 26.1 and above");
|
||||
}
|
||||
|
||||
return ATTACK_WRAPPER;
|
||||
}
|
||||
|
||||
@@ -100,6 +126,10 @@ public class WrappedEnumEntityUseAction extends AbstractWrapper implements Clona
|
||||
* @return the action for an interact.
|
||||
*/
|
||||
public static WrappedEnumEntityUseAction interact(Hand hand) {
|
||||
if (ACTION_CLASS_REMOVED) {
|
||||
return interactAt(hand, new Vector());
|
||||
}
|
||||
|
||||
Object handle = INTERACT.invoke(EnumWrappers.getHandConverter().getGeneric(hand));
|
||||
return new WrappedEnumEntityUseAction(handle);
|
||||
}
|
||||
@@ -111,8 +141,11 @@ public class WrappedEnumEntityUseAction extends AbstractWrapper implements Clona
|
||||
* @return the action for an interact_at.
|
||||
*/
|
||||
public static WrappedEnumEntityUseAction interactAt(Hand hand, Vector vector) {
|
||||
Object handle = INTERACT_AT.invoke(EnumWrappers.getHandConverter().getGeneric(hand),
|
||||
BukkitConverters.getVectorConverter().getGeneric(vector));
|
||||
Object genericHand = EnumWrappers.getHandConverter().getGeneric(hand);
|
||||
Object genericVector = BukkitConverters.getVectorConverter().getGeneric(vector);
|
||||
Object handle = ACTION_CLASS_REMOVED
|
||||
? PACKET_CONSTRUCTOR.invoke(0, genericHand, genericVector, false)
|
||||
: INTERACT_AT.invoke(genericHand, genericVector);
|
||||
return new WrappedEnumEntityUseAction(handle);
|
||||
}
|
||||
|
||||
@@ -174,6 +207,48 @@ public class WrappedEnumEntityUseAction extends AbstractWrapper implements Clona
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!ACTION_CLASS_REMOVED) {
|
||||
return super.equals(obj);
|
||||
}
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof WrappedEnumEntityUseAction)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WrappedEnumEntityUseAction that = (WrappedEnumEntityUseAction) obj;
|
||||
if (this.action != that.action) {
|
||||
return false;
|
||||
}
|
||||
if (this.action == EntityUseAction.ATTACK) {
|
||||
return true;
|
||||
}
|
||||
if (!Objects.equals(this.getHand(), that.getHand())) {
|
||||
return false;
|
||||
}
|
||||
return this.action != EntityUseAction.INTERACT_AT
|
||||
|| Objects.equals(this.getPosition(), that.getPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (!ACTION_CLASS_REMOVED) {
|
||||
return super.hashCode();
|
||||
}
|
||||
|
||||
int result = this.action.hashCode();
|
||||
if (this.action != EntityUseAction.ATTACK) {
|
||||
result = 31 * result + this.getHand().hashCode();
|
||||
}
|
||||
if (this.action == EntityUseAction.INTERACT_AT) {
|
||||
result = 31 * result + this.getPosition().hashCode();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a field accessor for the hand in the interact and interact_at type.
|
||||
* @return a field accessor for the hand field.
|
||||
|
||||
@@ -23,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
@@ -68,6 +69,7 @@ import com.comphenix.protocol.reflect.accessors.FieldAccessor;
|
||||
import com.comphenix.protocol.reflect.cloning.SerializableCloner;
|
||||
import com.comphenix.protocol.utility.MinecraftMethods;
|
||||
import com.comphenix.protocol.utility.MinecraftReflection;
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import com.comphenix.protocol.wrappers.BlockPosition;
|
||||
import com.comphenix.protocol.wrappers.BukkitConverters;
|
||||
import com.comphenix.protocol.wrappers.ComponentConverter;
|
||||
@@ -753,16 +755,60 @@ public class PacketContainerTest {
|
||||
assertEquals(2, (int) packet.getGameStateIDs().read(0));
|
||||
}
|
||||
|
||||
// @Test
|
||||
// TODO: needs to be fixed for 26.1
|
||||
@Test
|
||||
public void testUseEntity() {
|
||||
if (MinecraftVersion.v26_1.atOrAbove()) {
|
||||
testUseEntityWithoutActionClass();
|
||||
} else {
|
||||
testUseEntityWithActionClass();
|
||||
}
|
||||
}
|
||||
|
||||
private void testUseEntityWithoutActionClass() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Client.USE_ENTITY);
|
||||
packet.getIntegers().write(0, 42);
|
||||
packet.getBooleans().write(0, true);
|
||||
|
||||
StructureModifier<WrappedEnumEntityUseAction> actionModifier = packet.getEnumEntityUseActions();
|
||||
assertEquals(1, actionModifier.size());
|
||||
assertEquals(1, actionModifier.getFields().size());
|
||||
assertSame(packet.getHandle(), actionModifier.getTarget());
|
||||
assertSame(packet.getHandle().getClass(), actionModifier.getTargetType());
|
||||
actionModifier.getField(0);
|
||||
actionModifier.writeDefaults();
|
||||
assertNull(actionModifier.readSafely(1));
|
||||
actionModifier.writeSafely(1, WrappedEnumEntityUseAction.interact(Hand.MAIN_HAND));
|
||||
assertThrows(UnsupportedOperationException.class, WrappedEnumEntityUseAction::attack);
|
||||
|
||||
Vector position = new Vector(1, 199, 4);
|
||||
packet.getEnumEntityUseActions().write(0, WrappedEnumEntityUseAction.interactAt(Hand.MAIN_HAND, position));
|
||||
WrappedEnumEntityUseAction action = packet.getEnumEntityUseActions().read(0);
|
||||
assertEquals(EntityUseAction.INTERACT_AT, action.getAction());
|
||||
assertEquals(Hand.MAIN_HAND, action.getHand());
|
||||
assertEquals(position, action.getPosition());
|
||||
assertEquals(42, packet.getIntegers().read(0));
|
||||
assertTrue(packet.getBooleans().read(0));
|
||||
|
||||
WrappedEnumEntityUseAction clone = action.deepClone();
|
||||
assertEquals(EntityUseAction.INTERACT_AT, clone.getAction());
|
||||
assertEquals(Hand.MAIN_HAND, clone.getHand());
|
||||
assertEquals(position, clone.getPosition());
|
||||
assertEquals(action, clone);
|
||||
assertEquals(action.hashCode(), clone.hashCode());
|
||||
|
||||
packet.getEnumEntityUseActions().write(0, WrappedEnumEntityUseAction.interact(Hand.OFF_HAND));
|
||||
action = packet.getEnumEntityUseActions().read(0);
|
||||
assertEquals(EntityUseAction.INTERACT_AT, action.getAction());
|
||||
assertEquals(Hand.OFF_HAND, action.getHand());
|
||||
assertEquals(new Vector(), action.getPosition());
|
||||
}
|
||||
|
||||
private void testUseEntityWithActionClass() {
|
||||
PacketContainer packet = new PacketContainer(PacketType.Play.Client.USE_ENTITY);
|
||||
|
||||
WrappedEnumEntityUseAction action;
|
||||
WrappedEnumEntityUseAction clone;
|
||||
// test attack
|
||||
packet.getEnumEntityUseActions().write(0, WrappedEnumEntityUseAction.attack());
|
||||
action = packet.getEnumEntityUseActions().read(0);
|
||||
WrappedEnumEntityUseAction action = packet.getEnumEntityUseActions().read(0);
|
||||
// attack's handle should always be the same
|
||||
assertEquals(WrappedEnumEntityUseAction.attack(), action);
|
||||
assertEquals(EntityUseAction.ATTACK, action.getAction());
|
||||
@@ -770,7 +816,7 @@ public class PacketContainerTest {
|
||||
assertThrows(IllegalArgumentException.class, action::getHand);
|
||||
assertThrows(IllegalArgumentException.class, action::getPosition);
|
||||
// test cloning
|
||||
clone = action.deepClone();
|
||||
WrappedEnumEntityUseAction clone = action.deepClone();
|
||||
assertSame(WrappedEnumEntityUseAction.attack(), clone);
|
||||
|
||||
// test interact
|
||||
|
||||
Reference in new issue
Block a user