More plot analysis + made it more obvious that plot listing is interactive

This commit is contained in:
boy0001 2015-07-18 15:02:44 +10:00
parent e026ec31eb
commit a7cd8d995e
7 changed files with 198 additions and 143 deletions

View File

@ -1329,7 +1329,6 @@ public class PS {
// Clearing + Expiry // Clearing + Expiry
Settings.FAST_CLEAR = config.getBoolean("clear.fastmode"); Settings.FAST_CLEAR = config.getBoolean("clear.fastmode");
Settings.DELETE_PLOTS_ON_BAN = config.getBoolean("clear.on.ban"); Settings.DELETE_PLOTS_ON_BAN = config.getBoolean("clear.on.ban");
Settings.MIN_BLOCKS_CHANGED_IGNORED = config.getInt("clear.ignore-if-modified");
Settings.AUTO_CLEAR_DAYS = config.getInt("clear.auto.days"); Settings.AUTO_CLEAR_DAYS = config.getInt("clear.auto.days");
Settings.CLEAR_THRESHOLD = config.getInt("clear.auto.threshold"); Settings.CLEAR_THRESHOLD = config.getInt("clear.auto.threshold");
Settings.AUTO_CLEAR = config.getBoolean("clear.auto.enabled"); Settings.AUTO_CLEAR = config.getBoolean("clear.auto.enabled");

View File

@ -58,17 +58,56 @@ public class DebugExec extends SubCommand {
@Override @Override
public boolean execute(final PlotPlayer player, final String... args) { public boolean execute(final PlotPlayer player, final String... args) {
final List<String> allowed_params = Arrays.asList("analyze", "remove-flag", "stop-expire", "start-expire", "show-expired", "update-expired", "seen", "trim-check"); final List<String> allowed_params = Arrays.asList("calibrate-analysis", "remove-flag", "stop-expire", "start-expire", "show-expired", "update-expired", "seen", "trim-check");
if (args.length > 0) { if (args.length > 0) {
final String arg = args[0].toLowerCase(); final String arg = args[0].toLowerCase();
switch (arg) { switch (arg) {
case "analyze": { case "analyze": {
if (player == null) {
MainUtil.sendMessage(player, C.IS_CONSOLE);
return false;
}
Plot plot = MainUtil.getPlot(player.getLocation());
if (plot == null) {
MainUtil.sendMessage(player, C.NOT_IN_PLOT);
return false;
}
PlotAnalysis analysis = plot.getComplexity();
if (analysis != null) {
int complexity = analysis.getComplexity();
MainUtil.sendMessage(player, "Complexity: " + complexity);
return true;
}
MainUtil.sendMessage(player, "$1Starting task...");
HybridUtils.manager.analyzePlot(plot, new RunnableVal<PlotAnalysis>() {
@Override
public void run() {
MainUtil.sendMessage(player, "$1Done: $2use $3/plot debugexec analyze$2 for more information");
}
});
return true;
}
case "calibrate-analysis": {
if (args.length != 2) {
MainUtil.sendMessage(player, C.COMMAND_SYNTAX, "/plot debugexec analyze <threshold>");
MainUtil.sendMessage(player, "$1<threshold> $2= $1The percentage of plots you want to clear (100 clears 100% of plots so no point calibrating it)");
return false;
}
double threshold;
try {
threshold = Integer.parseInt(args[1]) / 100d;
}
catch (NumberFormatException e) {
MainUtil.sendMessage(player, "$2Invalid threshold: " + args[1]);
MainUtil.sendMessage(player, "$1<threshold> $2= $1The percentage of plots you want to clear as a number between 0 - 100");
return false;
}
PlotAnalysis.calcOptimalModifiers(new Runnable() { PlotAnalysis.calcOptimalModifiers(new Runnable() {
@Override @Override
public void run() { public void run() {
PS.log("&cTHIS FUNCTION IS A WORK IN PROGRESS"); PS.log("$1Thank you for calibrating PlotSquared plot expiry");
} }
}); }, threshold);
return true; return true;
} }
case "stop-expire": { case "stop-expire": {

View File

@ -472,6 +472,8 @@ public class list extends SubCommand {
.then("->") .then("->")
.color(ChatColor.GOLD) .color(ChatColor.GOLD)
.command("/plot list " + args[0] + " " + (page + 2)) .command("/plot list " + args[0] + " " + (page + 2))
.color(ChatColor.GRAY)
.then(C.CLICKABLE.s())
.send(((BukkitPlayer) player).player); .send(((BukkitPlayer) player).player);
return; return;
} }
@ -485,6 +487,8 @@ public class list extends SubCommand {
.then("->") .then("->")
.color(ChatColor.GOLD) .color(ChatColor.GOLD)
.command("/plot list " + args[0] + " " + (page + 2)) .command("/plot list " + args[0] + " " + (page + 2))
.color(ChatColor.GRAY)
.then(C.CLICKABLE.s())
.send(((BukkitPlayer) player).player); .send(((BukkitPlayer) player).player);
return; return;
} }
@ -498,6 +502,8 @@ public class list extends SubCommand {
.color(ChatColor.DARK_GRAY) .color(ChatColor.DARK_GRAY)
.then("->") .then("->")
.color(ChatColor.DARK_GRAY) .color(ChatColor.DARK_GRAY)
.color(ChatColor.GRAY)
.then(C.CLICKABLE.s())
.send(((BukkitPlayer) player).player); .send(((BukkitPlayer) player).player);
return; return;
} }

View File

@ -399,6 +399,7 @@ public enum C {
* List * List
*/ */
COMMENT_LIST_HEADER_PAGED("$2(Page $1%cur$2/$1%max$2) $1List of %amount% comments", "List"), COMMENT_LIST_HEADER_PAGED("$2(Page $1%cur$2/$1%max$2) $1List of %amount% comments", "List"),
CLICKABLE(" (interactive)", "List"),
PLOT_LIST_HEADER_PAGED("$2(Page $1%cur$2/$1%max$2) $1List of %amount% plots", "List"), PLOT_LIST_HEADER_PAGED("$2(Page $1%cur$2/$1%max$2) $1List of %amount% plots", "List"),
PLOT_LIST_HEADER("$1List of %word% plots", "List"), PLOT_LIST_HEADER("$1List of %word% plots", "List"),
PLOT_LIST_ITEM("$2>> $1%id$2:$1%world $2- $1%owner", "List"), PLOT_LIST_ITEM("$2>> $1%id$2:$1%world $2- $1%owner", "List"),

View File

@ -161,8 +161,7 @@ public class Settings {
* Days until a plot gets cleared * Days until a plot gets cleared
*/ */
public static int AUTO_CLEAR_DAYS = 360; public static int AUTO_CLEAR_DAYS = 360;
public static int CLEAR_THRESHOLD = 100; public static int CLEAR_THRESHOLD = -1;
public static int MIN_BLOCKS_CHANGED_IGNORED = -1;
public static int CLEAR_INTERVAL = 120; public static int CLEAR_INTERVAL = 120;
/** /**
* API Location * API Location

View File

@ -31,7 +31,7 @@ public class PlotAnalysis {
public int air_sd; public int air_sd;
public int variety_sd; public int variety_sd;
public double complexity; private int complexity;
public static PlotAnalysis MODIFIERS = new PlotAnalysis(); public static PlotAnalysis MODIFIERS = new PlotAnalysis();
@ -52,30 +52,30 @@ public class PlotAnalysis {
analysis.air_sd = values.get(8); analysis.air_sd = values.get(8);
analysis.variety_sd = values.get(9); analysis.variety_sd = values.get(9);
analysis.complexity = analysis.complexity = analysis.getComplexity();
+ (analysis.changes) * MODIFIERS.changes
+ (analysis.faces) * MODIFIERS.faces
+ (analysis.data) * MODIFIERS.data
+ (analysis.air) * MODIFIERS.air
+ (analysis.variety) * MODIFIERS.variety
+ (analysis.changes_sd) * MODIFIERS.changes_sd
+ (analysis.faces_sd) * MODIFIERS.faces_sd
+ (analysis.data_sd) * MODIFIERS.data_sd
+ (analysis.air_sd) * MODIFIERS.air_sd
+ (analysis.variety_sd) * MODIFIERS.variety_sd
;
return analysis; return analysis;
} }
return null; return null;
} }
public static void analyzePlot(Plot plot, RunnableVal<PlotAnalysis> whenDone) { public int getComplexity() {
PlotAnalysis analysis = getAnalysis(plot); if (complexity != 0) {
if (analysis != null) { return complexity;
whenDone.value = analysis;
if (whenDone != null) whenDone.run();
return;
} }
complexity = (this.changes) * MODIFIERS.changes
+ (this.faces) * MODIFIERS.faces
+ (this.data) * MODIFIERS.data
+ (this.air) * MODIFIERS.air
+ (this.variety) * MODIFIERS.variety
+ (this.changes_sd) * MODIFIERS.changes_sd
+ (this.faces_sd) * MODIFIERS.faces_sd
+ (this.data_sd) * MODIFIERS.data_sd
+ (this.air_sd) * MODIFIERS.air_sd
+ (this.variety_sd) * MODIFIERS.variety_sd;
return complexity;
}
public static void analyzePlot(Plot plot, RunnableVal<PlotAnalysis> whenDone) {
BukkitHybridUtils.manager.analyzePlot(plot, whenDone); BukkitHybridUtils.manager.analyzePlot(plot, whenDone);
} }
@ -91,8 +91,8 @@ public class PlotAnalysis {
PS.log("Calibration task already in progress!"); PS.log("Calibration task already in progress!");
return; return;
} }
if (threshold < 0 || threshold >= 1) { if (threshold <= 0 || threshold >= 1) {
PS.log("Invalid threshold provided!"); PS.log("Invalid threshold provided! (Cannot be 0 or 100 as then there's no point calibrating)");
return; return;
} }
running = true; running = true;
@ -295,13 +295,57 @@ public class PlotAnalysis {
PlotAnalysis.MODIFIERS.variety_sd = factor_variety_sd == 1 ? 0 : (int) (factor_variety_sd * 1000 / MathMan.getMean(variety_sd)); PlotAnalysis.MODIFIERS.variety_sd = factor_variety_sd == 1 ? 0 : (int) (factor_variety_sd * 1000 / MathMan.getMean(variety_sd));
PS.log(" - | variety_sd " + factor_variety_sd); PS.log(" - | variety_sd " + factor_variety_sd);
int[] complexity = new int[n];
PS.log(" $1Calculating threshold");
PlotAnalysis analysis = getAnalysis(plots.get(Arrays.asList(rank_ratings).indexOf(optimal_index))); int max = 0;
int min = 0;
for (int i = 0; i < n; i++) {
Plot plot = plots.get(i);
PlotAnalysis analysis = plot.getComplexity();
complexity[i] = analysis.complexity;
if (analysis.complexity < min) {
min = analysis.complexity;
}
else if (analysis.complexity > max) {
max = analysis.complexity;
}
}
int optimal_complexity = Integer.MAX_VALUE;
if (min > 0 && max < 102400) { // If low size, use my fast ranking algorithm
int[] rank_complexity = rank(complexity, max + 1);
for (int i = 0; i < n; i++) {
if (rank_complexity[i] == optimal_index) {
optimal_complexity = complexity[i];
break;
}
}
logln("Complexity: ");
logln(rank_complexity);
logln("Ratings: ");
logln(rank_ratings);
logln("Correlation: ");
logln(getCC(n, sum(square(getSD(rank_complexity, rank_ratings)))));
if (optimal_complexity == Integer.MAX_VALUE) {
PS.log("");
running = false;
return;
}
}
else { // Use the fast radix sort algorithm
int[] sorted = complexity.clone();
sort(sorted);
optimal_complexity = sorted[optimal_index];
logln("Complexity: ");
logln(sorted);
logln("Ratings: ");
logln(rank_ratings);
}
// Save calibration // Save calibration
PS.log(" $1Saving calibration"); PS.log(" $1Saving calibration");
YamlConfiguration config = PS.get().config; YamlConfiguration config = PS.get().config;
config.set("clear.auto.threshold", optimal_complexity);
config.set("clear.auto.calibration.changes", PlotAnalysis.MODIFIERS.changes); config.set("clear.auto.calibration.changes", PlotAnalysis.MODIFIERS.changes);
config.set("clear.auto.calibration.faces", PlotAnalysis.MODIFIERS.faces); config.set("clear.auto.calibration.faces", PlotAnalysis.MODIFIERS.faces);
config.set("clear.auto.calibration.data", PlotAnalysis.MODIFIERS.data); config.set("clear.auto.calibration.data", PlotAnalysis.MODIFIERS.data);
@ -318,13 +362,41 @@ public class PlotAnalysis {
e.printStackTrace(); e.printStackTrace();
} }
PS.log(" $1Done!"); PS.log("$1Done!");
running = false; running = false;
whenDone.run(); whenDone.run();
} }
}); });
} }
public static void logln(Object obj) {
System.out.println(log(obj));
}
public static String log(Object obj) {
String result = "";
if (obj.getClass().isArray()) {
String prefix = "";
for(int i=0; i<Array.getLength(obj); i++){
result += prefix + log(Array.get(obj, i));
prefix = ",";
}
return "( " + result + " )";
}
else if (obj instanceof List<?>) {
String prefix = "";
for (Object element : (List<?>) obj) {
result += prefix + log(element);
prefix = ",";
}
return "[ " + result + " ]";
}
else {
return obj.toString();
}
}
/** /**
* Get correllation coefficient * Get correllation coefficient
* @return * @return
@ -390,15 +462,24 @@ public class PlotAnalysis {
/** /**
* An optimized algorithm for ranking a very specific set of inputs<br> * An optimized algorithm for ranking a very specific set of inputs<br>
* - Input is an array of int with a max size of 102400 * - Input is an array of int with a max size of 102400<br>
* - This allows for optimizations beyond any standard sorting function * - A reduced sample space allows for sorting (and ranking in this case) in linear time
* @param input * @param input
* @return * @return
*/ */
public static int[] rank(final int[] input) { public static int[] rank(final int[] input) {
int[] cache = new int[102400]; return rank(input, 102400);
}
/**
* An optimized algorithm for ranking a very specific set of inputs
* @param input
* @return
*/
public static int[] rank(final int[] input, int size) {
int[] cache = new int[size];
int max = 0; int max = 0;
if (input.length < 102400) { if (input.length < size) {
for (int value : input) { for (int value : input) {
if (value > max) { if (value > max) {
max = value; max = value;

View File

@ -55,7 +55,7 @@ public class ExpireManager {
public void run() { public void run() {
try { try {
final List<Plot> plots = getOldPlots(world); final List<Plot> plots = getOldPlots(world);
PS.log("&7[&5Expire&dManager&7] &3Found " + plots.size() + " expired plots for " + world + "!"); PS.log("$2[&5Expire&dManager$2] $4Found " + plots.size() + " expired plots for " + world + "!");
expiredPlots.put(world, plots); expiredPlots.put(world, plots);
updatingPlots.put(world, false); updatingPlots.put(world, false);
} }
@ -82,18 +82,18 @@ public class ExpireManager {
} }
final Boolean updating = ExpireManager.updatingPlots.get(world); final Boolean updating = ExpireManager.updatingPlots.get(world);
if (updating) { if (updating) {
PS.log("&7[&5Expire&dManager&7] &3Waiting on fetch..."); PS.log("$2[&5Expire&dManager$2] $4Waiting on fetch...");
return; return;
} }
if (!expiredPlots.containsKey(world)) { if (!expiredPlots.containsKey(world)) {
PS.log("&7[&5Expire&dManager&7] &3Updating expired plots for: " + world); PS.log("$2[&5Expire&dManager$2] $4Updating expired plots for: " + world);
updateExpired(world); updateExpired(world);
return; return;
} }
final List<Plot> plots = expiredPlots.get(world); final List<Plot> plots = expiredPlots.get(world);
if ((plots == null) || (plots.size() == 0)) { if ((plots == null) || (plots.size() == 0)) {
if (updateExpired(world)) { if (updateExpired(world)) {
PS.log("&7[&5Expire&dManager&7] &3Re-evaluating expired plots for: " + world); PS.log("$2[&5Expire&dManager$2] $4Re-evaluating expired plots for: " + world);
return; return;
} }
continue; continue;
@ -101,7 +101,7 @@ public class ExpireManager {
final Plot plot = plots.iterator().next(); final Plot plot = plots.iterator().next();
if (!isExpired(plot)) { if (!isExpired(plot)) {
expiredPlots.get(world).remove(plot); expiredPlots.get(world).remove(plot);
PS.log("&7[&5Expire&dManager&7] &bSkipping no longer expired: " + plot); PS.log("$2[&5Expire&dManager$2] &bSkipping no longer expired: " + plot);
return; return;
} }
for (final UUID helper : plot.trusted) { for (final UUID helper : plot.trusted) {
@ -118,87 +118,53 @@ public class ExpireManager {
} }
final PlotManager manager = PS.get().getPlotManager(world); final PlotManager manager = PS.get().getPlotManager(world);
if (manager == null) { if (manager == null) {
PS.log("&7[&5Expire&dManager&7] &cThis is a friendly reminder to create or delete " + world +" as it is currently setup incorrectly"); PS.log("$2[&5Expire&dManager$2] &cThis is a friendly reminder to create or delete " + world +" as it is currently setup incorrectly");
expiredPlots.get(world).remove(plot); expiredPlots.get(world).remove(plot);
return; return;
} }
final PlotWorld plotworld = PS.get().getPlotWorld(world); final PlotWorld plotworld = PS.get().getPlotWorld(world);
// RunnableVal<Integer> run = new RunnableVal<Integer>() { RunnableVal<PlotAnalysis> run = new RunnableVal<PlotAnalysis>() {
// @Override @Override
// public void run() { public void run() {
// int changed = this.value; PlotAnalysis changed = this.value;
// if (Settings.MIN_BLOCKS_CHANGED_IGNORED > 0 || Settings.MIN_BLOCKS_CHANGED > 0 && manager instanceof ClassicPlotManager) { if (Settings.CLEAR_THRESHOLD != -1 && plotworld.TYPE == 0 && changed != null) {
// if (changed >= Settings.MIN_BLOCKS_CHANGED && Settings.MIN_BLOCKS_CHANGED > 0) { if (changed.getComplexity() > Settings.CLEAR_THRESHOLD) {
// PS.log("&7[&5Expire&dManager&7] &bKeep flag added to: " + plot.id + (changed != -1 ? " (changed " + value + ")" : "")); PS.log("$2[&5Expire&dManager$2] &bIgnoring modified plot: " + plot + " : " + changed.getComplexity() + " - " + changed.changes);
// FlagManager.addPlotFlag(plot, new Flag(FlagManager.getFlag("keep"), true)); FlagManager.addPlotFlag(plot, new Flag(FlagManager.getFlag("modified-blocks"), value));
// expiredPlots.get(world).remove(plot); expiredPlots.get(world).remove(plot);
// return; return;
// } }
// else if (changed >= Settings.MIN_BLOCKS_CHANGED_IGNORED && Settings.MIN_BLOCKS_CHANGED_IGNORED > 0) { }
// PS.log("&7[&5Expire&dManager&7] &bIgnoring modified plot: " + plot.id + (changed != -1 ? " (changed " + value + ")" : "")); if (plot.settings.isMerged()) {
// FlagManager.addPlotFlag(plot, new Flag(FlagManager.getFlag("modified-blocks"), value)); MainUtil.unlinkPlot(plot);
// expiredPlots.get(world).remove(plot); }
// return; plot.delete();
// } expiredPlots.get(world).remove(plot);
// } int complexity = changed == null ? 0 : changed.getComplexity();
// if (plot.settings.isMerged()) { int modified = changed == null ? 0 : changed.changes;
// MainUtil.unlinkPlot(plot); PS.log("$2[&5Expire&dManager$2] &cDeleted expired plot: " + plot + " : " + complexity + " - " + modified);
// } PS.log("$4 - World: " + plot.world);
// plot.delete(); if (plot.hasOwner()) {
// expiredPlots.get(world).remove(plot); PS.log("$4 - Owner: " + UUIDHandler.getName(plot.owner));
// PS.log("&7[&5Expire&dManager&7] &cDeleted expired plot: " + plot.id + (changed != -1 ? " (changed " + value + ")" : "")); } else {
// PS.log("&3 - World: " + plot.world); PS.log("$4 - Owner: Unowned");
// if (plot.hasOwner()) { }
// PS.log("&3 - Owner: " + UUIDHandler.getName(plot.owner)); }
// } else { };
// PS.log("&3 - Owner: Unowned"); if (Settings.CLEAR_THRESHOLD != -1 && plotworld.TYPE == 0) {
// }
// }
// };
if ((Settings.MIN_BLOCKS_CHANGED_IGNORED > 0 || Settings.CLEAR_THRESHOLD != 100) && plotworld.TYPE == 0) {
PlotAnalysis analysis = plot.getComplexity(); PlotAnalysis analysis = plot.getComplexity();
if (analysis != null) { if (analysis != null) {
/* if (analysis.getComplexity() > Settings.CLEAR_THRESHOLD) {
* TODO remove min blocks changed PS.log("$2[&5Expire&dManager$2] &bSkipping modified: " + plot);
* - it isn't an accurate way to determine plot complexity
*
* compare this plots complexity with every other plot:
* - If it is in the bottom (threshold)% then it will be cleared
* - That doesn't make sense, that would mean it would get significantly harder as time goes on.
* - I guess as time goes on you can become more strict?
*
* % of plots to clear - not sure how to do
* % within non cleared plots - doesn't work for first plot
* % of plots in clear queue - doesn't work if 1 plot
*
* could be determined during calibration
*
* or (faster)
*
* set threshold complexity during calibration
*
* ideal number of expired plots
*
* manually set complexity
*/
}
Flag flag = FlagManager.getPlotFlagAbs(plot, "analysis");
if (flag != null) {
if ((Integer) flag.getValue() > Settings.MIN_BLOCKS_CHANGED_IGNORED) {
PS.log("&7[&5Expire&dManager&7] &bSkipping modified: " + plot);
expiredPlots.get(world).remove(plot); expiredPlots.get(world).remove(plot);
this.run(); this.run();
return; return;
} }
} }
else { HybridUtils.manager.analyzePlot(plot, run);
HybridUtils.manager.checkModified(plot, run);
}
} }
else { else {
run.value = -1; run.value = null;
run.run(); run.run();
} }
return; return;
@ -271,42 +237,6 @@ public class ExpireManager {
continue; continue;
} }
if (isExpired(plot)) { if (isExpired(plot)) {
if (Settings.AUTO_CLEAR_CHECK_DISK) {
final String worldname = Bukkit.getWorlds().get(0).getName();
String foldername;
String filename = null;
if (PS.get().IMP.checkVersion(1, 7, 5)) {
foldername = "playerdata";
try {
final OfflinePlotPlayer op = UUIDHandler.uuidWrapper.getOfflinePlayer(uuid);
filename = op.getUUID() + ".dat";
} catch (final Throwable e) {
filename = uuid.toString() + ".dat";
}
} else {
foldername = "players";
final String playername = UUIDHandler.getName(uuid);
if (playername != null) {
filename = playername + ".dat";
}
}
if (filename != null) {
final File playerFile = new File(worldname + File.separator + foldername + File.separator + filename);
if (!playerFile.exists()) {
PS.log("Could not find file: " + filename);
} else {
try {
long last = playerFile.lastModified();
long compared = System.currentTimeMillis() - last;
if (compared < (86400000l * Settings.AUTO_CLEAR_DAYS)) {
continue;
}
} catch (final Exception e) {
PS.log("Please disable disk checking in old plot auto clearing; Could not read file: " + filename);
}
}
}
}
toRemove.add(plot); toRemove.add(plot);
} }
} }