diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/FileUUIDHandler.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/FileUUIDHandler.java index d1c302e91..15cf9b6ad 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/FileUUIDHandler.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/FileUUIDHandler.java @@ -26,6 +26,7 @@ import java.util.List; import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.World; +import org.bukkit.entity.Player; public class FileUUIDHandler extends UUIDHandlerImplementation { @@ -101,8 +102,10 @@ public class FileUUIDHandler extends UUIDHandlerImplementation { NbtFactory.NbtCompound bukkit = (NbtFactory.NbtCompound) compound.get("bukkit"); String name = (String) bukkit.get("lastKnownName"); long last = (long) bukkit.get("lastPlayed"); + long first = (long) bukkit.get("firstPlayed"); if (ExpireManager.IMP != null) { ExpireManager.IMP.storeDate(uuid, last); + ExpireManager.IMP.storeAccountAge(uuid, last - first); } toAdd.put(new StringWrapper(name), uuid); } @@ -168,6 +171,7 @@ public class FileUUIDHandler extends UUIDHandlerImplementation { StringWrapper wrap = new StringWrapper(name); if (!toAdd.containsKey(wrap)) { long last = (long) bukkit.get("lastPlayed"); + long first = (long) bukkit.get("firstPlayed"); if (Settings.UUID.OFFLINE) { if (Settings.UUID.FORCE_LOWERCASE && !name.toLowerCase().equals(name)) { uuid = FileUUIDHandler.this.uuidWrapper.getUUID(name); @@ -179,6 +183,7 @@ public class FileUUIDHandler extends UUIDHandlerImplementation { } if (ExpireManager.IMP != null) { ExpireManager.IMP.storeDate(uuid, last); + ExpireManager.IMP.storeAccountAge(uuid, last - first); } toAdd.put(wrap, uuid); } diff --git a/Core/src/main/java/com/intellectualcrafters/plot/config/Settings.java b/Core/src/main/java/com/intellectualcrafters/plot/config/Settings.java index 3fef2f141..6ca69efd2 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/config/Settings.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/config/Settings.java @@ -158,8 +158,10 @@ public class Settings extends Config { public int REQUIRED_PLOTS = -1; public boolean CONFIRMATION = true; public int DAYS = 7; + public int SKIP_ACCOUNT_AGE_DAYS = -1; public List WORLDS = new ArrayList<>(Collections.singletonList("*")); + @Comment("See: https://github.com/IntellectualSites/PlotSquared/wiki/Plot-analysis") public static final class CALIBRATION { public int VARIETY = 0; diff --git a/Core/src/main/java/com/intellectualcrafters/plot/util/expiry/ExpireManager.java b/Core/src/main/java/com/intellectualcrafters/plot/util/expiry/ExpireManager.java index d41f3dd7b..4643dec4e 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/util/expiry/ExpireManager.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/util/expiry/ExpireManager.java @@ -35,6 +35,7 @@ public class ExpireManager { public static ExpireManager IMP; private final ConcurrentHashMap dates_cache; + private final ConcurrentHashMap account_age_cache; private volatile HashSet plotsToDelete; private ArrayDeque tasks; /** @@ -45,6 +46,7 @@ public class ExpireManager { public ExpireManager() { tasks = new ArrayDeque<>(); dates_cache = new ConcurrentHashMap<>(); + account_age_cache = new ConcurrentHashMap<>(); } public void addTask(ExpiryTask task) { @@ -73,6 +75,16 @@ public class ExpireManager { } } + /** + * Gets the account last joined - first joined (or Long.MAX_VALUE) + * @param uuid + * @return result + */ + public long getAccountAge(UUID uuid) { + Long value = this.account_age_cache.get(uuid); + return value == null ? Long.MAX_VALUE : value; + } + public long getTimestamp(UUID uuid) { Long value = this.dates_cache.get(uuid); return value == null ? 0 : value; @@ -163,6 +175,8 @@ public class ExpireManager { if (applicable.isEmpty()) { return new ArrayList<>(); } + boolean shouldCheckAccountAge = false; + long diff = getAge(plot); if (diff == 0) { return new ArrayList<>(); @@ -172,11 +186,26 @@ public class ExpireManager { ExpiryTask et = applicable.poll(); if (et.applies(diff)) { applicable.add(et); + shouldCheckAccountAge |= et.getSettings().SKIP_ACCOUNT_AGE_DAYS != -1; } } if (applicable.isEmpty()) { return new ArrayList<>(); } + // Check account age + if (shouldCheckAccountAge) { + long accountAge = getAge(plot); + for (int i = 0; i < applicable.size(); i++) { + ExpiryTask et = applicable.poll(); + if (et.appliesAccountAge(accountAge)) { + applicable.add(et); + } + } + if (applicable.isEmpty()) { + return new ArrayList<>(); + } + } + // Run applicable non confirming tasks for (int i = 0; i < applicable.size(); i++) { ExpiryTask expiryTask = applicable.poll(); @@ -334,7 +363,19 @@ public class ExpireManager { } public void storeDate(UUID uuid, long time) { - this.dates_cache.put(uuid, time); + Long existing = this.dates_cache.put(uuid, time); + if (existing != null) { + long diff = time - existing; + if (diff > 0) { + Long account_age = this.account_age_cache.get(uuid); + if (account_age != null) + this.account_age_cache.put(uuid, account_age + diff); + } + } + } + + public void storeAccountAge(UUID uuid, long time) { + this.account_age_cache.put(uuid, time); } public HashSet getPendingExpired() { @@ -399,6 +440,18 @@ public class ExpireManager { return 0; } + public long getAccountAge(Plot plot) { + if (!plot.hasOwner() || Objects.equals(DBFunc.everyone, plot.owner) || UUIDHandler.getPlayer(plot.owner) != null || plot.getRunning() > 0) { + return Long.MAX_VALUE; + } + long max = 0; + for (UUID owner : plot.getOwners()) { + long age = getAccountAge(owner); + max = Math.max(age, max); + } + return max; + } + public long getAge(Plot plot) { if (!plot.hasOwner() || Objects.equals(DBFunc.everyone, plot.owner) || UUIDHandler.getPlayer(plot.owner) != null || plot.getRunning() > 0) { return 0; diff --git a/Core/src/main/java/com/intellectualcrafters/plot/util/expiry/ExpiryTask.java b/Core/src/main/java/com/intellectualcrafters/plot/util/expiry/ExpiryTask.java index 231113030..f61c92dd0 100644 --- a/Core/src/main/java/com/intellectualcrafters/plot/util/expiry/ExpiryTask.java +++ b/Core/src/main/java/com/intellectualcrafters/plot/util/expiry/ExpiryTask.java @@ -18,6 +18,10 @@ public class ExpiryTask { this.settings = settings; } + public Settings.Auto_Clear getSettings() { + return settings; + } + public boolean allowsArea(PlotArea area) { return settings.WORLDS.contains(area.toString()) || settings.WORLDS.contains(area.worldname) || settings.WORLDS.contains("*"); } @@ -99,6 +103,12 @@ public class ExpiryTask { return diff > TimeUnit.DAYS.toMillis(settings.DAYS) && diff > cutoffThreshold; } + public boolean appliesAccountAge(long accountAge) { + if (settings.SKIP_ACCOUNT_AGE_DAYS != -1) + return accountAge <= TimeUnit.DAYS.toMillis(settings.SKIP_ACCOUNT_AGE_DAYS); + return false; + } + public boolean needsAnalysis() { return settings.THRESHOLD > 0; }