162 lines
7.6 KiB
Java
162 lines
7.6 KiB
Java
/*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
package fr.neatmonster.nocheatplus.checks.blockbreak;
|
|
|
|
import org.bukkit.Material;
|
|
import org.bukkit.block.Block;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.inventory.ItemStack;
|
|
import org.bukkit.potion.PotionEffectType;
|
|
|
|
import fr.neatmonster.nocheatplus.actions.ParameterName;
|
|
import fr.neatmonster.nocheatplus.checks.Check;
|
|
import fr.neatmonster.nocheatplus.checks.CheckType;
|
|
import fr.neatmonster.nocheatplus.checks.ViolationData;
|
|
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
|
|
import fr.neatmonster.nocheatplus.compat.Bridge1_9;
|
|
import fr.neatmonster.nocheatplus.permissions.Permissions;
|
|
import fr.neatmonster.nocheatplus.players.IPlayerData;
|
|
import fr.neatmonster.nocheatplus.utilities.PotionUtil;
|
|
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
|
import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
|
|
|
|
/**
|
|
* A check used to verify if the player isn't breaking blocks faster than possible.
|
|
*/
|
|
public class FastBreak extends Check {
|
|
|
|
/**
|
|
* Instantiates a new fast break check.
|
|
*/
|
|
public FastBreak() {
|
|
super(CheckType.BLOCKBREAK_FASTBREAK);
|
|
}
|
|
|
|
/**
|
|
* Checks a player for fastbreak. This is NOT for creative mode.
|
|
*
|
|
* @param player
|
|
* the player
|
|
* @param block
|
|
* the block
|
|
* @param isInstaBreak
|
|
* @param data
|
|
* @param cc
|
|
* @param elaspedTime
|
|
* @return true, if successful
|
|
*/
|
|
public boolean check(final Player player, final Block block, final AlmostBoolean isInstaBreak,
|
|
final BlockBreakConfig cc, final BlockBreakData data, final IPlayerData pData) {
|
|
final long now = System.currentTimeMillis();
|
|
boolean cancel = false;
|
|
|
|
// Determine expected breaking time by block type.
|
|
final Material blockType = block.getType();
|
|
final long expectedBreakingTime = Math.max(0, Math.round((double) BlockProperties.getBreakingDuration(blockType, player) * (double) cc.fastBreakModSurvival / 100D));
|
|
|
|
final long elapsedTime;
|
|
// TODO: Concept for unbreakable blocks? Context: extreme VL.
|
|
// TODO: Should it be breakingTime instead of 0 for inconsistencies?
|
|
if (cc.fastBreakStrict) {
|
|
// Counting interact...break.
|
|
elapsedTime = (data.fastBreakBreakTime > data.fastBreakfirstDamage) ? 0 : now - data.fastBreakfirstDamage;
|
|
}
|
|
else {
|
|
// Counting break...break.
|
|
elapsedTime = (data.fastBreakBreakTime > now) ? 0 : now - data.fastBreakBreakTime;
|
|
}
|
|
|
|
// Check if the time used time is lower than expected.
|
|
if (isInstaBreak.decideOptimistically()) {
|
|
// Ignore those for now.
|
|
// TODO: Find out why this was commented out long ago a) did not fix mcMMO b) exploits.
|
|
// TODO: Maybe adjust time to min(time, SOMETHING) for MAYBE/YES.
|
|
}
|
|
else if (elapsedTime < 0) {
|
|
// Ignore it. TODO: ?
|
|
}
|
|
else if (elapsedTime + cc.fastBreakDelay < expectedBreakingTime) {
|
|
// lag or cheat or Minecraft.
|
|
|
|
// Count in server side lag, if desired.
|
|
final float lag = pData.getCurrentWorldDataSafe().shouldAdjustToLag(type)
|
|
? TickTask.getLag(expectedBreakingTime, true) : 1f;
|
|
|
|
final long missingTime = expectedBreakingTime - (long) (lag * elapsedTime);
|
|
|
|
if (missingTime > 0) {
|
|
// Add as penalty
|
|
data.fastBreakPenalties.add(now, (float) missingTime);
|
|
|
|
|
|
// Only raise a violation, if the total penalty score exceeds the contention duration (for lag, delay).
|
|
if (data.fastBreakPenalties.score(cc.fastBreakBucketFactor) > cc.fastBreakGrace) {
|
|
// TODO: maybe add one absolute penalty time for big amounts to stop breaking until then
|
|
final double vlAdded = (double) missingTime / 1000.0;
|
|
data.fastBreakVL += vlAdded;
|
|
final ViolationData vd = new ViolationData(this, player, data.fastBreakVL, vlAdded, cc.fastBreakActions);
|
|
if (vd.needsParameters()) {
|
|
vd.setParameter(ParameterName.BLOCK_TYPE, blockType.toString());
|
|
}
|
|
cancel = executeActions(vd).willCancel();
|
|
}
|
|
// else: still within contention limits.
|
|
}
|
|
}
|
|
else if (expectedBreakingTime > cc.fastBreakDelay) {
|
|
// Fast breaking does not decrease violation level.
|
|
data.fastBreakVL *= 0.9D;
|
|
}
|
|
|
|
// TODO: Rework to use (then hopefully completed) BlockBreakKey.
|
|
if (pData.isDebugActive(type)) {
|
|
tailDebugStats(player, isInstaBreak, blockType,
|
|
elapsedTime, expectedBreakingTime, data, pData);
|
|
}
|
|
else {
|
|
data.stats = null;
|
|
}
|
|
|
|
// (The break time is set in the listener).
|
|
|
|
return cancel;
|
|
}
|
|
|
|
private void tailDebugStats(final Player player, final AlmostBoolean isInstaBreak,
|
|
final Material blockType, final long elapsedTime, final long expectedBreakingTime,
|
|
final BlockBreakData data, final IPlayerData pData) {
|
|
if (pData.hasPermission(Permissions.ADMINISTRATION_DEBUG, player)) {
|
|
// General stats:
|
|
// TODO: Replace stats by new system (BlockBreakKey once complete), commands to inspect / auto-config.
|
|
data.setStats();
|
|
data.stats.addStats(data.stats.getId(blockType+ "/u", true), elapsedTime);
|
|
data.stats.addStats(data.stats.getId(blockType + "/r", true), expectedBreakingTime);
|
|
player.sendMessage(data.stats.getStatsStr(true));
|
|
// Send info about current break:
|
|
final ItemStack stack = Bridge1_9.getItemInMainHand(player);
|
|
final boolean isValidTool = BlockProperties.isValidTool(blockType, stack);
|
|
final double haste = PotionUtil.getPotionEffectAmplifier(player, PotionEffectType.FAST_DIGGING);
|
|
String msg = (isInstaBreak.decideOptimistically() ? ("[Insta=" + isInstaBreak + "]") : "[Normal]") + "[" + blockType + "] "+ elapsedTime + "u / " + expectedBreakingTime +"r (" + (isValidTool?"tool":"no-tool") + ")" + (Double.isInfinite(haste) ? "" : " haste=" + ((int) haste + 1));
|
|
player.sendMessage(msg);
|
|
// net.minecraft.server.Item mcItem = net.minecraft.server.Item.byId[stack.getTypeId()];
|
|
// if (mcItem != null) {
|
|
// double x = mcItem.getDestroySpeed(((CraftItemStack) stack).getHandle(), net.minecraft.server.Block.byId[blockId]);
|
|
// player.sendMessage("mc speed: " + x);
|
|
// }
|
|
}
|
|
}
|
|
|
|
}
|