mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2024-11-07 11:10:05 +01:00
Bleeding: Improved fast break check, can be switched with the oldcheck
setting. fastbreak.debug to true + nocheatplus.admin.debug gives output about breaking time and expected breaking time for balancing purposes. Improved WrongBlock.
This commit is contained in:
parent
120d17a23c
commit
6371e0f20c
@ -45,6 +45,7 @@ import fr.neatmonster.nocheatplus.metrics.Metrics.Graph;
|
||||
import fr.neatmonster.nocheatplus.metrics.Metrics.Plotter;
|
||||
import fr.neatmonster.nocheatplus.metrics.MetricsData;
|
||||
import fr.neatmonster.nocheatplus.players.Permissions;
|
||||
import fr.neatmonster.nocheatplus.utilities.BlockUtils;
|
||||
import fr.neatmonster.nocheatplus.utilities.LagMeasureTask;
|
||||
import fr.neatmonster.nocheatplus.utilities.TickTask;
|
||||
|
||||
@ -284,6 +285,9 @@ public class NoCheatPlus extends JavaPlugin implements Listener {
|
||||
configOutdated = true;
|
||||
} catch (final Exception e) {}
|
||||
|
||||
// Debug information about unknown blocks.
|
||||
if (!config.getBoolean(ConfPaths.BLOCKBREAK_FASTBREAK_OLDCHECK)) BlockUtils.dumpBlocks(config.getBoolean(ConfPaths.BLOCKBREAK_FASTBREAK_DEBUG, false)); // false);
|
||||
|
||||
// Tell the server administrator that we finished loading NoCheatPlus now.
|
||||
System.out.println("[NoCheatPlus] Version " + getDescription().getVersion() + " is enabled.");
|
||||
}
|
||||
|
@ -75,10 +75,13 @@ public class BlockBreakConfig extends ACheckConfig {
|
||||
public final ActionList directionActions;
|
||||
|
||||
public final boolean fastBreakCheck;
|
||||
public final boolean fastBreakDebug;
|
||||
public final int fastBreakBuckets;
|
||||
public final long fastBreakBucketDur;
|
||||
public final float fastBreakBucketFactor;
|
||||
public final int fastBreakBuffer;
|
||||
public final long fastBreakContention;
|
||||
public final long fastBreakDelay;
|
||||
public final int fastBreakInterval;
|
||||
public final boolean fastBreakOldCheck;
|
||||
public final ActionList fastBreakActions;
|
||||
@ -105,10 +108,13 @@ public class BlockBreakConfig extends ACheckConfig {
|
||||
directionActions = data.getActionList(ConfPaths.BLOCKBREAK_DIRECTION_ACTIONS, Permissions.BLOCKBREAK_DIRECTION);
|
||||
|
||||
fastBreakCheck = data.getBoolean(ConfPaths.BLOCKBREAK_FASTBREAK_CHECK);
|
||||
fastBreakDebug = data.getBoolean(ConfPaths.BLOCKBREAK_FASTBREAK_DEBUG, false); // hidden
|
||||
fastBreakContention = data.getLong(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_CONTENTION, 2000);
|
||||
fastBreakBucketDur = data.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_DUR, 4000);
|
||||
fastBreakBucketFactor = (float) data.getDouble(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_FACTOR, 0.99);
|
||||
fastBreakBuckets = data.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_BUCKETS_N, 30);
|
||||
fastBreakBuffer = data.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_BUFFER);
|
||||
fastBreakDelay = data.getLong(ConfPaths.BLOCKBREAK_FASTBREAK_DELAY, 50);
|
||||
fastBreakInterval = data.getInt(ConfPaths.BLOCKBREAK_FASTBREAK_INTERVAL);
|
||||
fastBreakOldCheck = data.getBoolean(ConfPaths.BLOCKBREAK_FASTBREAK_OLDCHECK);
|
||||
fastBreakActions = data.getActionList(ConfPaths.BLOCKBREAK_FASTBREAK_ACTIONS, Permissions.BLOCKBREAK_FASTBREAK);
|
||||
|
@ -6,9 +6,10 @@ import java.util.Map;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import fr.neatmonster.nocheatplus.checks.ACheckData;
|
||||
import fr.neatmonster.nocheatplus.checks.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckDataFactory;
|
||||
import fr.neatmonster.nocheatplus.checks.ICheckData;
|
||||
import fr.neatmonster.nocheatplus.utilities.ActionFrequency;
|
||||
import fr.neatmonster.nocheatplus.utilities.Stats;
|
||||
|
||||
/*
|
||||
* M#"""""""'M dP dP M#"""""""'M dP
|
||||
@ -77,6 +78,8 @@ public class BlockBreakData extends ACheckData {
|
||||
public int clickedY;
|
||||
public int clickedZ;
|
||||
|
||||
public final Stats stats;
|
||||
|
||||
// Data of the fast break check.
|
||||
public final ActionFrequency fastBreakPenalties;
|
||||
public int fastBreakBuffer;
|
||||
@ -95,6 +98,7 @@ public class BlockBreakData extends ACheckData {
|
||||
fastBreakBuffer = cc.fastBreakBuffer;
|
||||
fastBreakPenalties = new ActionFrequency(cc.fastBreakBuckets, cc.fastBreakBucketDur);
|
||||
wrongBlockVL = new ActionFrequency(6, 20000);
|
||||
stats = cc.fastBreakDebug?(new Stats("NCP/FASTBREAK")):null;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -96,6 +96,7 @@ public class BlockBreakListener implements Listener {
|
||||
// At least one check failed and demanded to cancel the event.
|
||||
if (cancelled)
|
||||
event.setCancelled(cancelled);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,6 +8,7 @@ import org.bukkit.entity.Player;
|
||||
import fr.neatmonster.nocheatplus.checks.Check;
|
||||
import fr.neatmonster.nocheatplus.checks.CheckType;
|
||||
import fr.neatmonster.nocheatplus.checks.combined.Improbable;
|
||||
import fr.neatmonster.nocheatplus.players.Permissions;
|
||||
import fr.neatmonster.nocheatplus.utilities.BlockUtils;
|
||||
|
||||
/*
|
||||
@ -86,21 +87,26 @@ public class FastBreak extends Check {
|
||||
}
|
||||
else{
|
||||
// First, check the game mode of the player and choose the right limit.
|
||||
long breakingTime = Math.round((double) cc.fastBreakInterval / 100D * (double) BlockUtils.getBreakingDuration(block.getTypeId(), player.getItemInHand()));
|
||||
long breakingTime = Math.round((double) cc.fastBreakInterval / 100D * (double) BlockUtils.getBreakingDuration(block.getTypeId(), player));
|
||||
if (player.getGameMode() == GameMode.CREATIVE)
|
||||
breakingTime = Math.round((double) cc.fastBreakInterval / 100D * (double) CREATIVE);
|
||||
|
||||
// fastBreakDamageTime is now first interact on block (!).
|
||||
if (now - data.fastBreakDamageTime < breakingTime){
|
||||
// lag or cheat or Minecraft.
|
||||
final long elapsedTime = now - data.fastBreakDamageTime;
|
||||
|
||||
// Check if the time used time is lower than expected.
|
||||
if (elapsedTime + cc.fastBreakDelay < breakingTime){
|
||||
// lag or cheat or Minecraft.
|
||||
|
||||
final long missingTime = breakingTime - elapsedTime;
|
||||
|
||||
|
||||
|
||||
// Add as penalty
|
||||
data.fastBreakPenalties.add(now, (float) missingTime);
|
||||
|
||||
if (data.fastBreakPenalties.getScore(1f) > cc.fastBreakContention){
|
||||
// Only raise a violation, if the total penalty score exceeds the contention duration (for lag, delay).
|
||||
if (data.fastBreakPenalties.getScore(cc.fastBreakBucketFactor) > cc.fastBreakContention){
|
||||
// TODO: maybe add one absolute penalty time for big amounts to stop breaking until then
|
||||
data.fastBreakVL += missingTime;
|
||||
cancel = executeActions(player, data.fastBreakVL, missingTime, cc.fastBreakActions);
|
||||
@ -113,8 +119,13 @@ public class FastBreak extends Check {
|
||||
data.fastBreakVL *= 0.9D;
|
||||
}
|
||||
|
||||
if (cc.fastBreakDebug && player.hasPermission(Permissions.ADMINISTRATION_DEBUG)){
|
||||
data.stats.addStats(data.stats.getId(Integer.toString(block.getTypeId())+"u", true), elapsedTime);
|
||||
data.stats.addStats(data.stats.getId(Integer.toString(block.getTypeId())+ "r", true), breakingTime);
|
||||
player.sendMessage(data.stats.getStatsStr(true));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Remember the block breaking time.
|
||||
data.fastBreakBreakTime = now;
|
||||
|
@ -25,6 +25,11 @@ public class WrongBlock extends Check {
|
||||
cancel = true;
|
||||
if (Improbable.check(player, 5.0f, now))
|
||||
cancel = true;
|
||||
// Reset, to prevent endless violation level farming.
|
||||
data.fastBreakDamageTime = now;
|
||||
data.clickedX = block.getX();
|
||||
data.clickedY = block.getY();
|
||||
data.clickedZ = block.getZ();
|
||||
}
|
||||
|
||||
return cancel;
|
||||
|
@ -66,12 +66,16 @@ public abstract class ConfPaths {
|
||||
public static final String BLOCKBREAK_DIRECTION_ACTIONS = BLOCKBREAK_DIRECTION + "actions";
|
||||
|
||||
private static final String BLOCKBREAK_FASTBREAK = BLOCKBREAK + "fastbreak.";
|
||||
public static final String BLOCKBREAK_FASTBREAK_DEBUG = BLOCKBREAK_FASTBREAK + "debug";
|
||||
public static final String BLOCKBREAK_FASTBREAK_CHECK = BLOCKBREAK_FASTBREAK + "active";
|
||||
private static final String BLOCKBREAK_FASTBREAK_BUCKETS = BLOCKBREAK + "buckets.";
|
||||
public static final String BLOCKBREAK_FASTBREAK_BUCKETS_CONTENTION = BLOCKBREAK_FASTBREAK_BUCKETS + "contention";
|
||||
public static final String BLOCKBREAK_FASTBREAK_BUCKETS_N = BLOCKBREAK_FASTBREAK_BUCKETS + "number";
|
||||
public static final String BLOCKBREAK_FASTBREAK_BUCKETS_DUR = BLOCKBREAK_FASTBREAK_BUCKETS + "duration";
|
||||
public static final String BLOCKBREAK_FASTBREAK_BUCKETS_FACTOR = BLOCKBREAK_FASTBREAK_BUCKETS + "factor";
|
||||
|
||||
public static final String BLOCKBREAK_FASTBREAK_BUFFER = BLOCKBREAK_FASTBREAK + "buffer";
|
||||
public static final String BLOCKBREAK_FASTBREAK_DELAY = BLOCKBREAK_FASTBREAK + "delay";
|
||||
public static final String BLOCKBREAK_FASTBREAK_INTERVAL = BLOCKBREAK_FASTBREAK + "interval";
|
||||
public static final String BLOCKBREAK_FASTBREAK_OLDCHECK = BLOCKBREAK_FASTBREAK + "oldcheck";
|
||||
public static final String BLOCKBREAK_FASTBREAK_ACTIONS = BLOCKBREAK_FASTBREAK + "actions";
|
||||
|
@ -81,7 +81,7 @@ public class DefaultConfig extends ConfigFile {
|
||||
set(ConfPaths.BLOCKBREAK_REACH_ACTIONS, "cancel vl>5 log:breach:0:2:if cancel");
|
||||
|
||||
set(ConfPaths.BLOCKBREAK_WRONGBLOCK_CHECK, true);
|
||||
set(ConfPaths.BLOCKBREAK_WRONGBLOCK_ACTIONS, "log:bwrong:0:5:if cancel vl>20 log:bwrong:0:5:if cancel cmd:kickwb");
|
||||
set(ConfPaths.BLOCKBREAK_WRONGBLOCK_ACTIONS, "cancel vl>5 log:bwrong:0:5:if cancel vl>20 log:bwrong:0:5:if cancel cmd:kickwb");
|
||||
|
||||
/*
|
||||
* 888 88b, 888 888 888 d8 d8
|
||||
|
@ -34,7 +34,10 @@ public class Permissions {
|
||||
public static final String ADMINISTRATION_REMOVEPLAYER = ADMINISTRATION + ".removeplayer";
|
||||
public static final String ADMINISTRATION_TELL = ADMINISTRATION + ".tell";
|
||||
public static final String ADMINISTRATION_TEMPKICK = ADMINISTRATION + ".tempkick";
|
||||
// Debug permission, for player spam (not in plugin.yml, currently).
|
||||
public static final String ADMINISTRATION_DEBUG = ADMINISTRATION + ".debug";
|
||||
|
||||
// Bypasses held extra from command permissions.
|
||||
private final static String BYPASS = NOCHEATPLUS + ".bypass";
|
||||
public static final String BYPASS_DENY_LOGIN = BYPASS + "denylogin";
|
||||
|
||||
|
@ -1,22 +1,502 @@
|
||||
package fr.neatmonster.nocheatplus.utilities;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
/**
|
||||
* Poperties of blocks.
|
||||
* @author mc_dev
|
||||
*
|
||||
*/
|
||||
public class BlockUtils {
|
||||
public static enum ToolType{
|
||||
NONE,
|
||||
SWORD,
|
||||
SHEARS,
|
||||
SPADE,
|
||||
AXE,
|
||||
PICKAXE,
|
||||
// HOE,
|
||||
}
|
||||
public static enum MaterialBase{
|
||||
NONE(0, 1f),
|
||||
WOOD(1, 2f),
|
||||
STONE(2, 4f),
|
||||
IRON(3, 6f),
|
||||
DIAMOND(4, 8f),
|
||||
GOLD(5, 12f);
|
||||
/** Index for array. */
|
||||
public final int index;
|
||||
public final float breakMultiplier;
|
||||
private MaterialBase(int index, float breakMultiplier){
|
||||
this.index = index;
|
||||
this.breakMultiplier = breakMultiplier;
|
||||
}
|
||||
public static final MaterialBase getById(final int id){
|
||||
for (final MaterialBase base : MaterialBase.values()){
|
||||
if (base.index == id) return base;
|
||||
}
|
||||
throw new IllegalArgumentException("Bad id: " + id);
|
||||
}
|
||||
}
|
||||
/** Properties of a tool. */
|
||||
public static class ToolProps{
|
||||
|
||||
public final ToolType toolType;
|
||||
public final MaterialBase materialBase;
|
||||
public ToolProps(ToolType toolType, MaterialBase materialBase){
|
||||
this.toolType = toolType;
|
||||
this.materialBase = materialBase;
|
||||
}
|
||||
public String toString(){
|
||||
return "ToolProps("+toolType + "/"+materialBase+")";
|
||||
}
|
||||
}
|
||||
/** Properties of a block. */
|
||||
public static class BlockProps{
|
||||
public float hardness = 1;
|
||||
|
||||
public final ToolProps tool;
|
||||
public final long[] breakingTimes;
|
||||
public final float hardness;
|
||||
public BlockProps(ToolProps tool, float hardness){
|
||||
this.tool = tool;
|
||||
this.hardness = hardness;
|
||||
breakingTimes = new long[6];
|
||||
for (int i = 0; i < 6; i++) {
|
||||
final float multiplier;
|
||||
if (tool.materialBase == null)
|
||||
multiplier = 1f;
|
||||
else if (i < tool.materialBase.index)
|
||||
multiplier = 1f;
|
||||
else
|
||||
multiplier = MaterialBase.getById(i).breakMultiplier * 3.33f;
|
||||
breakingTimes[i] = (long) (1000f * 5f * hardness / multiplier);
|
||||
}
|
||||
}
|
||||
public BlockProps(ToolProps tool, float hardness, long[] breakingTimes){
|
||||
this.tool = tool;
|
||||
this.breakingTimes = breakingTimes;
|
||||
this.hardness = hardness;
|
||||
}
|
||||
public String toString(){
|
||||
return "BlockProps(" + hardness + " / " + tool.toString() + " / " + Arrays.toString(breakingTimes) + ")";
|
||||
}
|
||||
}
|
||||
|
||||
protected static final int maxBlocks = 4096;
|
||||
|
||||
/** Properties by block id, might be extended to 4096 later for custom blocks.*/
|
||||
protected static final BlockProps[] blocks = new BlockProps[maxBlocks];
|
||||
|
||||
/** Map for the tool properties. */
|
||||
protected static Map<Integer, ToolProps> tools = new HashMap<Integer, ToolProps>(50, 0.5f);
|
||||
|
||||
/** Breaking time for indestructible materials. */
|
||||
public static final long indestructible = Long.MAX_VALUE;
|
||||
|
||||
/** Default tool properties (inappropriate tool). */
|
||||
public static final ToolProps noTool = new ToolProps(ToolType.NONE, MaterialBase.NONE);
|
||||
|
||||
public static final ToolProps woodSword = new ToolProps(ToolType.SWORD, MaterialBase.WOOD);
|
||||
|
||||
public static final ToolProps woodSpade = new ToolProps(ToolType.SPADE, MaterialBase.WOOD);
|
||||
|
||||
public static final ToolProps woodPickaxe = new ToolProps(ToolType.PICKAXE, MaterialBase.WOOD);
|
||||
|
||||
public static final ToolProps woodAxe = new ToolProps(ToolType.AXE, MaterialBase.WOOD);
|
||||
|
||||
public static final ToolProps stonePickaxe = new ToolProps(ToolType.PICKAXE, MaterialBase.STONE);
|
||||
|
||||
public static final ToolProps ironPickaxe = new ToolProps(ToolType.PICKAXE, MaterialBase.IRON);
|
||||
|
||||
public static final ToolProps diamondPickaxe = new ToolProps(ToolType.PICKAXE, MaterialBase.DIAMOND);
|
||||
|
||||
/** Times for instant breaking. */
|
||||
public static final long[] instantTimes = secToMs(0);
|
||||
|
||||
public static final long[] leafTimes = secToMs(0.3);
|
||||
|
||||
public static long[] glassTimes = secToMs(0.45);
|
||||
|
||||
public static final long[] gravelTimes = secToMs(0.9, 0.45, 0.25, 0.15, 0.15, 0.1);
|
||||
|
||||
public static long[] railsTimes = secToMs(1.05, 0.55, 0.3, 0.2, 0.15, 0.1);
|
||||
|
||||
public static final long[] woodTimes = secToMs(3, 1.5, 0.75, 0.5, 0.4, 0.25);
|
||||
|
||||
public static final long[] ironTimes = secToMs(15, 15, 1.15, 0.75, 0.6, 15);
|
||||
|
||||
public static final long[] diamondTimes = secToMs(15, 15, 15, 0.75, 0.6, 15);
|
||||
|
||||
private static final long[] indestructibleTimes = new long[] {indestructible, indestructible, indestructible, indestructible, indestructible, indestructible};
|
||||
|
||||
|
||||
/** Instantly breakable. */
|
||||
public static final BlockProps instantType = new BlockProps(noTool, 0, instantTimes);
|
||||
|
||||
public static final BlockProps glassType = new BlockProps(noTool, 0.3f, glassTimes);
|
||||
|
||||
public static final BlockProps gravelType = new BlockProps(woodSpade, 0.6f, gravelTimes);
|
||||
/** Stone type blocks. */
|
||||
public static final BlockProps stoneType = new BlockProps(woodPickaxe, 1.5f);
|
||||
|
||||
public static final BlockProps woodType = new BlockProps(woodAxe, 2, woodTimes);
|
||||
|
||||
public static final BlockProps brickType = new BlockProps(woodPickaxe, 2);
|
||||
|
||||
public static final BlockProps coalType = new BlockProps(woodPickaxe, 3);
|
||||
|
||||
public static final BlockProps ironType = new BlockProps(stonePickaxe, 3, ironTimes);
|
||||
|
||||
public static final BlockProps diamondType = new BlockProps(ironPickaxe, 3, diamondTimes);
|
||||
|
||||
public static final BlockProps hugeMushroomType = new BlockProps(woodAxe, 0.2f, secToMs(0.3, 0.15, 0.1, 0.05, 0.05, 0.05));
|
||||
|
||||
public static final BlockProps leafType = new BlockProps(noTool, 0.2f, leafTimes);
|
||||
|
||||
public static final BlockProps sandType = new BlockProps(woodSpade, 0.5f, secToMs(0.75, 0.4, 0.2, 0.15, 0.1, 0.1));
|
||||
|
||||
public static final BlockProps leverType = new BlockProps(noTool, 0.5f, secToMs(0.75));
|
||||
|
||||
public static final BlockProps sandStoneType = new BlockProps(woodPickaxe, 0.8f);
|
||||
|
||||
public static final BlockProps pumpkinType = new BlockProps(woodAxe, 1, secToMs(1.5, 0.75, 0.4, 0.25, 0.2, 0.15));
|
||||
|
||||
public static final BlockProps chestType = new BlockProps(woodAxe, 2.5f, secToMs(3.75, 1.9, 0.95, 0.65, 0.5, 0.35));
|
||||
|
||||
public static final BlockProps woodDoorType = new BlockProps(woodAxe, 3.0f, secToMs(4.5, 2.25, 1.15, 0.75, 0.6, 0.4));
|
||||
|
||||
public static final BlockProps dispenserType = new BlockProps(woodPickaxe, 3.5f);
|
||||
|
||||
public static final BlockProps ironDoorType = new BlockProps(woodPickaxe, 5);
|
||||
|
||||
private static final BlockProps indestructibleType = new BlockProps(noTool, -1f, indestructibleTimes);
|
||||
|
||||
/** Returned if unknown */
|
||||
public static final BlockProps defaultBlockProps = stoneType;
|
||||
|
||||
protected static final Material[] instantMat = new Material[]{
|
||||
// Named in wiki.
|
||||
Material.CROPS,
|
||||
Material.TRIPWIRE_HOOK, Material.TRIPWIRE,
|
||||
Material.TORCH,
|
||||
Material.TNT,
|
||||
Material.SUGAR_CANE_BLOCK,
|
||||
Material.SAPLING,
|
||||
Material.RED_ROSE, Material.YELLOW_FLOWER,
|
||||
Material.REDSTONE_WIRE,
|
||||
Material.REDSTONE_TORCH_ON, Material.REDSTONE_TORCH_OFF,
|
||||
Material.DIODE_BLOCK_ON, Material.DIODE_BLOCK_OFF,
|
||||
Material.PUMPKIN_STEM,
|
||||
Material.NETHER_WARTS,
|
||||
Material.BROWN_MUSHROOM, Material.RED_MUSHROOM,
|
||||
Material.MELON_STEM,
|
||||
Material.WATER_LILY,
|
||||
Material.LONG_GRASS,
|
||||
Material.FIRE,
|
||||
Material.DEAD_BUSH,
|
||||
//
|
||||
Material.CROPS,
|
||||
};
|
||||
|
||||
static{
|
||||
try{
|
||||
initTools();
|
||||
initBlocks();
|
||||
}
|
||||
catch(Throwable t){
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static void initTools() {
|
||||
tools.put(268, new ToolProps(ToolType.SWORD, MaterialBase.WOOD));
|
||||
tools.put(269, new ToolProps(ToolType.SPADE, MaterialBase.WOOD));
|
||||
tools.put(270, new ToolProps(ToolType.PICKAXE, MaterialBase.WOOD));
|
||||
tools.put(271, new ToolProps(ToolType.AXE, MaterialBase.WOOD));
|
||||
|
||||
tools.put(272, new ToolProps(ToolType.SWORD, MaterialBase.STONE));
|
||||
tools.put(273, new ToolProps(ToolType.SPADE, MaterialBase.STONE));
|
||||
tools.put(274, new ToolProps(ToolType.PICKAXE, MaterialBase.STONE));
|
||||
tools.put(275, new ToolProps(ToolType.AXE, MaterialBase.STONE));
|
||||
|
||||
tools.put(256, new ToolProps(ToolType.SPADE, MaterialBase.IRON));
|
||||
tools.put(257, new ToolProps(ToolType.PICKAXE, MaterialBase.IRON));
|
||||
tools.put(258, new ToolProps(ToolType.AXE, MaterialBase.IRON));
|
||||
tools.put(267, new ToolProps(ToolType.SWORD, MaterialBase.IRON));
|
||||
|
||||
tools.put(276, new ToolProps(ToolType.SWORD, MaterialBase.DIAMOND));
|
||||
tools.put(277, new ToolProps(ToolType.SPADE, MaterialBase.DIAMOND));
|
||||
tools.put(278, new ToolProps(ToolType.PICKAXE, MaterialBase.DIAMOND));
|
||||
tools.put(279, new ToolProps(ToolType.AXE, MaterialBase.DIAMOND));
|
||||
|
||||
tools.put(283, new ToolProps(ToolType.SWORD, MaterialBase.GOLD));
|
||||
tools.put(284, new ToolProps(ToolType.SPADE, MaterialBase.GOLD));
|
||||
tools.put(285, new ToolProps(ToolType.PICKAXE, MaterialBase.GOLD));
|
||||
tools.put(286, new ToolProps(ToolType.AXE, MaterialBase.GOLD));
|
||||
|
||||
tools.put(359, new ToolProps(ToolType.SHEARS, MaterialBase.NONE));
|
||||
}
|
||||
|
||||
|
||||
private static void initBlocks() {
|
||||
for (int i = 0; i <blocks.length; i++){
|
||||
blocks[i] = null;
|
||||
}
|
||||
//
|
||||
for (final Material mat : instantMat){
|
||||
blocks[mat.getId()] = instantType;
|
||||
}
|
||||
blocks[Material.SNOW.getId()] = new BlockProps(getToolProps(Material.WOOD_SPADE), 0.1f, secToMs(0.5, 0.1, 0.05, 0.05, 0.05, 0.05));
|
||||
for (Material mat : new Material[]{
|
||||
Material.VINE, Material.LEAVES, Material.COCOA, Material.BED_BLOCK}){
|
||||
blocks[mat.getId()] = leafType;
|
||||
}
|
||||
blocks[Material.SNOW_BLOCK.getId()] = new BlockProps(getToolProps(Material.WOOD_SPADE), 0.1f, secToMs(1, 0.15, 0.1, 0.05, 0.05, 0.05));
|
||||
blocks[Material.HUGE_MUSHROOM_1.getId()] = hugeMushroomType;
|
||||
blocks[Material.HUGE_MUSHROOM_2.getId()] = hugeMushroomType;
|
||||
for (Material mat : new Material[]{
|
||||
Material.REDSTONE_LAMP_ON, Material.REDSTONE_LAMP_OFF,
|
||||
Material.GLOWSTONE, Material.GLASS,
|
||||
}){
|
||||
blocks[mat.getId()] = glassType;
|
||||
}
|
||||
blocks[102] = glassType; // glass panes
|
||||
blocks[Material.NETHERRACK.getId()] = new BlockProps(woodPickaxe, 0.4f, secToMs(2, 0.3, 0.15, 0.1, 0.1, 0.05));
|
||||
blocks[Material.LADDER.getId()] = new BlockProps(noTool, 0.4f, secToMs(0.6));
|
||||
blocks[Material.CACTUS.getId()] = new BlockProps(noTool, 0.4f, secToMs(0.6));
|
||||
blocks[Material.WOOD_PLATE.getId()] = new BlockProps(woodAxe, 0.5f, secToMs(0.75, 0.4, 0.2, 0.15, 0.1, 0.1));
|
||||
blocks[Material.STONE_PLATE.getId()] = new BlockProps(woodPickaxe, 0.5f, secToMs(2.5, 0.4, 0.2, 0.15, 0.1, 0.07));
|
||||
blocks[Material.SAND.getId()] = sandType;
|
||||
blocks[Material.SOUL_SAND.getId()] = sandType;
|
||||
for (Material mat: new Material[]{Material.LEVER, Material.PISTON_BASE,
|
||||
Material.PISTON_EXTENSION, Material.PISTON_STICKY_BASE,
|
||||
Material.STONE_BUTTON, Material.PISTON_MOVING_PIECE}){
|
||||
blocks[mat.getId()] = leverType;
|
||||
}
|
||||
// blocks[Material.ICE.getId()] = new BlockProps(woodPickaxe, 0.5f, secToMs(2.5, 0.4, 0.2, 0.15, 0.1, 0.1));
|
||||
blocks[Material.ICE.getId()] = new BlockProps(woodPickaxe, 0.5f, secToMs(0.7, 0.35, 0.18, 0.12, 0.09, 0.06 ));
|
||||
blocks[Material.DIRT.getId()] = sandType;
|
||||
blocks[Material.CAKE_BLOCK.getId()] = leverType;
|
||||
blocks[Material.BREWING_STAND.getId()] = new BlockProps(woodPickaxe, 0.5f, secToMs(2.5, 0.4, 0.2, 0.15, 0.1, 0.1));
|
||||
blocks[Material.SPONGE.getId()] = new BlockProps(noTool, 0.6f, secToMs(0.9));
|
||||
for (Material mat : new Material[]{
|
||||
Material.MYCEL, Material.GRAVEL, Material.GRASS, Material.SOIL,
|
||||
Material.CLAY,
|
||||
}){
|
||||
blocks[mat.getId()] = gravelType;
|
||||
}
|
||||
for (Material mat : new Material[]{
|
||||
Material.RAILS, Material.POWERED_RAIL, Material.DETECTOR_RAIL,
|
||||
}){
|
||||
blocks[mat.getId()] = new BlockProps(woodPickaxe, 0.7f, railsTimes);
|
||||
}
|
||||
blocks[Material.MONSTER_EGGS.getId()] = new BlockProps(noTool, 0.75f, secToMs(1.15));
|
||||
blocks[Material.WOOL.getId()] = new BlockProps(noTool, 0.8f, secToMs(1.2));
|
||||
blocks[Material.SANDSTONE.getId()] = sandStoneType;
|
||||
blocks[Material.SANDSTONE_STAIRS.getId()] = sandStoneType;
|
||||
for (Material mat : new Material[]{
|
||||
Material.STONE, Material.SMOOTH_BRICK, Material.SMOOTH_STAIRS,
|
||||
}){
|
||||
blocks[mat.getId()] = stoneType;
|
||||
}
|
||||
blocks[Material.NOTE_BLOCK.getId()] = new BlockProps(woodAxe, 0.8f, secToMs(1.2, 0.6, 0.3, 0.2, 0.15, 0.1));
|
||||
blocks[Material.WALL_SIGN.getId()] = pumpkinType;
|
||||
blocks[Material.SIGN_POST.getId()] = pumpkinType;
|
||||
blocks[Material.PUMPKIN.getId()] = pumpkinType;
|
||||
blocks[Material.JACK_O_LANTERN.getId()] = pumpkinType;
|
||||
blocks[Material.MELON_BLOCK.getId()] = new BlockProps(noTool, 1, secToMs(1.5));
|
||||
blocks[Material.BOOKSHELF.getId()] = new BlockProps(woodAxe, 1.5f, secToMs(2.25, 1.15, 0.6, 0.4, 0.3, 0.2));
|
||||
for (Material mat : new Material[]{
|
||||
Material.WOOD_STAIRS, Material.WOOD, Material.WOOD_STEP, Material.LOG,
|
||||
Material.FENCE, Material.FENCE_GATE, Material.JUKEBOX,
|
||||
Material.JUNGLE_WOOD_STAIRS, Material.SPRUCE_WOOD_STAIRS,
|
||||
Material.BIRCH_WOOD_STAIRS,
|
||||
Material.WOOD_DOUBLE_STEP, // ?
|
||||
// double slabs ?
|
||||
}){
|
||||
blocks[mat.getId()] = woodType;
|
||||
}
|
||||
for (Material mat : new Material[]{
|
||||
Material.COBBLESTONE_STAIRS, Material.COBBLESTONE,
|
||||
Material.NETHER_BRICK, Material.NETHER_BRICK_STAIRS, Material.NETHER_FENCE,
|
||||
Material.CAULDRON, Material.BRICK, Material.BRICK_STAIRS,
|
||||
Material.MOSSY_COBBLESTONE, Material.BRICK, Material.BRICK_STAIRS,
|
||||
Material.STEP, Material.DOUBLE_STEP, // ?
|
||||
|
||||
}){
|
||||
blocks[mat.getId()] = brickType;
|
||||
}
|
||||
blocks[Material.WORKBENCH.getId()] = chestType;
|
||||
blocks[Material.CHEST.getId()] = chestType;
|
||||
blocks[Material.WOODEN_DOOR.getId()] = woodDoorType;
|
||||
blocks[Material.TRAP_DOOR.getId()] = woodDoorType;
|
||||
for (Material mat : new Material[]{
|
||||
Material.ENDER_STONE, Material.DRAGON_EGG, Material.COAL_ORE,
|
||||
|
||||
}){
|
||||
blocks[mat.getId()] = coalType;
|
||||
}
|
||||
for (Material mat : new Material[]{
|
||||
Material.LAPIS_ORE, Material.LAPIS_BLOCK, Material.IRON_ORE,
|
||||
|
||||
}){
|
||||
blocks[mat.getId()] = ironType;
|
||||
}
|
||||
for (Material mat : new Material[]{
|
||||
Material.REDSTONE_ORE, Material.GLOWING_REDSTONE_ORE,
|
||||
Material.EMERALD_ORE, Material.GOLD_ORE, Material.DIAMOND_ORE,
|
||||
Material.GOLD_BLOCK,
|
||||
|
||||
}){
|
||||
blocks[mat.getId()] = diamondType;
|
||||
}
|
||||
blocks[Material.FURNACE.getId()] = dispenserType;
|
||||
blocks[Material.BURNING_FURNACE.getId()] = dispenserType;
|
||||
blocks[Material.DISPENSER.getId()] = dispenserType;
|
||||
blocks[Material.WEB.getId()] = new BlockProps(woodSword, 4, secToMs(20, 0.4, 0.4, 0.4, 0.4, 0.4));
|
||||
|
||||
for (Material mat : new Material[]{
|
||||
Material.MOB_SPAWNER, Material.IRON_DOOR_BLOCK,
|
||||
Material.IRON_FENCE, Material.ENCHANTMENT_TABLE,
|
||||
Material.EMERALD_BLOCK,
|
||||
}){
|
||||
blocks[mat.getId()] = ironDoorType;
|
||||
}
|
||||
blocks[Material.IRON_BLOCK.getId()] = new BlockProps(stonePickaxe, 5, secToMs(25, 25, 1.9, 1.25, 0.95, 25));
|
||||
blocks[Material.DIAMOND_BLOCK.getId()] = new BlockProps(ironPickaxe, 5, secToMs(25, 25, 25, 1.25, 0.95, 25));
|
||||
blocks[Material.ENDER_CHEST.getId()] = new BlockProps(woodPickaxe, 22.5f, secToMs(112.5));
|
||||
blocks[Material.OBSIDIAN.getId()] = new BlockProps(diamondPickaxe, 50, secToMs(250, 250, 250, 250, 9.4, 250));
|
||||
|
||||
for (Material mat : new Material[]{
|
||||
Material.AIR, Material.ENDER_PORTAL, Material.ENDER_PORTAL_FRAME,
|
||||
Material.PORTAL, Material.LAVA, Material.WATER, Material.BEDROCK,
|
||||
Material.STATIONARY_LAVA, Material.STATIONARY_WATER,
|
||||
Material.LOCKED_CHEST,
|
||||
}){
|
||||
blocks[mat.getId()] = indestructibleType;
|
||||
}
|
||||
|
||||
// dumpBlocks(true); // Do at startup maybe.
|
||||
}
|
||||
|
||||
public static void dumpBlocks(boolean all) {
|
||||
List<String> missing = new LinkedList<String>();
|
||||
if (all) {
|
||||
System.out.println("[NoCheatPlus] Dump block properties for fastbreak check:");
|
||||
System.out.println("--- Present entries -------------------------------");
|
||||
}
|
||||
for (int i = 0; i < blocks.length; i++){
|
||||
String mat;
|
||||
try{
|
||||
Material temp = Material.getMaterial(i);
|
||||
if (!temp.isBlock()) continue;
|
||||
mat = temp.toString();
|
||||
}
|
||||
catch(Exception e){
|
||||
mat = "?";
|
||||
}
|
||||
if (blocks[i] == null){
|
||||
if (mat.equals("?")) continue;
|
||||
missing.add("* MISSING "+i + "(" + mat +") ");
|
||||
}
|
||||
else if (all) System.out.println(i + ": (" + mat + ") " + blocks[i].toString());
|
||||
}
|
||||
if (!missing.isEmpty()){
|
||||
Bukkit.getLogger().warning("[NoCheatPlus] The block breaking data is incomplete, interpret some as stone :");
|
||||
System.out.println("--- Missing entries -------------------------------");
|
||||
for (String spec : missing){
|
||||
System.out.println(spec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static long[] secToMs(final double s1, final double s2, final double s3, final double s4, final double s5, final double s6){
|
||||
return new long[] { (long) (s1 * 1000d), (long) (s2 * 1000d), (long) (s3 * 1000d), (long) (s4 * 1000d), (long) (s5 * 1000d), (long) (s6 * 1000d) };
|
||||
}
|
||||
|
||||
public static long[] secToMs(final double s1){
|
||||
final long v = (long) (s1 * 1000d);
|
||||
return new long[]{v, v, v, v, v, v};
|
||||
}
|
||||
|
||||
public static ToolProps getToolProps(final Material mat){
|
||||
if (mat == null) return noTool;
|
||||
else return getToolProps(mat.getId());
|
||||
}
|
||||
|
||||
public static ToolProps getToolProps(final Integer id){
|
||||
final ToolProps props = tools.get(id);
|
||||
if (props == null) return noTool;
|
||||
else return props;
|
||||
}
|
||||
|
||||
public static BlockProps getBlockProps(final int blockId){
|
||||
if (blockId <0 || blockId >= blocks.length || blocks[blockId] == null) return defaultBlockProps;
|
||||
else return blocks[blockId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method.
|
||||
* @param blockId
|
||||
* @param player
|
||||
* @return
|
||||
*/
|
||||
public static long getBreakingDuration(final int blockId, final Player player){
|
||||
return getBreakingDuration(blockId, player.getItemInHand(), player.getInventory().getHelmet(), player, player.getLocation());
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: repair signature some day (rid of PlayerLocation).
|
||||
* @param BlockId
|
||||
* @param itemInHand May be null.
|
||||
* @param helmet May be null.
|
||||
* @param location The normal location of a player.
|
||||
* @return
|
||||
*/
|
||||
public static long getBreakingDuration(final int blockId, final ItemStack itemInHand, final ItemStack helmet, final Player player, final Location location){
|
||||
final int x = location.getBlockX();
|
||||
final int y = location.getBlockY();
|
||||
final int z = location.getBlockZ();
|
||||
final World world = location.getWorld();
|
||||
final boolean onGround = isOnGround(player, location) || world.getBlockTypeIdAt(x, y, z) == Material.WATER_LILY.getId();
|
||||
final boolean inWater = isInWater(world.getBlockTypeIdAt(x, y + 1, z));
|
||||
return getBreakingDuration(blockId, itemInHand, onGround, inWater, helmet != null && helmet.containsEnchantment(Enchantment.WATER_WORKER));
|
||||
}
|
||||
|
||||
public static boolean isInWater(final int blockId) {
|
||||
if (blockId == Material.STATIONARY_WATER.getId() || blockId == Material.STATIONARY_LAVA.getId()) return true;
|
||||
// TODO: count in water height ?
|
||||
// TODO: lava ?
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Heavy but ...
|
||||
* @param world
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
* @return
|
||||
*/
|
||||
public static boolean isOnGround(Player player, Location location) {
|
||||
// return blockId != 0 && net.minecraft.server.Block.byId[blockId].//.c();// d();
|
||||
final PlayerLocation loc = new PlayerLocation();
|
||||
// Bit fat workaround, maybe put the object through from check listener ?
|
||||
loc.set(location, player);
|
||||
return loc.isOnGround();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the normal breaking duration, including enchantments, and tool properties.
|
||||
@ -24,8 +504,85 @@ public class BlockUtils {
|
||||
* @param itemInHand
|
||||
* @return
|
||||
*/
|
||||
public static long getBreakingDuration(final int blockId, final ItemStack itemInHand){
|
||||
// TODO: GET EXACT BREAKING TIME !
|
||||
return 95;
|
||||
public static long getBreakingDuration(final int blockId, final ItemStack itemInHand, final boolean onGround, final boolean inWater, final boolean aquaAffinity){
|
||||
// TODO: more configurability / load from file for blocks (i.e. set for shears etc.
|
||||
if (itemInHand == null) return getBreakingDuration(blockId, getBlockProps(blockId), noTool, onGround, inWater, aquaAffinity, 0);
|
||||
else{
|
||||
int efficiency = 0;
|
||||
if (itemInHand.containsEnchantment(Enchantment.DIG_SPEED)) efficiency = itemInHand.getEnchantmentLevel(Enchantment.DIG_SPEED);
|
||||
return getBreakingDuration(blockId, getBlockProps(blockId), getToolProps(itemInHand.getTypeId()), onGround, inWater, aquaAffinity, efficiency);
|
||||
}
|
||||
}
|
||||
|
||||
public static long getBreakingDuration(final int blockId, final BlockProps blockProps, final ToolProps toolProps, final boolean onGround, final boolean inWater, boolean aquaAffinity, int efficiency) {
|
||||
long duration;
|
||||
|
||||
boolean isValidTool = blockProps.tool.toolType == toolProps.toolType;
|
||||
|
||||
if (!isValidTool && efficiency > 0){
|
||||
// Efficiency makes the tool.
|
||||
// (wood, sand, gravel, ice)
|
||||
if (blockProps.hardness <= 2 && (blockProps.tool.toolType == ToolType.AXE || blockProps.tool.toolType == ToolType.SPADE
|
||||
|| (blockProps.hardness < 0.8
|
||||
&& (blockId != Material.NETHERRACK.getId() && blockId != Material.SNOW.getId() && blockId != Material.SNOW_BLOCK.getId() && blockId != Material.STONE_PLATE.getId())))){
|
||||
// Also roughly.
|
||||
isValidTool = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isValidTool){
|
||||
// appropriate tool
|
||||
duration = blockProps.breakingTimes[toolProps.materialBase.index];
|
||||
}
|
||||
else{
|
||||
// Inappropriate tool.
|
||||
duration = blockProps.breakingTimes[0];
|
||||
// Swords are always appropriate.
|
||||
if (toolProps.toolType == ToolType.SWORD) duration = (long) ((float) duration / 1.5f);
|
||||
}
|
||||
|
||||
// Specialties:
|
||||
if (toolProps.toolType == ToolType.SHEARS){
|
||||
// (Note: shears are not in the block props, anywhere)
|
||||
// Treat these extra (party experimental):
|
||||
if (blockId == Material.WEB.getId()){
|
||||
duration = 400;
|
||||
isValidTool = true;
|
||||
}
|
||||
else if (blockId == Material.WOOL.getId()){
|
||||
duration = 240;
|
||||
isValidTool = true;
|
||||
}
|
||||
else if (blockId == Material.LEAVES.getId()){
|
||||
duration = 20;
|
||||
isValidTool = true;
|
||||
}
|
||||
else if (blockId == Material.VINE.getId()){
|
||||
duration = 300;
|
||||
isValidTool = true;
|
||||
}
|
||||
}
|
||||
// (sword vs web already counted)
|
||||
|
||||
if (isValidTool || blockProps.tool.toolType == ToolType.NONE){
|
||||
if (inWater && ! aquaAffinity)
|
||||
duration *= 5;
|
||||
if (!onGround)
|
||||
duration *= 5;
|
||||
// Efficiency level.
|
||||
if (efficiency > 0){
|
||||
// This seems roughly correct.
|
||||
for (int i = 0; i < efficiency; i++){
|
||||
duration /= 1.33; // Matches well with obsidian.
|
||||
}
|
||||
}
|
||||
}
|
||||
return duration;
|
||||
}
|
||||
|
||||
public static void read(){
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
186
src/fr/neatmonster/nocheatplus/utilities/Stats.java
Normal file
186
src/fr/neatmonster/nocheatplus/utilities/Stats.java
Normal file
@ -0,0 +1,186 @@
|
||||
package fr.neatmonster.nocheatplus.utilities;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
/**
|
||||
* A not too fat stats class re-used from other plugins.
|
||||
* @author asofold
|
||||
*
|
||||
*/
|
||||
public final class Stats {
|
||||
|
||||
public static final class Entry{
|
||||
public long val = 0;
|
||||
public long n = 0;
|
||||
public long min = Long.MAX_VALUE;
|
||||
public long max = Long.MIN_VALUE;
|
||||
}
|
||||
|
||||
private long tsStats = 0;
|
||||
private long periodStats = 12345;
|
||||
private long nVerbose = 500;
|
||||
private long nDone = 0;
|
||||
private boolean logStats = false;
|
||||
private boolean showRange = true;
|
||||
|
||||
private final Map<Integer, Entry> entries = new HashMap<Integer, Stats.Entry>();
|
||||
private final DecimalFormat f;
|
||||
private final String label;
|
||||
|
||||
/**
|
||||
* Map id to name.
|
||||
*/
|
||||
private final Map<Integer, String> idKeyMap = new HashMap<Integer, String>();
|
||||
|
||||
/**
|
||||
* Map exact name to id.
|
||||
*/
|
||||
private final Map<String, Integer> keyIdMap = new HashMap<String, Integer>();
|
||||
|
||||
int maxId = 0;
|
||||
|
||||
public Stats(){
|
||||
this("[STATS]");
|
||||
}
|
||||
|
||||
public Stats(final String label){
|
||||
this.label = label;
|
||||
f = new DecimalFormat();
|
||||
f.setGroupingUsed(true);
|
||||
f.setGroupingSize(3);
|
||||
DecimalFormatSymbols s = f.getDecimalFormatSymbols();
|
||||
s.setGroupingSeparator(',');
|
||||
f.setDecimalFormatSymbols(s);
|
||||
}
|
||||
|
||||
public final void addStats(final Integer key, final long value){
|
||||
Entry entry = entries.get(key);
|
||||
if ( entry != null){
|
||||
entry.n += 1;
|
||||
entry.val += value;
|
||||
if (value < entry.min) entry.min = value;
|
||||
else if (value > entry.max) entry.max = value;
|
||||
} else{
|
||||
entry = new Entry();
|
||||
entry.val = value;
|
||||
entry.n = 1;
|
||||
entries.put(key, entry);
|
||||
entry.min = value;
|
||||
entry.max = value;
|
||||
}
|
||||
if (!logStats) return;
|
||||
nDone++;
|
||||
if ( nDone>nVerbose){
|
||||
nDone = 0;
|
||||
long ts = System.currentTimeMillis();
|
||||
if ( ts > tsStats+periodStats){
|
||||
tsStats = ts;
|
||||
// print out stats !
|
||||
System.out.println(getStatsStr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stats representation without ChatColor.
|
||||
* @return
|
||||
*/
|
||||
public final String getStatsStr() {
|
||||
return getStatsStr(false);
|
||||
}
|
||||
|
||||
public final String getStatsStr(final boolean colors) {
|
||||
final StringBuilder b = new StringBuilder(400);
|
||||
b.append(label+" ");
|
||||
boolean first = true;
|
||||
for (final Integer id : entries.keySet()){
|
||||
if ( !first) b.append(" | ");
|
||||
final Entry entry = entries.get(id);
|
||||
String av = f.format(entry.val / entry.n);
|
||||
String key = getKey(id);
|
||||
String n = f.format(entry.n);
|
||||
if (colors){
|
||||
key = ChatColor.GREEN + key + ChatColor.WHITE;
|
||||
n = ChatColor.AQUA + n + ChatColor.WHITE;
|
||||
av = ChatColor.YELLOW + av + ChatColor.WHITE;
|
||||
}
|
||||
b.append(key+" av="+av+" n="+n);
|
||||
if ( showRange) b.append(" rg="+f.format(entry.min)+"..."+f.format(entry.max));
|
||||
first = false;
|
||||
}
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns some string, if not key is there, stating that no key is there.
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public final String getKey(final Integer id) {
|
||||
String key = idKeyMap.get(id);
|
||||
if (key == null){
|
||||
key = "<no key for id: "+id+">";
|
||||
idKeyMap.put(id, key);
|
||||
keyIdMap.put(key, id);
|
||||
}
|
||||
return key;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new id for the key.
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public final Integer getNewId(final String key){
|
||||
maxId++;
|
||||
while (idKeyMap.containsKey(maxId)){
|
||||
maxId++; // probably not going to happen...
|
||||
}
|
||||
idKeyMap.put(maxId, key);
|
||||
keyIdMap.put(key, maxId);
|
||||
return maxId;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key
|
||||
* @param create if to create a key - id mapping if not existent.
|
||||
* @return
|
||||
*/
|
||||
public final Integer getId(final String key, final boolean create){
|
||||
final Integer id = keyIdMap.get(key);
|
||||
if (id == null){
|
||||
if (create) return getNewId(key);
|
||||
else return null;
|
||||
}
|
||||
else return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the id if present, returns null otherwise.
|
||||
* @param key not null
|
||||
* @return Key or null.
|
||||
*/
|
||||
public final Integer getId(final String key){
|
||||
return keyIdMap.get(key);
|
||||
}
|
||||
|
||||
public final void clear(){
|
||||
entries.clear();
|
||||
}
|
||||
|
||||
public final void setLogStats(final boolean log){
|
||||
logStats = log;
|
||||
}
|
||||
|
||||
public final void setShowRange(final boolean set){
|
||||
showRange = set;
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user