[BLEEDING] Reflection module: access entity bounds/height etc.

This should fix more issues with horse type.
This commit is contained in:
asofold 2016-11-22 19:25:13 +01:00
parent bb5afe0d2e
commit 12ce099eb1
8 changed files with 162 additions and 36 deletions

View File

@ -379,6 +379,24 @@ public class ReflectionUtil {
return defaultValue;
}
public static float getFloat(Field field, Object object, float defaultValue) {
try {
return field.getFloat(object);
}
catch (IllegalArgumentException e) {}
catch (IllegalAccessException e) {}
return defaultValue;
}
public static double getDouble(Field field, Object object, double defaultValue) {
try {
return field.getDouble(object);
}
catch (IllegalArgumentException e) {}
catch (IllegalAccessException e) {}
return defaultValue;
}
public static Object get(Field field, Object object, Object defaultValue) {
try {
return field.get(object);

View File

@ -15,6 +15,7 @@
package fr.neatmonster.nocheatplus.compat.cbreflect;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.NCPAPIProvider;
@ -50,7 +51,7 @@ public class MCAccessCBReflect extends MCAccessBukkitBase {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().warning(Streams.INIT, "The Minecraft version seems to be older than what Compat-CB-Reflect can support.");
this.knownSupportedVersion = false;
}
else if (GenericVersion.compareVersions(mcVersion, "1.10") > 0) {
else if (GenericVersion.compareVersions(mcVersion, "1.11") > 0) {
this.knownSupportedVersion = false;
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().warning(Streams.INIT, "The Minecraft version seems to be more recent than the one Compat-CB-Reflect has been built with - this might work, but there could be incompatibilities.");
} else {
@ -68,7 +69,7 @@ public class MCAccessCBReflect extends MCAccessBukkitBase {
@Override
public String getMCVersion() {
// Potentially all :p.
return "1.4.5-1.10|?";
return "1.4.5-1.11|?";
}
@Override
@ -169,24 +170,28 @@ public class MCAccessCBReflect extends MCAccessBukkitBase {
}
}
@Override
public double getHeight(Entity entity) {
try {
return helper.getHeight(entity);
}
catch (ReflectFailureException ex) {
return super.getHeight(entity);
}
}
@Override
public double getWidth(Entity entity) {
try {
return helper.getWidth(entity);
}
catch (ReflectFailureException ex) {
return super.getWidth(entity);
}
}
// TODO: ---- Missing (better to implement these) ----
// @Override
// public double getHeight(final Entity entity) {
// final net.minecraft.server.v1_8_R3.Entity mcEntity = ((CraftEntity) entity).getHandle();
// AxisAlignedBB boundingBox = mcEntity.getBoundingBox();
// final double entityHeight = Math.max(mcEntity.length, Math.max(mcEntity.getHeadHeight(), boundingBox.e - boundingBox.b));
// if (entity instanceof LivingEntity) {
// return Math.max(((LivingEntity) entity).getEyeHeight(), entityHeight);
// } else return entityHeight;
// }
// @Override
// public double getWidth(final Entity entity) {
// return ((CraftEntity) entity).getHandle().width;
// }
// @Override
// public AlmostBoolean isIllegalBounds(final Player player) {
// final EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();

View File

@ -0,0 +1,11 @@
package fr.neatmonster.nocheatplus.compat.cbreflect.reflect;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface MostlyHarmless {
}

View File

@ -129,10 +129,15 @@ public class ReflectAttributeAccess implements IAttributeAccess {
public ReflectAttributeAccess() {
try {
this.reflectBase = new ReflectBase();
ReflectAxisAlignedBB reflectAxisAlignedBB = null;
try {
reflectAxisAlignedBB = new ReflectAxisAlignedBB(reflectBase);
}
catch (NullPointerException e) {}
reflectGenericAttributes = new ReflectGenericAttributes(this.reflectBase);
reflectAttributeInstance = new ReflectAttributeInstance(this.reflectBase);
reflectAttributeModifier = new ReflectAttributeModifier(this.reflectBase);
reflectPlayer = new ReflectPlayer(reflectBase, new ReflectDamageSource(reflectBase));
reflectPlayer = new ReflectPlayer(reflectBase, reflectAxisAlignedBB, new ReflectDamageSource(reflectBase));
} catch (ClassNotFoundException ex) {
throw new RuntimeException("Not available.");
}

View File

@ -26,7 +26,14 @@ import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
* @author asofold
*
*/
public class ReflectEntityDamage extends ReflectGetHandleBase<Entity> {
public class ReflectEntity extends ReflectGetHandleBase<Entity> {
public final Field nmsWidth;
public final Field nmsLength; // Something like height.
@MostlyHarmless()
public final Field nmsHeight; // Not anymore in 1.11.
public final Method nmsGetBoundingBox;
public final Field nmsDead;
@ -34,14 +41,19 @@ public class ReflectEntityDamage extends ReflectGetHandleBase<Entity> {
public final boolean nmsDamageEntityInt;
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, ReflectAxisAlignedBB reflectAxisAlignedBB, ReflectDamageSource damageSource) throws ClassNotFoundException {
this(base, reflectAxisAlignedBB, damageSource, Class.forName(base.obcPackageName + ".entity.CraftEntity"), Class.forName(base.nmsPackageName + ".Entity"));
}
public ReflectEntityDamage(ReflectBase base, ReflectDamageSource damageSource, Class<?> obcClass, Class<?> nmsClass) throws ClassNotFoundException {
public ReflectEntity(ReflectBase base, ReflectAxisAlignedBB reflectAxisAlignedBB, ReflectDamageSource damageSource, Class<?> obcClass, Class<?> nmsClass) throws ClassNotFoundException {
// base
super(base, obcClass, nmsClass);
// width, length (height)
nmsWidth = ReflectionUtil.getField(nmsClass, "width", float.class);
nmsLength = ReflectionUtil.getField(nmsClass, "length", float.class);
nmsHeight = ReflectionUtil.getField(nmsClass, "height", float.class); // Rather old CB around 1.6.
// dead
nmsDead = ReflectionUtil.getField(nmsClass, "dead", boolean.class);
@ -53,6 +65,14 @@ public class ReflectEntityDamage extends ReflectGetHandleBase<Entity> {
} else {
nmsDamageEntityInt = true; // Uncertain.
}
// getBoundingBox
if (reflectAxisAlignedBB == null) {
this.nmsGetBoundingBox = null;
}
else {
this.nmsGetBoundingBox = ReflectionUtil.getMethodNoArgs(nmsClass, "getBoundingBox", reflectAxisAlignedBB.nmsClass);
}
}
@Override

View File

@ -19,6 +19,8 @@ import java.util.LinkedList;
import java.util.List;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.NCPAPIProvider;
@ -61,19 +63,28 @@ public class ReflectHelper {
protected final ReflectBase reflectBase;
protected final ReflectAxisAlignedBB reflectAxisAlignedBB;
protected final ReflectBlockPosition reflectBlockPosition;
protected final IReflectBlock reflectBlock;
protected final ReflectMaterial reflectMaterial;
protected final ReflectWorld reflectWorld;
protected final ReflectDamageSource reflectDamageSource;
protected final ReflectEntityDamage reflectEntity;
protected final ReflectEntity reflectEntity;
protected final ReflectEntity reflectLivingEntity;
protected final ReflectPlayer reflectPlayer;
public ReflectHelper() throws ReflectFailureException {
// TODO: Allow some to not work?
// TODO: Store one instance of ReflectFailureException?
// TODO: Allow some more to not work?
try {
this.reflectBase = new ReflectBase();
ReflectAxisAlignedBB reflectAxisAlignedBB = null;
try {
reflectAxisAlignedBB = new ReflectAxisAlignedBB(reflectBase);
}
catch (NullPointerException ex1) {}
this.reflectAxisAlignedBB = reflectAxisAlignedBB;
ReflectBlockPosition reflectBlockPosition = null;
try {
reflectBlockPosition = new ReflectBlockPosition(this.reflectBase);
@ -86,7 +97,8 @@ public class ReflectHelper {
try {
reflectBlockLatest = new ReflectBlock(this.reflectBase, this.reflectBlockPosition,
reflectMaterial, reflectWorld);
} catch (Throwable t) {}
}
catch (Throwable t) {}
if (reflectBlockLatest == null) {
// More lenient constructor.
this.reflectBlock = new ReflectBlockSix(this.reflectBase, this.reflectBlockPosition);
@ -96,8 +108,9 @@ public class ReflectHelper {
}
this.reflectDamageSource = new ReflectDamageSource(this.reflectBase);
this.reflectEntity = new ReflectEntityDamage(this.reflectBase, this.reflectDamageSource);
this.reflectPlayer = new ReflectPlayer(this.reflectBase, this.reflectDamageSource);
this.reflectEntity = new ReflectEntity(this.reflectBase, this.reflectAxisAlignedBB, this.reflectDamageSource);
this.reflectLivingEntity = new ReflectLivingEntity(this.reflectBase, this.reflectAxisAlignedBB, this.reflectDamageSource);
this.reflectPlayer = new ReflectPlayer(this.reflectBase, this.reflectAxisAlignedBB, this.reflectDamageSource);
}
catch (ClassNotFoundException ex) {
throw new ReflectFailureException(ex);
@ -105,6 +118,9 @@ public class ReflectHelper {
if (ConfigManager.getConfigFile().getBoolean(ConfPaths.LOGGING_EXTENDED_STATUS)) {
List<String> parts = new LinkedList<String>();
for (Field rootField : this.getClass().getDeclaredFields()) {
if (rootField.isAnnotationPresent(MostlyHarmless.class)) {
continue;
}
boolean accessible = rootField.isAccessible();
if (!accessible) {
rootField.setAccessible(true);
@ -118,6 +134,9 @@ public class ReflectHelper {
Class<?> clazz = obj.getClass();
// TODO: Skip attributes silently before 1.6.1 (and not unknown version).
for (Field field : clazz.getFields()) {
if (field.isAnnotationPresent(MostlyHarmless.class)) {
continue;
}
if (ReflectionUtil.get(field, obj, null) == null) {
parts.add(clazz.getName() + "." + field.getName());
}
@ -336,4 +355,52 @@ public class ReflectHelper {
return reflectBlock.nms_fetchBounds(nmsWorld, nmsBlock, x, y, z);
}
public double getWidth(final Entity entity) {
float width = -16f;
if (reflectEntity.nmsWidth != null) {
final Object handle = reflectEntity.getHandle(entity);
if (handle != null) {
width = ReflectionUtil.getFloat(reflectEntity.nmsWidth, handle, width);
}
}
if (width < 0f) {
throw new ReflectFailureException();
}
return (double) width;
}
public double getHeight(final Entity entity) {
float floatHeight = -16f;
final Object handle = reflectEntity.getHandle(entity); // TODO: Distinguish classes (living vs not)?
if (handle != null) {
if (reflectEntity.nmsLength != null) {
floatHeight = Math.max(ReflectionUtil.getFloat(reflectEntity.nmsLength, handle, floatHeight), floatHeight);
}
if (reflectEntity.nmsHeight != null) {
floatHeight = Math.max(ReflectionUtil.getFloat(reflectEntity.nmsHeight, handle, floatHeight), floatHeight);
}
}
double height = (double) floatHeight;
// TODO: Consider dropping the box for performance?
if (reflectAxisAlignedBB != null && reflectEntity.nmsGetBoundingBox != null) {
final Object box = ReflectionUtil.invokeMethodNoArgs(reflectEntity.nmsGetBoundingBox, handle);
if (box != null) {
// mcEntity.boundingBox.e - mcEntity.boundingBox.b
final double y2 = ReflectionUtil.getDouble(reflectAxisAlignedBB.nms_maxY, box, Double.MAX_VALUE);
final double y1 = ReflectionUtil.getDouble(reflectAxisAlignedBB.nms_minY, box, Double.MAX_VALUE);
if (y1 != Double.MAX_VALUE && y2 != Double.MAX_VALUE) {
height = Math.max(y2 - y1, height);
}
}
}
if (height < 0.0) {
throw new ReflectFailureException();
}
// On success only: Check eye height (MCAccessBukkit is better than just eye height.).
if (entity instanceof LivingEntity) {
height = Math.max(height, ((LivingEntity) entity).getEyeHeight());
}
return height;
}
}

View File

@ -18,16 +18,16 @@ import java.lang.reflect.Method;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
public class ReflectLivingEntity extends ReflectEntityDamage {
public class ReflectLivingEntity extends ReflectEntity {
public final Method nmsGetHealth;
public ReflectLivingEntity(ReflectBase base, ReflectDamageSource damageSource) throws ClassNotFoundException {
this(base, damageSource, Class.forName(base.obcPackageName + ".entity.CraftLivingEntity"), Class.forName(base.nmsPackageName + ".EntityLiving"));
public ReflectLivingEntity(ReflectBase base, ReflectAxisAlignedBB reflectAxisAlignedBB, ReflectDamageSource damageSource) throws ClassNotFoundException {
this(base, reflectAxisAlignedBB, damageSource, Class.forName(base.obcPackageName + ".entity.CraftLivingEntity"), Class.forName(base.nmsPackageName + ".EntityLiving"));
}
public ReflectLivingEntity(ReflectBase base, ReflectDamageSource damageSource, Class<?> obcClass, Class<?> nmsClass) throws ClassNotFoundException {
super(base, damageSource, obcClass, nmsClass);
public ReflectLivingEntity(ReflectBase base, ReflectAxisAlignedBB reflectAxisAlignedBB, ReflectDamageSource damageSource, Class<?> obcClass, Class<?> nmsClass) throws ClassNotFoundException {
super(base, reflectAxisAlignedBB, damageSource, obcClass, nmsClass);
this.nmsGetHealth = ReflectionUtil.getMethodNoArgs(nmsClass, "getHealth");
}

View File

@ -27,12 +27,12 @@ public class ReflectPlayer extends ReflectLivingEntity {
public final Method nmsGetAttributeInstance; // TODO: LivingEntity
public ReflectPlayer(ReflectBase base, ReflectDamageSource damageSource) throws ClassNotFoundException {
this(base, damageSource, Class.forName(base.obcPackageName + ".entity.CraftPlayer"), Class.forName(base.nmsPackageName + ".EntityPlayer"));
public ReflectPlayer(ReflectBase base, ReflectAxisAlignedBB reflectAxisAlignedBB, ReflectDamageSource damageSource) throws ClassNotFoundException {
this(base, reflectAxisAlignedBB, damageSource, Class.forName(base.obcPackageName + ".entity.CraftPlayer"), Class.forName(base.nmsPackageName + ".EntityPlayer"));
}
public ReflectPlayer(ReflectBase base, ReflectDamageSource damageSource, Class<?> obcClass, Class<?> nmsClass) throws ClassNotFoundException {
super(base, damageSource, obcClass, nmsClass);
public ReflectPlayer(ReflectBase base, ReflectAxisAlignedBB reflectAxisAlignedBB, ReflectDamageSource damageSource, Class<?> obcClass, Class<?> nmsClass) throws ClassNotFoundException {
super(base, reflectAxisAlignedBB, damageSource, obcClass, nmsClass);
// TODO: invulnerable etc.
// deathTicks
nmsDeathTicks = ReflectionUtil.getField(nmsClass, "deathTicks", int.class);