mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-09-27 14:13:11 +02:00
[BLIND] Continue to implement input specific penalty support.
Have a penalty list to collect input specific penalties from ViolationData and apply after event handling. Pass through the list to fight.critical. Missing: * Penalty factories and configuration. Penalty registry. Link with actions. * Pass through the penalty list to all fight checks. * (Implement default penalty types.) * ((Implement stored penalties.))
This commit is contained in:
parent
96e3869ff1
commit
274c15eccf
@ -74,6 +74,16 @@ public abstract class AbstractGenericPenalty<RI> implements GenericPenalty<RI> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyPrecisely(final RI input) {
|
||||
applyGenericEffects(input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addToPenaltyList(final IPenaltyList penaltyList) {
|
||||
penaltyList.addGenericPenalty(registeredInput, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override for implementation of input-specific effects.
|
||||
*
|
||||
|
@ -0,0 +1,107 @@
|
||||
package fr.neatmonster.nocheatplus.actions.types.penalty;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class DefaultPenaltyList implements IPenaltyList {
|
||||
|
||||
/**
|
||||
* Desperation.
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
* @param <RI>
|
||||
*/
|
||||
private static class GenericNode<RI> {
|
||||
private final List<GenericPenalty<RI>> penalties = new LinkedList<GenericPenalty<RI>>();
|
||||
|
||||
private void apply(final RI input) {
|
||||
for (final GenericPenalty<RI> penalty : penalties) {
|
||||
penalty.applyPrecisely(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isEmpty = true;
|
||||
private boolean hasGeneric = false;
|
||||
private boolean hasNonGeneric= false;
|
||||
private final Map<Class<?>, GenericNode<?>> genericPenalties = new LinkedHashMap<Class<?>, GenericNode<?>>();
|
||||
private final List<InputSpecificPenalty> inputSpecificPenalties = new LinkedList<InputSpecificPenalty>();
|
||||
|
||||
@Override
|
||||
public void addInputSpecificPenalty(final InputSpecificPenalty penalty) {
|
||||
if (penalty == null) {
|
||||
// Until decided how parsing / optimized lists are done.
|
||||
return;
|
||||
}
|
||||
if (penalty instanceof GenericPenalty) {
|
||||
((GenericPenalty<?>) penalty).addToPenaltyList(this);
|
||||
}
|
||||
else {
|
||||
inputSpecificPenalties.add(penalty);
|
||||
isEmpty = false;
|
||||
hasNonGeneric = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <RI> void addGenericPenalty(final Class<RI> registeredInput,
|
||||
final GenericPenalty<RI> penalty) {
|
||||
@SuppressWarnings("unchecked")
|
||||
GenericNode<RI> node = (GenericNode<RI>) genericPenalties.get(registeredInput);
|
||||
if (node == null) {
|
||||
node = new GenericNode<RI>();
|
||||
genericPenalties.put(registeredInput, node);
|
||||
}
|
||||
node.penalties.add(penalty);
|
||||
isEmpty = false;
|
||||
hasGeneric = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <RI, I extends RI> void applyGenericPenaltiesPrecisely(
|
||||
final Class<RI> type, final I input) {
|
||||
@SuppressWarnings("unchecked")
|
||||
final GenericNode<RI> node = (GenericNode<RI>) genericPenalties.get(type);
|
||||
if (node != null) {
|
||||
node.apply(input);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <I> void applyAllApplicableGenericPenalties(final I input) {
|
||||
final Class<?> inputClass = input.getClass();
|
||||
for (final Entry<Class<?>, GenericNode<?>> entry : genericPenalties.entrySet()) {
|
||||
if (entry.getKey().isAssignableFrom(inputClass)) {
|
||||
((GenericNode<? super I>) entry.getValue()).apply(input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyNonGenericPenalties(Object input) {
|
||||
for (final InputSpecificPenalty penalty : inputSpecificPenalties) {
|
||||
penalty.apply(input);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return isEmpty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGenericPenalties() {
|
||||
return hasGeneric;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNonGenericPenalties() {
|
||||
return hasNonGeneric;
|
||||
}
|
||||
|
||||
}
|
@ -30,4 +30,21 @@ public interface GenericPenalty<RI> extends InputSpecificPenalty {
|
||||
*/
|
||||
public Class<RI> getRegisteredInput();
|
||||
|
||||
/**
|
||||
* Internal convenience method to get around some of generics.
|
||||
* <hr>
|
||||
* <b>This method must not call
|
||||
* {@link IPenaltyList#addInputSpecificPenalty(InputSpecificPenalty)}</b>
|
||||
*
|
||||
* @param penaltyList
|
||||
*/
|
||||
public void addToPenaltyList(IPenaltyList penaltyList);
|
||||
|
||||
/**
|
||||
* Alternative to {@link #apply(Object)}, just typed.
|
||||
*
|
||||
* @param input
|
||||
*/
|
||||
public void applyPrecisely(RI input);
|
||||
|
||||
}
|
||||
|
@ -15,7 +15,19 @@
|
||||
package fr.neatmonster.nocheatplus.actions.types.penalty;
|
||||
|
||||
/**
|
||||
* Contain applicable penalty types that need to be handled outside of ViolationData.executeActions, for access by ViolationData.
|
||||
* Contain applicable penalty types that need to be handled outside of
|
||||
* ViolationData.executeActions, for access by ViolationData.
|
||||
* <hr/>
|
||||
* Excluded should be:
|
||||
* <ul>
|
||||
* <li>Penalties only applying to the player.</li>
|
||||
* </ul>
|
||||
* Specifically to be contained are:
|
||||
* <ul>
|
||||
* <li>InputSpecificPenalty</li>
|
||||
* <li>Generic (input specific) penalties.</li>
|
||||
* <ul/>
|
||||
* <hr/>
|
||||
*
|
||||
* @author asofold
|
||||
*
|
||||
@ -24,25 +36,54 @@ public interface IPenaltyList {
|
||||
// TODO: Typed ? + typed per input getter (mapped lists)
|
||||
|
||||
/**
|
||||
* Add an input-specific penalty.
|
||||
* Add an input-specific penalty. Generic penalties are stored extra for
|
||||
* more efficient processing.
|
||||
*
|
||||
* @param penalty
|
||||
*/
|
||||
public void addInputSpecificPenalty(InputSpecificPenalty penalty);
|
||||
|
||||
/**
|
||||
* Apply input specific penalties registered exactly for the given type,
|
||||
* using the given input.
|
||||
* Generic method to let the JVM deal with generics.
|
||||
*
|
||||
* @param input
|
||||
* @param registeredInput
|
||||
* @param penalty
|
||||
*/
|
||||
public <RI, I extends RI> void applyInputSpecificPenaltiesPrecisely(Class<RI> type, I input);
|
||||
public <RI> void addGenericPenalty(Class<RI> registeredInput, GenericPenalty<RI> penalty);
|
||||
|
||||
/**
|
||||
* Apply all penalties registered for the type and all super types of the
|
||||
* Apply generic penalties registered exactly for the given type, using the
|
||||
* given input.
|
||||
*
|
||||
* @param input
|
||||
*/
|
||||
public <I> void applyAllApplicableInputSpecificPenalties(I input);
|
||||
public <RI, I extends RI> void applyGenericPenaltiesPrecisely(Class<RI> type, I input);
|
||||
|
||||
/**
|
||||
* Apply all generic penalties registered for the type and all super types
|
||||
* of the given input
|
||||
*
|
||||
* @param input
|
||||
*/
|
||||
public <I> void applyAllApplicableGenericPenalties(I input);
|
||||
|
||||
/**
|
||||
* Specifically apply non-generic penalties.
|
||||
*
|
||||
* @param input
|
||||
*/
|
||||
public void applyNonGenericPenalties(Object input);
|
||||
|
||||
public boolean isEmpty();
|
||||
|
||||
public boolean hasGenericPenalties();
|
||||
|
||||
/**
|
||||
* Test for InputSpecificPenalty instances that are not GenericPenalty
|
||||
* instances.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean hasNonGenericPenalties();
|
||||
|
||||
}
|
||||
|
@ -19,6 +19,15 @@ public interface InputSpecificPenalty extends Penalty {
|
||||
/**
|
||||
* Apply the input-specific effects of a penalty, for other input than
|
||||
* Player.
|
||||
* <hr/>
|
||||
* Applying input specific penalties might only be possible within the
|
||||
* surrounding context of creation of ViolationData, i.e. during the event
|
||||
* handling. Input-specific effects will not apply within
|
||||
* ViolationData.executeActions, be it within the TickTask
|
||||
* (requestActionsExecution) or during handling a primary-thread check
|
||||
* failure. Instead input specific penalties are executed within the context
|
||||
* that provides the input, e.g. after handling a damage event.
|
||||
* <hr/>
|
||||
*
|
||||
* @param input
|
||||
* May be of unexpected type.
|
||||
|
@ -35,14 +35,18 @@ public interface Penalty {
|
||||
/**
|
||||
* Test if there are input-specific effects, other than with Player instance
|
||||
* input.
|
||||
* <hr/>
|
||||
* Applying input specific penalties might only be possible within the
|
||||
* surrounding context of creation of ViolationData, i.e. during the event
|
||||
* handling. Input-specific effects will not apply within
|
||||
* ViolationData.executeActions, be it within the TickTask
|
||||
* (requestActionsExecution) or during handling a primary-thread check
|
||||
* failure. Instead input specific penalties are executed within the context
|
||||
* that provides the input, e.g. after handling a damage event.
|
||||
* <hr/>
|
||||
*
|
||||
* @return If true, this instance must implement InputSpecificPenalty as
|
||||
* well. Applying input specific penalties might only be possible
|
||||
* within the surrounding context of creation of ViolationData, i.e.
|
||||
* during the event handling. Input-specific effects will not apply
|
||||
* within ViolationData.executeActions, be it within the TickTask
|
||||
* (requestActionsExecution) or during handling a primary-thread
|
||||
* check failure.
|
||||
* well.
|
||||
*/
|
||||
public boolean hasInputSpecificEffects();
|
||||
|
||||
|
@ -79,7 +79,7 @@ public class ViolationData implements IViolationInfo, ActionData {
|
||||
private final IPenaltyList penaltyList;
|
||||
|
||||
/**
|
||||
* Instantiates a new violation data without syupport for input-specific penalties..
|
||||
* Instantiates a new violation data without support for input-specific penalties..
|
||||
* <hr>
|
||||
* This constructor must be thread-safe for checks that might be executed
|
||||
* outside of the primary thread.
|
||||
|
@ -23,6 +23,7 @@ import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.actions.ParameterName;
|
||||
import fr.neatmonster.nocheatplus.actions.types.penalty.IPenaltyList;
|
||||
import fr.neatmonster.nocheatplus.checks.Check;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.ViolationData;
|
||||
@ -59,7 +60,7 @@ public class Critical extends Check {
|
||||
*/
|
||||
public boolean check(final Player player, final Location loc,
|
||||
final FightData data, final FightConfig cc,
|
||||
final IPlayerData pData) {
|
||||
final IPlayerData pData, final IPenaltyList penaltyList) {
|
||||
boolean cancel = false;
|
||||
|
||||
final double mcFallDistance = (double) player.getFallDistance();
|
||||
|
@ -34,6 +34,8 @@ import org.bukkit.event.player.PlayerItemHeldEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.actions.types.penalty.DefaultPenaltyList;
|
||||
import fr.neatmonster.nocheatplus.actions.types.penalty.IPenaltyList;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckListener;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.combined.Combined;
|
||||
@ -170,7 +172,8 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
|
||||
private boolean handleNormalDamage(final Player player, final boolean attackerIsFake,
|
||||
final Entity damaged, final boolean damagedIsFake,
|
||||
final double originalDamage, final double finalDamage,
|
||||
final int tick, final FightData data, final IPlayerData pData) {
|
||||
final int tick, final FightData data, final IPlayerData pData,
|
||||
final IPenaltyList penaltyList) {
|
||||
|
||||
final FightConfig cc = pData.getGenericInstance(FightConfig.class);
|
||||
|
||||
@ -337,7 +340,8 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
|
||||
}
|
||||
// TODO: Consider to always check improbable (first?). At least if config.always or speed or net.attackfrequency are enabled.
|
||||
|
||||
if (!cancelled && critical.isEnabled(player, pData) && critical.check(player, loc, data, cc, pData)) {
|
||||
if (!cancelled && critical.isEnabled(player, pData)
|
||||
&& critical.check(player, loc, data, cc, pData, penaltyList)) {
|
||||
// TODO: Check config for settings.
|
||||
cancelled = true;
|
||||
}
|
||||
@ -565,18 +569,23 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
|
||||
final FightData damagedData;
|
||||
final boolean damagedIsDead = damaged.isDead();
|
||||
final boolean damagedIsFake = !crossPlugin.getHandle().isNativeEntity(damaged);
|
||||
IPenaltyList penaltyList = null;
|
||||
if (damagedPlayer != null) {
|
||||
final IPlayerData damagedPData = DataManager.getPlayerData(damagedPlayer);
|
||||
damagedData = damagedPData.getGenericInstance(FightData.class);
|
||||
if (!damagedIsDead) {
|
||||
// God mode check.
|
||||
// (Do not test the savage.)
|
||||
if (damagedPData.isCheckActive(CheckType.FIGHT_GODMODE, damagedPlayer)
|
||||
&& godMode.check(damagedPlayer, damagedIsFake,
|
||||
if (damagedPData.isCheckActive(CheckType.FIGHT_GODMODE, damagedPlayer)) {
|
||||
if (penaltyList == null) {
|
||||
penaltyList = new DefaultPenaltyList();
|
||||
}
|
||||
if (godMode.check(damagedPlayer, damagedIsFake,
|
||||
BridgeHealth.getDamage(event), damagedData, damagedPData)) {
|
||||
// It requested to "cancel" the players invulnerability, so set their noDamageTicks to 0.
|
||||
damagedPlayer.setNoDamageTicks(0);
|
||||
}
|
||||
}
|
||||
// Adjust buffer for fast heal checks.
|
||||
if (BridgeHealth.getHealth(damagedPlayer) >= BridgeHealth.getMaxHealth(damagedPlayer)) {
|
||||
// TODO: Might use the same FightData instance for GodMode.
|
||||
@ -602,9 +611,23 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
|
||||
|
||||
// Attacking entities.
|
||||
if (event instanceof EntityDamageByEntityEvent) {
|
||||
onEntityDamageByEntity(damaged, damagedPlayer, damagedIsDead, damagedIsFake,
|
||||
damagedData, (EntityDamageByEntityEvent) event);
|
||||
if (penaltyList == null) {
|
||||
penaltyList = new DefaultPenaltyList();
|
||||
}
|
||||
onEntityDamageByEntity(damaged, damagedPlayer, damagedIsDead, damagedIsFake,
|
||||
damagedData, (EntityDamageByEntityEvent) event,
|
||||
penaltyList);
|
||||
}
|
||||
|
||||
if (penaltyList != null && !penaltyList.isEmpty()) {
|
||||
if (penaltyList.hasGenericPenalties()) {
|
||||
penaltyList.applyAllApplicableGenericPenalties(event);
|
||||
}
|
||||
if (penaltyList.hasNonGenericPenalties()) {
|
||||
penaltyList.applyNonGenericPenalties(event);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -618,7 +641,8 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
|
||||
*/
|
||||
private void onEntityDamageByEntity(final Entity damaged, final Player damagedPlayer,
|
||||
final boolean damagedIsDead, final boolean damagedIsFake,
|
||||
final FightData damagedData, final EntityDamageByEntityEvent event) {
|
||||
final FightData damagedData, final EntityDamageByEntityEvent event,
|
||||
final IPenaltyList penaltyList) {
|
||||
final Entity damager = event.getDamager();
|
||||
final int tick = TickTask.getTick();
|
||||
if (damagedPlayer != null && !damagedIsDead) {
|
||||
@ -658,7 +682,8 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
|
||||
UnusedVelocity.checkUnusedVelocity(attacker, CheckType.FIGHT, attackerPData);
|
||||
}
|
||||
// Workaround for subsequent melee damage eventsfor explosions. TODO: Legacy or not, need a KB.
|
||||
if (damageCause == DamageCause.BLOCK_EXPLOSION || damageCause == DamageCause.ENTITY_EXPLOSION) {
|
||||
if (damageCause == DamageCause.BLOCK_EXPLOSION
|
||||
|| damageCause == DamageCause.ENTITY_EXPLOSION) {
|
||||
// NOTE: Pigs don't have data.
|
||||
attackerData.lastExplosionEntityId = damaged.getEntityId();
|
||||
attackerData.lastExplosionDamageTick = tick;
|
||||
@ -688,7 +713,7 @@ public class FightListener extends CheckListener implements JoinLeaveListener{
|
||||
else if (handleNormalDamage(player, !crossPlugin.getHandle().isNativePlayer(player),
|
||||
damaged, damagedIsFake,
|
||||
BridgeHealth.getOriginalDamage(event), BridgeHealth.getFinalDamage(event),
|
||||
tick, attackerData, attackerPData)) {
|
||||
tick, attackerData, attackerPData, penaltyList)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user