mirror of
https://github.com/NoCheatPlus/NoCheatPlus.git
synced 2025-01-28 10:21:22 +01:00
Add a general purpose counter for stats/debug, and log+reset commands.
This may get changed around, e.g. to allow log output to file and other.
This commit is contained in:
parent
e0f81b43b6
commit
4176937dd1
@ -11,24 +11,26 @@ import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import fr.neatmonster.nocheatplus.command.actions.AllowLoginCommand;
|
||||
import fr.neatmonster.nocheatplus.command.actions.BanCommand;
|
||||
import fr.neatmonster.nocheatplus.command.actions.DenyLoginCommand;
|
||||
import fr.neatmonster.nocheatplus.command.actions.KickCommand;
|
||||
import fr.neatmonster.nocheatplus.command.actions.KickListCommand;
|
||||
import fr.neatmonster.nocheatplus.command.actions.TellCommand;
|
||||
import fr.neatmonster.nocheatplus.command.actions.DenyLoginCommand;
|
||||
import fr.neatmonster.nocheatplus.command.actions.AllowLoginCommand;
|
||||
import fr.neatmonster.nocheatplus.command.actions.delay.DelayCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.CommandsCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.InfoCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.InspectCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.LagCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.VersionCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.ReloadCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.RemovePlayerCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.VersionCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.exemption.ExemptCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.exemption.ExemptionsCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.exemption.UnexemptCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.log.LogCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.notify.NotifyCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.reset.ResetCommand;
|
||||
import fr.neatmonster.nocheatplus.components.INotifyReload;
|
||||
import fr.neatmonster.nocheatplus.config.ConfPaths;
|
||||
import fr.neatmonster.nocheatplus.config.ConfigFile;
|
||||
@ -77,7 +79,7 @@ public class NoCheatPlusCommand extends BaseCommand{
|
||||
*/
|
||||
public NoCheatPlusCommand(final JavaPlugin plugin, final List<INotifyReload> notifyReload) {
|
||||
super(plugin, "nocheatplus", null, new String[]{"ncp"});
|
||||
// Register sub commands:
|
||||
// Register sub commands (special order):
|
||||
for (BaseCommand cmd : new BaseCommand[]{
|
||||
new BanCommand(plugin),
|
||||
new CommandsCommand(plugin),
|
||||
@ -97,6 +99,8 @@ public class NoCheatPlusCommand extends BaseCommand{
|
||||
new DenyLoginCommand(plugin),
|
||||
new UnexemptCommand(plugin),
|
||||
new AllowLoginCommand(plugin),
|
||||
new LogCommand(plugin),
|
||||
new ResetCommand(plugin),
|
||||
}){
|
||||
addSubCommands(cmd);
|
||||
rootLabels.add(cmd.label);
|
||||
|
@ -0,0 +1,18 @@
|
||||
package fr.neatmonster.nocheatplus.command.admin.log;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import fr.neatmonster.nocheatplus.command.BaseCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.log.counters.CountersCommand;
|
||||
import fr.neatmonster.nocheatplus.permissions.Permissions;
|
||||
|
||||
public class LogCommand extends BaseCommand{
|
||||
|
||||
public LogCommand(JavaPlugin plugin) {
|
||||
super(plugin, "log", Permissions.COMMAND_LOG);
|
||||
addSubCommands(
|
||||
new CountersCommand(plugin)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
package fr.neatmonster.nocheatplus.command.admin.log.counters;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.command.BaseCommand;
|
||||
import fr.neatmonster.nocheatplus.stats.Counters;
|
||||
|
||||
public class CountersCommand extends BaseCommand {
|
||||
|
||||
public CountersCommand(JavaPlugin plugin) {
|
||||
super(plugin, "counters", null); // TODO: Maybe add a permission.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String alias, String[] args) {
|
||||
sender.sendMessage(NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(Counters.class).getMergedCountsString(true));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package fr.neatmonster.nocheatplus.command.admin.reset;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import fr.neatmonster.nocheatplus.command.BaseCommand;
|
||||
import fr.neatmonster.nocheatplus.command.admin.reset.counters.CountersCommand;
|
||||
import fr.neatmonster.nocheatplus.permissions.Permissions;
|
||||
|
||||
/**
|
||||
* Reset stuff, e.g. statistics counters.
|
||||
* @author dev1mc
|
||||
*
|
||||
*/
|
||||
public class ResetCommand extends BaseCommand{
|
||||
|
||||
public ResetCommand(JavaPlugin plugin) {
|
||||
super(plugin, "reset", Permissions.COMMAND_RESET);
|
||||
addSubCommands(
|
||||
new CountersCommand(plugin)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package fr.neatmonster.nocheatplus.command.admin.reset.counters;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import fr.neatmonster.nocheatplus.NCPAPIProvider;
|
||||
import fr.neatmonster.nocheatplus.command.BaseCommand;
|
||||
import fr.neatmonster.nocheatplus.stats.Counters;
|
||||
|
||||
public class CountersCommand extends BaseCommand {
|
||||
|
||||
public CountersCommand(JavaPlugin plugin) {
|
||||
super(plugin, "counters", null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String alias, String[] args) {
|
||||
NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(Counters.class).resetAll();
|
||||
sender.sendMessage("Counters reset.");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -30,9 +30,11 @@ public class Permissions {
|
||||
public static final String COMMAND_INFO = COMMAND + ".info";
|
||||
public static final String COMMAND_INSPECT = COMMAND + ".inspect";
|
||||
public static final String COMMAND_LAG = COMMAND + ".lag";
|
||||
public static final String COMMAND_LOG = COMMAND + ".log";
|
||||
public static final String COMMAND_NOTIFY = COMMAND + ".notify";
|
||||
public static final String COMMAND_RELOAD = COMMAND + ".reload";
|
||||
public static final String COMMAND_REMOVEPLAYER = COMMAND + ".removeplayer";
|
||||
public static final String COMMAND_RESET = COMMAND + ".reset";
|
||||
public static final String COMMAND_UNEXEMPT = COMMAND + ".unexempt";
|
||||
public static final String COMMAND_VERSION = COMMAND + ".version";
|
||||
|
||||
|
@ -0,0 +1,188 @@
|
||||
package fr.neatmonster.nocheatplus.stats;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
/**
|
||||
* Utility to count things, set up to get input from the primary server thread, as
|
||||
* well as from other threads. Consequently summaries for both are only
|
||||
* available from the primary thread.
|
||||
*
|
||||
* @author dev1mc
|
||||
*
|
||||
*/
|
||||
public class Counters {
|
||||
|
||||
/** Map strings for display/processing to "fast-access" ids. */
|
||||
private final Map<String, Integer> idMap = new LinkedHashMap<String, Integer>();
|
||||
|
||||
/** Keys by id. */
|
||||
private String[] keys = new String[0];
|
||||
// Not sure if to use longs.
|
||||
/** Primary thread. */
|
||||
private int[] ptCounts = new int[0];
|
||||
/** Synchronized. */
|
||||
private int[] syCounts = new int[0];
|
||||
// TODO: Consider adding extra counts or ActionFrequency to track "n per minute".
|
||||
|
||||
/**
|
||||
* Register a key and return the id that is used for access. If the key is already registered, the registered id is returned.<br>
|
||||
* Must only be called from the primary thread, or during (encapsulated) initialization.
|
||||
* @param key
|
||||
* @return The id to be used for adding to counts.
|
||||
*/
|
||||
public int registerKey(String key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("Key must not be null.");
|
||||
}
|
||||
Integer registeredId = idMap.get(key);
|
||||
if (registeredId != null) {
|
||||
return registeredId.intValue();
|
||||
}
|
||||
final int newId = ptCounts.length;
|
||||
idMap.put(key, newId);
|
||||
keys = Arrays.copyOf(keys, newId + 1);
|
||||
keys[newId] = key;
|
||||
ptCounts = Arrays.copyOf(ptCounts, newId + 1);
|
||||
synchronized (syCounts) {
|
||||
syCounts = Arrays.copyOf(syCounts, newId + 1);
|
||||
}
|
||||
return newId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for quick testing / uncertain contexts, checks
|
||||
* Bukkit.isPrimaryThread(), then delegates, thus is slower.
|
||||
*
|
||||
* @param id
|
||||
* @param count
|
||||
*/
|
||||
public void add(int id, int count) {
|
||||
if (Bukkit.isPrimaryThread()) {
|
||||
addPrimaryThread(id, count);
|
||||
} else {
|
||||
addSynchronized(id, count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Only call from the primary thread.
|
||||
* @param id
|
||||
* @param count
|
||||
*/
|
||||
public void addPrimaryThread(int id, int count) {
|
||||
ptCounts[id] += count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call from any thread.
|
||||
* @param id
|
||||
* @param count
|
||||
*/
|
||||
public void addSynchronized(int id, int count) {
|
||||
synchronized (syCounts) {
|
||||
syCounts[id] += count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset all counters to 0.<br>
|
||||
* Must only be called from the primary thread.
|
||||
*/
|
||||
public void resetAll() {
|
||||
for (int i = 0; i < ptCounts.length; i ++) {
|
||||
ptCounts[i] = 0;
|
||||
}
|
||||
synchronized (syCounts) {
|
||||
for (int i = 0; i < syCounts.length; i ++) {
|
||||
syCounts[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Integer> getPrimaryThreadCounts() {
|
||||
final Map<String, Integer> counts = new LinkedHashMap<String, Integer>();
|
||||
final int length = keys.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
counts.put(keys[i], ptCounts[i]);
|
||||
}
|
||||
return counts;
|
||||
}
|
||||
|
||||
public Map<String, Integer> getSynchronizedCounts() {
|
||||
final Map<String, Integer> counts = new LinkedHashMap<String, Integer>();
|
||||
final int[] syCounts;
|
||||
synchronized (this.syCounts) {
|
||||
syCounts = Arrays.copyOf(this.syCounts, this.syCounts.length);
|
||||
}
|
||||
for (int i = 0; i < syCounts.length; i++) {
|
||||
counts.put(keys[i], syCounts[i]);
|
||||
}
|
||||
return counts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a map for keys to counts, preserving the registration order of keys
|
||||
* for iteration (LinkedHashMap).<br>
|
||||
* Only call from the primary thread.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Map<String, Integer> getMergedCounts() {
|
||||
final Map<String, Integer> counts = new LinkedHashMap<String, Integer>();
|
||||
final int[] syCounts;
|
||||
synchronized (this.syCounts) {
|
||||
syCounts = Arrays.copyOf(this.syCounts, this.syCounts.length);
|
||||
}
|
||||
for (int i = 0; i < syCounts.length; i++) {
|
||||
counts.put(keys[i], syCounts[i] + ptCounts[i]);
|
||||
}
|
||||
return counts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a String (one line), which summarizes the contents: key merged-count.<br>
|
||||
* Only call in the primary thread.
|
||||
* @return
|
||||
*/
|
||||
public String getMergedCountsString() {
|
||||
return getMergedCountsString(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a String (one line), which summarizes the contents: key merged-count (pt count / sy count).<br>
|
||||
* Only call in the primary thread.
|
||||
* @param details If to show difference of primary thread / synchronized.
|
||||
* @return
|
||||
*/
|
||||
public String getMergedCountsString(final boolean details) {
|
||||
final StringBuilder builder = new StringBuilder(1024);
|
||||
final Map<String, Integer> syCounts = getSynchronizedCounts();
|
||||
final Map<String, Integer> ptCounts = getPrimaryThreadCounts();
|
||||
builder.append('|');
|
||||
for (final Entry<String, Integer> entry : ptCounts.entrySet()) {
|
||||
final String key = entry.getKey();
|
||||
builder.append(' ');
|
||||
builder.append(key);
|
||||
builder.append(' ');
|
||||
final int pt = entry.getValue();
|
||||
final int sy = syCounts.get(key);
|
||||
final int sum = pt + sy;
|
||||
builder.append(Integer.toString(sum));
|
||||
if (details && sum > 0) {
|
||||
builder.append(" (");
|
||||
builder.append(Integer.toString(pt));
|
||||
builder.append('/');
|
||||
builder.append(Integer.toString(sy));
|
||||
builder.append(')');
|
||||
}
|
||||
builder.append(" |");
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
@ -76,6 +76,7 @@ import fr.neatmonster.nocheatplus.permissions.Permissions;
|
||||
import fr.neatmonster.nocheatplus.players.DataManager;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerData;
|
||||
import fr.neatmonster.nocheatplus.players.PlayerMessageSender;
|
||||
import fr.neatmonster.nocheatplus.stats.Counters;
|
||||
import fr.neatmonster.nocheatplus.updates.Updates;
|
||||
import fr.neatmonster.nocheatplus.utilities.BlockProperties;
|
||||
import fr.neatmonster.nocheatplus.utilities.ColorUtil;
|
||||
@ -552,6 +553,7 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
|
||||
// Stop consistency checking task.
|
||||
if (consistencyCheckerTaskId != -1){
|
||||
sched.cancelTask(consistencyCheckerTaskId);
|
||||
consistencyCheckerTaskId = -1;
|
||||
}
|
||||
|
||||
// Just to be sure nothing gets left out.
|
||||
@ -574,6 +576,12 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
|
||||
}
|
||||
}
|
||||
|
||||
// Write some debug/statistics.
|
||||
final Counters counters = getGenericInstance(Counters.class);
|
||||
if (counters != null) {
|
||||
LogUtil.logInfo(counters.getMergedCountsString(true));
|
||||
}
|
||||
|
||||
// Hooks:
|
||||
// (Expect external plugins to unregister their hooks on their own.)
|
||||
// (No native hooks present, yet.)
|
||||
@ -688,6 +696,10 @@ public class NoCheatPlus extends JavaPlugin implements NoCheatPlusAPI {
|
||||
TickTask.cancel();
|
||||
TickTask.reset();
|
||||
|
||||
// Register some generic stuff.
|
||||
// Counters: debugging purposes, maybe integrated for statistics later.
|
||||
registerGenericInstance(new Counters());
|
||||
|
||||
// Read the configuration files.
|
||||
ConfigManager.init(this);
|
||||
|
||||
|
@ -299,6 +299,10 @@ permissions:
|
||||
description: Allow use of the ncp removeplayer command.
|
||||
nocheatplus.command.commands:
|
||||
description: Allow use of the ncp commands command.
|
||||
nocheatplus.command.log:
|
||||
description: Show various stats/debugging information. [Incomplete, experimental.]
|
||||
nocheatplus.command.reset:
|
||||
description: Reset statistics or debugging counters.
|
||||
# Legacy:
|
||||
nocheatplus.command.tempkick:
|
||||
description: Obsolete, use nocheatplus.command.denylogin instead.
|
||||
|
Loading…
Reference in New Issue
Block a user