diff --git a/src/config.yml b/src/config.yml index 43f6854..0beb080 100644 --- a/src/config.yml +++ b/src/config.yml @@ -42,6 +42,8 @@ toggleErr: "{prefix}&cUnable to toggle your ridability, contact an admin..." # Messages sent to the player when using command /prider-toggle statusOn: "{prefix}&aOther players can now ride you" statusOff: "{prefix}&aOther players cannot ride you anymore" +# Error message when you use a potion effect with wrong parameters +effectErr: "{prefix}&cError with potion effect {type}" # In the both 3 sections: (broadcast, player and duck) # - sub-section "ride" is used when a player riders another @@ -65,14 +67,6 @@ duck: whip: "{prefix}&e&l{player}&b whipped you, do you like that?" eject: "{prefix}&bYou've just ejected &e&l{player}&b, beware... I'm sure he will try again!" -# Bossbar displayed to ridden player -bossbar_on_ridden_player: - enabled: true - title: "{player} is ridding you!" # {player} will be replaced by the rider's name - color: YELLOW # Available values: BLUE, GREEN, PINK, PURPLE, RED, WHITE, YELLOW - style: SOLID # Available values: SOLID, SEGMENTED_6, SEGMENTED_10, SEGMENTED_12, SEGMENTED_20 - progress: 1.0 # Between 0 and 1 - # Cooldowns (in seconds) cooldowns: ride: @@ -125,11 +119,6 @@ consume_items: ride: false whip: true -# Disabled worlds (you can use « [] > to represents an empty list) -disabled_worlds: - - world1_to_disable - - World2_to_disable - # Define how many riders can sit on the same player's shoulders # You can set groups you need, and give the appropriate permission to your users. # Each groups you define will be checked with the permission "playerrider.duck." @@ -180,3 +169,70 @@ boost_whip_pitch: 1.3 hide_rider_maxPitch: 25 # 0 to disable this feature # Please note: This is not perfect, because if the player use third person view, it has no sense... # and unfortunately, this cannot be detected in a Spigot plugin (this is client side) + +##### New in version 1.14.1 ##### + +# Bossbar displayed to ridden player +bossbar_on_ridden_player: + enabled: true + title: "{player} is ridding you!" # {player} will be replaced by the rider's name + color: YELLOW # Available values: BLUE, GREEN, PINK, PURPLE, RED, WHITE, YELLOW + style: SOLID # Available values: SOLID, SEGMENTED_6, SEGMENTED_10, SEGMENTED_12, SEGMENTED_20 + progress: 1.0 # Between 0 and 1 + +# Disabled worlds (you can use « [] > to represents an empty list) +disabled_worlds: + - world1_to_disable + - World2_to_disable + +##### New in version 1.14.2 ##### + +# Disclaimer for those potion effects: +# It can be used by players to cure a higher effect, and I will not make a complex mechanic to prevent it. +# BUT, if a player has other types of effects before being mounted, those ones will not be affected by PlayerRider. +# It will only clear types of effect it had when the action begin when it stops. +# +# For example: (considering the default value of this config file with enabled = true) +# If a player is affected by a HUNGER effect for 2 minutes and is quickly mounted by another player, +# even if it's only for 1 second, he will be cured from HUNGER when this other player leaves his shoulder. +# +# So now you are warned about that, choose the effect you want to give with this in mind. + +# Suggested by Elguerrero: If enabled when a player has someone on his shoulder, he will be slow down +affect_ridden_player: + enabled: false + # Available types here: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/potion/PotionEffectType.html + # BEWARE: You have to verify for each effect you set if it can support the "max" multiplier value. + # I cannot garantee all effect will works with all values, so make your tests before. + # The effect showed here are arbitrary examples (I've tested those values but not using them on my server) + effects: + - type: SLOW # Potion effect type, see the link given above + init: 1 # (integer) Potion effect multiplier when the player has only one player on his shoulder + inc: 1 # (integer) Value to add for each additional player on his shoulder + max: 2 # (integer) Max value for the multiplier + duration: 1200 # (integer, ticks : 1 sec = 20 ticks) /!\ Refreshed when the ridden player moves + # You can add several effects, each defined like the previous one. Example: + - type: HUNGER + init: 1 + inc: 2 + max: 10 + duration: 1200 + +# Works like affect_ridden_player but affect the ridden player when he's being whipped +affect_whipped_player: + enabled: false + # Note: As it is the primary function of this whip feature, the speed boost applied is not modifiable here + # You can change its settings wieht the parameters "boost_amplifier" and associated. + # They are after the line « ##### [ the next parameters are ignored if boost_allowed: false ] ##### » + effects: + - type: JUMP + init: 1 + inc: -1 + max: 0 # When you set a negative "inc" value, max value is used as a minimum value + duration: 60 + + - type: CONFUSION + init: 0 + inc: 1 + max: 1 + duration: 60 diff --git a/src/me/arboriginal/PlayerRider/PR.java b/src/me/arboriginal/PlayerRider/PR.java new file mode 100644 index 0000000..8d19f49 --- /dev/null +++ b/src/me/arboriginal/PlayerRider/PR.java @@ -0,0 +1,75 @@ +package me.arboriginal.PlayerRider; + +import java.io.File; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.event.HandlerList; +import org.bukkit.plugin.java.JavaPlugin; + +public class PR extends JavaPlugin { + static File file; + static FileConfiguration config; + static PROptions options; + static PRcooldown cooldown; + static YamlConfiguration users; + + // JavaPlugin methods ----------------------------------------------------------------------------------------------- + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (command.getName().equalsIgnoreCase("prider-reload")) { + reloadConfig(); + PRUtils.userMessage(sender, "reload"); + + return true; + } + + if (command.getName().equalsIgnoreCase("prider-toggle")) { + if (sender instanceof Player) + PRUtils.userMessage(sender, PRUtils.rideToggle((Player) sender)); + else + PRUtils.userMessage(sender, "toggleWarn"); + return true; + } + + return super.onCommand(sender, command, label, args); + } + + @Override + public void onDisable() { + super.onDisable(); + + HandlerList.unregisterAll((JavaPlugin) this); + } + + @Override + public void onEnable() { + reloadConfig(); + + cooldown = new PRcooldown(); + users = new YamlConfiguration(); + file = new File(getDataFolder(), "usersPreferences.yml"); + + if (file.exists()) + users = YamlConfiguration.loadConfiguration(file); + else + PRUtils.dataSave(); + + getServer().getPluginManager().registerEvents(new PRListener(this), this); + } + + @Override + public void reloadConfig() { + super.reloadConfig(); + + saveDefaultConfig(); + config = getConfig(); + config.options().copyDefaults(true); + saveConfig(); + + options = new PROptions(); + } +} diff --git a/src/me/arboriginal/PlayerRider/PRListener.java b/src/me/arboriginal/PlayerRider/PRListener.java new file mode 100644 index 0000000..a510c69 --- /dev/null +++ b/src/me/arboriginal/PlayerRider/PRListener.java @@ -0,0 +1,234 @@ +package me.arboriginal.PlayerRider; + +import java.util.List; +import org.bukkit.Bukkit; +import org.bukkit.NamespacedKey; +import org.bukkit.boss.KeyedBossBar; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDamageEvent.DamageCause; +import org.bukkit.event.player.PlayerInteractEntityEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.spigotmc.event.entity.EntityDismountEvent; + +class PRListener implements Listener { + private PR plugin; + + // Constructor methods ---------------------------------------------------------------------------------------------- + + public PRListener(PR pr) { + plugin = pr; + } + + // Listener methods ------------------------------------------------------------------------------------------------- + + @EventHandler + private void onEntityDamage(EntityDamageEvent event) { + if (event.isCancelled()) return; + + Entity injured = event.getEntity(); + if (!PRUtils.isPlayer(injured)) return; + + if (PR.options.prevent_suffocation && event.getCause() == DamageCause.SUFFOCATION + && PRUtils.isPlayer(injured.getVehicle())) { + event.setCancelled(true); + return; + } + + if (PR.options.getoff_when_hurt && PRUtils.isPlayer(injured.getVehicle())) { + injured.leaveVehicle(); + return; + } + + if (PR.options.eject_when_hurt && injured.getPassengers().size() > 0) { + injured.eject(); + return; + } + } + + @EventHandler + private void onEntityDamageByEntityEvent(EntityDamageByEntityEvent event) { + Entity injured = event.getEntity(); + + if (!PRUtils.isPlayer(injured)) return; + + if (PR.options.prevent_hit_rider && PRUtils.isPlayer(event.getDamager())) { + Entity vehicle = injured.getVehicle(); + + if (vehicle != null && event.getDamager().equals(vehicle)) { + event.setCancelled(true); + return; + } + } + } + + @EventHandler + private void onEntityDismount(EntityDismountEvent event) { + if (event.isCancelled()) return; + + Entity player = event.getDismounted(); + if (!(player instanceof Player)) return; + + Entity duck = event.getEntity(); + if (!(duck instanceof Player)) return; + + if (!((Player) player).canSee(((Player) duck))) ((Player) player).showPlayer(plugin, ((Player) duck)); + + KeyedBossBar bossbar = Bukkit.getBossBar(bossbarKey(((Player) player))); + if (bossbar != null) bossbar.removeAll(); + + if (PR.options.effects_ridden_enabled) + PRUtils.effectsClear(((Player) player), PR.options.effects_ridden); + } + + @EventHandler + private void onPlayerInteract(PlayerInteractEvent event) { + // https://www.spigotmc.org/threads/how-would-i-stop-an-event-from-being-called-twice.135234/#post-1434104 + if (event.getHand() == EquipmentSlot.OFF_HAND || !PR.options.boost_allowed) return; + + Player player = event.getPlayer(); + + if (!PRUtils.playerAllowed(player, "whip") + || player.getLocation().getPitch() < PR.options.boost_maxPitch + || !PRUtils.isPlayer(player.getVehicle())) + return; + + ItemStack item = player.getInventory().getItemInMainHand(); + + if (!PR.options.allowed_items__whip.contains(item.getType().toString())) return; + + Player duck = (Player) player.getVehicle(); + + if (PR.cooldown.isActive("whip.perform", player, duck, true)) return; + + if (PR.options.boost_amplifier > 0 && PR.options.boost_duration > 0) { + if (PR.options.boost_whip_sound != null) { + player.playSound(player.getLocation(), + PR.options.boost_whip_sound, PR.options.boost_whip_volume, PR.options.boost_whip_pitch); + duck.playSound(duck.getLocation(), + PR.options.boost_whip_sound, PR.options.boost_whip_volume, PR.options.boost_whip_pitch); + } + + duck.addPotionEffect(new PotionEffect( + PotionEffectType.SPEED, PR.options.boost_duration, PR.options.boost_amplifier, false, false, false), true); + } + + PRUtils.consume(player, item, "whip"); + PRUtils.alert("whip", player, duck); + PR.cooldown.set("whip.perform", player, duck); + + if (PR.options.effects_whipped_enabled) + PRUtils.effectsApply(duck, PR.options.effects_whipped); + } + + @EventHandler + private void onPlayerInteractEntity(PlayerInteractEntityEvent event) { + // https://www.spigotmc.org/threads/how-would-i-stop-an-event-from-being-called-twice.135234/#post-1434104 + if (event.getHand() == EquipmentSlot.OFF_HAND || !PRUtils.isPlayer(event.getRightClicked())) return; + + Player player = event.getPlayer(); + + if (!PR.options.disabled_worlds.isEmpty() && PR.options.disabled_worlds.contains(player.getWorld().getName())) + return; + + Player duck = (Player) event.getRightClicked(); + + if (player.getPassengers().contains(duck)) { + if (player.getLocation().getPitch() < PR.options.eject_maxPitch + && player.hasPermission("playerrider.eject") + && !PR.cooldown.isActive("eject.perform", player, true)) { + player.eject(); + PRUtils.alert("eject", duck, player); + PR.cooldown.clear("eject.perform", player); + } + + return; + } + + if (!PRUtils.playerAllowed(player, "ride") || !PRUtils.rideIsActivated(duck) || player.isInsideVehicle()) return; + + ItemStack item = player.getInventory().getItemInMainHand(); + if (!PR.options.allowed_items__ride.contains(item.getType().toString())) return; + + List riders = duck.getPassengers(); + int count = 0; + + while (riders.size() == 1 && PRUtils.isPlayer(riders.get(0))) { + duck = (Player) riders.get(0); + count++; + + if (duck.equals(player)) return; + + riders = duck.getPassengers(); + } + + if (riders.size() > 0) return; + + if (!PRUtils.duckAllowed(duck, count + 1)) { + PRUtils.userMessage(player, "tooMany", player, duck); + return; + } + + if (duck.addPassenger(player)) { + PRUtils.consume(player, item, "ride"); + PRUtils.alert("ride", player, duck); + PR.cooldown.set("ride.perform", player, duck); + PR.cooldown.set("eject.perform", duck); + + if (!PRUtils.canSeeRider(duck) && duck.getPassengers().get(0).equals(player)) + duck.hidePlayer(plugin, player); + + if (PR.options.bossbar_enabled) { + KeyedBossBar bossbar = Bukkit.createBossBar(bossbarKey(duck), + PR.options.bossbar_title.replace("{player}", player.getName()), + PR.options.bossbar_color, PR.options.bossbar_style); + + bossbar.addPlayer(duck); + bossbar.setProgress(PR.options.bossbar_pct); + bossbar.setVisible(true); + } + + if (PR.options.effects_ridden_enabled && !duck.isInsideVehicle()) + PRUtils.effectsApply(duck, PR.options.effects_ridden); + } + else { + PRUtils.userMessage(player, "failed", player, duck); + } + } + + @EventHandler + private void onPlayerMove(PlayerMoveEvent event) { + if (event.isCancelled()) return; + + Player player = event.getPlayer(); + if (player.getPassengers().isEmpty()) return; + + Entity rider = player.getPassengers().get(0); + if (!(rider instanceof Player)) return; + + if (PR.options.effects_ridden_enabled) + PRUtils.effectsApply(((Player) player), PR.options.effects_ridden); + + if (PR.options.hide_rider_maxPitch == 0) return; + + if (PRUtils.canSeeRider(player)) + player.showPlayer(plugin, ((Player) rider)); + else + player.hidePlayer(plugin, ((Player) rider)); + } + + // Helper methods --------------------------------------------------------------------------------------------------- + + private NamespacedKey bossbarKey(Player player) { + return new NamespacedKey(plugin, "PlayerRider." + player.getUniqueId()); + } +} diff --git a/src/me/arboriginal/PlayerRider/PROptions.java b/src/me/arboriginal/PlayerRider/PROptions.java new file mode 100644 index 0000000..ea9b7f7 --- /dev/null +++ b/src/me/arboriginal/PlayerRider/PROptions.java @@ -0,0 +1,118 @@ +package me.arboriginal.PlayerRider; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.bukkit.Bukkit; +import org.bukkit.Sound; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarStyle; +import org.bukkit.potion.PotionEffectType; + +class PROptions { + BarColor bossbar_color; + BarStyle bossbar_style; + boolean boost_allowed, bossbar_enabled, effects_ridden_enabled, effects_whipped_enabled, + eject_when_hurt, getoff_when_hurt, prevent_hit_rider, prevent_suffocation; + double boost_maxPitch, bossbar_pct, eject_maxPitch, hide_rider_maxPitch; + float boost_whip_pitch, boost_whip_volume; + int boost_amplifier, boost_duration; + Sound boost_whip_sound; + String bossbar_title, file_not_writable_err, potion_effect_err; + + List effects_ridden, effects_whipped; + List allowed_items__ride, allowed_items__whip, disabled_worlds; + Set max_riders_groups; + + // Constructor methods ---------------------------------------------------------------------------------------------- + + PROptions() { + // Bossbar attributes values + bossbar_color = (BarColor) getEnumValue(BarColor.class, "bossbar_on_ridden_player.color"); + bossbar_style = (BarStyle) getEnumValue(BarStyle.class, "bossbar_on_ridden_player.style"); + // Effects list values + effects_ridden = getEffects("affect_ridden_player.effects"); + effects_whipped = getEffects("affect_whipped_player.effects"); + // Boolean values + boost_allowed = PR.config.getBoolean("boost_allowed"); + eject_when_hurt = PR.config.getBoolean("eject_when_hurt"); + getoff_when_hurt = PR.config.getBoolean("getoff_when_hurt"); + prevent_hit_rider = PR.config.getBoolean("prevent_hit_rider"); + prevent_suffocation = PR.config.getBoolean("prevent_suffocation"); + bossbar_enabled = (bossbar_color == null || bossbar_style == null) ? null + : PR.config.getBoolean("bossbar_on_ridden_player.enabled"); + effects_ridden_enabled = effects_ridden.isEmpty() ? false : PR.config.getBoolean("affect_ridden_player.enabled"); + effects_whipped_enabled = effects_ridden.isEmpty() ? false : PR.config.getBoolean("affect_whipped_player.enabled"); + // Double values + boost_maxPitch = PR.config.getDouble("boost_maxPitch"); + bossbar_pct = PR.config.getDouble("bossbar_on_ridden_player.progress"); + eject_maxPitch = PR.config.getDouble("eject_maxPitch"); + hide_rider_maxPitch = PR.config.getDouble("hide_rider_maxPitch"); + // Float values + boost_whip_pitch = (float) PR.config.getDouble("boost_whip_pitch"); + boost_whip_volume = (float) PR.config.getDouble("boost_whip_volume"); + // Integer values + boost_amplifier = PR.config.getInt("boost_amplifier"); + boost_duration = PR.config.getInt("boost_duration"); + // Sound values + boost_whip_sound = (boost_whip_volume > 0) ? (Sound) getEnumValue(Sound.class, "boost_whip_sound") : null; + // String values + bossbar_title = PR.config.getString("bossbar_on_ridden_player.title"); + file_not_writable_err = PRUtils.prepareMessage(PR.config.getString("fileErr")); + potion_effect_err = PRUtils.prepareMessage(PR.config.getString("effectErr")); + // String list & set values + allowed_items__ride = PR.config.getStringList("allowed_items.ride"); + allowed_items__whip = PR.config.getStringList("allowed_items.whip"); + disabled_worlds = PR.config.getStringList("disabled_worlds"); + max_riders_groups = PR.config.getConfigurationSection("max_riders").getKeys(false); + } + + // Package classes -------------------------------------------------------------------------------------------------- + + class PREffect { // @formatter:off + PotionEffectType type; int init, inc, max, duration; + PREffect(PotionEffectType a, int b, int c, int d, int e) { type = a; init = b; inc = c; max = d; duration = e; } + } // @formatter:on + + // Private methods -------------------------------------------------------------------------------------------------- + + private List getEffects(String path) { + List effects = new ArrayList(); + List> list = PR.config.getMapList(path); + if (list == null || list.isEmpty()) return effects; + + for (Map effect : list) { + if (!(effect instanceof Map)) continue; + + String typeName = (String) ((Map) effect).get("type"); + if (typeName == null || typeName.isEmpty()) continue; + + PotionEffectType type = PotionEffectType.getByName(typeName); + if (type == null) continue; + // @formatter:off + int init = (int) ((Map) effect).get("init"), + inc = (int) ((Map) effect).get("inc"), + max = (int) ((Map) effect).get("max"), + duration = (int) ((Map) effect).get("duration"); + // @formatter:on + effects.add(new PREffect(type, init, inc, max, duration)); + } + + return effects; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private Enum getEnumValue(Class enumClass, String path) { + String value = PR.config.getString(path); + if (value.isEmpty()) return null; + + try { + return Enum.valueOf((Class) enumClass, value); + } + catch (Exception e) { + Bukkit.getLogger().warning(PRUtils.prepareMessage(PR.config.getString("sndErr"))); + return null; + } + } +} diff --git a/src/me/arboriginal/PlayerRider/PRUtils.java b/src/me/arboriginal/PlayerRider/PRUtils.java new file mode 100644 index 0000000..b76363a --- /dev/null +++ b/src/me/arboriginal/PlayerRider/PRUtils.java @@ -0,0 +1,175 @@ +package me.arboriginal.PlayerRider; + +import java.io.IOException; +import java.util.List; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import me.arboriginal.PlayerRider.PROptions.PREffect; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; + +class PRUtils { + static void alert(String key, Player player, Player duck) { + if (!PR.cooldown.isActive(key + ".alertPlayer", player, duck)) { + userMessage(player, "player." + key, player, duck); + PR.cooldown.set(key + ".alertPlayer", player, duck); + } + + if (!PR.cooldown.isActive(key + ".alertDuck", player, duck)) { + userMessage(duck, "duck." + key, player, duck); + PR.cooldown.set(key + ".alertDuck", player, duck); + } + + if (!PR.cooldown.isActive(key + ".broadcast", player, duck)) { + broadcast(key, player, duck); + PR.cooldown.set(key + ".broadcast", player, duck); + } + } + + static void broadcast(String key, CommandSender player, CommandSender duck) { + String message = PR.config.getString("broadcast." + key); + + if (!message.isEmpty()) + Bukkit.broadcastMessage(prepareMessage(message, player, duck)); + } + + static boolean canSeeRider(Player player) { + return PR.options.hide_rider_maxPitch != 0 && player.getLocation().getPitch() < PR.options.hide_rider_maxPitch; + } + + static void consume(Player player, ItemStack item, String key) { + if (PR.config.getBoolean("consume_items." + key) + && !player.hasPermission("playerrider." + key + ".keepitem") + && item.getType() != Material.AIR) + item.setAmount(item.getAmount() - 1); + } + + static boolean dataSave() { + try { + if (!PR.file.exists()) PR.file.createNewFile(); + + PR.users.save(PR.file); + return true; + } + catch (IOException e) { + Bukkit.getLogger().severe(PR.options.file_not_writable_err); + return false; + } + } + + static boolean duckAllowed(Player duck, int passengersCount) { + for (String group : PR.options.max_riders_groups) + if ((group.equals("default") || duck.hasPermission("playerrider.duck." + group)) + && PR.config.getInt("max_riders." + group) >= passengersCount) + return true; + + return false; + } + + static void effectsClear(Player player, List effects) { + for (PREffect effect : effects) + player.removePotionEffect(effect.type); + } + + static void effectsApply(Player player, List effects) { + for (PREffect effect : effects) { + int amplifier = effectAmplifier(player, effect); + if (amplifier < 0) continue; + + try { + player.addPotionEffect(new PotionEffect(effect.type, effect.duration, amplifier, false, false, false), true); + } + catch (Exception e) { + Bukkit.getLogger().warning(PR.options.potion_effect_err.replace("type", effect.type.toString())); + } + } + } + //TODO: Apply on the main vehicle + refresh when unmount + + static int effectAmplifier(Player player, PREffect effect) { + int count = player.getPassengers().size(); + if (count == 0) return 0; + if (count == 1) return effect.init; + + int value = effect.init + (count - 1) * effect.inc; + + if (effect.inc < 0) + return Math.min(effect.max, value); + else + return Math.max(value, effect.max); + } + + static boolean isPlayer(Entity entity) { + return (entity instanceof Player) && !entity.hasMetadata("NPC"); + } + + static boolean playerAllowed(Player player, String key) { + return player.hasPermission("playerrider." + key) || player.hasPermission("playerrider." + key + ".keepitem"); + } + + static String prepareMessage(String message) { + return prepareMessage(message, null, null); + } + + static String prepareMessage(String message, CommandSender player, CommandSender duck) { + message = message.replace("{prefix}", PR.config.getString("prefix")); + // @formatter:off + if (player != null) message = message.replace("{player}", player.getName()); + if (duck != null) message = message.replace("{duck}", duck.getName()); + // @formatter:on + return ChatColor.translateAlternateColorCodes('&', message); + } + + static String rideKey(Player duck) { + return duck.getUniqueId() + ".ridable"; + } + + static boolean rideIsActivated(Player player) { + if (!player.hasPermission("playerrider.duck")) return false; + + String key = rideKey(player); + + return !PR.users.contains(key) || PR.users.getBoolean(key); + } + + static String rideToggle(Player player) { + String key = rideKey(player); + boolean status = !PR.users.contains(key) || PR.users.getBoolean(key); + + PR.users.set(key, !status); + if (!dataSave()) return "toggleErr"; + + return status ? "statusOff" : "statusOn"; + } + + static void userMessage(CommandSender sender, String key) { + userMessage(sender, key, null, null); + } + + static void userMessage(CommandSender sender, String key, CommandSender player, CommandSender duck) { + String message = PR.config.getString(key); + + if (!message.isEmpty()) { + sender.sendMessage(prepareMessage(message, player, duck)); + } + } + + static void warn(String key, Player player, Player duck, int delay) { + String[] parts = key.split("\\."); + + if (parts.length != 2 || !parts[1].equals("perform")) return; + + String message = PR.config.getString("warn_player_when_cooldown." + parts[0]); + + if (message.isEmpty()) return; + + ((Player) player).spigot().sendMessage(ChatMessageType.ACTION_BAR, + new TextComponent(prepareMessage(message.replace("{delay}", "" + delay), player, duck))); + } +} diff --git a/src/me/arboriginal/PlayerRider/PRcooldown.java b/src/me/arboriginal/PlayerRider/PRcooldown.java index 5529efe..daed93e 100644 --- a/src/me/arboriginal/PlayerRider/PRcooldown.java +++ b/src/me/arboriginal/PlayerRider/PRcooldown.java @@ -4,37 +4,36 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -public class PRcooldown { - public static HashMap cooldowns; - public static HashMap warnings; +class PRcooldown { + private HashMap cooldowns; - public PRcooldown() { + // Constructor methods ---------------------------------------------------------------------------------------------- + + PRcooldown() { cooldowns = new HashMap() { private static final long serialVersionUID = 1L; }; } - public String id(String key, CommandSender player, CommandSender duck) { - return key + "..." + player.getName() + "." + ((duck == null) ? ".." : duck.getName()); - } + // Package methods -------------------------------------------------------------------------------------------------- - public boolean isActive(String key, Player player) { - return isActive(key, player, null, false); + void clear(String key, Player player) { + clear(key, player, null); } - public boolean isActive(String key, Player player, boolean warn) { + boolean isActive(String key, Player player, boolean warn) { return isActive(key, player, null, warn); } - public boolean isActive(String key, Player player, Player duck) { + boolean isActive(String key, Player player, Player duck) { return isActive(key, player, duck, false); } - public boolean isActive(String key, Player player, Player duck, boolean warn) { + boolean isActive(String key, Player player, Player duck, boolean warn) { Long now = getCurrentTime(), next = get(key, player, duck); if (next > now) { - if (warn) PlayerRider.warn(key, player, duck, (int) Math.max(1, Math.floor((next - now) / 1000))); + if (warn) PRUtils.warn(key, player, duck, (int) Math.max(1, Math.floor((next - now) / 1000))); return true; } @@ -42,33 +41,35 @@ public boolean isActive(String key, Player player, Player duck, boolean warn) { return false; } - public Long getCurrentTime() { - return System.currentTimeMillis(); + void set(String key, Player player) { + set(key, player, null); } - public Long get(String key, Player player, Player duck) { - key = id(key, player, duck); + void set(String key, Player player, Player duck) { + int delay = PR.config.getInt("cooldowns." + key) * 1000; - return cooldowns.containsKey(key) ? cooldowns.get(key) : 0; + if (delay > 0) { + cooldowns.put(id(key, player, duck), getCurrentTime() + delay); + } } - public void clear(String key, Player player) { - clear(key, player, null); - } + // Private methods -------------------------------------------------------------------------------------------------- - public void clear(String key, Player player, Player duck) { + private void clear(String key, Player player, Player duck) { cooldowns.remove(id(key, player, duck)); } - public void set(String key, Player player) { - set(key, player, null); + private Long get(String key, Player player, Player duck) { + key = id(key, player, duck); + + return cooldowns.containsKey(key) ? cooldowns.get(key) : 0; } - public void set(String key, Player player, Player duck) { - int delay = PlayerRider.config.getInt("cooldowns." + key) * 1000; + private Long getCurrentTime() { + return System.currentTimeMillis(); + } - if (delay > 0) { - cooldowns.put(id(key, player, duck), getCurrentTime() + delay); - } + private String id(String key, CommandSender player, CommandSender duck) { + return key + "..." + player.getName() + "." + ((duck == null) ? ".." : duck.getName()); } } diff --git a/src/me/arboriginal/PlayerRider/PlayerRider.java b/src/me/arboriginal/PlayerRider/PlayerRider.java deleted file mode 100644 index 321a006..0000000 --- a/src/me/arboriginal/PlayerRider/PlayerRider.java +++ /dev/null @@ -1,454 +0,0 @@ -package me.arboriginal.PlayerRider; - -import java.io.File; -import java.io.IOException; -import java.util.List; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Sound; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarStyle; -import org.bukkit.boss.KeyedBossBar; -import org.bukkit.command.Command; -import org.bukkit.command.CommandSender; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.HandlerList; -import org.bukkit.event.Listener; -import org.bukkit.event.entity.EntityDamageByEntityEvent; -import org.bukkit.event.entity.EntityDamageEvent; -import org.bukkit.event.entity.EntityDamageEvent.DamageCause; -import org.bukkit.event.player.PlayerInteractEntityEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.inventory.EquipmentSlot; -import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.java.JavaPlugin; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import org.spigotmc.event.entity.EntityDismountEvent; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; - -public class PlayerRider extends JavaPlugin implements Listener { - public static FileConfiguration config; - public static Sound sound; - public static Float volume; - public static PRcooldown cooldown; - - private File file; - private YamlConfiguration users; - - // ----------------------------------------------------------------------------------------------- - // JavaPlugin methods - // ----------------------------------------------------------------------------------------------- - - @Override - public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { - if (command.getName().equalsIgnoreCase("prider-reload")) { - reloadConfig(); - userMessage(sender, "reload"); - - return true; - } - - if (command.getName().equalsIgnoreCase("prider-toggle")) { - if (sender instanceof Player) - userMessage(sender, rideToggle((Player) sender)); - else - userMessage(sender, "toggleWarn"); - return true; - } - - return super.onCommand(sender, command, label, args); - } - - @Override - public void onDisable() { - super.onDisable(); - - HandlerList.unregisterAll((JavaPlugin) this); - } - - @Override - public void onEnable() { - cooldown = new PRcooldown(); - - reloadConfig(); - dataLoad(); - - getServer().getPluginManager().registerEvents(this, this); - } - - @Override - public void reloadConfig() { - super.reloadConfig(); - - saveDefaultConfig(); - config = getConfig(); - config.options().copyDefaults(true); - saveConfig(); - - sound = null; - volume = (float) config.getDouble("boost_whip_volume"); - - if (volume > 0 && !config.getString("boost_whip_sound").isEmpty()) { - try { - sound = Sound.valueOf(config.getString("boost_whip_sound")); - } - catch (Exception e) { - getLogger().warning(prepareMessage(config.getString("sndErr"))); - } - } - } - - // ----------------------------------------------------------------------------------------------- - // Listener methods - // ----------------------------------------------------------------------------------------------- - - @EventHandler - public void onEntityDamage(EntityDamageEvent event) { - if (event.isCancelled()) return; - - Entity injured = event.getEntity(); - - if (!isPlayer(injured)) return; - - if (config.getBoolean("prevent_suffocation") - && event.getCause() == DamageCause.SUFFOCATION - && isPlayer(injured.getVehicle())) { - event.setCancelled(true); - return; - } - - if (config.getBoolean("getoff_when_hurt") && isPlayer(injured.getVehicle())) { - injured.leaveVehicle(); - return; - } - - if (config.getBoolean("eject_when_hurt") && injured.getPassengers().size() > 0) { - injured.eject(); - return; - } - } - - @EventHandler - public void onEntityDamageByEntityEvent(EntityDamageByEntityEvent event) { - Entity injured = event.getEntity(); - - if (!isPlayer(injured)) return; - - if (config.getBoolean("prevent_hit_rider") && isPlayer(event.getDamager())) { - Entity vehicle = injured.getVehicle(); - - if (vehicle != null && event.getDamager().equals(vehicle)) { - event.setCancelled(true); - return; - } - } - } - - @EventHandler - public void onEntityDismount(EntityDismountEvent event) { - if (event.isCancelled()) return; - - Entity player = event.getDismounted(); - if (!(player instanceof Player)) return; - - Entity duck = event.getEntity(); - if (!(duck instanceof Player)) return; - - ((Player) player).showPlayer(this, ((Player) duck)); - - KeyedBossBar bossbar = Bukkit.getBossBar(bossbarKey(((Player) player))); - if (bossbar != null) bossbar.removeAll(); - } - - @EventHandler - public void onPlayerInteract(PlayerInteractEvent event) { - // https://www.spigotmc.org/threads/how-would-i-stop-an-event-from-being-called-twice.135234/#post-1434104 - if (event.getHand() == EquipmentSlot.OFF_HAND) return; - - if (!config.getBoolean("boost_allowed")) return; - - Player player = event.getPlayer(); - - if (!playerAllowed(player, "whip") - || player.getLocation().getPitch() < config.getDouble("boost_maxPitch") - || !isPlayer(player.getVehicle())) - return; - - ItemStack item = player.getInventory().getItemInMainHand(); - - if (!config.getStringList("allowed_items.whip").contains(item.getType().toString())) return; - - Player duck = (Player) player.getVehicle(); - - if (cooldown.isActive("whip.perform", player, duck, true)) return; - - int amplifier = config.getInt("boost_amplifier"), duration = config.getInt("boost_duration"); - - if (amplifier > 0 && duration > 0) { - if (sound != null) { - player.playSound(player.getLocation(), sound, volume, (float) config.getDouble("boost_whip_pitch")); - duck.playSound(duck.getLocation(), sound, volume, (float) config.getDouble("boost_whip_pitch")); - } - - duck.addPotionEffect(new PotionEffect(PotionEffectType.SPEED, duration, amplifier, false, false, false), true); - } - - consume(player, item, "whip"); - alert("whip", player, duck); - cooldown.set("whip.perform", player, duck); - } - - @EventHandler - public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { - // https://www.spigotmc.org/threads/how-would-i-stop-an-event-from-being-called-twice.135234/#post-1434104 - if (event.getHand() == EquipmentSlot.OFF_HAND || !isPlayer(event.getRightClicked())) return; - - Player player = event.getPlayer(); - List list = config.getList("disabled_worlds"); - - if (!list.isEmpty() && list.contains(player.getWorld().getName())) return; - - Player duck = (Player) event.getRightClicked(); - - if (player.getPassengers().contains(duck)) { - if (player.getLocation().getPitch() < config.getDouble("eject_maxPitch") - && player.hasPermission("playerrider.eject") - && !cooldown.isActive("eject.perform", player, true)) { - player.eject(); - alert("eject", duck, player); - cooldown.clear("eject.perform", player); - } - - return; - } - - if (!playerAllowed(player, "ride") || !rideIsActivated(duck) || player.isInsideVehicle()) return; - - ItemStack item = player.getInventory().getItemInMainHand(); - - if (!config.getStringList("allowed_items.ride").contains(item.getType().toString())) return; - - List riders = duck.getPassengers(); - int count = 0; - - while (riders.size() == 1 && isPlayer(riders.get(0))) { - duck = (Player) riders.get(0); - count++; - - if (duck.equals(player)) { - return; - } - - riders = duck.getPassengers(); - } - - if (riders.size() > 0) return; - - if (!duckAllowed(duck, count + 1)) { - userMessage(player, "tooMany", player, duck); - return; - } - - if (duck.addPassenger(player)) { - consume(player, item, "ride"); - alert("ride", player, duck); - cooldown.set("ride.perform", player, duck); - cooldown.set("eject.perform", duck); - - if (canSeeRider(duck) && duck.getPassengers().get(0).equals(player)) - duck.hidePlayer(this, player); - - if (config.getBoolean("bossbar_on_ridden_player.enabled")) { - KeyedBossBar bossbar = Bukkit.createBossBar( - bossbarKey(duck), - config.getString("bossbar_on_ridden_player.title").replace("{player}", player.getName()), - BarColor.valueOf(config.getString("bossbar_on_ridden_player.color")), - BarStyle.valueOf(config.getString("bossbar_on_ridden_player.style"))); - - bossbar.addPlayer(duck); - bossbar.setProgress(config.getDouble("bossbar_on_ridden_player.progress")); - bossbar.setVisible(true); - } - } - else { - userMessage(player, "failed", player, duck); - } - } - - @EventHandler - public void onPlayerMove(PlayerMoveEvent event) { - if (event.isCancelled()) return; - - double maxPitch = config.getDouble("eject_maxPitch"); - if (maxPitch == 0) return; - - Player player = event.getPlayer(); - if (player.getPassengers().isEmpty()) return; - - Entity duck = player.getPassengers().get(0); - if (!(duck instanceof Player)) return; - - if (canSeeRider(player)) - player.hidePlayer(this, ((Player) duck)); - else - player.showPlayer(this, ((Player) duck)); - } - - // ----------------------------------------------------------------------------------------------- - // Custom methods - // ----------------------------------------------------------------------------------------------- - - private void alert(String key, Player player, Player duck) { - if (!cooldown.isActive(key + ".alertPlayer", player, duck)) { - userMessage(player, "player." + key, player, duck); - cooldown.set(key + ".alertPlayer", player, duck); - } - - if (!cooldown.isActive(key + ".alertDuck", player, duck)) { - userMessage(duck, "duck." + key, player, duck); - cooldown.set(key + ".alertDuck", player, duck); - } - - if (!cooldown.isActive(key + ".broadcast", player, duck)) { - broadcast(key, player, duck); - cooldown.set(key + ".broadcast", player, duck); - } - } - - private NamespacedKey bossbarKey(Player player) { - return new NamespacedKey(this, getName() + "." + player.getUniqueId()); - } - - private void broadcast(String key, CommandSender player, CommandSender duck) { - String message = config.getString("broadcast." + key); - - if (!message.isEmpty()) { - getServer().broadcastMessage(prepareMessage(message, player, duck)); - } - } - - private boolean canSeeRider(Player player) { - double max = config.getDouble("hide_rider_maxPitch"); - return max != 0 && player.getLocation().getPitch() > max; - } - - private void consume(Player player, ItemStack item, String key) { - if (config.getBoolean("consume_items." + key) - && !player.hasPermission("playerrider." + key + ".keepitem") - && item.getType() != Material.AIR) - item.setAmount(item.getAmount() - 1); - } - - private void dataLoad() { - users = new YamlConfiguration(); - file = new File(getDataFolder(), "usersPreferences.yml"); - - if (file.exists()) - users = YamlConfiguration.loadConfiguration(file); - else - dataSave(); - } - - private boolean dataSave() { - try { - if (!file.exists()) file.createNewFile(); - - users.save(file); - return true; - } - catch (IOException e) { - getLogger().severe(prepareMessage(config.getString("fileErr"))); - return false; - } - } - - private boolean duckAllowed(Player duck, int passengersCount) { - ConfigurationSection section = config.getConfigurationSection("max_riders"); - - for (String group : section.getKeys(false)) { - if ((group.equals("default") || duck.hasPermission("playerrider.duck." + group)) - && config.getInt("max_riders." + group) >= passengersCount) - return true; - } - - return false; - } - - private boolean isPlayer(Entity entity) { - return (entity instanceof Player) && !entity.hasMetadata("NPC"); - } - - private boolean playerAllowed(Player player, String key) { - return player.hasPermission("playerrider." + key) || player.hasPermission("playerrider." + key + ".keepitem"); - } - - private static String prepareMessage(String message) { - return prepareMessage(message, null, null); - } - - private static String prepareMessage(String message, CommandSender player, CommandSender duck) { - message = message.replace("{prefix}", config.getString("prefix")); - - if (player != null) message = message.replace("{player}", player.getName()); - if (duck != null) message = message.replace("{duck}", duck.getName()); - - return ChatColor.translateAlternateColorCodes('&', message); - } - - private String rideKey(Player duck) { - return duck.getUniqueId() + ".ridable"; - } - - private boolean rideIsActivated(Player player) { - if (!player.hasPermission("playerrider.duck")) return false; - - String key = rideKey(player); - - return !users.contains(key) || users.getBoolean(key); - } - - private String rideToggle(Player player) { - String key = rideKey(player); - boolean status = !users.contains(key) || users.getBoolean(key); - - users.set(key, !status); - if (!dataSave()) return "toggleErr"; - - return status ? "statusOff" : "statusOn"; - } - - private void userMessage(CommandSender sender, String key) { - userMessage(sender, key, null, null); - } - - private void userMessage(CommandSender sender, String key, CommandSender player, CommandSender duck) { - String message = config.getString(key); - - if (!message.isEmpty()) { - sender.sendMessage(prepareMessage(message, player, duck)); - } - } - - protected static void warn(String key, Player player, Player duck, int delay) { - String[] parts = key.split("\\."); - - if (parts.length != 2 || !parts[1].equals("perform")) return; - - String message = PlayerRider.config.getString("warn_player_when_cooldown." + parts[0]); - - if (message.isEmpty()) return; - - ((Player) player).spigot().sendMessage(ChatMessageType.ACTION_BAR, - new TextComponent(prepareMessage(message.replace("{delay}", "" + delay), player, duck))); - } -} diff --git a/src/plugin.yml b/src/plugin.yml index d5be0e6..6943411 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -1,6 +1,6 @@ name: PlayerRider description: Allow you to ride players. -version: 1.14.1 +version: 1.14.2 author: arboriginal website: https://www.spigotmc.org/resources/playerrider.62799/ @@ -12,7 +12,7 @@ softdepend: [ ] api-version: 1.13 database: false -main: me.arboriginal.PlayerRider.PlayerRider +main: me.arboriginal.PlayerRider.PR commands: prider-reload: