diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0617029..e98fad2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,2 +1,12 @@
+## 2.0.0
+- Renamed plugin to "BetterTridents"
+- Added new mechanics and config options:
+ - Bedrock impaling: Impaling enchantment behaves like in Bedrock (it damages ALL mobs touching water, not only ocean mobs). Default: Enabled
+ - Bedrock drop chance: Raises the drop chance for tridents to the bedrock value (25% for every drowned yielding a trident + 4% per looting level) Default: Enabled
+ - Return to offhand: Tridents thrown from the offhand will also return to the offhand when picking them up. Default: Enabled
+ - Disable loyalty portals: Prohibit tridents with Loyalty to travel through portals to avoid losing them. Default: Enabled
+- Added automatic config updater
+- Added reload command (/bettertridents, permission bettertridents.reload)
+
## 1.1.0
- Added UpdateChecker and bStats
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index ed2acb3..40626da 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,13 +4,13 @@
4.0.0
de.jeff_media
- NoTridentVoid
- NoTridentVoid
- 1.1.0
+ BetterTridents
+ BetterTridents
+ 2.0.0
${project.name}
- ${project.groupId}.notridentvoid.Main
+ ${project.groupId}.bettertridents.Main
UTF-8
1.8
@@ -45,7 +45,7 @@
de.jeff_media.updatechecker
- de.jeff_media.notridentvoid.updatechecker
+ de.jeff_media.bettertridents.updatechecker
org.bstats
diff --git a/src/main/java/de/jeff_media/notridentvoid/Main.java b/src/main/java/de/jeff_media/bettertridents/Main.java
similarity index 54%
rename from src/main/java/de/jeff_media/notridentvoid/Main.java
rename to src/main/java/de/jeff_media/bettertridents/Main.java
index b2dc576..df64c5b 100644
--- a/src/main/java/de/jeff_media/notridentvoid/Main.java
+++ b/src/main/java/de/jeff_media/bettertridents/Main.java
@@ -1,7 +1,9 @@
-package de.jeff_media.notridentvoid;
+package de.jeff_media.bettertridents;
-import de.jeff_media.notridentvoid.config.Config;
-import de.jeff_media.notridentvoid.listeners.ProjectileListener;
+import de.jeff_media.bettertridents.commands.ReloadCommand;
+import de.jeff_media.bettertridents.config.Config;
+import de.jeff_media.bettertridents.config.ConfigUpdater;
+import de.jeff_media.bettertridents.listeners.*;
import de.jeff_media.updatechecker.UpdateChecker;
import de.jeff_media.updatechecker.UserAgentBuilder;
import org.bstats.bukkit.Metrics;
@@ -11,6 +13,7 @@ import org.bukkit.NamespacedKey;
import org.bukkit.entity.Trident;
import org.bukkit.plugin.java.JavaPlugin;
+import java.io.File;
import java.util.ArrayList;
import java.util.UUID;
@@ -20,22 +23,41 @@ public class Main extends JavaPlugin {
private final ArrayList tridents = new ArrayList<>();
public static final Material SAFETY_MATERIAL = Material.BARRIER;
public static NamespacedKey LOYALTY_TAG;
+ public static NamespacedKey IMPALING_TAG;
+ public static NamespacedKey OFFHAND_TAG;
public static Main getInstance() {
return instance;
}
+ private boolean debug = false;
+
+ public void debug(String text) {
+ if(debug) getLogger().warning("[DEBUG] " + text);
+ }
@Override
public void onEnable() {
instance = this;
LOYALTY_TAG = new NamespacedKey(this, "loyalty");
+ IMPALING_TAG = new NamespacedKey(this, "impaling");
+ OFFHAND_TAG = new NamespacedKey(this, "offhand");
reload();
- Bukkit.getPluginManager().registerEvents(new ProjectileListener(), this);
+ Bukkit.getPluginManager().registerEvents(new VoidListener(), this);
+ Bukkit.getPluginManager().registerEvents(new DropListener(), this);
+ Bukkit.getPluginManager().registerEvents(new ImpalingListener(), this);
+ Bukkit.getPluginManager().registerEvents(new OffhandListener(), this);
+ Bukkit.getPluginManager().registerEvents(new TridentThrowListener(), this);
+ getCommand("bettertridents").setExecutor(new ReloadCommand());
@SuppressWarnings("unused") Metrics metrics = new Metrics(this, 11460);
}
public void reload() {
+ if(!new File(getDataFolder(), "config.yml").exists()) {
+ saveDefaultConfig();
+ }
+ reloadConfig();
new Config();
+ ConfigUpdater.updateConfig();
UpdateChecker.init(this, "https://api.jeff-media.de/notridentvoid/latest-version.txt")
.setDonationLink("https://paypal.me/mfnalex")
.setDownloadLink(92656)
@@ -47,17 +69,21 @@ public class Main extends JavaPlugin {
} else if(getConfig().getString(Config.CHECK_FOR_UPDATES).equalsIgnoreCase("on-startup")) {
UpdateChecker.getInstance().checkNow();
}
+ debug = getConfig().getBoolean(Config.DEBUG);
+ if(debug) {
+ getLogger().warning("Debug mode enabled - this may affect performance.");
+ }
}
- public void register(Trident trident) {
+ public void setLoyal(Trident trident) {
tridents.add(trident.getUniqueId());
}
- public boolean isRegistered(Trident trident) {
+ public boolean isLoyal(Trident trident) {
return tridents.contains(trident.getUniqueId());
}
- public void unregister(Trident trident) {
+ public void removeLoyal(Trident trident) {
tridents.remove(trident.getUniqueId());
}
}
diff --git a/src/main/java/de/jeff_media/bettertridents/commands/ReloadCommand.java b/src/main/java/de/jeff_media/bettertridents/commands/ReloadCommand.java
new file mode 100644
index 0000000..68054cc
--- /dev/null
+++ b/src/main/java/de/jeff_media/bettertridents/commands/ReloadCommand.java
@@ -0,0 +1,27 @@
+package de.jeff_media.bettertridents.commands;
+
+import de.jeff_media.bettertridents.Main;
+import de.jeff_media.bettertridents.config.Permissions;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.jetbrains.annotations.NotNull;
+
+public class ReloadCommand implements CommandExecutor {
+
+ private final Main main = Main.getInstance();
+
+ @Override
+ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
+
+ if(!sender.hasPermission(Permissions.RELOAD)) {
+ sender.sendMessage(command.getPermissionMessage());
+ return true;
+ }
+
+ main.reload();
+ sender.sendMessage(ChatColor.DARK_GREEN + main.getDescription().getName() + " v" + main.getDescription().getVersion() + ChatColor.GREEN + " has been reloaded.");
+ return true;
+ }
+}
diff --git a/src/main/java/de/jeff_media/bettertridents/config/Config.java b/src/main/java/de/jeff_media/bettertridents/config/Config.java
new file mode 100644
index 0000000..cd325c0
--- /dev/null
+++ b/src/main/java/de/jeff_media/bettertridents/config/Config.java
@@ -0,0 +1,35 @@
+package de.jeff_media.bettertridents.config;
+
+import de.jeff_media.bettertridents.Main;
+
+public class Config {
+
+ private final Main main = Main.getInstance();
+
+ public static final String BEDROCK_IMPALING = "bedrock-impaling";
+ public static final String CONFIG_PLUGIN_VERSION = "plugin-version";
+ public static final String VOID_SAVING = "void-saving";
+ public static final String CONFIG_VERSION = "config-version";
+ public static final String CHECK_FOR_UPDATES = "check-for-updates";
+ public static final String UPDATE_CHECK_INTERVAL = "update-check-interval";
+ public static final String DROP_BEDROCK_CHANCE = "bedrock-drop-chance";
+ public static final String RETURN_TO_OFFHAND = "return-to-offhand";
+ public static final String DISABLE_LOYALTY_PORTALS = "disable-loyalty-portals";
+ public static final String DEBUG = "debug";
+
+ public Config() {
+ addDefault(VOID_SAVING, true);
+ addDefault(DROP_BEDROCK_CHANCE, true);
+ addDefault(CHECK_FOR_UPDATES, "true");
+ addDefault(UPDATE_CHECK_INTERVAL, 4);
+ addDefault(BEDROCK_IMPALING, true);
+ addDefault(RETURN_TO_OFFHAND, true);
+ addDefault(DISABLE_LOYALTY_PORTALS, true);
+ addDefault(DEBUG, false);
+ }
+
+ private void addDefault(String node, Object value) {
+ main.getConfig().addDefault(node, value);
+ }
+
+}
diff --git a/src/main/java/de/jeff_media/bettertridents/config/ConfigUpdater.java b/src/main/java/de/jeff_media/bettertridents/config/ConfigUpdater.java
new file mode 100644
index 0000000..9a25e1b
--- /dev/null
+++ b/src/main/java/de/jeff_media/bettertridents/config/ConfigUpdater.java
@@ -0,0 +1,208 @@
+package de.jeff_media.bettertridents.config;
+
+import de.jeff_media.bettertridents.Main;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+
+/**
+ * Updates the config file. When a new config file is shipped with AngelChest, it will save the new
+ * file and replace all default values with the values that were set in the old config file.
+ */
+public final class ConfigUpdater {
+
+ // Lines STARTING WITH these names will be treated as String lists
+ private static final String[] LINES_CONTAINING_STRING_LISTS = {};
+ // Lines STARTING WITH these names will never get the old value applied
+ private static final String[] LINES_IGNORED = {"config-version:", "plugin-version:"};
+ // Lines STARTING WITH these names will get no quotes although they would match one of the lists below
+ private static final String[] CONFLICTING_NODES_NEEDING_NO_QUOTES = {};
+ // Lines STARTING WITH these names will get their values wrapped in double quotes
+ private static final String[] NODES_NEEDING_DOUBLE_QUOTES = {};
+ // Lines STARTING WITH these names will get their values wrapped in single quotes
+ private static final String[] NODES_NEEDING_SINGLE_QUOTES = {};
+
+ private static void backupCurrentConfig(final Main main) {
+ final File oldFile = new File(getFilePath(main, "config.yml"));
+ final File newFile = new File(getFilePath(main, "config-backup-" + main.getConfig().getString(Config.CONFIG_PLUGIN_VERSION) + ".yml"));
+ if (newFile.exists()) newFile.delete();
+ if (oldFile.getAbsoluteFile().renameTo(newFile.getAbsoluteFile())) {
+ main.debug("Could not rename " + oldFile.getAbsolutePath() + " to " + newFile.getAbsolutePath());
+ }
+ }
+
+ /**
+ * For debugging the config updater only
+ */
+ private static void debug(final Logger logger, final String message) {
+ if (false) {
+ logger.warning(message);
+ }
+ }
+
+ private static String getFilePath(final Main main, final String fileName) {
+ return main.getDataFolder() + File.separator + fileName;
+ }
+
+ private static List getNewConfigAsArrayList(final Main main) {
+ final List lines;
+ try {
+ lines = Files.readAllLines(Paths.get(getFilePath(main, "config.yml")), StandardCharsets.UTF_8);
+ return lines;
+ } catch (final IOException ioException) {
+ ioException.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * Returns the config version of the currently installed AngelChest default config
+ *
+ * @return default config version
+ */
+ private static long getNewConfigVersion() {
+ final InputStream in = Main.getInstance().getClass().getResourceAsStream("/config-version.txt");
+ final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ try {
+ return Long.parseLong(reader.readLine());
+ } catch (final IOException ioException) {
+ ioException.printStackTrace();
+ return 0;
+ }
+
+ }
+
+ /**
+ * Returns a String representing the correct quotes to use for this key's value
+ *
+ * @param line line/key to get the quotes for
+ * @return double quote, single quote or empty string, according to the key name
+ */
+ private static String getQuotes(final String line) {
+ for(final String test : CONFLICTING_NODES_NEEDING_NO_QUOTES) {
+ if(line.startsWith(test)) {
+ return "";
+ }
+ }
+ for (final String test : NODES_NEEDING_DOUBLE_QUOTES) {
+ if (line.startsWith(test)) {
+ return "\"";
+ }
+ }
+ for (final String test : NODES_NEEDING_SINGLE_QUOTES) {
+ if (line.startsWith(test)) {
+ return "'";
+ }
+ }
+ return "";
+ }
+
+ private static boolean lineContainsIgnoredNode(final String line) {
+ for (final String test : LINES_IGNORED) {
+ if (line.startsWith(test)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean lineIsStringList(final String line) {
+ for (final String test : LINES_CONTAINING_STRING_LISTS) {
+ if (line.startsWith(test)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static void saveArrayListToConfig(final Main main, final List lines) {
+ try {
+ final BufferedWriter fw = Files.newBufferedWriter(new File(getFilePath(main, "config.yml")).toPath(), StandardCharsets.UTF_8);
+ for (final String line : lines) {
+ fw.write(line + System.lineSeparator());
+ }
+ fw.close();
+ } catch (final IOException ioException) {
+ ioException.printStackTrace();
+ }
+ }
+
+ /**
+ * Attempts to update the config
+ */
+ public static void updateConfig() {
+ final Main main = Main.getInstance();
+ final Logger logger = main.getLogger();
+ debug(logger, "Newest config version = " + getNewConfigVersion());
+ debug(logger, "Current config version = " + main.getConfig().getLong(Config.CONFIG_VERSION));
+ if (main.getConfig().getLong(Config.CONFIG_VERSION) >= getNewConfigVersion()) {
+ debug(logger, "The config currently used has an equal or newer version than the one shipped with this release.");
+ return;
+ }
+
+ logger.info("===========================================");
+ logger.info("You are using an outdated config file.");
+ logger.info("Your config file will now be updated to the");
+ logger.info("newest version. You changes will be kept.");
+ logger.info("===========================================");
+
+ backupCurrentConfig(main);
+ main.saveDefaultConfig();
+
+ final Set oldConfigNodes = main.getConfig().getKeys(false);
+ final ArrayList newConfig = new ArrayList<>();
+
+ // Iterate through ALL lines from the new default config
+ for (final String defaultLine : getNewConfigAsArrayList(main)) {
+
+ String updatedLine = defaultLine;
+
+ /*if (Daddy.allows(Features.GENERIC)) {
+ if (updatedLine.startsWith("# PREMIUM FEATURE: ONLY AVAILABLE IN AngelChestPlus!")) {
+ updatedLine = null;
+ }
+ } else*/
+ if (defaultLine.startsWith("-") || defaultLine.startsWith(" -") || defaultLine.startsWith(" -")) {
+ debug(logger, "Not including default String list entry: " + defaultLine);
+ updatedLine = null;
+ } else if (lineContainsIgnoredNode(defaultLine)) {
+ debug(logger, "Not updating this line: " + defaultLine);
+ } else if (lineIsStringList(defaultLine)) {
+ updatedLine = null;
+ newConfig.add(defaultLine);
+ final String node = defaultLine.split(":")[0];
+ for (final String entry : main.getConfig().getStringList(node)) {
+ newConfig.add("- " + entry);
+ }
+ } else {
+ for (final String node : oldConfigNodes) {
+ // Iterate through all keys from the old config file.
+ if (defaultLine.startsWith(node + ":")) {
+ // This key from the old file matches this line from the new file! Updating...
+ final String quotes = getQuotes(node);
+ String value = main.getConfig().get(node).toString();
+
+ // The hologram text needs special escaping for the newline symbols
+ if (node.equals("hologram-text")) {
+ value = value.replaceAll("\n", "\\\\n");
+ }
+
+ updatedLine = node + ": " + quotes + value + quotes;
+ }
+ }
+ }
+
+ if (updatedLine != null) {
+ newConfig.add(updatedLine);
+ }
+ }
+
+ saveArrayListToConfig(main, newConfig);
+ }
+}
diff --git a/src/main/java/de/jeff_media/bettertridents/config/Permissions.java b/src/main/java/de/jeff_media/bettertridents/config/Permissions.java
new file mode 100644
index 0000000..990b82e
--- /dev/null
+++ b/src/main/java/de/jeff_media/bettertridents/config/Permissions.java
@@ -0,0 +1,6 @@
+package de.jeff_media.bettertridents.config;
+
+public class Permissions {
+ public static final String SAVE_VOID = "bettertridents.savevoid";
+ public static final String RELOAD = "bettertridents.reload";
+}
diff --git a/src/main/java/de/jeff_media/bettertridents/listeners/DropListener.java b/src/main/java/de/jeff_media/bettertridents/listeners/DropListener.java
new file mode 100644
index 0000000..d56c031
--- /dev/null
+++ b/src/main/java/de/jeff_media/bettertridents/listeners/DropListener.java
@@ -0,0 +1,60 @@
+package de.jeff_media.bettertridents.listeners;
+
+import de.jeff_media.bettertridents.Main;
+import de.jeff_media.bettertridents.config.Config;
+import de.jeff_media.bettertridents.utils.EnchantmentUtils;
+import org.bukkit.GameRule;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.Drowned;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
+import org.bukkit.event.entity.EntityDeathEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.Damageable;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.util.Random;
+
+public class DropListener implements Listener {
+
+ private final Main main = Main.getInstance();
+ final Random random = new Random();
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ private void onKillDrowned(EntityDeathEvent event) {
+ if (!main.getConfig().getBoolean(Config.DROP_BEDROCK_CHANCE)) return;
+ if (!(event.getEntity().getLastDamageCause() instanceof EntityDamageByEntityEvent)) return;
+ EntityDamageByEntityEvent damageEvent = (EntityDamageByEntityEvent) event.getEntity().getLastDamageCause();
+ if (damageEvent.getDamager().getType() != EntityType.PLAYER) return;
+ Player lastDamager = (Player) damageEvent.getDamager();
+ int fortune = EnchantmentUtils.getLevelFromTrident(lastDamager, Enchantment.LOOT_BONUS_MOBS);
+ if (!(event.getEntity() instanceof Drowned)) return;
+
+ Drowned drowned = (Drowned) event.getEntity();
+ if (!drowned.getWorld().getGameRuleValue(GameRule.DO_MOB_LOOT)) return;
+ if (drowned.getEquipment().getItemInMainHand().getType() != Material.TRIDENT) return;
+
+ for (ItemStack drop : event.getDrops()) {
+ if (drop.getType() == Material.TRIDENT) return;
+ }
+
+ main.debug("Using bedrock drop chance...");
+
+ int chance = random.nextInt(100);
+ main.debug("Drop chance: " + chance);
+ if (chance > 25 + (4 * fortune)) return;
+ ItemStack trident = new ItemStack(Material.TRIDENT);
+ Damageable meta = (Damageable) trident.getItemMeta();
+ meta.setDamage(random.nextInt(248) + 1);
+ trident.setItemMeta((ItemMeta) meta);
+ event.getDrops().add(trident);
+
+ }
+
+
+}
diff --git a/src/main/java/de/jeff_media/bettertridents/listeners/ImpalingListener.java b/src/main/java/de/jeff_media/bettertridents/listeners/ImpalingListener.java
new file mode 100644
index 0000000..250ec9e
--- /dev/null
+++ b/src/main/java/de/jeff_media/bettertridents/listeners/ImpalingListener.java
@@ -0,0 +1,111 @@
+package de.jeff_media.bettertridents.listeners;
+
+import de.jeff_media.bettertridents.Main;
+import de.jeff_media.bettertridents.config.Config;
+import de.jeff_media.bettertridents.utils.EnchantmentUtils;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.Particle;
+import org.bukkit.World;
+import org.bukkit.block.Block;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.*;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityDamageByEntityEvent;
+
+import java.util.Random;
+
+public class ImpalingListener implements Listener {
+
+ private final Main main = Main.getInstance();
+
+ private final Random random = new Random();
+
+ private static boolean isAquatic(EntityType type) {
+ switch (type) {
+ case DOLPHIN:
+ case GUARDIAN:
+ case ELDER_GUARDIAN:
+ case SQUID:
+ case TURTLE:
+ case COD:
+ case SALMON:
+ case PUFFERFISH:
+ case TROPICAL_FISH:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private static boolean isInRain(Entity entity) {
+ World world = entity.getWorld();
+ if (!world.hasStorm()) return false;
+ Location min = entity.getBoundingBox().getMin().toLocation(world);
+ Location max = entity.getBoundingBox().getMax().toLocation(world);
+ for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
+ for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
+ Block highest = world.getHighestBlockAt(x, z);
+ if (highest == null || highest.getType().isAir()) return true;
+ if (highest.getY() < entity.getLocation().getY()) return true;
+ }
+ }
+ return false;
+ }
+
+ private static boolean isInWater(Entity entity) {
+ World world = entity.getWorld();
+ Location min = entity.getBoundingBox().getMin().toLocation(entity.getWorld());
+ Location max = entity.getBoundingBox().getMax().toLocation(entity.getWorld());
+ for (int x = min.getBlockX(); x <= max.getBlockX(); x++) {
+ for (int y = min.getBlockY(); y <= max.getBlockY(); y++) {
+ for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) {
+ if (world.getBlockAt(x, y, z).getType() == Material.WATER) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ private void displayEnchantedHit(Entity entity) {
+ for (int i = 0; i < 16 * 3; i++) {
+ double d = (this.random.nextFloat() * 2.0F - 1.0F);
+ double e = (this.random.nextFloat() * 2.0F - 1.0F);
+ double f = (this.random.nextFloat() * 2.0F - 1.0F);
+ if (Math.sqrt(d) + Math.sqrt(e) + Math.sqrt(f) <= 1.0D) {
+ Location loc = entity.getLocation().clone();
+ loc.add((entity.getWidth() * (d / 4.0D)),
+ (entity.getHeight() * (0.5D + e / 4.0D)),
+ (entity.getWidth() * (f / 4.0D)));
+ loc.getWorld().spawnParticle(Particle.CRIT_MAGIC, loc, 0, d, e + 0.2D, f);
+ }
+ }
+ }
+
+
+
+ @EventHandler(ignoreCancelled = true)
+ private void onHitByImpaling(EntityDamageByEntityEvent event) {
+ if (!main.getConfig().getBoolean(Config.BEDROCK_IMPALING)) return;
+
+ Entity entity = event.getEntity();
+ int impaling = 0;
+ if (event.getDamager().getType() == EntityType.TRIDENT) {
+ impaling = EnchantmentUtils.getImpaling((Trident) event.getDamager());
+ } else if (event.getDamager().getType() == EntityType.PLAYER) {
+ impaling = ((Player) event.getDamager()).getInventory().getItemInMainHand().getEnchantmentLevel(Enchantment.IMPALING);
+ }
+
+ if (impaling > 0) {
+ if (!isAquatic(entity.getType()) && (isInRain(entity) || isInWater(entity))) {
+ event.setDamage(event.getDamage() + (2.5 * impaling));
+ main.debug("Adjusting Impaling damage: adding " + 2.5*impaling + " damage");
+ displayEnchantedHit(entity);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/de/jeff_media/bettertridents/listeners/OffhandListener.java b/src/main/java/de/jeff_media/bettertridents/listeners/OffhandListener.java
new file mode 100644
index 0000000..4761858
--- /dev/null
+++ b/src/main/java/de/jeff_media/bettertridents/listeners/OffhandListener.java
@@ -0,0 +1,39 @@
+package de.jeff_media.bettertridents.listeners;
+
+import de.jeff_media.bettertridents.Main;
+import de.jeff_media.bettertridents.config.Config;
+import de.jeff_media.bettertridents.tasks.MoveToOffhand;
+import de.jeff_media.bettertridents.utils.EnchantmentUtils;
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.Trident;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerPickupArrowEvent;
+import org.bukkit.inventory.ItemStack;
+
+public class OffhandListener implements Listener {
+
+ private final Main main = Main.getInstance();
+
+ @EventHandler(ignoreCancelled = true)
+ private void onPickupTrident(PlayerPickupArrowEvent event) {
+ main.debug("onPickupTrident");
+ if (!main.getConfig().getBoolean(Config.RETURN_TO_OFFHAND)) return;
+ if (!(event.getArrow() instanceof Trident)) return;
+ Trident trident = (Trident) event.getArrow();
+ if(!EnchantmentUtils.isOffhandThrown(trident)) {
+ main.debug("This trident wasn't thrown from the offhand.");
+ return;
+ }
+ Player player = event.getPlayer();
+ if (player.getInventory().getItemInOffHand().getType() != Material.AIR) return;
+
+ ItemStack tridentItem = event.getItem().getItemStack().clone();
+
+ main.debug("Starting offhand task...");
+ new MoveToOffhand(player, tridentItem).runTask(main);
+ }
+}
+
+
diff --git a/src/main/java/de/jeff_media/bettertridents/listeners/PortalListener.java b/src/main/java/de/jeff_media/bettertridents/listeners/PortalListener.java
new file mode 100644
index 0000000..0f2286f
--- /dev/null
+++ b/src/main/java/de/jeff_media/bettertridents/listeners/PortalListener.java
@@ -0,0 +1,28 @@
+package de.jeff_media.bettertridents.listeners;
+
+import de.jeff_media.bettertridents.Main;
+import de.jeff_media.bettertridents.config.Config;
+import de.jeff_media.bettertridents.utils.EnchantmentUtils;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Trident;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.EntityPortalEvent;
+
+public class PortalListener implements Listener {
+
+ private final Main main = Main.getInstance();
+
+ @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
+ public void onTridentEnterPortal(EntityPortalEvent event) {
+ if(!main.getConfig().getBoolean(Config.DISABLE_LOYALTY_PORTALS)) return;
+ if(event.getEntityType() != EntityType.TRIDENT) return;
+ Trident trident = (Trident) event.getEntity();
+ if(EnchantmentUtils.getLoyalty(trident)>0) {
+ main.debug("Prevented loyalty trident from travelling through portqal");
+ event.setCancelled(true);
+ }
+ }
+
+}
diff --git a/src/main/java/de/jeff_media/bettertridents/listeners/TridentThrowListener.java b/src/main/java/de/jeff_media/bettertridents/listeners/TridentThrowListener.java
new file mode 100644
index 0000000..0ae2e58
--- /dev/null
+++ b/src/main/java/de/jeff_media/bettertridents/listeners/TridentThrowListener.java
@@ -0,0 +1,49 @@
+package de.jeff_media.bettertridents.listeners;
+
+import de.jeff_media.bettertridents.Main;
+import de.jeff_media.bettertridents.utils.EnchantmentUtils;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.Trident;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.ProjectileLaunchEvent;
+import org.bukkit.persistence.PersistentDataType;
+
+public class TridentThrowListener implements Listener {
+
+ private final Main main = Main.getInstance();
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onTridentThrow(ProjectileLaunchEvent event) {
+ if (event.getEntityType() != EntityType.TRIDENT) return;
+ main.debug("Trident throw Listener: ProjectileLaunchEvent");
+
+ Trident trident = (Trident) event.getEntity();
+ if (!(trident.getShooter() instanceof Player)) {
+ main.debug("This trident wasn't thrown by a player.");
+ return;
+ }
+ Player player = (Player) trident.getShooter();
+
+ // Impaling
+ int impaling = EnchantmentUtils.getLevelFromTrident(player, Enchantment.IMPALING);
+ main.debug("Applying impaling level " + impaling);
+ EnchantmentUtils.registerImpaling((Trident) event.getEntity(), impaling);
+
+ // Loyalty
+ int loyalty = EnchantmentUtils.getLevelFromTrident(player, Enchantment.LOYALTY);
+ main.debug("Applying loyalty level " + loyalty);
+ EnchantmentUtils.registerLoyalty((Trident) event.getEntity(), loyalty);
+
+ // Offhand
+ if (player.getInventory().getItemInMainHand().getType() == Material.TRIDENT) return;
+ if (player.getInventory().getItemInOffHand().getType() != Material.TRIDENT) return;
+ trident.getPersistentDataContainer().set(Main.OFFHAND_TAG, PersistentDataType.BYTE, (byte) 1);
+ main.debug("This trident was thrown by the offhand.");
+ }
+
+}
diff --git a/src/main/java/de/jeff_media/bettertridents/listeners/VoidListener.java b/src/main/java/de/jeff_media/bettertridents/listeners/VoidListener.java
new file mode 100644
index 0000000..b07730d
--- /dev/null
+++ b/src/main/java/de/jeff_media/bettertridents/listeners/VoidListener.java
@@ -0,0 +1,64 @@
+package de.jeff_media.bettertridents.listeners;
+
+import de.jeff_media.bettertridents.Main;
+import de.jeff_media.bettertridents.config.Config;
+import de.jeff_media.bettertridents.tasks.WatchTrident;
+import de.jeff_media.bettertridents.utils.EnchantmentUtils;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.Trident;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.entity.ProjectileLaunchEvent;
+import org.bukkit.inventory.ItemStack;
+
+public class VoidListener implements Listener {
+
+ private final Main main = Main.getInstance();
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onThrowTrident(ProjectileLaunchEvent event) {
+ main.debug("VoidListener");
+ if (event.getEntityType() != EntityType.TRIDENT) {
+ main.debug("Not a trident");
+ return;
+ }
+ Trident trident = (Trident) event.getEntity();
+ //if (main.isLoyal(trident)) return;
+ if (!(trident.getShooter() instanceof Player)) {
+ main.debug("Not shot by player");
+ return;
+ }
+ Player player = (Player) trident.getShooter();
+ ItemStack tridentItem = null;
+ if (player.getInventory().getItemInOffHand() != null) {
+ if (player.getInventory().getItemInOffHand().getType() == Material.TRIDENT) {
+ tridentItem = player.getInventory().getItemInOffHand();
+ }
+ }
+ if (player.getInventory().getItemInMainHand() != null) {
+ if (player.getInventory().getItemInMainHand().getType() == Material.TRIDENT) {
+ tridentItem = player.getInventory().getItemInMainHand();
+ }
+ }
+ if (tridentItem == null) {
+ main.debug("tridentItem not found");
+ return;
+ }
+ if (!EnchantmentUtils.hasLoyalty(tridentItem)) {
+ main.debug("No loyalty");
+ return;
+ }
+ if(!main.getConfig().getBoolean(Config.VOID_SAVING)) {
+ main.debug("Void Saving disabled");
+ return;
+ }
+ main.setLoyal(trident);
+ main.debug("New task: WatchTrident");
+ new WatchTrident(trident).runTaskTimer(main,1,1);
+ Bukkit.getScheduler().runTaskLater(main,() ->main.removeLoyal(trident),1200);
+ }
+}
diff --git a/src/main/java/de/jeff_media/bettertridents/tasks/MoveToOffhand.java b/src/main/java/de/jeff_media/bettertridents/tasks/MoveToOffhand.java
new file mode 100644
index 0000000..106d1d9
--- /dev/null
+++ b/src/main/java/de/jeff_media/bettertridents/tasks/MoveToOffhand.java
@@ -0,0 +1,27 @@
+package de.jeff_media.bettertridents.tasks;
+
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.scheduler.BukkitRunnable;
+
+public class MoveToOffhand extends BukkitRunnable {
+ private final Player player;
+ private final ItemStack tridentItem;
+
+ public MoveToOffhand(Player player, ItemStack tridentItem) {
+ this.player = player;
+ this.tridentItem = tridentItem;
+ }
+
+ @Override
+ public void run() {
+ for (ItemStack item : player.getInventory()) {
+ if (item != null && item.equals(tridentItem)) {
+ player.getInventory().remove(item);
+ player.getInventory().setItemInOffHand(item.clone());
+ break;
+ }
+ }
+ player.updateInventory();
+ }
+}
diff --git a/src/main/java/de/jeff_media/notridentvoid/tasks/RemoveBarrier.java b/src/main/java/de/jeff_media/bettertridents/tasks/RemoveBarrier.java
similarity index 91%
rename from src/main/java/de/jeff_media/notridentvoid/tasks/RemoveBarrier.java
rename to src/main/java/de/jeff_media/bettertridents/tasks/RemoveBarrier.java
index 1d17e85..c29146e 100644
--- a/src/main/java/de/jeff_media/notridentvoid/tasks/RemoveBarrier.java
+++ b/src/main/java/de/jeff_media/bettertridents/tasks/RemoveBarrier.java
@@ -1,6 +1,6 @@
-package de.jeff_media.notridentvoid.tasks;
+package de.jeff_media.bettertridents.tasks;
-import de.jeff_media.notridentvoid.Main;
+import de.jeff_media.bettertridents.Main;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
diff --git a/src/main/java/de/jeff_media/notridentvoid/tasks/WatchTrident.java b/src/main/java/de/jeff_media/bettertridents/tasks/WatchTrident.java
similarity index 89%
rename from src/main/java/de/jeff_media/notridentvoid/tasks/WatchTrident.java
rename to src/main/java/de/jeff_media/bettertridents/tasks/WatchTrident.java
index 244c518..5ddd7b6 100644
--- a/src/main/java/de/jeff_media/notridentvoid/tasks/WatchTrident.java
+++ b/src/main/java/de/jeff_media/bettertridents/tasks/WatchTrident.java
@@ -1,6 +1,6 @@
-package de.jeff_media.notridentvoid.tasks;
+package de.jeff_media.bettertridents.tasks;
-import de.jeff_media.notridentvoid.Main;
+import de.jeff_media.bettertridents.Main;
import org.bukkit.Location;
import org.bukkit.entity.Trident;
import org.bukkit.scheduler.BukkitRunnable;
@@ -37,7 +37,7 @@ public class WatchTrident extends BukkitRunnable {
}
nextLocation.getBlock().setType(Main.SAFETY_MATERIAL);
-
+ Main.getInstance().debug("New Task: RemoveBarrier");
new RemoveBarrier(trident, nextLocation.getBlock()).runTaskTimer(Main.getInstance(), 1, 1);
cancel();
}
diff --git a/src/main/java/de/jeff_media/bettertridents/utils/EnchantmentUtils.java b/src/main/java/de/jeff_media/bettertridents/utils/EnchantmentUtils.java
new file mode 100644
index 0000000..e977cef
--- /dev/null
+++ b/src/main/java/de/jeff_media/bettertridents/utils/EnchantmentUtils.java
@@ -0,0 +1,56 @@
+package de.jeff_media.bettertridents.utils;
+
+import de.jeff_media.bettertridents.Main;
+import org.bukkit.Material;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.Trident;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.persistence.PersistentDataType;
+
+public class EnchantmentUtils {
+
+ public static int getLevelFromTrident(Player player, Enchantment enchantment) {
+ ItemStack item = player.getInventory().getItemInMainHand();
+ if(item.getType()!= Material.TRIDENT) {
+ item = player.getInventory().getItemInOffHand();
+ }
+ if(item.getType()!=Material.TRIDENT) return 0;
+ if (!item.hasItemMeta()) return 0;
+ ItemMeta meta = item.getItemMeta();
+ if (meta.hasEnchant(enchantment)) {
+ return meta.getEnchantLevel(enchantment);
+ }
+ return 0;
+ }
+
+ public static int getImpaling(Trident trident) {
+ return trident.getPersistentDataContainer().getOrDefault(Main.IMPALING_TAG, PersistentDataType.INTEGER, 0);
+ }
+
+ public static void registerImpaling(Trident trident, int level) {
+ if(level == 0) return;
+ trident.getPersistentDataContainer().set(Main.IMPALING_TAG, PersistentDataType.INTEGER, level);
+ }
+
+ public static int getLoyalty(Trident trident) {
+ return trident.getPersistentDataContainer().getOrDefault(Main.LOYALTY_TAG, PersistentDataType.INTEGER, 0);
+ }
+
+ public static void registerLoyalty(Trident trident, int level) {
+ if(level == 0) return;
+ trident.getPersistentDataContainer().set(Main.LOYALTY_TAG, PersistentDataType.INTEGER, level);
+ }
+
+ public static boolean isOffhandThrown(Trident trident) {
+ return trident.getPersistentDataContainer().has(Main.OFFHAND_TAG, PersistentDataType.BYTE);
+ }
+
+ public static boolean hasLoyalty(ItemStack item) {
+ if (!item.hasItemMeta()) return false;
+ ItemMeta meta = item.getItemMeta();
+ return meta.hasEnchant(Enchantment.LOYALTY);
+ }
+
+}
diff --git a/src/main/java/de/jeff_media/notridentvoid/config/Config.java b/src/main/java/de/jeff_media/notridentvoid/config/Config.java
deleted file mode 100644
index 9764ab0..0000000
--- a/src/main/java/de/jeff_media/notridentvoid/config/Config.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package de.jeff_media.notridentvoid.config;
-
-import de.jeff_media.notridentvoid.Main;
-
-public class Config {
-
- private final Main main = Main.getInstance();
-
- public static final String VOID_SAVING = "void-saving";
- public static final String CHECK_FOR_UPDATES = "check-for-updates";
- public static final String UPDATE_CHECK_INTERVAL = "update-check-interval";
-
- public Config() {
- addDefault(VOID_SAVING, true);
- }
-
- private void addDefault(String node, Object value) {
- main.getConfig().set(node, value);
- }
-
-}
diff --git a/src/main/java/de/jeff_media/notridentvoid/config/Permissions.java b/src/main/java/de/jeff_media/notridentvoid/config/Permissions.java
deleted file mode 100644
index 9dd0abd..0000000
--- a/src/main/java/de/jeff_media/notridentvoid/config/Permissions.java
+++ /dev/null
@@ -1,5 +0,0 @@
-package de.jeff_media.notridentvoid.config;
-
-public class Permissions {
- public static final String NOTRIDENTVOID_USE = "notridentvoid.use";
-}
diff --git a/src/main/java/de/jeff_media/notridentvoid/listeners/ProjectileListener.java b/src/main/java/de/jeff_media/notridentvoid/listeners/ProjectileListener.java
deleted file mode 100644
index 16921f0..0000000
--- a/src/main/java/de/jeff_media/notridentvoid/listeners/ProjectileListener.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package de.jeff_media.notridentvoid.listeners;
-
-import de.jeff_media.notridentvoid.Main;
-import de.jeff_media.notridentvoid.config.Config;
-import de.jeff_media.notridentvoid.tasks.WatchTrident;
-import org.bukkit.Bukkit;
-import org.bukkit.Material;
-import org.bukkit.enchantments.Enchantment;
-import org.bukkit.entity.EntityType;
-import org.bukkit.entity.Player;
-import org.bukkit.entity.Trident;
-import org.bukkit.event.EventHandler;
-import org.bukkit.event.EventPriority;
-import org.bukkit.event.Listener;
-import org.bukkit.event.entity.ProjectileLaunchEvent;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
-
-public class ProjectileListener implements Listener {
-
- private final Main main = Main.getInstance();
-
- private boolean hasLoyalty(ItemStack item) {
- if(!item.hasItemMeta()) return false;
- ItemMeta meta = item.getItemMeta();
- return meta.hasEnchant(Enchantment.LOYALTY);
- }
-
- @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
- public void onShoot(ProjectileLaunchEvent event) {
- if(event.getEntityType() != EntityType.TRIDENT) return;
- Trident trident = (Trident) event.getEntity();
- if(main.isRegistered(trident)) return;
- //if(!hasLoyalty(trident)) return;
- if(!(trident.getShooter() instanceof Player)) return;
- Player player = (Player) trident.getShooter();
- ItemStack tridentItem = null;
- if(player.getInventory().getItemInOffHand() != null) {
- if(player.getInventory().getItemInOffHand().getType() == Material.TRIDENT) {
- tridentItem = player.getInventory().getItemInOffHand();
- }
- }
- if(player.getInventory().getItemInMainHand() != null) {
- if(player.getInventory().getItemInMainHand().getType() == Material.TRIDENT) {
- tridentItem = player.getInventory().getItemInMainHand();
- }
- }
- if(tridentItem == null) return;
- if(!hasLoyalty(tridentItem)) return;
- if(!main.getConfig().getBoolean(Config.VOID_SAVING)) return;
- main.register(trident);
- new WatchTrident(trident).runTaskTimer(main,1,1);
- Bukkit.getScheduler().runTaskLater(main,() ->main.unregister(trident),20);
- }
-}
diff --git a/src/main/resources/config-version.txt b/src/main/resources/config-version.txt
new file mode 100644
index 0000000..eaa3551
--- /dev/null
+++ b/src/main/resources/config-version.txt
@@ -0,0 +1 @@
+${config.version}
\ No newline at end of file
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index ae1c936..af7dcc4 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -8,7 +8,7 @@
# Permissions #
###############
-# notridentvoid.use
+# bettertridents.savevoid
# Allows to use the "void-saving" feature
# Default: true
@@ -17,6 +17,22 @@
# This is currently the only function of this plugin :P
void-saving: true
+# When enabled, the Impaling enchantment behaves like in Bedrock edition: it deals extra damage to mobs
+# touching water or rain.
+# In 1.17+, this is no longer needed ( https://minecraft.fandom.com/wiki/Java_Edition_Combat_Test_4 )
+bedrock-impaling: true
+
+# When enabled, Drowned drop tridents as often as in Bedrock edition.
+# Default Java Edition drop chance: 8.5% (up to 11.5% with Looting 3) for all Drowned holding a trident
+# Bedrock Edition drop chance: 25% (up to 37% with Looting 3) for all Drowned holding a trident
+bedrock-drop-chance: true
+
+# When enabled, tridents thrown from the offhand will go back to the offhand slot when picked up
+return-to-offhand: true
+
+# When enabled, tridents enchanted with loyalty will be prevented from travelling through portals
+disable-loyalty-portals: true
+
# Should we check for updates?
# When enabled, a message is printed in the console if a new version has
# been found, and OPs will be notified when they join the server.
@@ -28,6 +44,9 @@ check-for-updates: true
# When check-for-updates is true, AngelChest will check every X hours
update-check-interval: 4
+# Debug mode - you probably don't want this
+debug: false
+
# NEVER CHANGE THE VALUES BELOW!
plugin-version: ${project.version}
config-version: ${config.version}
\ No newline at end of file
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index ed4c62e..e9a9159 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -10,7 +10,19 @@ load: STARTUP
awareness:
- !@UTF8
commands:
+ bettertridents:
+ description: Reloads the config file
+ permission: bettertridents.reload
+ usage: /
permissions:
- notridentvoid.use:
+ bettertridents.*:
+ description: Allows to use all BetterTridents features
+ children:
+ - bettertridents.savevoid
+ default: op
+ bettertridents.savevoid:
description: Prevents tridents enchanted with loyalty to get lost in the void
- default: true
\ No newline at end of file
+ default: true
+ bettertridents.reload:
+ description: Allows to reload the config file using /bettertridents
+ default: op
\ No newline at end of file