diff --git a/config.yml b/config.yml index dc52109..6f62ab0 100644 --- a/config.yml +++ b/config.yml @@ -57,7 +57,12 @@ Actions: Enabled: true WorldChange: false Interval: 3600000 - Diff-Interval: 1000 + # Enables differential logging and searching of inventories down to the second. + # This feature is experimental and will consume more disk space. + Diff-Interval: 0 + # Use this if you run into issues with death inventories being empty. + # This is usually due to a plugin like DeathChests clearing the inventory before AuxProtect sees it. + LowestPriority: false launch: Enabled: true grab: @@ -74,6 +79,64 @@ Actions: Enabled: true elytra: Enabled: true + gamemode: + Enabled: true + explode: + Enabled: true + auctionbuy: + Enabled: true + lightning: + Enabled: true + vein: + Enabled: true + pay: + Enabled: true + auctionlist: + Enabled: true + activity: + Enabled: true + alert: + Enabled: true + totem: + Enabled: true + jobs: + Enabled: true + tame: + Enabled: true + censor: + Enabled: true + breakitem: + Enabled: true + tp: + Enabled: true + towncreate: + Enabled: true + nationdelete: + Enabled: true + townyname: + Enabled: true + townrename: + Enabled: true + townjoin: + Enabled: true + nationrename: + Enabled: true + townmerge: + Enabled: true + nationjoin: + Enabled: true + townclaim: + Enabled: true + townbank: + Enabled: true + nationcreate: + Enabled: true + towndelete: + Enabled: true + townmayor: + Enabled: true + nationbank: + Enabled: true # Automatically check for updates and display notifications in game. # It's recommended to leave this enabled, as I'm constantly improving the plugin. checkforupdates: true \ No newline at end of file diff --git a/en-us.yml b/en-us.yml index 2bce276..fc711f6 100644 --- a/en-us.yml +++ b/en-us.yml @@ -136,4 +136,28 @@ actions: p: add itemframe n: remove itemframe ahlist: listed on ah - ahbuy: bought from ah \ No newline at end of file + ahbuy: bought from ah + townyname: named + towncreate: created town + townrename: renamed town to + towndelete: deleted town + townjoin: + p: joined town + n: left town + townclaim: + p: claimed + n: unclaimed + townmerge: merged into + townmayor: became the mayor of + townbank: + p: deposited + n: withdrew + nationcreate: created nation + nationrename: renamed nation + nationdelete: deleted nation + nationjoin: + p: joined nation + n: left nation + nationbank: + p: deposited + n: withdrew \ No newline at end of file diff --git a/jars/AuctionHouse-1.19-3.3.1.jar b/jars/AuctionHouse-1.19-3.3.1.jar new file mode 100644 index 0000000..7bddbf6 Binary files /dev/null and b/jars/AuctionHouse-1.19-3.3.1.jar differ diff --git a/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.jar b/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.jar new file mode 100644 index 0000000..7bddbf6 Binary files /dev/null and b/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.jar differ diff --git a/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.jar.md5 b/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.jar.md5 new file mode 100644 index 0000000..6b867be --- /dev/null +++ b/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.jar.md5 @@ -0,0 +1 @@ +d35928238d1bde85ab595887981778ab \ No newline at end of file diff --git a/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.jar.sha1 b/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.jar.sha1 new file mode 100644 index 0000000..569eee1 --- /dev/null +++ b/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.jar.sha1 @@ -0,0 +1 @@ +e5f8477f8bd3fc2781ecc5ea4327214a6b9b151f \ No newline at end of file diff --git a/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.pom b/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.pom new file mode 100644 index 0000000..7671be1 --- /dev/null +++ b/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.pom @@ -0,0 +1,8 @@ + + + 4.0.0 + AuctionHouse + AuctionHouse + 1.19-3.3.1 + diff --git a/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.pom.md5 b/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.pom.md5 new file mode 100644 index 0000000..62630c6 --- /dev/null +++ b/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.pom.md5 @@ -0,0 +1 @@ +5462c29004390ec8d562f7391c2ea36f \ No newline at end of file diff --git a/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.pom.sha1 b/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.pom.sha1 new file mode 100644 index 0000000..5a29fde --- /dev/null +++ b/local-maven-repo/AuctionHouse/AuctionHouse/1.19-3.3.1/AuctionHouse-1.19-3.3.1.pom.sha1 @@ -0,0 +1 @@ +c0379648e4bc86f80cc64f7451516acbc3e02ac5 \ No newline at end of file diff --git a/local-maven-repo/AuctionHouse/AuctionHouse/maven-metadata.xml b/local-maven-repo/AuctionHouse/AuctionHouse/maven-metadata.xml new file mode 100644 index 0000000..4d9842a --- /dev/null +++ b/local-maven-repo/AuctionHouse/AuctionHouse/maven-metadata.xml @@ -0,0 +1,12 @@ + + + AuctionHouse + AuctionHouse + + 1.19-3.3.1 + + 1.19-3.3.1 + + 20221024002907 + + diff --git a/local-maven-repo/AuctionHouse/AuctionHouse/maven-metadata.xml.md5 b/local-maven-repo/AuctionHouse/AuctionHouse/maven-metadata.xml.md5 new file mode 100644 index 0000000..466339f --- /dev/null +++ b/local-maven-repo/AuctionHouse/AuctionHouse/maven-metadata.xml.md5 @@ -0,0 +1 @@ +96df14c31a51be743854e8eb96ed8b4f \ No newline at end of file diff --git a/local-maven-repo/AuctionHouse/AuctionHouse/maven-metadata.xml.sha1 b/local-maven-repo/AuctionHouse/AuctionHouse/maven-metadata.xml.sha1 new file mode 100644 index 0000000..50d66cb --- /dev/null +++ b/local-maven-repo/AuctionHouse/AuctionHouse/maven-metadata.xml.sha1 @@ -0,0 +1 @@ +e055ff957032acf6b5025a0c99a377f776801f84 \ No newline at end of file diff --git a/plugin.yml b/plugin.yml index 494258e..05194a1 100644 --- a/plugin.yml +++ b/plugin.yml @@ -3,7 +3,7 @@ version: %VERSION% main: dev.heliosares.auxprotect.spigot.AuxProtectSpigot description: A plugin designed to supplement CoreProtect in a few ways. api-version: 1.13 -softdepend: [ShopGUIPlus, ChestShop, AuctionHouse, Vault, CoreProtect, EconomyShopGUI, EconomyShopGUI-Premium, DynamicShop, Jobs, Essentials] +softdepend: [ShopGUIPlus, ChestShop, AuctionHouse, Vault, CoreProtect, EconomyShopGUI, EconomyShopGUI-Premium, DynamicShop, Jobs, Essentials, Towny] loadbefore: [AdvancedPortals] commands: diff --git a/pom.xml b/pom.xml index 7a1d8f8..402f942 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 AuxProtect AuxProtect - 1.2-pre2 + 1.2-pre4 AuxProtect ${project.artifactId}-${project.version} @@ -95,6 +95,14 @@ essentials-repo https://repo.essentialsx.net/releases/ + + glaremasters repo + https://repo.glaremasters.me/repository/towny/ + + + local-maven-repo + file:///${project.basedir}/local-maven-repo + @@ -155,13 +163,6 @@ EconomyShopGUI-API 1.2.0 - - com.auctionhouse - auctionhouse - 1.0 - system - ${jars}/AuctionHouse-1.19-3.3.1.jar - com.github.7sat SSDynamicShop @@ -180,6 +181,17 @@ 2.19.7 provided + + com.palmergames.bukkit.towny + towny + 0.98.2.0 + provided + + + AuctionHouse + AuctionHouse + 1.19-3.3.1 + ${env.USERPROFILE}/eclipse-workspace/jars diff --git a/src/dev/heliosares/auxprotect/bungee/AuxProtectBungee.java b/src/dev/heliosares/auxprotect/bungee/AuxProtectBungee.java index d0a5584..ad1c2ca 100644 --- a/src/dev/heliosares/auxprotect/bungee/AuxProtectBungee.java +++ b/src/dev/heliosares/auxprotect/bungee/AuxProtectBungee.java @@ -161,7 +161,7 @@ public class AuxProtectBungee extends Plugin implements Listener, IAuxProtect { print(e); } - config = new APConfig(configurationFile); + config = new APConfig(this, configurationFile); } @Override @@ -272,7 +272,7 @@ public class AuxProtectBungee extends Plugin implements Listener, IAuxProtect { @Override public void reloadConfig() { - config = new APConfig(configurationFile); + config = new APConfig(this, configurationFile); } @Override @@ -289,4 +289,10 @@ public class AuxProtectBungee extends Plugin implements Listener, IAuxProtect { public void setDebug(int debug) { this.debug = debug; } + + @Override + public boolean isHooked(String name) { + // TODO Future implementation + return false; + } } diff --git a/src/dev/heliosares/auxprotect/bungee/command/APBCommand.java b/src/dev/heliosares/auxprotect/bungee/command/APBCommand.java index 8606399..1a5d62d 100644 --- a/src/dev/heliosares/auxprotect/bungee/command/APBCommand.java +++ b/src/dev/heliosares/auxprotect/bungee/command/APBCommand.java @@ -171,7 +171,7 @@ public class APBCommand extends Command implements TabExecutor { if (currentArg.startsWith("action:") || currentArg.startsWith("a:")) { String action = currentArg.split(":")[0] + ":"; for (EntryAction eaction : EntryAction.values()) { - if (eaction.isBungee() && eaction.isEnabled()) { + if (eaction.exists(plugin) && eaction.isEnabled()) { String actString = eaction.toString().toLowerCase(); if (eaction.hasDual) { possible.add(action + "+" + actString); diff --git a/src/dev/heliosares/auxprotect/core/APConfig.java b/src/dev/heliosares/auxprotect/core/APConfig.java index e078a1b..6fd0b80 100644 --- a/src/dev/heliosares/auxprotect/core/APConfig.java +++ b/src/dev/heliosares/auxprotect/core/APConfig.java @@ -3,11 +3,11 @@ package dev.heliosares.auxprotect.core; import org.bukkit.configuration.file.FileConfiguration; import dev.heliosares.auxprotect.database.EntryAction; +import dev.heliosares.auxprotect.utils.KeyUtil; import net.md_5.bungee.config.Configuration; public class APConfig { - private boolean privateRelease = false; private boolean inventoryOnWorldChange; private boolean checkforupdates; private long posInterval; @@ -16,6 +16,7 @@ public class APConfig { private long moneyInterval; private boolean overrideCommands; private boolean skipV6Migration; + private KeyUtil key; public boolean isInventoryOnWorldChange() { return inventoryOnWorldChange; @@ -42,15 +43,26 @@ public class APConfig { } public boolean isPrivate() { - return privateRelease; + if (key == null) + return false; + return key.isPrivate(); + } + + public boolean isDonor() { + if (key == null) + return false; + return key.isValid(); } public boolean isOverrideCommands() { return overrideCommands; } - public APConfig(FileConfiguration config) { - privateRelease = config.getBoolean("private"); + public APConfig(IAuxProtect plugin, FileConfiguration config) { + String keystr = config.getString("donorkey"); + if (keystr != null) { + key = new KeyUtil(keystr); + } checkforupdates = config.getBoolean("checkforupdates", true); inventoryOnWorldChange = config.getBoolean("Actions.inventory.WorldChange", false); posInterval = config.getLong("Actions.pos.Interval", 10000); @@ -59,23 +71,41 @@ public class APConfig { moneyInterval = config.getLong("Actions.money.Interval", 600000); skipV6Migration = config.getBoolean("skipv6migration"); for (EntryAction action : EntryAction.values()) { + if (!action.exists(plugin)) { + action.setEnabled(false); + continue; + } + if (action == EntryAction.USERNAME) { + action.setEnabled(true); + continue; + } boolean enabled = config.getBoolean("Actions." + action.toString().toLowerCase() + ".Enabled", true); boolean priority = config.getBoolean("Actions." + action.toString().toLowerCase() + ".LowestPriority", false); action.setEnabled(enabled); action.setLowestpriority(priority); + config.set("Actions." + action.toString().toLowerCase() + ".Enabled", enabled); } overrideCommands = config.getBoolean("OverrideCommands"); } - public APConfig(Configuration config) { - privateRelease = config.getBoolean("private"); + public APConfig(IAuxProtect plugin, Configuration config) { + String keystr = config.getString("donorkey"); + if (keystr != null) { + key = new KeyUtil(keystr); + } checkforupdates = config.getBoolean("checkforupdates", true); for (EntryAction action : EntryAction.values()) { - if (!action.isBungee()) { + if (!action.exists(plugin)) { + action.setEnabled(false); + continue; + } + if (action == EntryAction.USERNAME) { + action.setEnabled(true); continue; } boolean enabled = config.getBoolean("Actions." + action.toString().toLowerCase() + ".Enabled", true); + config.set("Actions." + action.toString().toLowerCase() + ".Enabled", enabled); action.setEnabled(enabled); } } diff --git a/src/dev/heliosares/auxprotect/core/IAuxProtect.java b/src/dev/heliosares/auxprotect/core/IAuxProtect.java index 6d11aa5..e763aeb 100644 --- a/src/dev/heliosares/auxprotect/core/IAuxProtect.java +++ b/src/dev/heliosares/auxprotect/core/IAuxProtect.java @@ -49,4 +49,6 @@ public interface IAuxProtect { public MySender getConsoleSender(); public boolean isShuttingDown(); + + public boolean isHooked(String name); } diff --git a/src/dev/heliosares/auxprotect/database/DatabaseRunnable.java b/src/dev/heliosares/auxprotect/database/DatabaseRunnable.java index 5bad03d..e7b170a 100644 --- a/src/dev/heliosares/auxprotect/database/DatabaseRunnable.java +++ b/src/dev/heliosares/auxprotect/database/DatabaseRunnable.java @@ -15,9 +15,8 @@ public class DatabaseRunnable implements Runnable { private final SQLManager sqlManager; private final IAuxProtect plugin; private static HashMap lastTimes = new HashMap<>(); -// private long running = 0; -// private long lastWarn = 0; - private long lastPolled = 0; + private long running = 0; + private long lastWarn = 0; private ConcurrentLinkedQueue pickups = new ConcurrentLinkedQueue<>(); private static final long pickupCacheTime = 1500; private ConcurrentLinkedQueue jobsentries = new ConcurrentLinkedQueue<>(); @@ -66,78 +65,80 @@ public class DatabaseRunnable implements Runnable { return; } // TODO was this necessary? -// if (running > 0) { -// if (System.currentTimeMillis() - running > 20000) { -// if (System.currentTimeMillis() - lastWarn > 60000) { -// lastWarn = System.currentTimeMillis(); -// plugin.warning("Overlapping logging windows > 20 seconds by " -// + (System.currentTimeMillis() - running) + " ms."); -// } -// } -// plugin.debug("Overlapping logging windows by " + (System.currentTimeMillis() - running) + " ms.", 1); -// return; -// } -// running = System.currentTimeMillis(); + if (running > 0) { + if (System.currentTimeMillis() - running > 20000) { + if (System.currentTimeMillis() - lastWarn > 60000) { + lastWarn = System.currentTimeMillis(); + plugin.warning("Overlapping logging windows > 20 seconds by " + + (System.currentTimeMillis() - running) + " ms."); + } + } + plugin.debug("Overlapping logging windows by " + (System.currentTimeMillis() - running) + " ms.", 1); + if (System.currentTimeMillis() - running < 300000) { + return; + } else { + plugin.warning("Overlapping logging windows by 5 minutes, continuing."); + } + } + running = System.currentTimeMillis(); checkCache(); - if (System.currentTimeMillis() - lastPolled > 3000 || queue.size() > 50) { - DbEntry entry; - long start = System.nanoTime(); + DbEntry entry; + long start = System.nanoTime(); - HashMap> entriesHash = new HashMap<>(); - - lastPolled = System.currentTimeMillis(); - while ((entry = queue.poll()) != null) { - if (plugin.getDebug() >= 2) { - String debug = String.format("§9%s §f%s§7(%d) §9%s §7", entry.getUser(), - entry.getAction().getText(plugin, entry.getState()), - entry.getAction().getId(entry.getState()), entry.getTarget()); - if (entry.getData() != null && entry.getData().length() > 0) { - String data = entry.getData(); - if (data.length() > 64) { - data = data.substring(0, 64) + "..."; - } - debug += "(" + data + ")"; + HashMap> entriesHash = new HashMap<>(); + while ((entry = queue.poll()) != null) { + if (plugin.getDebug() >= 2) { + String debug = String.format("§9%s §f%s§7(%d) §9%s §7", entry.getUser(), + entry.getAction().getText(plugin, entry.getState()), + entry.getAction().getId(entry.getState()), entry.getTarget()); + if (entry.getData() != null && entry.getData().length() > 0) { + String data = entry.getData(); + if (data.length() > 64) { + data = data.substring(0, 64) + "..."; } - plugin.debug(debug, 2); + debug += "(" + data + ")"; + } + plugin.debug(debug, 2); + } - Table table = entry.getAction().getTable(); + Table table = entry.getAction().getTable(); - if (table == null) { + if (table == null) { + continue; + } + + ArrayList entriesList = entriesHash.get(table); + if (entriesList == null) { + entriesList = new ArrayList<>(); + } + entriesList.add(entry); + entriesHash.put(table, entriesList); + } + + for (Entry> entryPair : entriesHash.entrySet()) { + try { + int size = entryPair.getValue().size(); + if (size == 0) { continue; } - - ArrayList entriesList = entriesHash.get(table); - if (entriesList == null) { - entriesList = new ArrayList<>(); - } - entriesList.add(entry); - entriesHash.put(table, entriesList); - } - - for (Entry> entryPair : entriesHash.entrySet()) { - try { - int size = entryPair.getValue().size(); - if (size == 0) { - continue; - } - sqlManager.put(entryPair.getKey(), entryPair.getValue()); - plugin.debug(debugLogStatement(start, size, entryPair.getKey()), 1); - start = System.nanoTime(); - } catch (Exception e) { - plugin.print(e); - } + sqlManager.put(entryPair.getKey(), entryPair.getValue()); + plugin.debug(debugLogStatement(start, size, entryPair.getKey()), 1); + start = System.nanoTime(); + } catch (Exception e) { + plugin.print(e); } } - } catch (Exception e) { - plugin.print(e); - } - sqlManager.cleanup(); -// running = 0; + sqlManager.cleanup(); + } catch (Throwable e) { + plugin.print(e); + } finally { + running = 0; + } } private String debugLogStatement(long start, int count, Table table) { diff --git a/src/dev/heliosares/auxprotect/database/DbEntry.java b/src/dev/heliosares/auxprotect/database/DbEntry.java index 6702e9a..24d7fdb 100644 --- a/src/dev/heliosares/auxprotect/database/DbEntry.java +++ b/src/dev/heliosares/auxprotect/database/DbEntry.java @@ -1,6 +1,6 @@ package dev.heliosares.auxprotect.database; -import javax.annotation.Nonnull; +import javax.annotation.Nullable; import org.bukkit.Location; @@ -8,9 +8,9 @@ public class DbEntry { private final long time; - private final EntryAction action; - private final boolean state; - private String data; + protected final EntryAction action; + protected final boolean state; + protected String data; public final String world; public final int x; @@ -21,12 +21,12 @@ public class DbEntry { public final int yaw; protected String userLabel; - private String user; - private int uid; + protected String user; + protected int uid; - private String targetLabel; - private String target; - private int target_id; + protected String targetLabel; + protected String target; + protected int target_id; private boolean hasBlob; private byte[] blob; @@ -68,7 +68,7 @@ public class DbEntry { * @param state Specifies the state of EntryAction (i.e +mount vs -mount), * if applicable, otherwise false. * - * @param location Should not be null. Will throw NullPointerException + * @param location May be null * * @param targetLabel The label of the target, see userLabel for details. * @@ -77,11 +77,13 @@ public class DbEntry { * * @throws NullPointerException */ - public DbEntry(String userLabel, EntryAction action, boolean state, @Nonnull Location location, String targetLabel, + public DbEntry(String userLabel, EntryAction action, boolean state, @Nullable Location location, String targetLabel, String data) throws NullPointerException { - this(userLabel, action, state, location.getWorld().getName(), location.getBlockX(), location.getBlockY(), - location.getBlockZ(), (int) Math.round(location.getPitch()), (int) Math.round(location.getYaw()), - targetLabel, data); + this(userLabel, action, state, location == null ? null : location.getWorld().getName(), + location == null ? 0 : location.getBlockX(), location == null ? 0 : location.getBlockY(), + location == null ? 0 : location.getBlockZ(), + location == null ? 0 : (int) Math.round(location.getPitch()), + location == null ? 0 : (int) Math.round(location.getYaw()), targetLabel, data); } protected DbEntry(long time, int uid, EntryAction action, boolean state, String world, int x, int y, int z, diff --git a/src/dev/heliosares/auxprotect/database/EntryAction.java b/src/dev/heliosares/auxprotect/database/EntryAction.java index 78dd541..f38efc5 100644 --- a/src/dev/heliosares/auxprotect/database/EntryAction.java +++ b/src/dev/heliosares/auxprotect/database/EntryAction.java @@ -1,34 +1,19 @@ package dev.heliosares.auxprotect.database; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Set; +import dev.heliosares.auxprotect.bungee.AuxProtectBungee; import dev.heliosares.auxprotect.core.IAuxProtect; +import dev.heliosares.auxprotect.spigot.AuxProtectSpigot; public class EntryAction { private static final HashMap values = new HashMap<>(); private static final Set usedids = new HashSet<>(); - public static EntryAction[] values() { - return values.values().toArray(new EntryAction[0]); - } - - public static EntryAction getAction(String key) { - return values.get(key); - } - - public static EntryAction getAction(int id) { - if (id == 0) - return null; - for (EntryAction action : values.values()) { - if (action.id == id || action.idPos == id) { - return action; - } - } - return null; - } - // START MAIN (0) public static final EntryAction LEASH = new EntryAction("leash", 2, 3); public static final EntryAction SESSION = new EntryAction("session", 4, 5); @@ -73,6 +58,7 @@ public class EntryAction { // START LONGTERM (768) public static final EntryAction IP = new EntryAction("ip", 768); public static final EntryAction USERNAME = new EntryAction("username", 769); + public static final EntryAction TOWNYNAME = new EntryAction("townyname", 770); // END LONGTERM (1023) // START INVENTORY (1024) @@ -102,6 +88,23 @@ public class EntryAction { public static final EntryAction VEIN = new EntryAction("vein", 1300); // END XRAY(1309) + // START TOWNY (1310) + public static final EntryAction TOWNCREATE = new EntryAction("towncreate", 1310); + public static final EntryAction TOWNRENAME = new EntryAction("townrename", 1311); + public static final EntryAction TOWNDELETE = new EntryAction("towndelete", 1312); + public static final EntryAction TOWNJOIN = new EntryAction("townjoin", 1313, 1314); + public static final EntryAction TOWNCLAIM = new EntryAction("townclaim", 1315, 1316); + public static final EntryAction TOWNMERGE = new EntryAction("townmerge", 1317); + public static final EntryAction TOWNMAYOR = new EntryAction("townmayor", 1318); + public static final EntryAction TOWNBANK = new EntryAction("townbank", 1319, 1320); + + public static final EntryAction NATIONCREATE = new EntryAction("nationcreate", 1400); + public static final EntryAction NATIONRENAME = new EntryAction("nationrename", 1401); + public static final EntryAction NATIONDELETE = new EntryAction("nationdelete", 1402); + public static final EntryAction NATIONJOIN = new EntryAction("nationjoin", 1403, 1404); + public static final EntryAction NATIONBANK = new EntryAction("nationbank", 1405, 1406); + // END TOWNY (1499) + public final boolean hasDual; public final int id; public final int idPos; @@ -180,18 +183,24 @@ public class EntryAction { return "actions." + toString().toLowerCase(); } - public boolean isBungee() { - if (id == MSG.id || id == COMMAND.id || id == IP.id || id == USERNAME.id || id == SESSION.id) { - return true; + public boolean exists(IAuxProtect plugin) { + if (!plugin.getAPConfig().isPrivate()) { + if (equals(IGNOREABANDONED) || equals(VEIN)) { + return false; + } } - return false; - } - - public boolean isSpigot() { - if (id == MSG.id) { + if (plugin instanceof AuxProtectSpigot) { + if (id == MSG.id) { + return false; + } + return true; + } else if (plugin instanceof AuxProtectBungee) { + if (equals(MSG) || equals(COMMAND) || equals(IP) || equals(USERNAME) || equals(SESSION)) { + return true; + } return false; } - return true; + return false; } public Table getTable() { @@ -219,10 +228,13 @@ public class EntryAction { if (id < 1310) { return Table.AUXPROTECT_XRAY; } - if (id > 10000) { + if (id < 1500) { + return Table.AUXPROTECT_TOWNY; + } + if (id > 1000000) { return Table.AUXPROTECT_API; } - return null; + throw new IllegalArgumentException("Action with unknown table: " + toString() + ", id=" + id); } public int getId(boolean state) { @@ -237,7 +249,7 @@ public class EntryAction { } public void setEnabled(boolean state) { - if (this.equals(USERNAME)) { // Don't allow this to be disabled. + if (equals(USERNAME)) { // Don't allow this to be disabled. enabled = true; return; } @@ -250,12 +262,11 @@ public class EntryAction { } @Override - public boolean equals(Object other_) { - if (!(other_ instanceof EntryAction)) { - return false; + public boolean equals(Object other) { + if (other instanceof EntryAction otherEntry) { + return this.id == otherEntry.id && this.idPos == otherEntry.idPos; } - EntryAction other = (EntryAction) other_; - return this.id == other.id && this.idPos == other.idPos; + return false; } public boolean isLowestpriority() { @@ -266,4 +277,23 @@ public class EntryAction { this.lowestpriority = lowestpriority; } + public static Collection values() { + return Collections.unmodifiableCollection(values.values()); + } + + public static EntryAction getAction(String key) { + return values.get(key); + } + + public static EntryAction getAction(int id) { + if (id == 0) + return null; + for (EntryAction action : values.values()) { + if (action.id == id || action.idPos == id) { + return action; + } + } + return null; + } + } diff --git a/src/dev/heliosares/auxprotect/database/InvDiffManager.java b/src/dev/heliosares/auxprotect/database/InvDiffManager.java index e7f00a1..a16b0b1 100644 --- a/src/dev/heliosares/auxprotect/database/InvDiffManager.java +++ b/src/dev/heliosares/auxprotect/database/InvDiffManager.java @@ -8,6 +8,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -44,23 +45,13 @@ public class InvDiffManager { long lastused; final long blobid; final byte[] ablob; + final int hash; BlobCache(long blobid, byte[] ablob) { this.blobid = blobid; this.ablob = ablob; this.lastused = System.currentTimeMillis(); - } - - boolean matches(byte[] other) { - if (ablob.length != other.length) { - return false; - } - for (int i = 0; i < ablob.length; i++) { - if (ablob[i] != other[i]) { - return false; - } - } - return true; + hash = Arrays.hashCode(ablob); } } @@ -72,7 +63,7 @@ public class InvDiffManager { final long time = System.currentTimeMillis(); Integer damage = null; if (qty != 0 && item != null) { - if (item.getItemMeta() != null && item.getItemMeta() instanceof Damageable meta) { + if (item.getItemMeta() != null && item.getItemMeta()instanceof Damageable meta) { damage = meta.getDamage(); meta.setDamage(0); item.setItemMeta(meta); @@ -116,9 +107,16 @@ public class InvDiffManager { long cachedid = -1; boolean purge = System.currentTimeMillis() - lastpurged > 10 * 60 * 1000L; Iterator it = cache.iterator(); + int hash = Arrays.hashCode(blob); for (BlobCache other = null; it.hasNext();) { other = it.next(); - if (other.matches(blob)) { + // TODO needs tested, should be fine + out: if (other.hash == hash && blob.length == other.ablob.length) { + for (int i = 0; i < blob.length; i++) { + if (blob[i] != other.ablob[i]) { + break out; // This iteration isn't really necessary, just a check + } + } cachedid = other.blobid; if (!purge) break; @@ -266,7 +264,7 @@ public class InvDiffManager { item.setAmount(qty); plugin.debug("setting slot " + slot + " to " + qty); } - if (item.getItemMeta() != null && item.getItemMeta() instanceof Damageable meta) { + if (item.getItemMeta() != null && item.getItemMeta()instanceof Damageable meta) { int damage = rs.getInt("damage"); if (!rs.wasNull()) { meta.setDamage(damage); diff --git a/src/dev/heliosares/auxprotect/database/SQLManager.java b/src/dev/heliosares/auxprotect/database/SQLManager.java index e588b84..e92f033 100644 --- a/src/dev/heliosares/auxprotect/database/SQLManager.java +++ b/src/dev/heliosares/auxprotect/database/SQLManager.java @@ -32,6 +32,8 @@ import com.google.common.io.Files; import dev.heliosares.auxprotect.core.IAuxProtect; import dev.heliosares.auxprotect.core.MySender; +import dev.heliosares.auxprotect.towny.TownyEntry; +import dev.heliosares.auxprotect.towny.TownyManager; import dev.heliosares.auxprotect.utils.BidiMapCache; import dev.heliosares.auxprotect.utils.InvSerialization; import dev.heliosares.auxprotect.utils.MovingAverage; @@ -62,6 +64,7 @@ public class SQLManager { private final LookupManager lookupmanager; private MigrationManager migrationmanager; private final InvDiffManager invdiffmanager; + private final TownyManager townymanager; public LookupManager getLookupManager() { return lookupmanager; @@ -71,6 +74,10 @@ public class SQLManager { return invdiffmanager; } + public TownyManager getTownyManager() { + return townymanager; + } + public static SQLManager getInstance() { return instance; } @@ -114,6 +121,14 @@ public class SQLManager { } tablePrefix = prefix; } + { + TownyManager tm = null; + try { + tm = new TownyManager((dev.heliosares.auxprotect.spigot.AuxProtectSpigot) plugin, this); + } catch (Throwable ignored) { + } + this.townymanager = tm; + } this.sqliteFile = sqliteFile; } @@ -135,7 +150,11 @@ public class SQLManager { plugin.info("Connected!"); count(); + plugin.info("There are currently " + rowcount + " rows"); + if (townymanager != null) { + townymanager.init(); + } } public void close() { @@ -1041,6 +1060,9 @@ public class SQLManager { if (table == Table.AUXPROTECT_XRAY) { short rating = rs.getShort("rating"); entry = new XrayEntry(time, uid, world, x, y, z, target_id, rating, data); + } else if (table == Table.AUXPROTECT_TOWNY || entryAction.equals(EntryAction.TOWNYNAME)) { + entry = new TownyEntry(time, uid, entryAction, state, world, x, y, z, pitch, yaw, target, + target_id, data); } else { entry = new DbEntry(time, uid, entryAction, state, world, x, y, z, pitch, yaw, target, target_id, data); @@ -1359,7 +1381,7 @@ public class SQLManager { if (worlds.containsKey(world)) { return worlds.get(world); } - if (Bukkit.getWorld(world) == null) { + if (world == null || Bukkit.getWorld(world) == null) { return -1; } @@ -1433,8 +1455,6 @@ public class SQLManager { uuids.put(uid, uuid); return uid; } - } catch (SQLException e) { - plugin.print(e); } } catch (SQLException e) { plugin.print(e); @@ -1452,7 +1472,7 @@ public class SQLManager { if (result.next()) { int uid = result.getInt(1); uuids.put(uid, uuid); - plugin.debug("New UUID: " + uuid + ":" + uid, 3); + plugin.debug("New UUID: " + uuid + ":" + uid, 1); rowcount++; return uid; } @@ -1692,6 +1712,8 @@ public class SQLManager { public void cleanup() { usernames.cleanup(); uuids.cleanup(); + if (townymanager != null) + townymanager.cleanup(); } public Collection getCachedUsernames() { diff --git a/src/dev/heliosares/auxprotect/database/Table.java b/src/dev/heliosares/auxprotect/database/Table.java index ffd1329..10edf49 100644 --- a/src/dev/heliosares/auxprotect/database/Table.java +++ b/src/dev/heliosares/auxprotect/database/Table.java @@ -7,7 +7,9 @@ public enum Table { AUXPROTECT_COMMANDS, AUXPROTECT_POSITION, AUXPROTECT_API, AUXPROTECT_UIDS, AUXPROTECT_WORLDS, AUXPROTECT_API_ACTIONS, AUXPROTECT_VERSION, AUXPROTECT_INVBLOB, - AUXPROTECT_INVDIFF, AUXPROTECT_INVDIFFBLOB; + AUXPROTECT_INVDIFF, AUXPROTECT_INVDIFFBLOB, + + AUXPROTECT_TOWNY; @Override public String toString() { @@ -35,6 +37,7 @@ public enum Table { case AUXPROTECT_COMMANDS: case AUXPROTECT_POSITION: case AUXPROTECT_API: + case AUXPROTECT_TOWNY: return true; default: return false; @@ -48,6 +51,7 @@ public enum Table { case AUXPROTECT_SPAM: case AUXPROTECT_API: case AUXPROTECT_XRAY: + case AUXPROTECT_TOWNY: return true; default: return false; @@ -79,6 +83,7 @@ public enum Table { case AUXPROTECT_COMMANDS: case AUXPROTECT_POSITION: case AUXPROTECT_API: + case AUXPROTECT_TOWNY: return true; default: return false; @@ -124,7 +129,8 @@ public enum Table { return "(time, uid, world_id, x, y, z, target)"; } else if (bungee) { return "(time, uid, action_id, target_id, data)"; - } else if (this == Table.AUXPROTECT_MAIN || this == Table.AUXPROTECT_SPAM || this == Table.AUXPROTECT_API) { + } else if (this == Table.AUXPROTECT_MAIN || this == Table.AUXPROTECT_SPAM || this == Table.AUXPROTECT_API + || this == Table.AUXPROTECT_TOWNY) { return "(time, uid, action_id, world_id, x, y, z, target_id, data)"; } else if (this == Table.AUXPROTECT_INVENTORY) { return "(time, uid, action_id, world_id, x, y, z, target_id, data, hasblob)"; @@ -174,6 +180,7 @@ public enum Table { case AUXPROTECT_SPAM: case AUXPROTECT_API: case AUXPROTECT_XRAY: + case AUXPROTECT_TOWNY: return 9; case AUXPROTECT_POSITION: case AUXPROTECT_INVENTORY: diff --git a/src/dev/heliosares/auxprotect/spigot/AuxProtectSpigot.java b/src/dev/heliosares/auxprotect/spigot/AuxProtectSpigot.java index 074b85a..83dc642 100644 --- a/src/dev/heliosares/auxprotect/spigot/AuxProtectSpigot.java +++ b/src/dev/heliosares/auxprotect/spigot/AuxProtectSpigot.java @@ -4,7 +4,10 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; +import java.util.function.Supplier; import java.util.logging.Level; import org.bukkit.Bukkit; @@ -15,6 +18,7 @@ import org.bukkit.command.CommandSender; import org.bukkit.command.PluginCommand; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.event.Listener; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; @@ -30,12 +34,14 @@ import dev.heliosares.auxprotect.database.DatabaseRunnable; import dev.heliosares.auxprotect.database.DbEntry; import dev.heliosares.auxprotect.database.EntryAction; import dev.heliosares.auxprotect.database.SQLManager; +import dev.heliosares.auxprotect.database.Table; import dev.heliosares.auxprotect.database.XrayEntry; import dev.heliosares.auxprotect.spigot.command.APCommand; import dev.heliosares.auxprotect.spigot.command.APCommandTab; import dev.heliosares.auxprotect.spigot.command.ClaimInvCommand; import dev.heliosares.auxprotect.spigot.command.WatchCommand; import dev.heliosares.auxprotect.spigot.listeners.*; +import dev.heliosares.auxprotect.towny.TownyListener; import dev.heliosares.auxprotect.utils.Language; import dev.heliosares.auxprotect.utils.Telemetry; import dev.heliosares.auxprotect.utils.UpdateChecker; @@ -93,7 +99,8 @@ public class AuxProtectSpigot extends JavaPlugin implements IAuxProtect { debug = getConfig().getInt("debug", 0); - config = new APConfig(this.getConfig()); + config = new APConfig(this, this.getConfig()); + this.saveConfig(); YMLManager langManager = new YMLManager("en-us", this); langManager.load(true); @@ -210,81 +217,38 @@ public class AuxProtectSpigot extends JavaPlugin implements IAuxProtect { getServer().getPluginManager().registerEvents(new CommandListener(this), this); getServer().getPluginManager().registerEvents(new XrayListener(this), this); - if (setupEconomy()) { - Telemetry.reportHook(this, "Vault", true); - } else { - Telemetry.reportHook(this, "Vault", false); - } + // this feels cursed to run setupEconomy() like this... + Telemetry.reportHook(this, "Vault", setupEconomy()); - try { - String name = "ShopGuiPlus"; - Plugin plugin = getPlugin(name); - if (plugin != null && plugin.isEnabled()) { - getServer().getPluginManager().registerEvents(new ShopGUIPlusListener(this), this); - Telemetry.reportHook(this, name, true); - } else { - Telemetry.reportHook(this, name, false); + hook(() -> { + return new ShopGUIPlusListener(this); + }, "ShopGuiPlus"); + hook(() -> { + return new EconomyShopGUIListener(this); + }, "EconomyShopGUI", "EconomyShopGUI-Premium"); + hook(() -> { + return new DynamicShopListener(this); + }, "DynamicShop"); + hook(() -> { + return new ChestShopListener(this); + }, "ChestShop"); + hook(() -> { + return new AuctionHouseListener(this); + }, "AuctionHouse"); + hook(() -> { + return new JobsListener(this); + }, "Jobs"); + hook(() -> { + return new EssentialsListener(this); + }, "Essentials"); + if (!hook(() -> { + return new TownyListener(this); + }, "Towny")) { + for (EntryAction action : EntryAction.values()) { + if (action.getTable() == Table.AUXPROTECT_TOWNY) { + action.setEnabled(false); + } } - - name = "EconomyShopGUI"; - plugin = getPlugin(name); - if (plugin == null) { - plugin = getServer().getPluginManager().getPlugin("EconomyShopGUI-Premium"); - } - if (plugin != null && plugin.isEnabled()) { - getServer().getPluginManager().registerEvents(new EconomyShopGUIListener(this), this); - Telemetry.reportHook(this, name, true); - } else { - Telemetry.reportHook(this, name, false); - } - - name = "DynamicShop"; - plugin = getPlugin(name); - if (plugin != null && plugin.isEnabled()) { - getServer().getPluginManager().registerEvents(new DynamicShopListener(this), this); - Telemetry.reportHook(this, name, true); - } else { - Telemetry.reportHook(this, name, false); - } - - name = "ChestShop"; - plugin = getPlugin(name); - if (plugin != null && plugin.isEnabled()) { - getServer().getPluginManager().registerEvents(new ChestShopListener(this), this); - Telemetry.reportHook(this, name, true); - } else { - Telemetry.reportHook(this, name, false); - } - - name = "AuctionHouse"; - plugin = getPlugin(name); - if (plugin != null && plugin.isEnabled()) { - getServer().getPluginManager().registerEvents(new AuctionHouseListener(this), this); - Telemetry.reportHook(this, name, true); - } else { - Telemetry.reportHook(this, name, false); - } - - name = "Jobs"; - plugin = getPlugin(name); - if (plugin != null && plugin.isEnabled()) { - getServer().getPluginManager().registerEvents(new JobsListener(this), this); - Telemetry.reportHook(this, name, true); - } else { - Telemetry.reportHook(this, name, false); - } - - name = "Essentials"; - plugin = getPlugin(name); - if (plugin != null && plugin.isEnabled()) { - getServer().getPluginManager().registerEvents(new EssentialsListener(this), this); - Telemetry.reportHook(this, name, true); - } else { - Telemetry.reportHook(this, name, false); - } - } catch (Exception e) { - warning("Exception while hooking other plugins"); - print(e); } this.getCommand("claiminv").setExecutor(claiminvcommand = new ClaimInvCommand(this)); @@ -507,6 +471,36 @@ public class AuxProtectSpigot extends JavaPlugin implements IAuxProtect { } } + private boolean hook(Supplier listener, String... names) { + boolean hook = false; + try { + Plugin plugin = null; + for (String name : names) { + plugin = getPlugin(name); + if (plugin != null) { + break; + } + } + hook = plugin != null && plugin.isEnabled(); + if (hook) { + getServer().getPluginManager().registerEvents(listener.get(), this); + hooks.add(plugin.getName()); + } + } catch (Exception e) { + warning("Exception while hooking " + names[0]); + print(e); + hook = false; + } + Telemetry.reportHook(this, names[0], hook); + return hook; + } + + private final Set hooks = new HashSet<>(); + + public boolean isHooked(String name) { + return hooks.contains(name); + } + private Plugin getPlugin(String name) { for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) { if (plugin.getName().equalsIgnoreCase(name)) { @@ -694,7 +688,7 @@ public class AuxProtectSpigot extends JavaPlugin implements IAuxProtect { @Override public void reloadConfig() { super.reloadConfig(); - config = new APConfig(this.getConfig()); + config = new APConfig(this, this.getConfig()); } @Override diff --git a/src/dev/heliosares/auxprotect/spigot/command/LookupCommandTab.java b/src/dev/heliosares/auxprotect/spigot/command/LookupCommandTab.java index cc8b7d8..ef65642 100644 --- a/src/dev/heliosares/auxprotect/spigot/command/LookupCommandTab.java +++ b/src/dev/heliosares/auxprotect/spigot/command/LookupCommandTab.java @@ -64,7 +64,7 @@ public class LookupCommandTab implements TabCompleter { if (currentArg.startsWith("action:") || currentArg.startsWith("a:")) { String action = currentArg.split(":")[0] + ":"; for (EntryAction eaction : EntryAction.values()) { - if (eaction.isSpigot() && eaction.isEnabled()) { + if (eaction.exists(plugin) && eaction.isEnabled()) { String actString = eaction.toString().toLowerCase(); if (eaction.hasDual) { possible.add(action + "+" + actString); diff --git a/src/dev/heliosares/auxprotect/spigot/listeners/EntityListener.java b/src/dev/heliosares/auxprotect/spigot/listeners/EntityListener.java index 16968b0..22590bd 100644 --- a/src/dev/heliosares/auxprotect/spigot/listeners/EntityListener.java +++ b/src/dev/heliosares/auxprotect/spigot/listeners/EntityListener.java @@ -74,19 +74,19 @@ public class EntityListener implements Listener { @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityExplodeEvent(EntityExplodeEvent e) { String cause; - if (e.getEntity() instanceof TNTPrimed tnt && tnt.getSource() != null) { - if (tnt.getSource() instanceof Projectile proj && proj.getShooter() != null) { + if (e.getEntity()instanceof TNTPrimed tnt && tnt.getSource() != null) { + if (tnt.getSource()instanceof Projectile proj && proj.getShooter() != null) { cause = AuxProtectSpigot.getLabel(proj.getShooter()); } else { cause = AuxProtectSpigot.getLabel(tnt.getSource()); } } else if (e.getEntity() instanceof LivingEntity) { - if (e.getEntity() instanceof Monster monster && monster.getTarget() != null) { + if (e.getEntity()instanceof Monster monster && monster.getTarget() != null) { cause = AuxProtectSpigot.getLabel(monster.getTarget()); } else { cause = AuxProtectSpigot.getLabel(e.getEntity()); } - } else if (e.getEntity() instanceof Projectile proj && proj.getShooter() != null) { + } else if (e.getEntity()instanceof Projectile proj && proj.getShooter() != null) { cause = AuxProtectSpigot.getLabel(proj.getShooter()); } else { cause = "#env"; diff --git a/src/dev/heliosares/auxprotect/towny/TownyEntry.java b/src/dev/heliosares/auxprotect/towny/TownyEntry.java new file mode 100644 index 0000000..14195d2 --- /dev/null +++ b/src/dev/heliosares/auxprotect/towny/TownyEntry.java @@ -0,0 +1,62 @@ +package dev.heliosares.auxprotect.towny; + +import org.bukkit.Location; + +import dev.heliosares.auxprotect.database.DbEntry; +import dev.heliosares.auxprotect.database.EntryAction; +import dev.heliosares.auxprotect.database.SQLManager; + +public class TownyEntry extends DbEntry { + + public TownyEntry(String userLabel, EntryAction action, boolean state, Location location, String targetLabel, + String data) throws NullPointerException { + super(userLabel, action, state, location, targetLabel, data); + } + + public TownyEntry(String userLabel, EntryAction action, boolean state, String targetLabel, String data) { + super(userLabel, action, state, targetLabel, data); + } + + public TownyEntry(long time, int uid, EntryAction action, boolean state, String world, int x, int y, int z, + int pitch, int yaw, String target, int target_id, String data) { + super(time, uid, action, state, world, x, y, z, pitch, yaw, target, target_id, data); + } + + public String getUser() { + if (user != null) { + return user; + } + if (!getUserUUID().startsWith("$t") || getUserUUID().length() != 38) { + return super.getUser(); + } + user = SQLManager.getInstance().getTownyManager().getNameFromID(getUid()); + if (user == null) { + user = getUserUUID(); + } + return user; + } + + public int getTargetId() { + if (action.getTable().hasStringTarget()) { + return -1; + } + if (target_id > 0) { + return target_id; + } + return target_id = SQLManager.getInstance().getUIDFromUUID(getTargetUUID(), true); + } + + public String getTarget() { + if (target != null) { + return target; + } + if (!getTargetUUID().startsWith("$t") || getTargetUUID().length() != 38) { + return super.getTarget(); + } + target = SQLManager.getInstance().getTownyManager().getNameFromID(getTargetId()); + if (target == null) { + target = getTargetUUID(); + } + return target; + } +} diff --git a/src/dev/heliosares/auxprotect/towny/TownyListener.java b/src/dev/heliosares/auxprotect/towny/TownyListener.java new file mode 100644 index 0000000..5690e14 --- /dev/null +++ b/src/dev/heliosares/auxprotect/towny/TownyListener.java @@ -0,0 +1,200 @@ +package dev.heliosares.auxprotect.towny; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import com.palmergames.bukkit.towny.event.BankTransactionEvent; +import com.palmergames.bukkit.towny.event.DeleteNationEvent; +import com.palmergames.bukkit.towny.event.DeleteTownEvent; +import com.palmergames.bukkit.towny.event.NationAddTownEvent; +import com.palmergames.bukkit.towny.event.NationRemoveTownEvent; +import com.palmergames.bukkit.towny.event.NationTransactionEvent; +import com.palmergames.bukkit.towny.event.NewDayEvent; +import com.palmergames.bukkit.towny.event.NewNationEvent; +import com.palmergames.bukkit.towny.event.NewTownEvent; +import com.palmergames.bukkit.towny.event.RenameNationEvent; +import com.palmergames.bukkit.towny.event.RenameTownEvent; +import com.palmergames.bukkit.towny.event.TownAddResidentEvent; +import com.palmergames.bukkit.towny.event.TownClaimEvent; +import com.palmergames.bukkit.towny.event.TownRemoveResidentEvent; +import com.palmergames.bukkit.towny.event.TownTransactionEvent; +import com.palmergames.bukkit.towny.event.town.TownMayorChangeEvent; +import com.palmergames.bukkit.towny.event.town.TownMergeEvent; +import com.palmergames.bukkit.towny.event.town.TownUnclaimEvent; +import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; +import com.palmergames.bukkit.towny.exceptions.TownyException; +import com.palmergames.bukkit.towny.object.Coord; +import com.palmergames.bukkit.towny.object.Government; +import com.palmergames.bukkit.towny.object.Nation; +import com.palmergames.bukkit.towny.object.WorldCoord; + +import dev.heliosares.auxprotect.database.EntryAction; +import dev.heliosares.auxprotect.spigot.AuxProtectSpigot; + +public class TownyListener implements Listener { + private final AuxProtectSpigot plugin; + + public TownyListener(AuxProtectSpigot plugin) { + this.plugin = plugin; + } + + // General + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(NewDayEvent e) { + e.getBankruptedTowns(); + e.getFallenNations(); + e.getFallenTowns(); + + // TODO does delete town handle this? + } + + // Towns + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(NewTownEvent e) { + plugin.getSqlManager().getTownyManager().updateName(e.getTown()); + try { + plugin.add(new TownyEntry(AuxProtectSpigot.getLabel(e.getTown().getMayor().getPlayer()), + EntryAction.TOWNCREATE, false, toLoc(e.getTown().getHomeBlock().getWorldCoord()), + TownyManager.getLabel(e.getTown()), null)); + } catch (NullPointerException | TownyException e1) { + plugin.print(e1); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(RenameTownEvent e) { + plugin.getSqlManager().getTownyManager().updateName(e.getTown()); + Player mayor = e.getTown().getMayor().getPlayer(); + plugin.add(new TownyEntry(AuxProtectSpigot.getLabel(mayor), EntryAction.TOWNRENAME, false, mayor.getLocation(), + TownyManager.getLabel(e.getTown()), e.getOldName() + " -> " + e.getTown().getName())); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(DeleteTownEvent e) { + plugin.getSqlManager().getTownyManager().updateName(e.getTownUUID(), e.getTownName()); + plugin.add(new TownyEntry("$" + e.getMayorUUID().toString(), EntryAction.TOWNDELETE, false, + e.getMayor().getPlayer().getLocation(), "$t" + e.getTownUUID(), "")); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(TownAddResidentEvent e) { + plugin.add(new TownyEntry("$" + e.getResident().getUUID().toString(), EntryAction.TOWNJOIN, true, + e.getResident().getPlayer().getLocation(), TownyManager.getLabel(e.getTown()), "")); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(TownRemoveResidentEvent e) { + plugin.add(new TownyEntry("$" + e.getResident().getUUID().toString(), EntryAction.TOWNJOIN, false, + e.getResident().getPlayer().getLocation(), TownyManager.getLabel(e.getTown()), "")); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(TownClaimEvent e) { + try { + plugin.add(new TownyEntry("$" + e.getResident().getUUID().toString(), EntryAction.TOWNCLAIM, true, + toLoc(e.getTownBlock().getWorldCoord()), TownyManager.getLabel(e.getTownBlock().getTown()), "")); + } catch (NullPointerException | NotRegisteredException e1) { + plugin.print(e1); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(TownUnclaimEvent e) { + plugin.add(new TownyEntry(TownyManager.getLabel(e.getTown()), EntryAction.TOWNCLAIM, false, + toLoc(e.getWorldCoord()), "", "")); + } + + private static Location toLoc(Coord coord) { + if (coord instanceof WorldCoord c) { + return new Location(c.getBukkitWorld(), c.getX() * 16, 128, c.getZ() * 16); + } + return null; + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(TownMergeEvent e) { + plugin.add(new TownyEntry("$t" + e.getSuccumbingTownUUID(), EntryAction.TOWNCLAIM, false, + TownyManager.getLabel(e.getRemainingTown()), "")); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(TownMayorChangeEvent e) { + plugin.add(new TownyEntry(AuxProtectSpigot.getLabel(e.getNewMayor().getPlayer()), EntryAction.TOWNMAYOR, false, + e.getNewMayor().getPlayer().getLocation(), getLabel(e.getTown()), + "Prior: " + e.getOldMayor().getName())); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(TownTransactionEvent e) { + handleBank(e, e.getTown(), EntryAction.TOWNBANK); + } + + private void handleBank(BankTransactionEvent e, Government g, EntryAction action) { + String user = "#server"; + Location loc = null; + if (e.getTransaction().getPlayer() != null) { + user = AuxProtectSpigot.getLabel(e.getTransaction().getPlayer()); + loc = e.getTransaction().getPlayer().getLocation(); + } + boolean state; + switch (e.getTransaction().getType()) { + case ADD: + case DEPOSIT: + state = true; + break; + default: + state = false; + } + String data = plugin.formatMoney(e.getTransaction().getAmount()) + ", Bal: " + + plugin.formatMoney(e.getAccount().getHoldingBalance()); + plugin.add(new TownyEntry(user, action, state, loc, TownyManager.getLabel(g), data)); + } + + // Nations + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(NewNationEvent e) { + Player king = e.getNation().getKing().getPlayer(); + plugin.getSqlManager().getTownyManager().updateName(e.getNation()); + plugin.add(new TownyEntry(AuxProtectSpigot.getLabel(king), EntryAction.TOWNCREATE, false, king.getLocation(), + TownyManager.getLabel(e.getNation()), null)); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(RenameNationEvent e) { + plugin.getSqlManager().getTownyManager().updateName(e.getNation()); + Player mayor = e.getNation().getKing().getPlayer(); + plugin.add(new TownyEntry(AuxProtectSpigot.getLabel(mayor), EntryAction.TOWNRENAME, false, mayor.getLocation(), + TownyManager.getLabel(e.getNation()), e.getOldName() + " -> " + e.getNation().getName())); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(DeleteNationEvent e) { + plugin.getSqlManager().getTownyManager().updateName(e.getNationUUID(), e.getNationName()); + plugin.add( + new TownyEntry("$" + e.getNationKing(), EntryAction.TOWNDELETE, false, "$t" + e.getNationUUID(), "")); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(NationAddTownEvent e) { + plugin.add(new TownyEntry(getLabel(e.getTown()), EntryAction.NATIONJOIN, true, getLabel(e.getNation()), "")); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(NationRemoveTownEvent e) { + plugin.add(new TownyEntry(getLabel(e.getTown()), EntryAction.NATIONJOIN, false, getLabel(e.getNation()), "")); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void on(NationTransactionEvent e) { + handleBank(e, e.getNation(), EntryAction.NATIONBANK); + } + + public static String getLabel(Government gov) { + return "#" + (gov instanceof Nation ? "N" : "T") + gov.getUUID().toString(); + } +} diff --git a/src/dev/heliosares/auxprotect/towny/TownyManager.java b/src/dev/heliosares/auxprotect/towny/TownyManager.java new file mode 100644 index 0000000..873f632 --- /dev/null +++ b/src/dev/heliosares/auxprotect/towny/TownyManager.java @@ -0,0 +1,161 @@ +package dev.heliosares.auxprotect.towny; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +import org.bukkit.scheduler.BukkitRunnable; + +import com.palmergames.bukkit.towny.TownyUniverse; +import com.palmergames.bukkit.towny.object.Government; + +import dev.heliosares.auxprotect.database.EntryAction; +import dev.heliosares.auxprotect.database.SQLManager; +import dev.heliosares.auxprotect.database.Table; +import dev.heliosares.auxprotect.spigot.AuxProtectSpigot; +import dev.heliosares.auxprotect.utils.BidiMapCache; + +public class TownyManager { + private final AuxProtectSpigot plugin; + private final SQLManager sql; + private BidiMapCache names = new BidiMapCache<>(300000L, 300000L, true); + + public TownyManager(AuxProtectSpigot plugin, SQLManager sql) { + this.plugin = plugin; + this.sql = sql; + } + + public void init() { + plugin.info("Checking for new towns/nations..."); + TownyUniverse.getInstance().getTowns().forEach((town) -> { + sql.getTownyManager().updateName(town); + }); + TownyUniverse.getInstance().getNations().forEach((nation) -> { + sql.getTownyManager().updateName(nation); + }); + } + + public String getNameFromID(int uid) { + if (uid < 0) { + return null; + } + if (uid == 0) { + return ""; + } + if (names.containsKey(uid)) { + return names.get(uid); + } + /* + * if (plugin.isBungee()) { return uuid; } else { OfflinePlayer player = + * Bukkit.getOfflinePlayer(UUID.fromString(uuid.substring(1))); if (player != + * null) { usernames.put(uuid, player.getName()); return player.getName + */ + + String stmt = "SELECT * FROM " + Table.AUXPROTECT_LONGTERM.toString() + + " WHERE action_id=? AND uid=?\nORDER BY time DESC\nLIMIT 1;"; + plugin.debug(stmt, 3); + + Connection connection; + try { + connection = sql.getConnection(); + } catch (SQLException e1) { + plugin.print(e1); + return null; + } + try (PreparedStatement pstmt = connection.prepareStatement(stmt)) { + pstmt.setInt(1, EntryAction.TOWNYNAME.id); + pstmt.setInt(2, uid); + try (ResultSet results = pstmt.executeQuery()) { + if (results.next()) { + String username = results.getString("target"); + plugin.debug("Resolved UID " + uid + " to " + username); + if (username != null) { + names.put(uid, username); + return username; + } + } + } + } catch (SQLException e) { + plugin.print(e); + } finally { + sql.returnConnection(connection); + } + return null; + } + +// public int getIDFromName(String name, boolean insert) { +// if (name == null) { +// return -1; +// } +// if (names.containsValue(name)) { +// return names.getKey(name); +// } +// String stmt = "SELECT * FROM " + Table.AUXPROTECT_LONGTERM.toString() +// + " WHERE action_id=? AND lower(target)=?\nORDER BY time DESC\nLIMIT 1;"; +// plugin.debug(stmt, 3); +// +// Connection connection; +// try { +// connection = sql.getConnection(); +// } catch (SQLException e1) { +// plugin.print(e1); +// return -1; +// } +// try (PreparedStatement pstmt = connection.prepareStatement(stmt)) { +// pstmt.setInt(1, EntryAction.TOWNYNAME.id); +// pstmt.setString(2, name.toLowerCase()); +// try (ResultSet results = pstmt.executeQuery()) { +// if (results.next()) { +// int uid = results.getInt("uid"); +// String username_ = results.getString("target"); +// plugin.debug("Resolved username " + username_ + " to UID " + uid, 5); +// if (username_ != null && uid > 0) { +// names.put(uid, username_); +// return uid; +// } +// } +// } +// } catch (SQLException e) { +// plugin.print(e); +// } finally { +// sql.returnConnection(connection); +// } +// return -1; +// } + + public void updateName(Government gov) { + this.updateName(gov.getUUID(), gov.getName()); + } + + public void updateName(UUID uuid, String name) { + new BukkitRunnable() { + + @Override + public void run() { + final int uid = sql.getUIDFromUUID("$t" + uuid, true); + if (uid <= 0) { + plugin.warning("Failed to insert new town/nation name: " + name); + return; + } + plugin.debug("Handling " + name); + + String newestusername = getNameFromID(uid); + if (!name.equalsIgnoreCase(newestusername)) { + plugin.debug("New town name: " + name + " for " + newestusername); + plugin.add(new TownyEntry("$t" + uuid, EntryAction.TOWNYNAME, false, name, "")); + } + names.put(uid, name); + } + }.runTaskAsynchronously(plugin); + } + + public static String getLabel(Government gov) { + return "$t" + gov.getUUID().toString(); + } + + public void cleanup() { + names.cleanup(); + } +} diff --git a/src/dev/heliosares/auxprotect/utils/KeyUtil.java b/src/dev/heliosares/auxprotect/utils/KeyUtil.java new file mode 100644 index 0000000..14de627 --- /dev/null +++ b/src/dev/heliosares/auxprotect/utils/KeyUtil.java @@ -0,0 +1,104 @@ +package dev.heliosares.auxprotect.utils; + +import java.util.Base64; +import java.security.Key; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import javax.crypto.Cipher; + +public class KeyUtil { + + private static final String RSA = "RSA"; + + public static String do_RSADecryption(byte[] cipherText, Key key) throws Exception { + Cipher cipher = Cipher.getInstance(RSA); + + cipher.init(Cipher.DECRYPT_MODE, key); + byte[] result = cipher.doFinal(cipherText); + + return new String(result); + } + + private static final long[] BLACKLIST = new long[] {}; + private static final PublicKey PUBLIC_KEY; + static { + PublicKey key = null; + try { + key = KeyFactory.getInstance(RSA).generatePublic(new X509EncodedKeySpec(Base64.getDecoder().decode( + "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAILcEjoZ4U1e3YIBTcgbSdPjowBlXTUe23eB9rcf4DUS3WY5AZGCoYOaGsXJGgVduNf8Bk8VfbsN/gcYd2HwCzsCAwEAAQ=="))); + } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { + e.printStackTrace(); + } + PUBLIC_KEY = key; + } + private final boolean isValid; + private final boolean isBlacklisted; + private final boolean isMalformed; + private final boolean isPrivate; + + public KeyUtil(String key) { + boolean isValid = false; + boolean isBlacklisted = false; + boolean isPrivate = false; + boolean isMalformed = false; + long gen = -1; + out: try { + String[] parts = key.split("\\."); + String name = parts[0]; + key = parts[1]; + key = do_RSADecryption(decode(key), PUBLIC_KEY); + if (!key.endsWith("." + name)) { + isValid = false; + isMalformed = true; + break out; + } + gen = Long.parseLong(key.substring(0, key.indexOf("."))); + for (long other : BLACKLIST) { + if (other == gen) { + isBlacklisted = true; + isValid = false; + break out; + } + } + isValid = gen <= System.currentTimeMillis() && gen > 1577854800000L; + isPrivate = name.matches("private(_.*)?"); + } catch (Exception e) { + e.printStackTrace(); + isMalformed = true; + isValid = false; + } + this.isBlacklisted = isBlacklisted; + this.isPrivate = isPrivate; + this.isValid = isValid; + this.isMalformed = isMalformed; + } + + public boolean isValid() { + if (isBlacklisted || isMalformed) { + return false; + } + return isValid; + } + + public boolean isBlacklisted() { + return isBlacklisted; + } + + public boolean isPrivate() { + if (!isValid()) { + return false; + } + return isPrivate; + } + + public boolean isMalformed() { + return isMalformed; + } + + private static byte[] decode(String str) { + return Base64.getDecoder().decode(str); + } +}