Sketch a reflection based provider for IEntityAccessLastPositionAndLook.
Directly following: * Boat fly check based on VehicleUpdateEvent and fetching last pos. * Implement a native access based provider for EntityAccessLastPositionAndLook, after testing the reflection based one. Likely following: * Implement the same fly checks based on PlayerMoveEvent for horses and pigs too, for the case server-side fly checking is disabled. * Configurability for individual types of enbtities, at least a flag for activation. * Not sure if a fall-back to VehicleMoveEvent should be kept, setup shouldn't be all too complicated.
This commit is contained in:
parent
bb2c2d0cb6
commit
554c8635e7
|
@ -0,0 +1,26 @@
|
|||
package fr.neatmonster.nocheatplus.utilities;
|
||||
|
||||
/**
|
||||
* Simple parameter/thing validation.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public class Validate {
|
||||
|
||||
/**
|
||||
* Throw a NullPointerException if any given object is null.
|
||||
*
|
||||
* @param objects
|
||||
* @throws NullPointerException
|
||||
* If any object is null.
|
||||
*/
|
||||
public static void validateNotNull(final Object...objects) {
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
if (objects[i] == null) {
|
||||
throw new NullPointerException("Object at index " + i + " is null.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -14,7 +14,14 @@ import fr.neatmonster.nocheatplus.logging.Streams;
|
|||
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.StringUtil;
|
||||
|
||||
public class ReflectBlock {
|
||||
/**
|
||||
* Classic Block with 6 consecutive getter methods for the shape and
|
||||
* updateShape.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public class ReflectBlockSix {
|
||||
|
||||
/** Obfuscated nms names, allowing to find the order in the source code under certain circumstances. */
|
||||
private static final List<String> possibleNames = new ArrayList<String>();
|
||||
|
@ -41,7 +48,7 @@ public class ReflectBlock {
|
|||
public final Method nmsGetMinZ;
|
||||
public final Method nmsGetMaxZ;
|
||||
|
||||
public ReflectBlock(ReflectBase base, ReflectBlockPosition blockPosition) throws ClassNotFoundException {
|
||||
public ReflectBlockSix(ReflectBase base, ReflectBlockPosition blockPosition) throws ClassNotFoundException {
|
||||
final Class<?> clazz = Class.forName(base.nmsPackageName + ".Block");
|
||||
// byID (static)
|
||||
nmsGetById = ReflectionUtil.getMethod(clazz, "getById", int.class);
|
|
@ -3,6 +3,8 @@ package fr.neatmonster.nocheatplus.compat.cbreflect.reflect;
|
|||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
|
||||
|
||||
/**
|
||||
|
@ -10,29 +12,25 @@ import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
|
|||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public class ReflectEntity {
|
||||
public class ReflectEntityDamage extends ReflectGetHandleBase<Entity> {
|
||||
|
||||
public final Field nmsDead;
|
||||
|
||||
public final Method obcGetHandle;
|
||||
|
||||
public final Method nmsDamageEntity;
|
||||
|
||||
|
||||
public final boolean nmsDamageEntityInt;
|
||||
|
||||
public ReflectEntity(ReflectBase base, ReflectDamageSource damageSource) throws ClassNotFoundException {
|
||||
public ReflectEntityDamage(ReflectBase base, ReflectDamageSource damageSource) throws ClassNotFoundException {
|
||||
this(base, damageSource, Class.forName(base.obcPackageName + ".entity.CraftEntity"), Class.forName(base.nmsPackageName + ".Entity"));
|
||||
|
||||
}
|
||||
|
||||
public ReflectEntity(ReflectBase base, ReflectDamageSource damageSource, Class<?> obcClass, Class<?> nmsClass) throws ClassNotFoundException {
|
||||
// getHandle
|
||||
obcGetHandle = ReflectionUtil.getMethodNoArgs(obcClass, "getHandle");
|
||||
// TODO: Consider throw in case of getHandle missing.
|
||||
|
||||
public ReflectEntityDamage(ReflectBase base, ReflectDamageSource damageSource, Class<?> obcClass, Class<?> nmsClass) throws ClassNotFoundException {
|
||||
// base
|
||||
super(base, obcClass, nmsClass);
|
||||
|
||||
// dead
|
||||
nmsDead = ReflectionUtil.getField(nmsClass, "dead", boolean.class);
|
||||
|
||||
|
||||
// damageEntity(...)
|
||||
nmsDamageEntity = ReflectionUtil.getMethod(nmsClass, "damageEntity",
|
||||
new Class<?>[]{damageSource.nmsClass, float.class}, new Class<?>[]{damageSource.nmsClass, int.class});
|
||||
|
@ -43,4 +41,9 @@ public class ReflectEntity {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fail() {
|
||||
// Unused.
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package fr.neatmonster.nocheatplus.compat.cbreflect.reflect;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.bukkit.entity.Entity;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.components.location.IEntityAccessLastPositionAndLook;
|
||||
import fr.neatmonster.nocheatplus.components.location.ISetPositionWithLook;
|
||||
import fr.neatmonster.nocheatplus.logging.Streams;
|
||||
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
|
||||
import fr.neatmonster.nocheatplus.utilities.Validate;
|
||||
|
||||
/**
|
||||
* Access last position and look. This must be able to work independently of
|
||||
* MCAccess. Should be registered as generic instance for
|
||||
* IEntityAccessLastPositionAndLook.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public class ReflectEntityLastPositionAndLook extends ReflectGetHandleBase<Entity> implements IEntityAccessLastPositionAndLook {
|
||||
|
||||
public final Field lastX, lastY, lastZ, lastYaw, lastPitch;
|
||||
|
||||
public ReflectEntityLastPositionAndLook() throws ClassNotFoundException {
|
||||
this(new ReflectBase());
|
||||
}
|
||||
|
||||
public ReflectEntityLastPositionAndLook(ReflectBase base) throws ClassNotFoundException {
|
||||
this(base, Class.forName(base.obcPackageName + ".entity.CraftEntity"), Class.forName(base.nmsPackageName + ".Entity"));
|
||||
}
|
||||
|
||||
public ReflectEntityLastPositionAndLook(ReflectBase base, Class<?> obcClass, Class<?> nmsClass) throws ClassNotFoundException, NoSuchFieldError {
|
||||
super(base, obcClass, nmsClass);
|
||||
lastX = ReflectionUtil.getField(nmsClass, "lastX", double.class);
|
||||
lastY = ReflectionUtil.getField(nmsClass, "lastY", double.class);
|
||||
lastZ = ReflectionUtil.getField(nmsClass, "lastZ", double.class);
|
||||
lastYaw = ReflectionUtil.getField(nmsClass, "lastYaw", float.class);
|
||||
lastPitch = ReflectionUtil.getField(nmsClass, "lastPitch", float.class);
|
||||
Validate.validateNotNull(lastX, lastY, lastZ, lastYaw, lastPitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPositionAndLook(final Entity entity, final ISetPositionWithLook location) {
|
||||
try {
|
||||
performSet(entity, location);
|
||||
}
|
||||
catch (Throwable t) {
|
||||
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().warning(Streams.STATUS, "Could not retrieve last location for Entity: " + entity.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private void performSet(final Entity entity, final ISetPositionWithLook location) throws IllegalArgumentException, IllegalAccessException {
|
||||
final Object nmsObject = getHandle(entity);
|
||||
location.setX(lastX.getDouble(nmsObject));
|
||||
location.setY(lastY.getDouble(nmsObject));
|
||||
location.setZ(lastZ.getDouble(nmsObject));
|
||||
location.setYaw(lastYaw.getFloat(nmsObject));
|
||||
location.setPitch(lastPitch.getFloat(nmsObject));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void fail() {
|
||||
throw new RuntimeException("Not available."); // To be caught internally.
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package fr.neatmonster.nocheatplus.compat.cbreflect.reflect;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
|
||||
|
||||
/**
|
||||
* Base for reflection on entities
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
* @param <BO>
|
||||
* Bukkit object type for getHandle.
|
||||
*/
|
||||
public abstract class ReflectGetHandleBase <BO> {
|
||||
|
||||
public final Method obcGetHandle;
|
||||
|
||||
public ReflectGetHandleBase(ReflectBase base, Class<?> obcClass, Class<?> nmsClass) throws ClassNotFoundException {
|
||||
// getHandle
|
||||
obcGetHandle = ReflectionUtil.getMethodNoArgs(obcClass, "getHandle");
|
||||
// TODO: Consider throw in case of getHandle missing.
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke getHandle on the bukkit object.
|
||||
*
|
||||
* @param bukkitObject
|
||||
* @return
|
||||
*/
|
||||
public Object getHandle(BO bukkitObject) {
|
||||
// TODO: CraftPlayer check (isAssignableFrom)?
|
||||
if (this.obcGetHandle == null) {
|
||||
fail();
|
||||
}
|
||||
final Object handle = ReflectionUtil.invokeMethodNoArgs(this.obcGetHandle, bukkitObject);
|
||||
if (handle == null) {
|
||||
fail();
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
protected abstract void fail();
|
||||
|
||||
}
|
|
@ -49,12 +49,12 @@ public class ReflectHelper {
|
|||
protected final ReflectBase reflectBase;
|
||||
|
||||
protected final ReflectBlockPosition reflectBlockPosition;
|
||||
protected final ReflectBlock reflectBlock;
|
||||
protected final ReflectBlockSix reflectBlock;
|
||||
protected final ReflectMaterial reflectMaterial;
|
||||
protected final ReflectWorld reflectWorld;
|
||||
|
||||
protected final ReflectDamageSource reflectDamageSource;
|
||||
protected final ReflectEntity reflectEntity;
|
||||
protected final ReflectEntityDamage reflectEntity;
|
||||
protected final ReflectPlayer reflectPlayer;
|
||||
|
||||
protected final ReflectGenericAttributes reflectGenericAttributes;
|
||||
|
@ -72,12 +72,12 @@ public class ReflectHelper {
|
|||
}
|
||||
catch (ClassNotFoundException ex) {}
|
||||
this.reflectBlockPosition = reflectBlockPosition;
|
||||
this.reflectBlock = new ReflectBlock(this.reflectBase, this.reflectBlockPosition);
|
||||
this.reflectBlock = new ReflectBlockSix(this.reflectBase, this.reflectBlockPosition);
|
||||
this.reflectMaterial = new ReflectMaterial(this.reflectBase);
|
||||
this.reflectWorld = new ReflectWorld(this.reflectBase);
|
||||
|
||||
this.reflectDamageSource = new ReflectDamageSource(this.reflectBase);
|
||||
this.reflectEntity = new ReflectEntity(this.reflectBase, this.reflectDamageSource);
|
||||
this.reflectEntity = new ReflectEntityDamage(this.reflectBase, this.reflectDamageSource);
|
||||
this.reflectPlayer = new ReflectPlayer(this.reflectBase, this.reflectDamageSource);
|
||||
ReflectGenericAttributes reflectGenericAttributes = null;
|
||||
ReflectAttributeInstance reflectAttributeInstance = null;
|
||||
|
|
|
@ -4,7 +4,7 @@ import java.lang.reflect.Method;
|
|||
|
||||
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
|
||||
|
||||
public class ReflectLivingEntity extends ReflectEntity {
|
||||
public class ReflectLivingEntity extends ReflectEntityDamage {
|
||||
|
||||
public final Method nmsGetHealth;
|
||||
|
||||
|
|
|
@ -17,6 +17,6 @@ public interface IEntityAccessLastPositionAndLook {
|
|||
* This instance gets updated by last coordinates and looking
|
||||
* direction.
|
||||
*/
|
||||
public void setPositionAndLook(Entity entity, ISetLocationWithLook location);
|
||||
public void setPositionAndLook(Entity entity, ISetPositionWithLook location);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package fr.neatmonster.nocheatplus.compat;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.compat.cbreflect.reflect.ReflectEntityLastPositionAndLook;
|
||||
import fr.neatmonster.nocheatplus.components.location.IEntityAccessLastPositionAndLook;
|
||||
import fr.neatmonster.nocheatplus.logging.Streams;
|
||||
|
||||
|
@ -28,11 +29,33 @@ public class EntityAccessFactory {
|
|||
}
|
||||
|
||||
private void setupLastPositionWithLook() {
|
||||
final String[] names = new String[] {
|
||||
|
||||
};
|
||||
IEntityAccessLastPositionAndLook res = null;
|
||||
// TODO:
|
||||
// // Reference by class name (native access).
|
||||
// final String[] names = new String[] {
|
||||
// // TODO: Spigot 1.9: fr.neatmonster.nocheatplus.compat.spigotcb1_9_R1.EntityAccessLastPositionAndLook
|
||||
// };
|
||||
// for (final String name : names) {
|
||||
// try {
|
||||
// res = (IEntityAccessLastPositionAndLook) Class.forName(name).newInstance();
|
||||
// if (res != null) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// catch (Throwable t) {
|
||||
// // Skip.
|
||||
// }
|
||||
// }
|
||||
// Reflection based.
|
||||
if (res == null) {
|
||||
try {
|
||||
res = new ReflectEntityLastPositionAndLook();
|
||||
}
|
||||
catch (Throwable t) {
|
||||
// Ignore.
|
||||
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().debug(Streams.TRACE_FILE, t);
|
||||
}
|
||||
}
|
||||
// Register / log.
|
||||
register(IEntityAccessLastPositionAndLook.class, res);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue