(adapt) Adjust mcMMO hook to build 84 of NCP. Use exemption mechanisms

where possible for better performance.
This commit is contained in:
asofold 2012-09-12 18:27:52 +02:00
parent 5d4a2ac5cb
commit c9d1b1e490
6 changed files with 329 additions and 80 deletions

View File

@ -32,15 +32,20 @@ Generic abstract class for the mcMMO style cancelling of next x events + ticks a
add stats hook ?
add a good mechanism for adding external configurable hooks (read automatically from the cncp config).
*** 6.1.X
!(add) Use some exemption mechanism for npcs (generic player class hook + citizens).
? add event before reading config (for better hook integration).
!consider remove: clearing the VL ? => probably not, needs redesign to also monitor block break. + only clear the necessary bits (not frequency)
! try: insta break: keep exemption (unless cancelled) for next block break event (!). -> maybe ncp
VERSION HISTORY
---------------------------
(6.1.3)
- (adapt) Adjust mcMMO hook to build 84 of NCP. Use exemption mechanisms where possible for better performance.
(6.1.2)
- (adapt) To NoCheatPlus build 82 and up.

View File

@ -40,6 +40,7 @@ import fr.neatmonster.nocheatplus.hooks.NCPHookManager;
*/
public class CompatNoCheatPlus extends JavaPlugin implements Listener {
private static CompatNoCheatPlus instance = null;
private final Settings settings = new Settings();
@ -89,6 +90,14 @@ public class CompatNoCheatPlus extends JavaPlugin implements Listener {
return true;
}
/**
* Get the plugin instance.
* @return
*/
public static CompatNoCheatPlus getInstance(){
return instance;
}
/**
* API to add a hook. Adds the hook AND registers listeners if enabled. Also respects the configuration for preventing hooks.<br>
* If you want to not register the listeners use NCPHookManager.
@ -144,16 +153,27 @@ public class CompatNoCheatPlus extends JavaPlugin implements Listener {
}
/**
* Called before loading settings.
* Called before loading settings, adds available hooks into a list, so they will be able to read config.
*/
private void setupBuiltinHooks() {
builtinHooks.clear();
// Might-fail hooks:
// Set speed
try{
builtinHooks.add(new me.asofold.bpl.cncp.hooks.generic.HookSetSpeed());
}
catch (Throwable t){}
// Simple hooks:
// Citizens 2
try{
builtinHooks.add(new me.asofold.bpl.cncp.hooks.citizens2.HookCitizens2());
}
catch (Throwable t){}
// mcMMO
try{
builtinHooks.add(new me.asofold.bpl.cncp.hooks.mcmmo.HookmcMMO());
}
catch (Throwable t){}
// Simple generic hooks
for (Hook hook : new Hook[]{
new HookPlayerClass(),
new HookBlockBreak(),
@ -164,7 +184,7 @@ public class CompatNoCheatPlus extends JavaPlugin implements Listener {
}
/**
* Add standard hooks if available.
* Add standard hooks if enabled.
*/
private void addAvailableHooks() {
@ -181,22 +201,12 @@ public class CompatNoCheatPlus extends JavaPlugin implements Listener {
catch (Throwable t){}
}
}
// Citizens 2
try{
addHook(new me.asofold.bpl.cncp.hooks.citizens2.HookCitizens2());
}
catch (Throwable t){}
// mcMMO
try{
addHook(new me.asofold.bpl.cncp.hooks.mcmmo.HookmcMMO());
}
catch (Throwable t){}
}
@Override
public void onEnable() {
enabled = false; // make sure
instance = this;
// (no cleanup)
// Settings:
@ -299,6 +309,7 @@ public class CompatNoCheatPlus extends JavaPlugin implements Listener {
enabled = false;
// remove all registered cncp hooks:
unregisterHooks();
instance = null; // Set last.
super.onDisable();
}

View File

@ -1,6 +1,10 @@
package me.asofold.bpl.cncp.hooks.citizens2;
import me.asofold.bpl.cncp.config.compatlayer.CompatConfig;
import me.asofold.bpl.cncp.config.compatlayer.CompatConfigFactory;
import me.asofold.bpl.cncp.config.compatlayer.ConfigUtil;
import me.asofold.bpl.cncp.hooks.AbstractHook;
import me.asofold.bpl.cncp.hooks.generic.ConfigurableHook;
import net.citizensnpcs.api.CitizensAPI;
import org.bukkit.entity.Player;
@ -8,9 +12,13 @@ import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.hooks.NCPHook;
public class HookCitizens2 extends AbstractHook {
public class HookCitizens2 extends AbstractHook implements ConfigurableHook{
private Object ncpHook = null;
protected Object ncpHook = null;
protected boolean enabled = true;
protected String configPrefix = "citizens2.";
public HookCitizens2(){
assertPluginPresent("Citizens");
@ -50,4 +58,21 @@ public class HookCitizens2 extends AbstractHook {
return (NCPHook) ncpHook;
}
@Override
public void applyConfig(CompatConfig cfg, String prefix) {
enabled = cfg.getBoolean(prefix + configPrefix + "enabled", true);
}
@Override
public boolean updateConfig(CompatConfig cfg, String prefix) {
CompatConfig defaults = CompatConfigFactory.getConfig(null);
defaults.set(prefix + configPrefix + "enabled", true);
return ConfigUtil.forceDefaults(defaults, cfg);
}
@Override
public boolean isEnabled() {
return enabled;
}
}

View File

@ -137,6 +137,7 @@ public class ExemptionManager{
public boolean addExemption(final Player player, final CheckType type){
final Status status = addExemption(player.getName(), type, NCPExemptionManager.isExempted(player, type));
if (status == Status.NEEDS_EXEMPTION) NCPExemptionManager.exemptPermanently(player, type);
// System.out.println("add: " + type.toString() + " -> " + status);
return status == Status.EXEMPTED;
}
@ -170,6 +171,7 @@ public class ExemptionManager{
final Status status = removeExemption(player.getName(), type, NCPExemptionManager.isExempted(player, type));
if (status == Status.NEEDS_EXEMPTION) NCPExemptionManager.exemptPermanently(player, type);
else if (status == Status.NEEDS_UNEXEMPTION) NCPExemptionManager.unexempt(player, type);
// System.out.println("remove: " + type.toString() + " -> " + status);
return status == Status.EXEMPTED || status == Status.NEEDS_EXEMPTION;
}

View File

@ -1,34 +1,80 @@
package me.asofold.bpl.cncp.hooks.mcmmo;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import me.asofold.bpl.cncp.CompatNoCheatPlus;
import me.asofold.bpl.cncp.hooks.generic.ExemptionManager;
import me.asofold.bpl.cncp.hooks.mcmmo.HookmcMMO.HookFacade;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.hooks.NCPHook;
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
import fr.neatmonster.nocheatplus.utilities.BlockUtils;
import fr.neatmonster.nocheatplus.utilities.BlockUtils.ToolProps;
import fr.neatmonster.nocheatplus.utilities.BlockUtils.ToolType;
public class HookFacadeImpl implements HookFacade, NCPHook {
private final Map<CheckType, Integer> cancelChecksBlockBreak = new HashMap<CheckType, Integer>();
private final Map<CheckType, Integer> cancelChecksBlockDamage = new HashMap<CheckType, Integer>();
private final Map<CheckType, Integer> cancelChecksDamage = new HashMap<CheckType, Integer>();
private String cancel = null;
private long cancelTicks = 0;
protected final ExemptionManager exMan = new ExemptionManager();
private final Map<CheckType, Integer> cancelChecks = new HashMap<CheckType, Integer>();
/** Normal click per block skills. */
protected final CheckType[] exemptBreakNormal = new CheckType[]{
CheckType.BLOCKBREAK_FASTBREAK, CheckType.BLOCKBREAK_FREQUENCY,
CheckType.BLOCKBREAK_NOSWING,
};
public HookFacadeImpl(){
protected final CheckType[] exemptBreakMany = new CheckType[]{
CheckType.BLOCKBREAK, CheckType.COMBINED_IMPROBABLE,
};
/** Fighting damage of effects such as bleeding or area (potentially). */
protected final CheckType[] exemptFightEffect = new CheckType[]{
CheckType.FIGHT_SPEED, CheckType.FIGHT_DIRECTION,
CheckType.FIGHT_ANGLE, CheckType.FIGHT_NOSWING,
CheckType.FIGHT_REACH, CheckType.COMBINED_IMPROBABLE,
};
// Presets for after failure exemption.
protected final Map<CheckType, Integer> cancelChecksBlockBreak = new HashMap<CheckType, Integer>();
// protected final Map<CheckType, Integer> cancelChecksBlockDamage = new HashMap<CheckType, Integer>();
// protected final Map<CheckType, Integer> cancelChecksDamage = new HashMap<CheckType, Integer>();
protected int clicksPerSecond;
protected String cancel = null;
protected long cancelTicks = 0;
protected final Map<CheckType, Integer> cancelChecks = new HashMap<CheckType, Integer>();
/**
* Last block breaking time
*/
protected final Map<String, ActionFrequency> lastBreak = new HashMap<String, ActionFrequency>(50);
/** Counter for nested events to cancel break counting. */
protected int breakCancel = 0;
protected int lastBreakAddCount = 0;
protected long lastBreakCleanup = 0;
public HookFacadeImpl(int clicksPerSecond){
this.clicksPerSecond = clicksPerSecond;
cancelChecksBlockBreak.put(CheckType.BLOCKBREAK_NOSWING, 1);
cancelChecksBlockBreak.put(CheckType.BLOCKBREAK_FASTBREAK, 2);
cancelChecksBlockDamage.put(CheckType.BLOCKBREAK_FASTBREAK, 1);
cancelChecksDamage.put(CheckType.FIGHT_ANGLE, 1);
cancelChecksDamage.put(CheckType.FIGHT_SPEED, 1);
cancelChecksBlockBreak.put(CheckType.BLOCKBREAK_FASTBREAK, 1);
//
// cancelChecksBlockDamage.put(CheckType.BLOCKBREAK_FASTBREAK, 1);
//
// cancelChecksDamage.put(CheckType.FIGHT_ANGLE, 1);
// cancelChecksDamage.put(CheckType.FIGHT_SPEED, 1);
}
@Override
@ -38,14 +84,15 @@ public class HookFacadeImpl implements HookFacade, NCPHook {
@Override
public String getHookVersion() {
return "1.0.0";
return "2.0";
}
@Override
public final boolean onCheckFailure(CheckType checkType, final Player player) {
// System.out.println("[cncp] Handle event: " + event.getEventName());
// System.out.println(player.getName() + " -> " + checkType + "---------------------------");
// Somewhat generic canceling mechanism (within the same tick).
// Might later fail, if block break event gets scheduled after block damage having set insta break, instead of letting them follow directly.
if (cancel == null){
// System.out.println("[cncp] Return on cancel == null: "+event.getPlayer().getName());
return false;
}
@ -53,22 +100,17 @@ public class HookFacadeImpl implements HookFacade, NCPHook {
if (cancel.equals(name)){
if (player.getTicksLived() != cancelTicks){
// System.out.println("[cncp] No cancel (ticks/player): "+event.getPlayer().getName());
cancel = null;
}
else{
final Integer n = cancelChecks.get(checkType);
if (n == null){
// System.out.println("[cncp] Expired("+check+"): "+event.getPlayer().getName());
return false;
}
else if (n > 0){
// System.out.println("Check with n = "+n);
if (n == 1) cancelChecks.remove(checkType);
else cancelChecks.put(checkType, n - 1);
}
// else: allow arbitrary numbers
// System.out.println("[cncp] Cancel: "+event.getPlayer().getName());
return true;
}
}
@ -82,26 +124,115 @@ public class HookFacadeImpl implements HookFacade, NCPHook {
this.cancelChecks.putAll(cancelChecks);
}
@Override
public final void setPlayerDamage(final Player player) {
setPlayer(player, cancelChecksDamage);
public ToolProps getToolProps(final ItemStack stack){
if (stack == null) return BlockUtils.noTool;
else return BlockUtils.getToolProps(stack.getTypeId());
}
public void addExemption(final Player player, final CheckType[] types){
for (final CheckType type : types){
exMan.addExemption(player, type);
}
}
public void removeExemption(final Player player, final CheckType[] types){
for (final CheckType type : types){
exMan.removeExemption(player, type);
}
}
@Override
public final void setPlayerBlockDamage(final Player player) {
setPlayer(player, cancelChecksBlockDamage);
public final void damageLowest(final Player player) {
// System.out.println("damage lowest");
// setPlayer(player, cancelChecksDamage);
addExemption(player, exemptFightEffect);
}
@Override
public final void setPlayerBlockBreak(final Player player) {
public final void blockDamageLowest(final Player player) {
// System.out.println("block damage lowest");
// setPlayer(player, cancelChecksBlockDamage);
if (getToolProps(player.getItemInHand()).toolType == ToolType.AXE) addExemption(player, exemptBreakMany);
else addExemption(player, exemptBreakNormal);
}
@Override
public final boolean blockBreakLowest(final Player player) {
// System.out.println("block break lowest");
final boolean isAxe = getToolProps(player.getItemInHand()).toolType == ToolType.AXE;
if (breakCancel > 0){
breakCancel ++;
return true;
}
final String name = player.getName();
ActionFrequency freq = lastBreak.get(name);
final long now = System.currentTimeMillis();
if (freq == null){
freq = new ActionFrequency(3, 333);
freq.add(now, 1f);
lastBreak.put(name, freq);
lastBreakAddCount ++;
if (lastBreakAddCount > 100){
lastBreakAddCount = 0;
cleanupLastBreaks();
}
}
else if (!isAxe){
freq.add(now, 1f);
if (freq.getScore(1f) > (float) clicksPerSecond){
breakCancel ++;
return true;
}
}
addExemption(player, exemptBreakNormal);
if (!isAxe){
setPlayer(player, cancelChecksBlockBreak);
Bukkit.getScheduler().scheduleSyncDelayedTask(Bukkit.getPluginManager().getPlugin("CompatNoCheatPlus"), new Runnable() {
Bukkit.getScheduler().scheduleSyncDelayedTask(CompatNoCheatPlus.getInstance(), new Runnable() {
@Override
public void run() {
CheckType.removeData(player.getName(), CheckType.BLOCKBREAK_FASTBREAK);
}
});
}
return false;
}
protected void cleanupLastBreaks() {
final long ts = System.currentTimeMillis();
if (ts - lastBreakCleanup < 30000) return;
lastBreakCleanup = ts;
final List<String> rem = new LinkedList<String>();
for (final Entry<String, ActionFrequency> entry : lastBreak.entrySet()){
if (entry.getValue().getScore(1f) == 0f) rem.add(entry.getKey());
}
for (final String key :rem){
lastBreak.remove(key);
}
}
@Override
public void damageMonitor(Player player) {
// System.out.println("damage monitor");
removeExemption(player, exemptFightEffect);
}
@Override
public void blockDamageMonitor(Player player) {
// System.out.println("block damage monitor");
if (getToolProps(player.getItemInHand()).toolType == ToolType.AXE) addExemption(player, exemptBreakMany);
else removeExemption(player, exemptBreakNormal);
}
@Override
public void blockBreakMontitor(Player player) {
if (breakCancel > 0){
breakCancel --;
return;
}
// System.out.println("block break monitor");
removeExemption(player, exemptBreakNormal);
}

View File

@ -1,6 +1,10 @@
package me.asofold.bpl.cncp.hooks.mcmmo;
import me.asofold.bpl.cncp.config.compatlayer.CompatConfig;
import me.asofold.bpl.cncp.config.compatlayer.CompatConfigFactory;
import me.asofold.bpl.cncp.config.compatlayer.ConfigUtil;
import me.asofold.bpl.cncp.hooks.AbstractHook;
import me.asofold.bpl.cncp.hooks.generic.ConfigurableHook;
import me.asofold.bpl.cncp.utils.PluginGetter;
import org.bukkit.entity.Entity;
@ -17,7 +21,7 @@ import com.gmail.nossr50.events.fake.FakeEntityDamageByEntityEvent;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.hooks.NCPHook;
public final class HookmcMMO extends AbstractHook implements Listener {
public final class HookmcMMO extends AbstractHook implements Listener, ConfigurableHook {
/**
* To let the listener access this.
@ -25,13 +29,24 @@ public final class HookmcMMO extends AbstractHook implements Listener {
*
*/
public static interface HookFacade{
public void setPlayerDamage(Player player);
public void setPlayerBlockDamage(Player player);
public void setPlayerBlockBreak(Player player);
public void damageLowest(Player player);
public void damageMonitor(Player player);
public void blockDamageLowest(Player player);
public void blockDamageMonitor(Player player);
/**
* If to cancel the event.
* @param player
* @return
*/
public boolean blockBreakLowest(Player player);
public void blockBreakMontitor(Player player);
}
private HookFacade ncpHook = null;
protected HookFacade ncpHook = null;
protected boolean enabled = true;
protected String configPrefix = "mcmmo.";
public HookmcMMO(){
@ -39,7 +54,9 @@ public final class HookmcMMO extends AbstractHook implements Listener {
}
private final PluginGetter<mcMMO> fetch = new PluginGetter<mcMMO>("mcMMO");
protected final PluginGetter<mcMMO> fetch = new PluginGetter<mcMMO>("mcMMO");
protected int blocksPerSecond = 30;
@ -50,14 +67,21 @@ public final class HookmcMMO extends AbstractHook implements Listener {
@Override
public String getHookVersion() {
return "1.2";
return "2.0";
}
@Override
public CheckType[] getCheckTypes() {
return new CheckType[]{
CheckType.BLOCKBREAK_FASTBREAK, CheckType.BLOCKBREAK_NOSWING,
CheckType.FIGHT_ANGLE, CheckType.FIGHT_SPEED,
CheckType.BLOCKBREAK_FASTBREAK, CheckType.BLOCKBREAK_NOSWING, // old ones
// CheckType.BLOCKBREAK_DIRECTION, CheckType.BLOCKBREAK_FREQUENCY,
// CheckType.BLOCKBREAK_WRONGBLOCK, CheckType.BLOCKBREAK_REACH,
//
// CheckType.FIGHT_ANGLE, CheckType.FIGHT_SPEED, // old ones
//
// CheckType.FIGHT_DIRECTION, CheckType.FIGHT_NOSWING,
// CheckType.FIGHT_REACH,
};
}
@ -67,33 +91,84 @@ public final class HookmcMMO extends AbstractHook implements Listener {
return new Listener[]{this, fetch};
}
@EventHandler(priority=EventPriority.LOWEST)
final void onDamageLowest(final FakeEntityDamageByEntityEvent event){
// TODO might change with API
final Entity entity = event.getDamager();
if (entity instanceof Player)
ncpHook.setPlayerDamage((Player) entity);
}
@EventHandler(priority=EventPriority.LOWEST)
final void onBlockBreakLowest(final FakeBlockBreakEvent event){
ncpHook.setPlayerBlockBreak(event.getPlayer());
}
@EventHandler(priority=EventPriority.LOWEST)
final void onBlockDamageLowest(final FakeBlockDamageEvent event){
ncpHook.setPlayerBlockDamage(event.getPlayer());
}
@Override
public NCPHook getNCPHook() {
if (ncpHook == null){
ncpHook = new HookFacadeImpl();
ncpHook = new HookFacadeImpl(blocksPerSecond);
}
return (NCPHook) ncpHook;
}
///////////////////////////
// Damage (fight)
//////////////////////////
@EventHandler(priority=EventPriority.LOWEST)
final void onDamageLowest(final FakeEntityDamageByEntityEvent event){
final Entity entity = event.getDamager();
if (entity instanceof Player)
ncpHook.damageLowest((Player) entity);
}
@EventHandler(priority=EventPriority.MONITOR)
final void onDamageMonitor(final FakeEntityDamageByEntityEvent event){
final Entity entity = event.getDamager();
if (entity instanceof Player)
ncpHook.damageMonitor((Player) entity);
}
///////////////////////////
// Block damage
//////////////////////////
@EventHandler(priority=EventPriority.LOWEST)
final void onBlockDamageLowest(final FakeBlockDamageEvent event){
ncpHook.blockDamageLowest(event.getPlayer());
}
@EventHandler(priority=EventPriority.LOWEST)
final void onBlockDamageMonitor(final FakeBlockDamageEvent event){
ncpHook.blockDamageMonitor(event.getPlayer());
}
///////////////////////////
// Block break
//////////////////////////
@EventHandler(priority=EventPriority.LOWEST)
final void onBlockBreakLowest(final FakeBlockBreakEvent event){
if (ncpHook.blockBreakLowest(event.getPlayer())){
event.setCancelled(true);
// System.out.println("Cancelled for frequency.");
}
}
@EventHandler(priority=EventPriority.MONITOR)
final void onBlockBreakLMonitor(final FakeBlockBreakEvent event){
ncpHook.blockBreakMontitor(event.getPlayer());
}
/////////////////////////////////
// Config
/////////////////////////////////
@Override
public void applyConfig(CompatConfig cfg, String prefix) {
enabled = cfg.getBoolean(prefix + configPrefix + "enabled", true);
blocksPerSecond = cfg.getInt(prefix + configPrefix + "clickspersecond", 30);
}
@Override
public boolean updateConfig(CompatConfig cfg, String prefix) {
CompatConfig defaults = CompatConfigFactory.getConfig(null);
defaults.set(prefix + configPrefix + "enabled", true);
defaults.set(prefix + configPrefix + "clickspersecond", 30);
return ConfigUtil.forceDefaults(defaults, cfg);
}
@Override
public boolean isEnabled() {
return enabled;
}
}