201 lines
7.2 KiB
Java
201 lines
7.2 KiB
Java
package com.comphenix.protocol.wrappers;
|
|
|
|
import java.lang.reflect.Modifier;
|
|
import java.util.Arrays;
|
|
|
|
import com.comphenix.protocol.PacketType;
|
|
import com.comphenix.protocol.reflect.EquivalentConverter;
|
|
import com.comphenix.protocol.reflect.FuzzyReflection;
|
|
import com.comphenix.protocol.reflect.accessors.Accessors;
|
|
import com.comphenix.protocol.reflect.accessors.ConstructorAccessor;
|
|
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.wrappers.EnumWrappers.EntityUseAction;
|
|
import com.comphenix.protocol.wrappers.EnumWrappers.Hand;
|
|
|
|
import org.bukkit.util.Vector;
|
|
|
|
/**
|
|
* Represents an entity used action used in the UseEntity packet sent by the client.
|
|
* @author derklaro
|
|
*/
|
|
public class WrappedEnumEntityUseAction extends AbstractWrapper implements ClonableWrapper {
|
|
|
|
public static final EquivalentConverter<WrappedEnumEntityUseAction> CONVERTER = Converters.handle(AbstractWrapper::getHandle,
|
|
WrappedEnumEntityUseAction::fromHandle, WrappedEnumEntityUseAction.class);
|
|
|
|
private static final Class<?> PACKET_CLASS = PacketType.Play.Client.USE_ENTITY.getPacketClass();
|
|
private static final Class<?>[] DECLARED_CLASSES = PACKET_CLASS.getDeclaredClasses();
|
|
|
|
private static final Class<?> HANDLE_TYPE = MinecraftReflection.getEnumEntityUseActionClass();
|
|
private static final MethodAccessor ACTION_USE = MinecraftReflection.getEntityUseActionEnumMethodAccessor();
|
|
|
|
private static final ConstructorAccessor INTERACT = useAction(EnumWrappers.getHandClass());
|
|
private static final ConstructorAccessor INTERACT_AT = 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 final EntityUseAction action;
|
|
// these fields are only available for interact & interact_at
|
|
private FieldAccessor handAccessor;
|
|
private FieldAccessor positionAccessor;
|
|
|
|
/**
|
|
* Construct a new wrapper for the entity use action class in the UseEntity packet.
|
|
* @param handle - the NMS handle.
|
|
*/
|
|
private WrappedEnumEntityUseAction(Object handle) {
|
|
super(HANDLE_TYPE);
|
|
setHandle(handle);
|
|
|
|
action = EnumWrappers.getEntityUseActionConverter().getSpecific(ACTION_USE.invoke(handle));
|
|
}
|
|
|
|
/**
|
|
* Finds a constructor of a declared class in the UseEntity class. Used to find the action class implementations.
|
|
* @param parameterTypes - the types the constructor of the class must have.
|
|
* @return a constructor for a matching class.
|
|
* @throws IllegalArgumentException if no constructor was found.
|
|
*/
|
|
private static ConstructorAccessor useAction(Class<?>... parameterTypes) {
|
|
for (Class<?> subClass : DECLARED_CLASSES) {
|
|
ConstructorAccessor accessor = Accessors.getConstructorAccessorOrNull(subClass, parameterTypes);
|
|
if (accessor != null) {
|
|
return accessor;
|
|
}
|
|
}
|
|
throw new IllegalArgumentException(
|
|
"No constructor with " + Arrays.toString(parameterTypes) + " in " + PACKET_CLASS);
|
|
}
|
|
|
|
/**
|
|
* Construct a new wrapper for the entity use action class in the UseEntity packet.
|
|
* @param handle - the NMS handle.
|
|
* @return the created wrapper.
|
|
*/
|
|
public static WrappedEnumEntityUseAction fromHandle(Object handle) {
|
|
return new WrappedEnumEntityUseAction(handle);
|
|
}
|
|
|
|
/**
|
|
* Get the jvm static action for attacking an entity.
|
|
* @return the action for an entity attack.
|
|
*/
|
|
public static WrappedEnumEntityUseAction attack() {
|
|
return ATTACK_WRAPPER;
|
|
}
|
|
|
|
/**
|
|
* Get an action for interacting with an entity.
|
|
* @param hand - the hand used for the interact.
|
|
* @return the action for an interact.
|
|
*/
|
|
public static WrappedEnumEntityUseAction interact(Hand hand) {
|
|
Object handle = INTERACT.invoke(EnumWrappers.getHandConverter().getGeneric(hand));
|
|
return new WrappedEnumEntityUseAction(handle);
|
|
}
|
|
|
|
/**
|
|
* Get an action for interacting with an entity at a specific location.
|
|
* @param hand - the hand used for the interact.
|
|
* @param vector - the position of the interact.
|
|
* @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));
|
|
return new WrappedEnumEntityUseAction(handle);
|
|
}
|
|
|
|
/**
|
|
* Get the action used for the interact.
|
|
* @return the interact action.
|
|
*/
|
|
public EntityUseAction getAction() {
|
|
return action;
|
|
}
|
|
|
|
/**
|
|
* Get the hand used for the interact. Only available if this represents interact or interact_at.
|
|
* @return the hand used for the interact.
|
|
* @throws IllegalArgumentException if called for attack.
|
|
*/
|
|
public Hand getHand() {
|
|
return EnumWrappers.getHandConverter().getSpecific(getHandAccessor().get(handle));
|
|
}
|
|
|
|
/**
|
|
* Sets the hand used for the interact.
|
|
* @param hand the used hand.
|
|
* @throws IllegalArgumentException if called for attack.
|
|
*/
|
|
public void setHand(Hand hand) {
|
|
getHandAccessor().set(handle, EnumWrappers.getHandConverter().getGeneric(hand));
|
|
}
|
|
|
|
/**
|
|
* Get the position of the interact. Only available if this represents interact_at.
|
|
* @return the position of the interact.
|
|
* @throws IllegalArgumentException if called for attack or interact.
|
|
*/
|
|
public Vector getPosition() {
|
|
return BukkitConverters.getVectorConverter().getSpecific(getPositionAccessor().get(handle));
|
|
}
|
|
|
|
/**
|
|
* Sets the position of the interact.
|
|
* @param position the position.
|
|
* @throws IllegalArgumentException if called for attack or interact.
|
|
*/
|
|
public void setPosition(Vector position) {
|
|
getPositionAccessor().set(handle, BukkitConverters.getVectorConverter().getGeneric(position));
|
|
}
|
|
|
|
@Override
|
|
public WrappedEnumEntityUseAction deepClone() {
|
|
switch (action) {
|
|
case ATTACK:
|
|
return WrappedEnumEntityUseAction.attack();
|
|
case INTERACT:
|
|
return WrappedEnumEntityUseAction.interact(getHand());
|
|
case INTERACT_AT:
|
|
return WrappedEnumEntityUseAction.interactAt(getHand(), getPosition());
|
|
default:
|
|
throw new IllegalArgumentException("Invalid EntityUseAction: " + action);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a field accessor for the hand in the interact and interact_at type.
|
|
* @return a field accessor for the hand field.
|
|
* @throws IllegalArgumentException if called for attack.
|
|
*/
|
|
private FieldAccessor getHandAccessor() {
|
|
if (handAccessor == null) {
|
|
handAccessor = MinecraftReflection.getHandEntityUseActionEnumFieldAccessor(handle);
|
|
}
|
|
return handAccessor;
|
|
}
|
|
|
|
/**
|
|
* Get a field accessor for the position in the interact_at type.
|
|
* @return a field accessor for the position field.
|
|
* @throws IllegalArgumentException if called for attack or interact.
|
|
*/
|
|
public FieldAccessor getPositionAccessor() {
|
|
if (positionAccessor == null) {
|
|
positionAccessor = MinecraftReflection.getVec3EntityUseActionEnumFieldAccessor(handle);
|
|
}
|
|
return positionAccessor;
|
|
}
|
|
}
|