2.0.0 release

This commit is contained in:
mfnalex 2021-05-24 18:39:16 +02:00
parent 2fa8a67436
commit bb813d746b
23 changed files with 798 additions and 101 deletions

View File

@ -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

10
pom.xml
View File

@ -4,13 +4,13 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.jeff_media</groupId>
<name>NoTridentVoid</name>
<artifactId>NoTridentVoid</artifactId>
<version>1.1.0</version>
<name>BetterTridents</name>
<artifactId>BetterTridents</artifactId>
<version>2.0.0</version>
<properties>
<spigot.prefix>${project.name}</spigot.prefix>
<spigot.main>${project.groupId}.notridentvoid.Main</spigot.main>
<spigot.main>${project.groupId}.bettertridents.Main</spigot.main>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
@ -45,7 +45,7 @@
<!-- Replace "your.package" with your plugin's package name -->
<relocation>
<pattern>de.jeff_media.updatechecker</pattern>
<shadedPattern>de.jeff_media.notridentvoid.updatechecker</shadedPattern>
<shadedPattern>de.jeff_media.bettertridents.updatechecker</shadedPattern>
</relocation>
<relocation>
<pattern>org.bstats</pattern>

View File

@ -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<UUID> 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());
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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<String> getNewConfigAsArrayList(final Main main) {
final List<String> 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<String> 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<String> oldConfigNodes = main.getConfig().getKeys(false);
final ArrayList<String> 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);
}
}

View File

@ -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";
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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.");
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -1,5 +0,0 @@
package de.jeff_media.notridentvoid.config;
public class Permissions {
public static final String NOTRIDENTVOID_USE = "notridentvoid.use";
}

View File

@ -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);
}
}

View File

@ -0,0 +1 @@
${config.version}

View File

@ -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}

View File

@ -10,7 +10,19 @@ load: STARTUP
awareness:
- !@UTF8
commands:
bettertridents:
description: Reloads the config file
permission: bettertridents.reload
usage: /<command>
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
default: true
bettertridents.reload:
description: Allows to reload the config file using /bettertridents
default: op