Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Re-add/repair reflection based attribute access.
- Loading branch information
Showing
2 changed files
with
193 additions
and
1 deletion.
There are no files selected for viewing
192 changes: 192 additions & 0 deletions
192
...main/java/fr/neatmonster/nocheatplus/compat/cbreflect/reflect/ReflectAttributeAccess.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
package fr.neatmonster.nocheatplus.compat.cbreflect.reflect; | ||
|
||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Method; | ||
import java.util.UUID; | ||
|
||
import org.bukkit.entity.Player; | ||
|
||
import fr.neatmonster.nocheatplus.components.modifiers.IAttributeAccess; | ||
import fr.neatmonster.nocheatplus.utilities.AttribUtil; | ||
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil; | ||
|
||
public class ReflectAttributeAccess implements IAttributeAccess { | ||
|
||
private static class ReflectGenericAttributes { | ||
public final Object nmsMOVEMENT_SPEED; | ||
|
||
public ReflectGenericAttributes(ReflectBase base) throws ClassNotFoundException { | ||
Class<?> clazz = Class.forName(base.nmsPackageName + ".GenericAttributes"); | ||
Class<?> clazzIAttribute = Class.forName(base.nmsPackageName + ".IAttribute"); | ||
Object nmsMOVEMENT_SPEED = null; | ||
nmsMOVEMENT_SPEED = get_nmsMOVEMENT_SPEED("MOVEMENT_SPEED", clazz, clazzIAttribute); | ||
if (nmsMOVEMENT_SPEED == null) { | ||
nmsMOVEMENT_SPEED = get_nmsMOVEMENT_SPEED("d", clazz, clazzIAttribute); | ||
} | ||
if (nmsMOVEMENT_SPEED == null) { | ||
throw new RuntimeException("Not available."); | ||
} | ||
else { | ||
this.nmsMOVEMENT_SPEED = nmsMOVEMENT_SPEED; | ||
} | ||
} | ||
|
||
private Object get_nmsMOVEMENT_SPEED(String fieldName, Class<?> clazz, Class<?> type) { | ||
Field field = ReflectionUtil.getField(clazz, fieldName, type); | ||
if (field != null) { | ||
return ReflectionUtil.get(field, clazz, null); | ||
} | ||
else { | ||
return null; | ||
} | ||
} | ||
|
||
} | ||
|
||
private static class ReflectAttributeInstance { | ||
/** (Custom naming.) */ | ||
public final Method nmsGetBaseValue; | ||
public final Method nmsGetValue; | ||
|
||
/** (Custom naming.) */ | ||
public final Method nmsGetAttributeModifier; | ||
|
||
public ReflectAttributeInstance(ReflectBase base) throws ClassNotFoundException { | ||
Class<?> clazz = Class.forName(base.nmsPackageName + ".AttributeInstance"); | ||
// Base value. | ||
Method method = ReflectionUtil.getMethodNoArgs(clazz, "b", double.class); | ||
if (method == null) { | ||
// TODO: Consider to search (as long as only two exist). | ||
method = ReflectionUtil.getMethodNoArgs(clazz, "getBaseValue", double.class); | ||
if (method == null) { | ||
method = ReflectionUtil.getMethodNoArgs(clazz, "getBase", double.class); | ||
} | ||
} | ||
nmsGetBaseValue = method; | ||
// Value (final value). | ||
method = ReflectionUtil.getMethodNoArgs(clazz, "getValue", double.class); | ||
if (method == null) { | ||
// TODO: Consider to search (as long as only two exist). | ||
method = ReflectionUtil.getMethodNoArgs(clazz, "e", double.class); // 1.6.1 | ||
} | ||
nmsGetValue = method; | ||
// Get AttributeModifier. | ||
// TODO: If name changes: scan. | ||
method = ReflectionUtil.getMethod(clazz, "a", UUID.class); | ||
if (method == null) { | ||
method = ReflectionUtil.getMethod(clazz, "getAttributeModifier", UUID.class); | ||
if (method == null) { | ||
method = ReflectionUtil.getMethod(clazz, "getModifier", UUID.class); | ||
} | ||
} | ||
nmsGetAttributeModifier = method; | ||
if (nmsGetAttributeModifier == null || nmsGetBaseValue == null || nmsGetValue == null) { | ||
throw new RuntimeException("Not available."); | ||
} | ||
} | ||
|
||
} | ||
|
||
private static class ReflectAttributeModifier { | ||
/** (Custom naming.) */ | ||
public Method nmsGetOperation; | ||
/** (Custom naming.) */ | ||
public Method nmsGetValue; | ||
|
||
public ReflectAttributeModifier(ReflectBase base) throws ClassNotFoundException { | ||
Class<?> clazz = Class.forName(base.nmsPackageName + ".AttributeModifier"); | ||
// TODO: Scan in a more future proof way. | ||
nmsGetOperation = ReflectionUtil.getMethodNoArgs(clazz, "c", int.class); | ||
nmsGetValue = ReflectionUtil.getMethodNoArgs(clazz, "d", double.class); | ||
if (nmsGetOperation == null || nmsGetValue == null) { | ||
throw new RuntimeException("Not available."); | ||
} | ||
} | ||
|
||
} | ||
|
||
// TODO: Register each and every one of these as generic instances and fetch from there. | ||
private ReflectBase reflectBase; | ||
private ReflectGenericAttributes reflectGenericAttributes; | ||
private ReflectAttributeInstance reflectAttributeInstance; | ||
private ReflectAttributeModifier reflectAttributeModifier; | ||
private ReflectPlayer reflectPlayer; | ||
|
||
public ReflectAttributeAccess() { | ||
try { | ||
this.reflectBase = new ReflectBase(); | ||
reflectGenericAttributes = new ReflectGenericAttributes(this.reflectBase); | ||
reflectAttributeInstance = new ReflectAttributeInstance(this.reflectBase); | ||
reflectAttributeModifier = new ReflectAttributeModifier(this.reflectBase); | ||
reflectPlayer = new ReflectPlayer(reflectBase, new ReflectDamageSource(reflectBase)); | ||
} catch (ClassNotFoundException ex) { | ||
throw new RuntimeException("Not available."); | ||
} | ||
if (reflectBase.nmsPackageName == null || reflectBase.obcPackageName == null | ||
|| reflectPlayer.obcGetHandle == null) { | ||
throw new RuntimeException("Not available."); | ||
} | ||
} | ||
|
||
@Override | ||
public double getSpeedAttributeMultiplier(Player player) { | ||
return getSpeedAttributeMultiplier(player, true); | ||
} | ||
|
||
@Override | ||
public double getSprintAttributeMultiplier(Player player) { | ||
return nmsAttributeInstance_getSprintAttributeModifierMultiplier(getMovementSpeedAttributeInstance(player)); | ||
} | ||
|
||
/** | ||
* Get the speed attribute (MOVEMENT_SPEED) for a player. | ||
* @param handle EntityPlayer | ||
* @return AttributeInstance | ||
*/ | ||
private Object getMovementSpeedAttributeInstance(Player player) { | ||
return ReflectionUtil.invokeMethod(this.reflectPlayer.nmsGetAttributeInstance, getHandle(player), this.reflectGenericAttributes.nmsMOVEMENT_SPEED); | ||
} | ||
|
||
/** | ||
* | ||
* @param player | ||
* @param removeSprint If to calculate away the sprint boost modifier. | ||
* @return | ||
*/ | ||
private double getSpeedAttributeMultiplier(Player player, boolean removeSprint) { | ||
Object attributeInstance = getMovementSpeedAttributeInstance(player); | ||
double val = ((Double) ReflectionUtil.invokeMethodNoArgs(this.reflectAttributeInstance.nmsGetValue, attributeInstance)).doubleValue() / ((Double) ReflectionUtil.invokeMethodNoArgs(this.reflectAttributeInstance.nmsGetBaseValue, attributeInstance)).doubleValue(); | ||
if (!removeSprint) { | ||
return val; | ||
} | ||
else { | ||
final double sprintModifier = nmsAttributeInstance_getSprintAttributeModifierMultiplier(attributeInstance); | ||
if (sprintModifier == 1.0) { | ||
return val; | ||
} | ||
else { | ||
return val / sprintModifier; | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* (Not an existing method.) | ||
* @param attributeInstance | ||
*/ | ||
private double nmsAttributeInstance_getSprintAttributeModifierMultiplier(Object attributeInstance) { | ||
Object mod = ReflectionUtil.invokeMethod(this.reflectAttributeInstance.nmsGetAttributeModifier, attributeInstance, AttribUtil.ID_SPRINT_BOOST); | ||
if (mod == null) { | ||
return 1.0; | ||
} | ||
else { | ||
return AttribUtil.getMultiplier((Integer) ReflectionUtil.invokeMethodNoArgs(this.reflectAttributeModifier.nmsGetOperation, mod), (Double) ReflectionUtil.invokeMethodNoArgs(this.reflectAttributeModifier.nmsGetValue, mod)); | ||
} | ||
} | ||
|
||
private Object getHandle(Player player) { | ||
Object handle = ReflectionUtil.invokeMethodNoArgs(this.reflectPlayer.obcGetHandle, player); | ||
return handle; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters