mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2025-01-02 22:07:50 +01:00
Fix cancelling of bukkit task, moving around some things, use
"SimpleLocation" instead of Block in blockplaced checks.
This commit is contained in:
parent
99a197607b
commit
04ec82eef6
@ -3,7 +3,7 @@ name: NoCheat
|
|||||||
author: Evenprime
|
author: Evenprime
|
||||||
|
|
||||||
main: cc.co.evenprime.bukkit.nocheat.NoCheat
|
main: cc.co.evenprime.bukkit.nocheat.NoCheat
|
||||||
version: 2.14a
|
version: 2.15
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
nocheat:
|
nocheat:
|
||||||
|
@ -115,6 +115,7 @@ public class NoCheat extends JavaPlugin {
|
|||||||
eventManagers.add(new EntityDamageEventManager(this));
|
eventManagers.add(new EntityDamageEventManager(this));
|
||||||
eventManagers.add(new SwingEventManager(this));
|
eventManagers.add(new SwingEventManager(this));
|
||||||
TimedEventManager m = new TimedEventManager(this);
|
TimedEventManager m = new TimedEventManager(this);
|
||||||
|
taskId = m.taskId; // There's a bukkit task, remember its id
|
||||||
eventManagers.add(m);
|
eventManagers.add(m);
|
||||||
|
|
||||||
// Then set up a task to monitor server lag
|
// Then set up a task to monitor server lag
|
||||||
@ -150,10 +151,6 @@ public class NoCheat extends JavaPlugin {
|
|||||||
data.clearCriticalData(playerName);
|
data.clearCriticalData(playerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void playerJoined(String playerName) {
|
|
||||||
clearCriticalData(playerName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Performance getPerformance(Type type) {
|
public Performance getPerformance(Type type) {
|
||||||
return performance.get(type);
|
return performance.get(type);
|
||||||
}
|
}
|
||||||
@ -192,10 +189,9 @@ public class NoCheat extends JavaPlugin {
|
|||||||
if(log != null) {
|
if(log != null) {
|
||||||
log.logToConsole(low, message);
|
log.logToConsole(low, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reloadConfig() {
|
public void reloadConfiguration() {
|
||||||
conf.cleanup();
|
conf.cleanup();
|
||||||
this.conf = new ConfigurationManager(this.getDataFolder().getPath());
|
this.conf = new ConfigurationManager(this.getDataFolder().getPath());
|
||||||
data.cleanDataMap();
|
data.cleanDataMap();
|
||||||
|
@ -11,7 +11,6 @@ import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
|
|||||||
import cc.co.evenprime.bukkit.nocheat.config.util.ActionList;
|
import cc.co.evenprime.bukkit.nocheat.config.util.ActionList;
|
||||||
import cc.co.evenprime.bukkit.nocheat.data.BaseData;
|
import cc.co.evenprime.bukkit.nocheat.data.BaseData;
|
||||||
import cc.co.evenprime.bukkit.nocheat.data.ExecutionHistory;
|
import cc.co.evenprime.bukkit.nocheat.data.ExecutionHistory;
|
||||||
import cc.co.evenprime.bukkit.nocheat.data.LogData;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will trace the history of action executions to decide if an action 'really'
|
* Will trace the history of action executions to decide if an action 'really'
|
||||||
@ -40,11 +39,11 @@ public class ActionManager {
|
|||||||
|
|
||||||
if(history.executeAction(ac, time)) {
|
if(history.executeAction(ac, time)) {
|
||||||
if(ac instanceof LogAction) {
|
if(ac instanceof LogAction) {
|
||||||
executeLogAction((LogAction) ac, data.log, cc);
|
executeLogAction((LogAction) ac, data, cc);
|
||||||
} else if(ac instanceof SpecialAction) {
|
} else if(ac instanceof SpecialAction) {
|
||||||
special = true;
|
special = true;
|
||||||
} else if(ac instanceof ConsolecommandAction) {
|
} else if(ac instanceof ConsolecommandAction) {
|
||||||
executeConsoleCommand((ConsolecommandAction) ac, data.log);
|
executeConsoleCommand((ConsolecommandAction) ac, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,11 +51,11 @@ public class ActionManager {
|
|||||||
return special;
|
return special;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeLogAction(LogAction l, LogData data, ConfigurationCache cc) {
|
private void executeLogAction(LogAction l, BaseData data, ConfigurationCache cc) {
|
||||||
plugin.log(l.level, cc.logging.prefix + l.getLogMessage(data), cc);
|
plugin.log(l.level, cc.logging.prefix + l.getLogMessage(data), cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void executeConsoleCommand(ConsolecommandAction action, LogData data) {
|
private void executeConsoleCommand(ConsolecommandAction action, BaseData data) {
|
||||||
String command = action.getCommand(data);
|
String command = action.getCommand(data);
|
||||||
try {
|
try {
|
||||||
plugin.getServer().dispatchCommand(plugin.getServer().getConsoleSender(), command);
|
plugin.getServer().dispatchCommand(plugin.getServer().getConsoleSender(), command);
|
||||||
|
@ -8,6 +8,7 @@ import org.bukkit.Location;
|
|||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import cc.co.evenprime.bukkit.nocheat.data.BaseData;
|
||||||
import cc.co.evenprime.bukkit.nocheat.data.LogData;
|
import cc.co.evenprime.bukkit.nocheat.data.LogData;
|
||||||
import cc.co.evenprime.bukkit.nocheat.data.PreciseLocation;
|
import cc.co.evenprime.bukkit.nocheat.data.PreciseLocation;
|
||||||
import cc.co.evenprime.bukkit.nocheat.data.SimpleLocation;
|
import cc.co.evenprime.bukkit.nocheat.data.SimpleLocation;
|
||||||
@ -83,7 +84,7 @@ public abstract class ActionWithParameters extends Action {
|
|||||||
* @param data
|
* @param data
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
protected String getMessage(final LogData data) {
|
protected String getMessage(final BaseData data) {
|
||||||
StringBuilder log = new StringBuilder(100); // Should be big enough most
|
StringBuilder log = new StringBuilder(100); // Should be big enough most
|
||||||
// of the time
|
// of the time
|
||||||
|
|
||||||
@ -98,9 +99,11 @@ public abstract class ActionWithParameters extends Action {
|
|||||||
return log.toString();
|
return log.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getParameter(WildCard wildcard, LogData data) {
|
private String getParameter(WildCard wildcard, BaseData bdata) {
|
||||||
// The == is correct here, as these really are identical objects, not
|
// The == is correct here, as these really are identical objects, not
|
||||||
// only equal
|
// only equal
|
||||||
|
final LogData data = bdata.log;
|
||||||
|
|
||||||
switch (wildcard) {
|
switch (wildcard) {
|
||||||
|
|
||||||
case PLAYER:
|
case PLAYER:
|
||||||
@ -163,7 +166,7 @@ public abstract class ActionWithParameters extends Action {
|
|||||||
return data.text;
|
return data.text;
|
||||||
|
|
||||||
case PLACE_LOCATION: {
|
case PLACE_LOCATION: {
|
||||||
SimpleLocation l = data.placedLocation;
|
SimpleLocation l = bdata.blockplace.blockPlaced;
|
||||||
if(l.isSet()) {
|
if(l.isSet()) {
|
||||||
return String.format(Locale.US, "%d %d %d", l.x, l.y, l.z);
|
return String.format(Locale.US, "%d %d %d", l.x, l.y, l.z);
|
||||||
} else {
|
} else {
|
||||||
@ -172,7 +175,7 @@ public abstract class ActionWithParameters extends Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case PLACE_AGAINST: {
|
case PLACE_AGAINST: {
|
||||||
SimpleLocation l = data.placedAgainstLocation;
|
SimpleLocation l = bdata.blockplace.blockPlacedAgainst;
|
||||||
if(l.isSet()) {
|
if(l.isSet()) {
|
||||||
return String.format(Locale.US, "%d %d %d", l.x, l.y, l.z);
|
return String.format(Locale.US, "%d %d %d", l.x, l.y, l.z);
|
||||||
} else {
|
} else {
|
||||||
@ -181,7 +184,7 @@ public abstract class ActionWithParameters extends Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case BLOCK_TYPE: {
|
case BLOCK_TYPE: {
|
||||||
Material type = data.placedType;
|
Material type = bdata.blockplace.placedType;
|
||||||
if(type == null) {
|
if(type == null) {
|
||||||
return "null";
|
return "null";
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package cc.co.evenprime.bukkit.nocheat.actions.types;
|
package cc.co.evenprime.bukkit.nocheat.actions.types;
|
||||||
|
|
||||||
import cc.co.evenprime.bukkit.nocheat.data.LogData;
|
import cc.co.evenprime.bukkit.nocheat.data.BaseData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute a command by imitating an admin typing the command directly into the
|
* Execute a command by imitating an admin typing the command directly into the
|
||||||
@ -14,8 +14,8 @@ public class ConsolecommandAction extends ActionWithParameters {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCommand(LogData ldata) {
|
public String getCommand(BaseData data) {
|
||||||
|
|
||||||
return super.getMessage(ldata);
|
return super.getMessage(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package cc.co.evenprime.bukkit.nocheat.actions.types;
|
package cc.co.evenprime.bukkit.nocheat.actions.types;
|
||||||
|
|
||||||
import cc.co.evenprime.bukkit.nocheat.data.LogData;
|
import cc.co.evenprime.bukkit.nocheat.data.BaseData;
|
||||||
import cc.co.evenprime.bukkit.nocheat.log.Colors;
|
import cc.co.evenprime.bukkit.nocheat.log.Colors;
|
||||||
import cc.co.evenprime.bukkit.nocheat.log.LogLevel;
|
import cc.co.evenprime.bukkit.nocheat.log.LogLevel;
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ public class LogAction extends ActionWithParameters {
|
|||||||
this.level = level;
|
this.level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getLogMessage(final LogData ldata) {
|
public String getLogMessage(final BaseData data) {
|
||||||
return super.getMessage(ldata);
|
return super.getMessage(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ public class BlockPlaceCheck {
|
|||||||
if(blockPlaced != null && blockPlacedAgainst != null) {
|
if(blockPlaced != null && blockPlacedAgainst != null) {
|
||||||
data.blockplace.blockPlaced.set(blockPlaced);
|
data.blockplace.blockPlaced.set(blockPlaced);
|
||||||
data.blockplace.blockPlacedAgainst.set(blockPlacedAgainst);
|
data.blockplace.blockPlacedAgainst.set(blockPlacedAgainst);
|
||||||
|
data.blockplace.placedType = blockPlaced.getType();
|
||||||
|
|
||||||
if(!cancel && direction) {
|
if(!cancel && direction) {
|
||||||
cancel = directionCheck.check(player, data, cc);
|
cancel = directionCheck.check(player, data, cc);
|
||||||
@ -49,10 +50,10 @@ public class BlockPlaceCheck {
|
|||||||
if(!cancel && reach) {
|
if(!cancel && reach) {
|
||||||
cancel = reachCheck.check(player, data, cc);
|
cancel = reachCheck.check(player, data, cc);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if(!cancel && onliquid) {
|
if(!cancel && onliquid) {
|
||||||
cancel = onLiquidCheck.check(player, data, blockPlaced, blockPlacedAgainst, cc);
|
cancel = onLiquidCheck.check(player, data, cc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return cancel;
|
return cancel;
|
||||||
|
@ -2,7 +2,6 @@ package cc.co.evenprime.bukkit.nocheat.checks.blockplace;
|
|||||||
|
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import cc.co.evenprime.bukkit.nocheat.NoCheat;
|
import cc.co.evenprime.bukkit.nocheat.NoCheat;
|
||||||
@ -10,6 +9,7 @@ import cc.co.evenprime.bukkit.nocheat.config.cache.ConfigurationCache;
|
|||||||
import cc.co.evenprime.bukkit.nocheat.data.BaseData;
|
import cc.co.evenprime.bukkit.nocheat.data.BaseData;
|
||||||
import cc.co.evenprime.bukkit.nocheat.data.BlockPlaceData;
|
import cc.co.evenprime.bukkit.nocheat.data.BlockPlaceData;
|
||||||
import cc.co.evenprime.bukkit.nocheat.data.LogData;
|
import cc.co.evenprime.bukkit.nocheat.data.LogData;
|
||||||
|
import cc.co.evenprime.bukkit.nocheat.data.SimpleLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -22,29 +22,27 @@ public class OnLiquidCheck {
|
|||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean check(final Player player, final BaseData data, final Block blockPlaced, final Block blockPlacedAgainst, final ConfigurationCache cc) {
|
public boolean check(final Player player, final BaseData data, final ConfigurationCache cc) {
|
||||||
|
|
||||||
boolean cancel = false;
|
boolean cancel = false;
|
||||||
|
|
||||||
final BlockPlaceData blockplace = data.blockplace;
|
final BlockPlaceData blockplace = data.blockplace;
|
||||||
|
final SimpleLocation blockplaced = blockplace.blockPlaced;
|
||||||
final LogData log = data.log;
|
final LogData log = data.log;
|
||||||
|
|
||||||
if(blockPlaced == null || blockPlaced.isEmpty() || (blockPlacedAgainst != null && isSolid(blockPlacedAgainst.getTypeId()))) {
|
if(isSolid(blockplace.placedType.getId())) {
|
||||||
// all ok
|
// all ok
|
||||||
} else if(nextToSolid(blockPlaced.getWorld(), blockPlaced.getX(), blockPlaced.getY(), blockPlaced.getZ())) {
|
} else if(nextToSolid(player.getWorld(), blockplaced.x, blockplaced.y, blockplaced.z)) {
|
||||||
// all ok
|
// all ok
|
||||||
} else {
|
} else {
|
||||||
blockplace.onliquidViolationLevel += 1;
|
blockplace.onliquidViolationLevel += 1;
|
||||||
log.check = "blockplace.onliquid";
|
log.check = "blockplace.onliquid";
|
||||||
log.placedLocation.set(blockPlaced);
|
|
||||||
log.placedType = blockPlaced.getType();
|
|
||||||
log.placedAgainstLocation.set(blockPlacedAgainst);
|
|
||||||
|
|
||||||
cancel = plugin.execute(player, cc.blockplace.onliquidActions, (int) blockplace.onliquidViolationLevel, blockplace.history, cc);
|
cancel = plugin.execute(player, cc.blockplace.onliquidActions, (int) blockplace.onliquidViolationLevel, blockplace.history, cc);
|
||||||
}
|
}
|
||||||
|
|
||||||
blockplace.onliquidViolationLevel *= 0.95D; // Reduce level over
|
blockplace.onliquidViolationLevel *= 0.95D; // Reduce level over
|
||||||
// time
|
// time
|
||||||
|
|
||||||
return cancel;
|
return cancel;
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,6 @@ public class TimedCheck {
|
|||||||
|
|
||||||
// Enough is enough
|
// Enough is enough
|
||||||
data.log.check = "timed.godmode";
|
data.log.check = "timed.godmode";
|
||||||
data.log.godmodeTicksBehind = data.timed.ticksBehind;
|
|
||||||
|
|
||||||
cancel = plugin.execute(player, cc.timed.godmodeActions, (int) data.timed.godmodeVL, data.timed.history, cc);
|
cancel = plugin.execute(player, cc.timed.godmodeActions, (int) data.timed.godmodeVL, data.timed.history, cc);
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ public class CommandHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
sender.sendMessage("[NoCheat] Reloading configuration");
|
sender.sendMessage("[NoCheat] Reloading configuration");
|
||||||
plugin.reloadConfig();
|
plugin.reloadConfiguration();
|
||||||
sender.sendMessage("[NoCheat] Configuration reloaded");
|
sender.sendMessage("[NoCheat] Configuration reloaded");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -12,7 +12,7 @@ public class BaseData extends Data {
|
|||||||
|
|
||||||
private final Data[] data; // for convenience
|
private final Data[] data; // for convenience
|
||||||
|
|
||||||
public long lastUsedTime;
|
protected long lastUsedTime;
|
||||||
|
|
||||||
public boolean armswung;
|
public boolean armswung;
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package cc.co.evenprime.bukkit.nocheat.data;
|
package cc.co.evenprime.bukkit.nocheat.data;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -8,10 +10,16 @@ public class BlockPlaceData extends Data {
|
|||||||
public double onliquidViolationLevel = 0.0D;
|
public double onliquidViolationLevel = 0.0D;
|
||||||
public double reachViolationLevel = 0.0D;
|
public double reachViolationLevel = 0.0D;
|
||||||
public final ExecutionHistory history = new ExecutionHistory();
|
public final ExecutionHistory history = new ExecutionHistory();
|
||||||
public double noswingVL = 0.0D;
|
|
||||||
public double directionViolationLevel = 0.0D;
|
public double directionViolationLevel = 0.0D;
|
||||||
public long directionLastViolationTime = 0;
|
public long directionLastViolationTime = 0;
|
||||||
|
|
||||||
public final SimpleLocation blockPlacedAgainst = new SimpleLocation();
|
public final SimpleLocation blockPlacedAgainst = new SimpleLocation();
|
||||||
public final SimpleLocation blockPlaced = new SimpleLocation();
|
public final SimpleLocation blockPlaced = new SimpleLocation();
|
||||||
|
public Material placedType;
|
||||||
|
|
||||||
|
public void clearCriticalData() {
|
||||||
|
blockPlacedAgainst.reset();
|
||||||
|
blockPlaced.reset();
|
||||||
|
placedType = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package cc.co.evenprime.bukkit.nocheat.data;
|
package cc.co.evenprime.bukkit.nocheat.data;
|
||||||
|
|
||||||
import org.bukkit.Material;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Everything that could be relevant for logging or consolecommand actions
|
* Everything that could be relevant for logging or consolecommand actions
|
||||||
*/
|
*/
|
||||||
@ -9,15 +7,10 @@ public class LogData extends Data {
|
|||||||
|
|
||||||
public String check;
|
public String check;
|
||||||
public int violationLevel;
|
public int violationLevel;
|
||||||
public final PreciseLocation toLocation = new PreciseLocation();
|
public final PreciseLocation toLocation = new PreciseLocation();
|
||||||
public int packets;
|
public int packets;
|
||||||
public String text;
|
public String text;
|
||||||
public final SimpleLocation placedLocation = new SimpleLocation();
|
|
||||||
public Material placedType;
|
|
||||||
public final SimpleLocation placedAgainstLocation = new SimpleLocation();
|
|
||||||
public double reachdistance;
|
public double reachdistance;
|
||||||
public float falldistance;
|
public float falldistance;
|
||||||
public String playerName;
|
public String playerName;
|
||||||
public int godmodeTicksBehind;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ public final class SimpleLocation {
|
|||||||
public int x;
|
public int x;
|
||||||
public int y;
|
public int y;
|
||||||
public int z;
|
public int z;
|
||||||
|
|
||||||
public SimpleLocation() {
|
public SimpleLocation() {
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
@ -34,10 +34,11 @@ public final class SimpleLocation {
|
|||||||
y = location.getBlockY();
|
y = location.getBlockY();
|
||||||
z = location.getBlockZ();
|
z = location.getBlockZ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public final boolean isSet() {
|
public final boolean isSet() {
|
||||||
return x != Integer.MAX_VALUE;
|
return x != Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final void reset() {
|
public final void reset() {
|
||||||
x = Integer.MAX_VALUE;
|
x = Integer.MAX_VALUE;
|
||||||
y = Integer.MAX_VALUE;
|
y = Integer.MAX_VALUE;
|
||||||
|
@ -26,7 +26,7 @@ public class TimedEventManager implements EventManager {
|
|||||||
|
|
||||||
private final Performance timedPerformance;
|
private final Performance timedPerformance;
|
||||||
|
|
||||||
public int taskId = -1;
|
public final int taskId;
|
||||||
|
|
||||||
public TimedEventManager(final NoCheat plugin) {
|
public TimedEventManager(final NoCheat plugin) {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
@ -36,7 +36,7 @@ public class TimedEventManager implements EventManager {
|
|||||||
this.timedPerformance = plugin.getPerformance(Type.TIMED);
|
this.timedPerformance = plugin.getPerformance(Type.TIMED);
|
||||||
|
|
||||||
// "register a listener" for passed time
|
// "register a listener" for passed time
|
||||||
taskId = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {
|
this.taskId = plugin.getServer().getScheduler().scheduleSyncRepeatingTask(plugin, new Runnable() {
|
||||||
|
|
||||||
private int executions = 0;
|
private int executions = 0;
|
||||||
private int loopsize = 10;
|
private int loopsize = 10;
|
||||||
@ -83,7 +83,7 @@ public class TimedEventManager implements EventManager {
|
|||||||
}, 0, 1);
|
}, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onTimedEvent(Player player, int elapsedTicks) {
|
private void onTimedEvent(Player player, int elapsedTicks) {
|
||||||
|
|
||||||
// Performance counter setup
|
// Performance counter setup
|
||||||
long nanoTimeStart = 0;
|
long nanoTimeStart = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user