Fix AttackFrequency for MC 1.7.10 and MC 1.7.2.

This commit is contained in:
asofold 2017-04-19 14:10:12 +02:00
parent b3a9898900
commit 672c6cf71f
1 changed files with 113 additions and 11 deletions

View File

@ -14,6 +14,7 @@
*/
package fr.neatmonster.nocheatplus.checks.net.protocollib;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.bukkit.entity.Player;
@ -31,11 +32,70 @@ import fr.neatmonster.nocheatplus.checks.net.NetConfig;
import fr.neatmonster.nocheatplus.checks.net.NetData;
import fr.neatmonster.nocheatplus.config.ConfPaths;
import fr.neatmonster.nocheatplus.config.ConfigManager;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
public class UseEntityAdapter extends BaseAdapter {
private static class LegacyReflectionSet {
/** Hacks. */
final Class<?> packetClass_legacy;
final Class<?> enumClassAction_legacy;
final Method methodGetAction_legacy;
final Method methodName_legacy;
/**
*
* @param versionDetail
* @throws RuntimeException
* if not matching/supported.
*/
private LegacyReflectionSet(String versionDetail) {
Class<?> packetClass = ReflectionUtil.getClass("net.minecraft.server." + versionDetail + ".PacketPlayInUseEntity");
Class<?> actionClass = ReflectionUtil.getClass("net.minecraft.server." + versionDetail + ".EnumEntityUseAction");
Method methodGetAction = (packetClass == null || actionClass == null) ? null : ReflectionUtil.getMethodNoArgs(packetClass, "c", actionClass);
if (packetClass == null || actionClass == null || methodGetAction == null) {
this.packetClass_legacy = null;
this.enumClassAction_legacy = null;
this.methodGetAction_legacy = null;
this.methodName_legacy = null;
}
else {
this.packetClass_legacy = packetClass;
this.enumClassAction_legacy = actionClass;
this.methodGetAction_legacy = methodGetAction;
this.methodName_legacy = ReflectionUtil.getMethodNoArgs(enumClassAction_legacy, "name", String.class);
}
if (this.methodName_legacy == null) {
throw new RuntimeException("Not supported.");
}
}
String getActionFromNMSPacket(Object handle) {
final Class<?> clazz = handle.getClass();
if (clazz != packetClass_legacy) {
return null;
}
final Object action = ReflectionUtil.invokeMethodNoArgs(methodGetAction_legacy, handle);
if (action == null) {
return null;
}
final Object actionName = ReflectionUtil.invokeMethodNoArgs(methodName_legacy, action);
if (actionName instanceof String) {
return (String) actionName;
}
else {
return null;
}
}
}
private static final int INTERPRETED = 0x01;
private static final int ATTACK = 0x02;
private final AttackFrequency attackFrequency;
private final LegacyReflectionSet legacySet;
public UseEntityAdapter(Plugin plugin) {
super(plugin, PacketType.Play.Client.USE_ENTITY);
@ -44,6 +104,18 @@ public class UseEntityAdapter extends BaseAdapter {
NCPAPIProvider.getNoCheatPlusAPI().addFeatureTags("checks", Arrays.asList(AttackFrequency.class.getSimpleName()));
}
attackFrequency = new AttackFrequency();
LegacyReflectionSet set = null;
for (String versionDetail : new String[] {"v1_7_R4", "v1_7_R1"}) {
try {
set = new LegacyReflectionSet(versionDetail);
if (set != null) {
break;
}
}
catch (RuntimeException e) {} // +-
}
this.legacySet = set;
NCPAPIProvider.getNoCheatPlusAPI().addComponent(attackFrequency);
}
@ -67,23 +139,53 @@ public class UseEntityAdapter extends BaseAdapter {
}
final PacketContainer packet = event.getPacket();
final StructureModifier<EntityUseAction> actions = packet.getEntityUseActions();
if (actions.size() != 1) {
// TODO: Log warning once.
return;
}
final EntityUseAction action = actions.read(0);
boolean cancel = false;
if (action == EntityUseAction.ATTACK && attackFrequency.isEnabled(player, data, cc) && attackFrequency.check(player, time, data, cc)) {
cancel = true;
}
// MIGHT: use entity, use block both on packet level?
boolean isAttack = false;
boolean packetInterpreted = false;
if (legacySet != null) {
// Attempt to extract legacy information.
final int flags = getAction_legacy(packet);
if ((flags & INTERPRETED) != 0 ) {
packetInterpreted = true;
if ((flags & ATTACK) != 0) {
isAttack = true;
}
}
}
if (!packetInterpreted) {
// Handle as if latest.
final StructureModifier<EntityUseAction> actions;
actions = packet.getEntityUseActions();
if (actions.size() == 1 && actions.read(0) == EntityUseAction.ATTACK) {
isAttack = true;
packetInterpreted = true;
}
}
if (!packetInterpreted) {
// TODO: Log warning once, if the packet could not be interpreted.
return;
}
// Run checks.
boolean cancel = false;
// AttackFrequency
if (isAttack && attackFrequency.isEnabled(player, data, cc)
&& attackFrequency.check(player, time, data, cc)) {
cancel = true;
}
if (cancel) {
event.setCancelled(true);
}
}
private int getAction_legacy(final PacketContainer packetContainer) {
// (For some reason the object didn't appear work with equality checks, thus compare the short string.)
final String actionName = legacySet.getActionFromNMSPacket(packetContainer.getHandle());
return actionName == null ? 0 : (INTERPRETED | ("ATTACK".equals(actionName) ? ATTACK : 0));
}
}