diff --git a/src/main/java/pers/xanadu/enderdragon/listener/DragonAttackListener.java b/src/main/java/pers/xanadu/enderdragon/listener/DragonAttackListener.java new file mode 100644 index 0000000..de53154 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/DragonAttackListener.java @@ -0,0 +1,45 @@ +package pers.xanadu.enderdragon.listener; + +import org.bukkit.entity.*; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.potion.PotionEffect; +import pers.xanadu.enderdragon.manager.DragonManager; +import pers.xanadu.enderdragon.util.ExtraPotionEffect; +import pers.xanadu.enderdragon.util.MyDragon; + +public class DragonAttackListener implements Listener { + @EventHandler(priority = EventPriority.LOW) + public void OnDragonAttack(final EntityDamageByEntityEvent e){ + Entity victim = e.getEntity(); + Entity attack = e.getDamager(); + if(!(attack instanceof EnderDragon)) return; + EnderDragon dragon = (EnderDragon) attack; + String unique_name = DragonManager.getSpecialKey(dragon); + if(unique_name == null) return; + MyDragon myDragon = DragonManager.mp.get(unique_name); + if(myDragon == null) return; + e.setDamage(Math.max(0.1, e.getDamage() + myDragon.attack_damage_modify)); + if(victim instanceof Player){ + Player player = (Player) victim; + for(PotionEffect effect : myDragon.attack_potion_effect){ + player.addPotionEffect(effect); + } + for(ExtraPotionEffect effect : myDragon.attack_extra_effect){ + effect.apply(player); + } + if(!myDragon.suck_blood_enable) return; + double suck = e.getFinalDamage() * myDragon.suck_blood_rate + myDragon.suck_blood_base_amount; + dragon.setHealth(Math.min(dragon.getHealth()+suck,dragon.getMaxHealth())); + } + else{ + if(!myDragon.suck_blood_enable) return; + if(myDragon.suck_blood_only_player) return; + double suck = e.getFinalDamage() * myDragon.suck_blood_rate + myDragon.suck_blood_base_amount; + dragon.setHealth(Math.min(dragon.getHealth()+suck,dragon.getMaxHealth())); + } + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/listener/DragonBaseHurtListener.java b/src/main/java/pers/xanadu/enderdragon/listener/DragonBaseHurtListener.java new file mode 100644 index 0000000..50e7289 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/DragonBaseHurtListener.java @@ -0,0 +1,33 @@ +package pers.xanadu.enderdragon.listener; + +import org.bukkit.entity.*; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import pers.xanadu.enderdragon.event.DragonDamageByPlayerEvent; + +import static pers.xanadu.enderdragon.EnderDragon.pm; + +public class DragonBaseHurtListener implements Listener { + @EventHandler(priority = EventPriority.HIGHEST) + public void BaseAttackToDragon(EntityDamageByEntityEvent e){ + if(e.isCancelled()) return; + if(e.getDamage() <= 0.0) return; + Entity victim = e.getEntity(); + Entity entity = e.getDamager(); + if(victim instanceof EnderDragon){ + EnderDragon dragon = (EnderDragon) victim; + if(entity instanceof Player){ + Player player = (Player) entity; + pm.callEvent(new DragonDamageByPlayerEvent(player,dragon,e.getCause(),e.getFinalDamage())); + } + else if(entity instanceof Projectile){ + Projectile projectile = (Projectile) entity; + if(!(projectile.getShooter() instanceof Player)) return; + Player damager = (Player) projectile.getShooter(); + pm.callEvent(new DragonDamageByPlayerEvent(damager,dragon,e.getCause(),e.getFinalDamage())); + } + } + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/listener/DragonDamageByPlayerListener.java b/src/main/java/pers/xanadu/enderdragon/listener/DragonDamageByPlayerListener.java new file mode 100644 index 0000000..c84fe1b --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/DragonDamageByPlayerListener.java @@ -0,0 +1,60 @@ +package pers.xanadu.enderdragon.listener; + +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import pers.xanadu.enderdragon.config.Config; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.event.DragonDamageByPlayerEvent; +import pers.xanadu.enderdragon.manager.DamageManager; + +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +public class DragonDamageByPlayerListener implements Listener { + + @EventHandler(priority = EventPriority.HIGHEST) + public void OnDragonDamageByPlayer(final DragonDamageByPlayerEvent e){ + Player p = e.getDamager(); + EnderDragon dragon = e.getDragon(); + double health = dragon.getHealth(); + double damage = Math.min(e.getFinalDamage(),health); + if(damage > 0.0d){ + UUID dragon_uid = dragon.getUniqueId(); + ConcurrentHashMap mp = DamageManager.data.computeIfAbsent(dragon_uid, k->new ConcurrentHashMap<>()); + mp.compute(p.getName(),(k,v)->v==null?damage:v+damage); + } + //Bukkit.broadcastMessage(RewardManager.data.get(dragon.getUniqueId()).get(p.getUniqueId())+""); + double max_health = dragon.getMaxHealth(); + double remain_health = Math.max(health-e.getFinalDamage(),0.0); + String str = Lang.dragon_damage_display.replaceAll("%damage%", format(damage)).replaceAll("%remain_health%",format(remain_health)).replaceAll("%max_health%",format(max_health)); + switch (Config.damage_visible_mode.toLowerCase()){ + case "actionbar" : { + p.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(str)); + break; + } + case "chatbox" : { + Lang.sendFeedback(p,str); + break; + } + case "subtitle" : { + p.sendTitle("",str,5,40,5); + break; + } + default : { + + } + + } + } + + private String format(double d0){ + return String.format("%.2f",d0); + } + +} + diff --git a/src/main/java/pers/xanadu/enderdragon/listener/DragonDeathListener.java b/src/main/java/pers/xanadu/enderdragon/listener/DragonDeathListener.java new file mode 100644 index 0000000..43cad70 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/DragonDeathListener.java @@ -0,0 +1,163 @@ +package pers.xanadu.enderdragon.listener; + +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.EnderDragon; +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.EntityDeathEvent; +import org.bukkit.scheduler.BukkitRunnable; +import pers.xanadu.enderdragon.config.Config; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.manager.DamageManager; +import pers.xanadu.enderdragon.manager.DragonManager; +import pers.xanadu.enderdragon.manager.TimerManager; +import pers.xanadu.enderdragon.util.MyDragon; +import pers.xanadu.enderdragon.util.Pair; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +import static pers.xanadu.enderdragon.EnderDragon.*; + +public class DragonDeathListener implements Listener { + @EventHandler + public void OnDragonDeath(final EntityDeathEvent e){ + if(!(e.getEntity() instanceof EnderDragon)) return; + EnderDragon dragon = (EnderDragon) e.getEntity(); + String unique_name = DragonManager.getSpecialKey(dragon); + if(unique_name == null) return; + MyDragon myDragon = DragonManager.mp.get(unique_name); + if(myDragon == null) return; + int times = data.getInt("times"); + data.set("times",times+1); + try{ + data.save(dataF); + }catch (IOException ex){ + Lang.error(Lang.plugin_file_save_error.replaceAll("\\{file_name}",dataF.getName())); + } + e.setDroppedExp(myDragon.exp_drop); + if(myDragon.dragon_egg_spawn_chance > ThreadLocalRandom.current().nextDouble(100)){ + new BukkitRunnable() { + @Override + public void run() { + Block block = e.getEntity().getWorld().getBlockAt(myDragon.dragon_egg_spawn_x, myDragon.dragon_egg_spawn_y, myDragon.dragon_egg_spawn_z); + block.setType(Material.DRAGON_EGG); + } + }.runTaskLater(plugin, myDragon.dragon_egg_spawn_delay); + } + Player p = e.getEntity().getKiller(); + myDragon.reward_dist.handle_dist(myDragon,dragon,p); + { + List processed = new ArrayList<>(); + if(p != null){ + for(String str : myDragon.death_broadcast_msg){ + processed.add(str.replaceAll("%times%",String.valueOf(times)).replaceAll("%player%",p.getDisplayName())); + } + } + else{ + StringBuilder names = new StringBuilder(); + List entities = dragon.getNearbyEntities(5,5,5); + for (Entity entity : entities) { + if (entity instanceof Player) { + names.append(((Player) entity).getDisplayName()).append(","); + } + } + String name = names.toString(); + if(name.equals("")) name = Lang.dragon_no_killer; + if(name.endsWith(",")) name = name.substring(0,name.length()-1); + for(String str : myDragon.death_broadcast_msg){ + processed.add(str.replaceAll("%times%",String.valueOf(times)).replaceAll("%player%", name)); + } + } + handleBroadcast(processed,myDragon,dragon); + } + DamageManager.data.remove(dragon.getUniqueId()); + Lang.runCommands(myDragon.death_cmd,p); + if(p != null){ + for(String str : myDragon.msg_to_killer){ + Lang.sendFeedback(p,str.replaceAll("%times%",String.valueOf(times))); + } + } + TimerManager.startTimer(dragon.getWorld().getName()); + } + public static void handleBroadcast(final List list,final MyDragon myDragon,final EnderDragon dragon){ + boolean find = false; + for(String str : list){ + if(str.contains("{damage_statistics}")){ + find = true; + break; + } + } + if(!find) Lang.broadcastMSG(list); + else{ + final TextComponent hover = getHover(myDragon,dragon); + for(String str : list){ + final String[] splits = str.split("\\{damage_statistics}"); + final ComponentBuilder builder = new ComponentBuilder(Lang.plugin_prefix); + int size = splits.length; + for(int i=0;ip.spigot().sendMessage(builder.create())); + } + } + } + public static TextComponent getHover(final MyDragon myDragon,final EnderDragon dragon) { + final TextComponent text = new TextComponent(Lang.dragon_damage_statistics_text); + List> list = DamageManager.getDamageList(dragon.getUniqueId()); + list.sort(DamageManager::sortByDamage); + double sum = 0d; + for(Pair pair : list){ + sum += pair.second; + } + StringBuilder builder = new StringBuilder(); + for(String raw : Lang.dragon_damage_statistics_hover_prefix){ + builder.append(raw + .replaceAll("%dragon_display_name%",myDragon.display_name) + .replaceAll("%damage_sum%",String.format("%.2f",sum)) + ).append("\n"); + } + int i = 0; + for(Pair pair : list){ + String raw = Lang.dragon_damage_statistics_hover_mt; + if(i < Config.damage_statistics_limit){ + double damage = pair.second; + double percent = damage/sum*100; + builder.append(raw + .replaceAll("%rank%", String.valueOf(++i)) + .replaceAll("%player%", pair.first) + .replaceAll("%damage%",String.format("%.2f",damage)) + .replaceAll("%percent%",String.format("%.2f%%",percent)) + ).append("\n"); + } + } + if(list.size()-i>0){ + String raw = Lang.dragon_damage_statistics_hover_exceeds_limit; + builder.append(raw + .replaceAll("%exceeds_number%", String.valueOf(list.size()-i)) + ).append("\n"); + } + for(String raw : Lang.dragon_damage_statistics_hover_suffix){ + builder.append(raw + .replaceAll("%dragon_display_name%",myDragon.display_name) + .replaceAll("%damage_sum%",String.format("%.2f",sum)) + ); + } + BaseComponent[] cmp = new ComponentBuilder(builder.toString()).create(); + text.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT,cmp)); + return text; + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/listener/DragonExplosionHurtListener.java b/src/main/java/pers/xanadu/enderdragon/listener/DragonExplosionHurtListener.java new file mode 100644 index 0000000..b68d63b --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/DragonExplosionHurtListener.java @@ -0,0 +1,93 @@ +package pers.xanadu.enderdragon.listener; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityDamageByBlockEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.player.PlayerBedEnterEvent; +import pers.xanadu.enderdragon.event.DragonDamageByPlayerEvent; +import pers.xanadu.enderdragon.event.PlayerExplodeDragonEvent; + +import java.util.Collection; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +import static pers.xanadu.enderdragon.EnderDragon.pm; +import static pers.xanadu.enderdragon.manager.WorldManager.getExplosionDragon; + +public class DragonExplosionHurtListener implements Listener { + + private static final ConcurrentHashMap mp = new ConcurrentHashMap<>(); + + @EventHandler(priority = EventPriority.HIGHEST) + public void OnDragonDamageByTNT(final EntityDamageByEntityEvent e){ + if(e.isCancelled()) return; + if(e.getDamage() <= 0.0) return; + Entity victim = e.getEntity(); + Entity entity = e.getDamager(); + if(victim instanceof EnderDragon){ + EnderDragon dragon = (EnderDragon) victim; + if(entity instanceof TNTPrimed){ + TNTPrimed tnt = (TNTPrimed) entity; + if(!(tnt.getSource() instanceof Player)) return; + Player damager = (Player) tnt.getSource(); + pers.xanadu.enderdragon.EnderDragon.pm.callEvent(new DragonDamageByPlayerEvent(damager,dragon,e.getCause(),e.getFinalDamage())); + } + } + } + + /** + * 用tnt隔着方块炸龙也能触发 + */ + @EventHandler(priority = EventPriority.HIGHEST) + public void OnDragonDamageByExplode(final EntityDamageByBlockEvent e){ + long time = pers.xanadu.enderdragon.EnderDragon.getInstance().getWorldDataManager().getGameTime(e.getEntity().getWorld()); + EntityDamageEvent.DamageCause cause = e.getCause(); + if(e.getCause() != EntityDamageEvent.DamageCause.BLOCK_EXPLOSION) return; + Entity entity = e.getEntity(); + if(entity instanceof EnderDragon){ + //Bukkit.broadcastMessage(e.getFinalDamage()+"awa"); + EnderDragon dragon = (EnderDragon) entity; + for(UUID uuid : mp.keySet()){ + PlayerExplodeDragonEvent ped = mp.get(uuid); + if(ped == null) continue; + if(ped.getTime() != time) continue; + if(ped.getEnderDragon().getUniqueId() != dragon.getUniqueId()) continue; + //mp.remove(uuid); + pm.callEvent(new DragonDamageByPlayerEvent(ped.getPlayer(),dragon,cause,e.getFinalDamage())); + //Bukkit.broadcastMessage("final: "+e.getFinalDamage()); + break; + } + } + } + @EventHandler(priority = EventPriority.HIGH) + public void OnPlayerClickBed(final PlayerBedEnterEvent e){ + Player p = e.getPlayer(); + if(p.getWorld().getEnvironment() != World.Environment.THE_END) return; + long time = pers.xanadu.enderdragon.EnderDragon.getInstance().getWorldDataManager().getGameTime(e.getPlayer().getWorld()); + Location bed_loc = e.getBed().getLocation(); + Collection entities = getExplosionDragon(5f,bed_loc); + for(EnderDragon dragon : entities){ + UUID uuid = p.getUniqueId(); + mp.put(uuid,new PlayerExplodeDragonEvent(time,p,dragon,bed_loc)); + break; + } + } + + + public static void clearUID(final UUID uuid){ + mp.remove(uuid); + } + public static void addUID(final UUID uuid,final PlayerExplodeDragonEvent ped){ + mp.put(uuid,ped); + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/listener/DragonFireballListener.java b/src/main/java/pers/xanadu/enderdragon/listener/DragonFireballListener.java new file mode 100644 index 0000000..c26ec98 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/DragonFireballListener.java @@ -0,0 +1,66 @@ +package pers.xanadu.enderdragon.listener; + +import org.bukkit.Bukkit; +import org.bukkit.Color; +import org.bukkit.Particle; +import org.bukkit.entity.AreaEffectCloud; +import org.bukkit.entity.DragonFireball; +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.Projectile; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EnderDragonChangePhaseEvent; +import org.bukkit.event.entity.EntitySpawnEvent; +import org.bukkit.event.entity.ProjectileLaunchEvent; +import org.bukkit.potion.PotionEffect; +import org.bukkit.projectiles.ProjectileSource; +import pers.xanadu.enderdragon.util.MyDragon; + +import static pers.xanadu.enderdragon.manager.DragonManager.getSpecialKey; +import static pers.xanadu.enderdragon.manager.DragonManager.mp; + +public class DragonFireballListener implements Listener { + + @EventHandler + public void OnDragonChangePhase(EnderDragonChangePhaseEvent e){ + //Bukkit.broadcastMessage("old: "+e.getCurrentPhase()); + //Bukkit.broadcastMessage("new: "+e.getNewPhase()); + } + @EventHandler + public void OnDragonFireballLaunch(ProjectileLaunchEvent e){ + Projectile projectile = e.getEntity(); + if(!(projectile instanceof DragonFireball)) return; + Bukkit.broadcastMessage("DragonFireball launched!"); + DragonFireball fireball = (DragonFireball) e.getEntity(); + ProjectileSource source = projectile.getShooter(); + if(source instanceof EnderDragon){ + Bukkit.broadcastMessage("status set!"); + } + + } + + @EventHandler(priority = EventPriority.HIGH) + public void OnEffectCloudSpawn(final EntitySpawnEvent e){ + if(!(e.getEntity() instanceof AreaEffectCloud)) return; + AreaEffectCloud effectCloud = (AreaEffectCloud) e.getEntity(); + if(effectCloud.getSource() == null) return; + if(!(effectCloud.getSource() instanceof EnderDragon)) return; + EnderDragon dragon = (EnderDragon) effectCloud.getSource(); + String unique_name = getSpecialKey(dragon); + if(unique_name == null) return; + MyDragon myDragon = mp.get(unique_name); + if(myDragon == null) return; + effectCloud.setRadius((float) myDragon.effect_cloud_original_radius); + effectCloud.setRadiusPerTick((float) myDragon.effect_cloud_expand_speed/20f); + effectCloud.setDuration(myDragon.effect_cloud_duration * 20); + if(myDragon.effect_cloud_color_R != -1){ + effectCloud.setParticle(Particle.SPELL_MOB); + effectCloud.setColor(Color.fromRGB(myDragon.effect_cloud_color_R,myDragon.effect_cloud_color_G,myDragon.effect_cloud_color_B)); + } + effectCloud.clearCustomEffects(); + for(PotionEffect effect : myDragon.effect_cloud_potion){ + effectCloud.addCustomEffect(effect,true); + } + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/listener/DragonHealListener.java b/src/main/java/pers/xanadu/enderdragon/listener/DragonHealListener.java new file mode 100644 index 0000000..60351d4 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/DragonHealListener.java @@ -0,0 +1,26 @@ +package pers.xanadu.enderdragon.listener; + +import org.bukkit.entity.EnderDragon; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityRegainHealthEvent; +import pers.xanadu.enderdragon.util.MyDragon; + +import static pers.xanadu.enderdragon.manager.DragonManager.getSpecialKey; +import static pers.xanadu.enderdragon.manager.DragonManager.mp; + +public class DragonHealListener implements Listener { + @EventHandler(priority = EventPriority.HIGH) + public void OnDragonHeal(final EntityRegainHealthEvent e){ + if(!(e.getEntity() instanceof EnderDragon)) return; + EnderDragon dragon = (EnderDragon) e.getEntity(); + if(!e.getRegainReason().equals(EntityRegainHealthEvent.RegainReason.ENDER_CRYSTAL)) return; + String unique_name = getSpecialKey(dragon); + if(unique_name == null) return; + MyDragon myDragon = mp.get(unique_name); + if(myDragon == null) return; + e.setAmount(myDragon.crystal_heal_speed / 2d); + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/listener/DragonSpawnListener.java b/src/main/java/pers/xanadu/enderdragon/listener/DragonSpawnListener.java new file mode 100644 index 0000000..005997c --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/DragonSpawnListener.java @@ -0,0 +1,71 @@ +package pers.xanadu.enderdragon.listener; + +import org.bukkit.attribute.Attribute; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarStyle; +import org.bukkit.boss.BossBar; +import org.bukkit.entity.*; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.CreatureSpawnEvent; +import pers.xanadu.enderdragon.config.Config; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.manager.DamageManager; +import pers.xanadu.enderdragon.util.MyDragon; +import pers.xanadu.enderdragon.util.Version; + +import java.util.concurrent.ConcurrentHashMap; + +import static pers.xanadu.enderdragon.EnderDragon.*; +import static pers.xanadu.enderdragon.manager.DragonManager.*; +import static pers.xanadu.enderdragon.manager.GlowManager.*; + +public class DragonSpawnListener implements Listener { + @EventHandler(priority = EventPriority.LOW) + public void OnDragonSpawn(final CreatureSpawnEvent e){ + if(!(e.getEntity() instanceof EnderDragon)) return; + if(Config.blacklist_worlds.contains(e.getEntity().getWorld().getName())) return; + EnderDragon dragon = (EnderDragon) e.getEntity(); + MyDragon myDragon = judge(); + if(myDragon == null) { + Lang.warn("special_dragon_jude_mode setting error!"); + return; + } + setSpecialKey(dragon, myDragon.unique_name); + DamageManager.data.put(dragon.getUniqueId(),new ConcurrentHashMap<>()); + int times = data.getInt("times"); + Lang.runCommands(myDragon.spawn_cmd); + for(String str : myDragon.spawn_broadcast_msg){ + Lang.broadcastMSG(str.replaceAll("%times%",String.valueOf(times))); + } + dragon.setCustomName(myDragon.display_name); + setAttribute(dragon, Attribute.GENERIC_MAX_HEALTH, myDragon.max_health); + dragon.setHealth(myDragon.spawn_health); + dragon.setMaximumNoDamageTicks(myDragon.no_damage_tick); + + //modifyAttribute(dragon, Attribute.GENERIC_MOVEMENT_SPEED, myDragon.move_speed_modify);// + + modifyAttribute(dragon, Attribute.GENERIC_ARMOR, myDragon.armor_modify); + + modifyAttribute(dragon, Attribute.GENERIC_ARMOR_TOUGHNESS, myDragon.armor_toughness_modify); + String color = myDragon.glow_color.toUpperCase(); + if(!color.equals("NONE")) setGlowingColor(dragon,getGlowColor(color)); + else dragon.setGlowing(false); + String bossBar_color = myDragon.bossbar_color.toUpperCase(); + String bossBar_style = myDragon.bossbar_style.toUpperCase(); + + if(Version.mcMainVersion >= 14){ + BossBar bossBar = dragon.getBossBar(); + if(bossBar != null){ + bossBar.setColor(BarColor.valueOf(bossBar_color)); + bossBar.setStyle(BarStyle.valueOf(bossBar_style)); + } + } + else if(Version.mcMainVersion >= 12){ + getInstance().getBossBarManager().setBossBar(dragon.getWorld(),myDragon.display_name,bossBar_color,bossBar_style); + } + //dragon.getMetadata(); + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/listener/EndGatewayListener.java b/src/main/java/pers/xanadu/enderdragon/listener/EndGatewayListener.java new file mode 100644 index 0000000..e3bbbce --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/EndGatewayListener.java @@ -0,0 +1,21 @@ +package pers.xanadu.enderdragon.listener; + +import org.bukkit.entity.Item; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerDropItemEvent; + +public class EndGatewayListener implements Listener { +// @EventHandler +// public void OnEndGateWaySpawn(final PortalCreateEvent e){ +// Bukkit.broadcastMessage("123"); +// List list = e.getBlocks(); +// list.forEach(block -> Bukkit.broadcastMessage(block.toString())); +// } +// @EventHandler +// public void OnEndGateWaySpawn2(final EntityCreatePortalEvent e){ +// Bukkit.broadcastMessage("12345"); +// +// } +} + diff --git a/src/main/java/pers/xanadu/enderdragon/listener/InventoryListener.java b/src/main/java/pers/xanadu/enderdragon/listener/InventoryListener.java new file mode 100644 index 0000000..7ce64c2 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/InventoryListener.java @@ -0,0 +1,123 @@ +package pers.xanadu.enderdragon.listener; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryDragEvent; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.PlayerInventory; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.gui.*; +import pers.xanadu.enderdragon.gui.holder.Menu; +import pers.xanadu.enderdragon.gui.holder.MenuEditor; +import pers.xanadu.enderdragon.gui.slot.PageJumpSlot; +import pers.xanadu.enderdragon.manager.DragonManager; +import pers.xanadu.enderdragon.manager.GuiManager; +import pers.xanadu.enderdragon.manager.RewardManager; +import pers.xanadu.enderdragon.util.MyDragon; + +public class InventoryListener implements Listener { + @EventHandler(priority = EventPriority.LOWEST) + public void OnInventoryClick(final InventoryClickEvent e){ + InventoryHolder holder = e.getInventory().getHolder(); + if(!(holder instanceof GUIHolder)) return; + GUIHolder guiHolder = (GUIHolder) holder; + if(!(guiHolder.getGUI() instanceof GUIWrapper)) return; + e.setCancelled(true); + GUIWrapper guiWrapper = (GUIWrapper) guiHolder.getGUI(); + if(e.getClickedInventory() instanceof PlayerInventory){ + return; + } + if(e.getRawSlot() >= 54 || e.getRawSlot() < 0){ //点击箱子以外界面会返回-999 + return; + } + Player p = (Player) e.getWhoClicked(); + GUISlot slot = guiWrapper.getSlot(e.getRawSlot()); + GUISlotType type = slot.getType(); + if(type == GUISlotType.EMPTY || type == GUISlotType.TIP || type == GUISlotType.PAGE_TIP){ + return; + } + if(type == GUISlotType.PAGE_PREV){ + guiWrapper.prev(); + p.updateInventory(); + return; + } + if(type == GUISlotType.PAGE_NEXT){ + guiWrapper.next(); + p.updateInventory(); + return; + } + + if(holder instanceof Menu){ + if(e.getClick() != ClickType.LEFT && e.getClick() != ClickType.RIGHT){ + return; + } + if(type == GUISlotType.ITEM_SLOT){ + return; + } + if(type == GUISlotType.PAGE_JUMP){ + String name = ((PageJumpSlot)slot).getGuiName(); + GuiManager.openGui(p,name,false); + return; + } + if(type == GUISlotType.DRAGON_SLOT){ + String unique_name = guiWrapper.getData(guiWrapper.getPage(),e.getRawSlot()); + MyDragon dragon = DragonManager.mp.get(unique_name); + if(dragon == null){ + Lang.sendFeedback(p,Lang.gui_not_found); + return; + } + GuiManager.openGui(p,dragon.drop_gui,dragon.unique_name,false); + return; + } + } + else if(holder instanceof MenuEditor){ + MenuEditor menuEditor = (MenuEditor) holder; + if(e.getClick() != ClickType.LEFT && e.getClick() != ClickType.RIGHT && e.getClick() != ClickType.SHIFT_RIGHT){ + return; + } + if(type == GUISlotType.ITEM_SLOT){ + if(e.getClick() != ClickType.SHIFT_RIGHT) return; + int idx = guiWrapper.getPage()*guiWrapper.getItemSize()+guiWrapper.getItemSlotIdx(e.getRawSlot()); + //Bukkit.broadcastMessage(idx+""); + boolean b = RewardManager.removeItem(menuEditor.getDragon_key(),idx); + if(b) { + p.sendMessage(Lang.command_drop_item_remove_succeed); + guiWrapper.updateItemChanges(true); + } + else p.sendMessage(Lang.command_drop_item_remove_fail); + return; + } + if(type == GUISlotType.PAGE_JUMP){ + String name = ((PageJumpSlot)slot).getGuiName(); + GuiManager.openGui(p,name,true); + return; + } + if(type == GUISlotType.DRAGON_SLOT){ + String unique_name = guiWrapper.getData(guiWrapper.getPage(),e.getRawSlot()); + MyDragon dragon = DragonManager.mp.get(unique_name); + if(dragon == null){ + Lang.sendFeedback(p,Lang.gui_not_found); + return; + } + GuiManager.openGui(p,dragon.drop_gui,dragon.unique_name,true); + return; + } + } + + } + @EventHandler(priority = EventPriority.LOWEST) + public void OnInventoryDrag(final InventoryDragEvent e){ + InventoryHolder holder = e.getInventory().getHolder(); + if(!(holder instanceof GUIHolder)) return; + if(holder instanceof Menu){ + GUIHolder guiHolder = (GUIHolder) holder; + if(!(guiHolder.getGUI() instanceof GUIWrapper)) return; + e.setCancelled(true); + } + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/listener/PlayerListener.java b/src/main/java/pers/xanadu/enderdragon/listener/PlayerListener.java new file mode 100644 index 0000000..930299d --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/PlayerListener.java @@ -0,0 +1,83 @@ +package pers.xanadu.enderdragon.listener; + +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.*; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.ItemStack; +import pers.xanadu.enderdragon.config.Config; +import pers.xanadu.enderdragon.manager.GlowManager; + +import java.util.Collection; + +public class PlayerListener implements Listener { + @EventHandler + public void onPlayerJoin(final PlayerJoinEvent e){ + Player p = e.getPlayer(); + GlowManager.setScoreBoard(p); + } + + @EventHandler + public void onPlayerQuit(final PlayerQuitEvent e){ + DragonExplosionHurtListener.clearUID(e.getPlayer().getUniqueId()); + } + + @EventHandler(priority = EventPriority.HIGHEST) + public void OnCrystalPlaced(final PlayerInteractEvent e){ + if(!Config.resist_player_respawn) return; + if(e.getAction() != Action.RIGHT_CLICK_BLOCK) return; + if(e.getMaterial() != Material.END_CRYSTAL) return; + if(e.getClickedBlock() == null) return; + Material blockType = e.getClickedBlock().getType(); + if(blockType != Material.OBSIDIAN && blockType != Material.BEDROCK) return; + World world = e.getPlayer().getWorld(); + if(world.getEnvironment() != World.Environment.THE_END) return; + Block block = e.getClickedBlock(); + int d0 = block.getX(); + int d1 = block.getY() + 1; + int d2 = block.getZ(); + if(world.getBlockAt(d0, d1, d2).getType() != Material.AIR) return; + Location cen = block.getLocation().clone().add(0.5,1,0.5); + Collection list = world.getNearbyEntities(cen,0.5,1,0.5); + if(!list.isEmpty()) return; + e.setCancelled(true); + if(e.getPlayer().getGameMode() != GameMode.CREATIVE){ + ItemStack item = e.getItem(); + assert item != null; + int amount = item.getAmount(); + e.getItem().setAmount(amount-1); + } + EnderCrystal crystal = (EnderCrystal) world.spawnEntity(cen,EntityType.ENDER_CRYSTAL); + crystal.setShowingBottom(false); + } + + @EventHandler(priority = EventPriority.LOW) + public void OnDragonBreathGather(final PlayerInteractEvent e){ + if(!Config.resist_dragon_breath_gather) return; + if(e.getMaterial() != Material.GLASS_BOTTLE) return; + if(e.getAction() != Action.RIGHT_CLICK_BLOCK && e.getAction() != Action.RIGHT_CLICK_AIR) return; + World world = e.getPlayer().getWorld(); + if(world.getEnvironment() != World.Environment.THE_END) return; + Player p = e.getPlayer(); + Location cen = p.getLocation().clone().add(0d,0.9d,0d); + Collection list = world.getNearbyEntities(cen,2.3d,2.9d,2.3d); + for(Entity entity : list){ + if(entity instanceof AreaEffectCloud) { + AreaEffectCloud effectCloud = (AreaEffectCloud) entity; + if(effectCloud.getSource() instanceof EnderDragon){ + e.setCancelled(true); + break; + } + } + } + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/listener/PluginDisableListener.java b/src/main/java/pers/xanadu/enderdragon/listener/PluginDisableListener.java new file mode 100644 index 0000000..d7bbc47 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/PluginDisableListener.java @@ -0,0 +1,16 @@ +package pers.xanadu.enderdragon.listener; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.server.PluginDisableEvent; + +import static pers.xanadu.enderdragon.EnderDragon.*; + +public class PluginDisableListener implements Listener { + @EventHandler + public void OnPluginDisable(final PluginDisableEvent e){ + if(e.getPlugin().equals(plugin)){ + disableAll(); + } + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/listener/RespawnAnchorExplodeListener.java b/src/main/java/pers/xanadu/enderdragon/listener/RespawnAnchorExplodeListener.java new file mode 100644 index 0000000..167e5d7 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/RespawnAnchorExplodeListener.java @@ -0,0 +1,45 @@ +package pers.xanadu.enderdragon.listener; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.data.type.RespawnAnchor; +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.EquipmentSlot; +import pers.xanadu.enderdragon.event.PlayerExplodeDragonEvent; + +import java.util.Collection; +import java.util.UUID; + +import static pers.xanadu.enderdragon.manager.WorldManager.getExplosionDragon; + +public class RespawnAnchorExplodeListener implements Listener { + @EventHandler(priority = EventPriority.HIGH) + public void OnRespawnAnchorExplode(final PlayerInteractEvent e){ + if(e.getAction() != Action.RIGHT_CLICK_BLOCK) return; + Block block = e.getClickedBlock(); + if(block == null || block.getType() != Material.RESPAWN_ANCHOR) return; + RespawnAnchor anchor = (RespawnAnchor) block.getBlockData(); + Player p = e.getPlayer(); + Material offHand = p.getInventory().getItemInOffHand().getType(); + if(e.getHand()== EquipmentSlot.HAND && e.getMaterial()!=Material.GLOWSTONE && offHand==Material.GLOWSTONE) return; + if(e.getMaterial()==Material.GLOWSTONE && anchor.getCharges()<4) return; + if(anchor.getCharges()==0) return; + if(pers.xanadu.enderdragon.EnderDragon.getInstance().getRespawnAnchorManager().isRespawnAnchorWorks(p.getWorld())) return; + if(p.isSneaking() && (p.getItemInHand().getType()!=Material.AIR || offHand!=Material.AIR)) return; + long time = pers.xanadu.enderdragon.EnderDragon.getInstance().getWorldDataManager().getGameTime(e.getPlayer().getWorld()); + Location loc = block.getLocation(); + Collection entities = getExplosionDragon(5f,loc); + for(EnderDragon dragon : entities){ + UUID uuid = p.getUniqueId(); + DragonExplosionHurtListener.addUID(uuid,new PlayerExplodeDragonEvent(time,p,dragon,loc)); + break; + } + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/listener/mythiclib/PlayerAttackListener.java b/src/main/java/pers/xanadu/enderdragon/listener/mythiclib/PlayerAttackListener.java new file mode 100644 index 0000000..f532c66 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/listener/mythiclib/PlayerAttackListener.java @@ -0,0 +1,27 @@ +package pers.xanadu.enderdragon.listener.mythiclib; + +import io.lumine.mythic.lib.api.event.PlayerAttackEvent; +import io.lumine.mythic.lib.damage.DamageMetadata; +import org.bukkit.entity.EnderDragon; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import pers.xanadu.enderdragon.event.DragonDamageByPlayerEvent; + +import static pers.xanadu.enderdragon.EnderDragon.pm; + +public class PlayerAttackListener implements Listener { + @EventHandler(priority = EventPriority.HIGH) + public void onPlayerAttack(final PlayerAttackEvent e){ + if(e.isCancelled()) return; + if(!(e.getEntity() instanceof org.bukkit.entity.EnderDragon)) return; + EnderDragon dragon = (EnderDragon) e.getEntity(); + DamageMetadata damage = e.getDamage(); + double final_damage = damage.getDamage(); + if(final_damage > 0.0d){ + DragonDamageByPlayerEvent event = new DragonDamageByPlayerEvent(e.getAttacker().getPlayer(),dragon, e.toBukkit().getCause(), final_damage); + pm.callEvent(event); + } + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/manager/ActionManager.java b/src/main/java/pers/xanadu/enderdragon/manager/ActionManager.java new file mode 100644 index 0000000..d805594 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/manager/ActionManager.java @@ -0,0 +1,40 @@ +package pers.xanadu.enderdragon.manager; + +import org.bukkit.entity.Player; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.hook.HookManager; +import pers.xanadu.enderdragon.maven.DependencyManager; +import pers.xanadu.enderdragon.util.ColorUtil; + +public class ActionManager { + public static void executeAction(final Player player,final String[] args){ + String raw = getRawText(args,3); + switch (args[2]){ + case "tell:" : { + player.sendMessage(ColorUtil.parse(HookManager.parsePapi(player,raw))); + return; + } + case "tell-colorless:" : { + player.sendMessage(HookManager.parsePapi(player,raw)); + return; + } + case "tell-raw:" : { + player.sendMessage(raw); + return; + } + case "groovy:" : { + if(DependencyManager.isGroovyLoaded()) GroovyManager.eval(raw,player); + else Lang.sendFeedback(player,Lang.expansion_groovy_disable); + return; + } + } + } + private static String getRawText(final String[] args,int from){ + if(from<0 || from>=args.length) throw new IllegalArgumentException("Index out of bounds!"); + StringBuilder sb = new StringBuilder(args[from]); + for(int i=from+1;i> data = new ConcurrentHashMap<>(); + public static List> getDamageList(UUID uuid){ + ConcurrentHashMap mp = data.get(uuid); + List> list = new ArrayList<>(); + if(mp == null) return list; + mp.forEach((k,v)->list.add(new Pair<>(k,v))); + return list; + } + public static int sortByDamage(Pair p1, Pair p2){ + if(p2.second>p1.second) return 1; + if(p2.second.equals(p1.second)) return 0; + return -1; + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/manager/DragonManager.java b/src/main/java/pers/xanadu/enderdragon/manager/DragonManager.java new file mode 100644 index 0000000..20759aa --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/manager/DragonManager.java @@ -0,0 +1,464 @@ +package pers.xanadu.enderdragon.manager; + +import org.bukkit.*; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeInstance; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.boss.DragonBattle; +import org.bukkit.command.CommandSender; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.*; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; +import pers.xanadu.enderdragon.config.Config; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.reward.RewardDist; +import pers.xanadu.enderdragon.util.ExtraPotionEffect; +import pers.xanadu.enderdragon.util.MyDragon; +import pers.xanadu.enderdragon.util.Version; + +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; + +import static pers.xanadu.enderdragon.EnderDragon.*; + +public class DragonManager { + public static ArrayList dragons = new ArrayList<>(); + public static HashMap mp = new HashMap<>(); + public static List dragon_names = new ArrayList<>(); + private static int sum = 0; + private static final int[][] nxt = {{3,0},{0,3},{-3,0},{0,-3}}; + private Method DragonBattle_e; + private Method getX; + private Method getY; + private Method getZ; + + public static void reload(){ + new BukkitRunnable(){ + @Override + public void run(){ + dragons.clear(); + mp.clear(); + dragon_names.clear(); + sum = 0; + if(Config.dragon_setting_file == null){ + Lang.error("\"dragon_setting_file\" in config.yml is empty!"); + Lang.warn("Plugin will use the default config..."); + Config.dragon_setting_file = new ArrayList<>(); + Config.dragon_setting_file.add("default:5"); + Config.dragon_setting_file.add("special:5"); + } + for(String str : Config.dragon_setting_file){ + String[] s = str.split(":"); + if(s.length != 2){ + Lang.error("\"dragon_setting_file\" in config.yml error! Key: " + str); + continue; + } + String path = "setting/" + s[0] + ".yml"; + int edge = -1; + try { + edge = Integer.parseInt(s[1]); + } catch (NumberFormatException ignored){} + if(edge < 0) { + Lang.error("\"dragon_setting_file\" in config.yml error! Key: " + str); + continue; + } + File file = new File(plugin.getDataFolder(),path); + if(!file.exists()) { + try{ + plugin.saveResource("setting/"+file.getName(),false); + file = new File(plugin.getDataFolder(),path); + }catch (Exception ignored){ + Lang.error("Not Found setting/" + s[0] + ".yml ,skipped it."); + continue; + } + } + FileConfiguration fc = YamlConfiguration.loadConfiguration(file); + if(!Version.setting_dragon.equals(fc.getString("version"))){ + Lang.warn(Lang.plugin_wrong_file_version.replace("{file_name}", file.getName())); + } + readSettingFile(fc,edge); + } + dragons.sort((o1, o2) -> o2.priority - o1.priority); + RewardManager.reload(); + } + }.runTaskAsynchronously(plugin); + + } + public static MyDragon judge(){ + if(Config.special_dragon_jude_mode.equalsIgnoreCase("weight")){ + int cnt = 0, random = ThreadLocalRandom.current().nextInt(0, sum); + for(MyDragon cur : dragons){ + if(cnt <= random && cnt + cur.edge > random){ + return cur; + } + cnt += cur.edge; + } + } + else if(Config.special_dragon_jude_mode.equalsIgnoreCase("pc")){ + Iterator it = dragons.iterator(); + MyDragon cur = null; + while (it.hasNext()){ + cur = it.next(); + boolean judge = cur.spawn_chance > ThreadLocalRandom.current().nextDouble(100); + if(judge) return cur; + } + return cur; + } + else if(Config.special_dragon_jude_mode.equalsIgnoreCase("edge")){ + int cnt = 0, random = ThreadLocalRandom.current().nextInt(0, sum); + for(MyDragon cur : dragons){ + if(cnt <= random && cnt + cur.edge > random){ + return cur; + } + cnt += cur.edge; + } + Lang.error("\"edge\" in \"special_dragon_jude_mode\" of config.yml is deprecated!Please use \"weight\" instead."); + } + return null; + } + public static void setSpecialKey(Entity e, String key){ + e.addScoreboardTag(key); + } + public static String getSpecialKey(Entity e){ + for(MyDragon a : dragons){ + if(e.getScoreboardTags().contains(a.unique_name)) return a.unique_name; + } + return null; + } + public static void readSettingFile(FileConfiguration f,int edge){ + MyDragon myDragon = new MyDragon(); + myDragon.unique_name = f.getString("unique_name","default"); + if(mp.containsKey(myDragon.unique_name)){ + Lang.error("The unique_name conflict! Key: "+myDragon.unique_name); + return; + } + myDragon.icon = ItemManager.readFromBukkit(f,"icon"); + myDragon.display_name = f.getString("display_name","Special Dragon"); + myDragon.drop_gui = f.getString("drop_gui"); + myDragon.edge = edge; + myDragon.priority = f.getInt("priority",1); + myDragon.spawn_chance = f.getDouble("spawn_chance",0); + myDragon.max_health = f.getInt("max_health",200); + myDragon.spawn_health = f.getInt("spawn_health",200); + myDragon.no_damage_tick = f.getInt("no_damage_tick",10); + myDragon.exp_drop = f.getInt("exp_drop",500); + myDragon.dragon_egg_spawn_delay = f.getInt("dragon_egg_spawn.delay",410); + myDragon.dragon_egg_spawn_x = f.getInt("dragon_egg_spawn.x",0); + myDragon.dragon_egg_spawn_y = f.getInt("dragon_egg_spawn.y",70); + myDragon.dragon_egg_spawn_z = f.getInt("dragon_egg_spawn.z",0); + myDragon.dragon_egg_spawn_chance = f.getDouble("dragon_egg_spawn.chance",0); + //myDragon.move_speed_modify = f.getDouble("move_speed_modify",0); + myDragon.armor_modify = f.getDouble("armor_modify",0); + myDragon.armor_toughness_modify = f.getDouble("armor_toughness_modify",0); + myDragon.crystal_heal_speed = f.getDouble("crystal_heal_speed",2.0); + + myDragon.attack_damage_modify = f.getDouble("attack.damage_modify",0); + + myDragon.suck_blood_enable = f.getBoolean("suck_blood.enable",true); + myDragon.suck_blood_rate = f.getDouble("suck_blood.rate",50) / 100d; + myDragon.suck_blood_base_amount = f.getDouble("suck_blood.base_amount",1); + myDragon.suck_blood_only_player = f.getBoolean("suck_blood.only_player",true); + + List extraEffect = new ArrayList<>(); + int fire = f.getInt("attack.extra_effect.fire"); + if(fire>0) extraEffect.add(new ExtraPotionEffect(ExtraPotionEffect.ExtraPotionEffectType.fire,fire)); + if(Version.mcMainVersion >= 17){ + int freeze = f.getInt("attack.extra_effect.freeze"); + if(freeze>0) extraEffect.add(new ExtraPotionEffect(ExtraPotionEffect.ExtraPotionEffectType.freeze,freeze)); + } + myDragon.attack_extra_effect = extraEffect; + + List stringList = f.getStringList("attack.potion_effect"); + List potions = new ArrayList<>(); + for(String string : stringList){ + String[] s = string.split(" "); + if(s.length != 3) continue; + PotionEffectType type = PotionEffectType.getByName(s[0].toUpperCase()); + if(type == null){ + Lang.error("Unknown potion type: " + s[0]); + continue; + } + int duration = -1; + try { + duration = Integer.parseInt(s[1]); + } catch (NumberFormatException ex){ + Lang.error("Wrong number format: " + s[1]); + } + if(duration == -1) continue; + int level = -1; + try { + level = Integer.parseInt(s[2]); + } catch (NumberFormatException ex){ + Lang.error("Wrong number format: " + s[2]); + } + if(level == -1) continue; + PotionEffect potionEffect = new PotionEffect(type,duration*20,level-1); + potions.add(potionEffect); + } + myDragon.attack_potion_effect = potions; + myDragon.spawn_cmd = f.getStringList("spawn_cmd"); + myDragon.death_cmd = f.getStringList("death_cmd"); + myDragon.spawn_broadcast_msg = f.getStringList("spawn_broadcast_msg"); + myDragon.death_broadcast_msg = f.getStringList("death_broadcast_msg"); + myDragon.msg_to_killer = f.getStringList("msg_to_killer"); + myDragon.glow_color = f.getString("glow_color","random"); + myDragon.bossbar_color = f.getString("bossbar.color","WHITE"); + myDragon.bossbar_style = f.getString("bossbar.style","SOLID"); + myDragon.effect_cloud_original_radius = f.getDouble("effect_cloud.original_radius",3); + myDragon.effect_cloud_expand_speed = f.getDouble("effect_cloud.expand_speed",0.1333333); + myDragon.effect_cloud_duration = f.getInt("effect_cloud.duration",60); + String effect_cloud_color = f.getString("effect_cloud.color","none"); + String[] s0 = effect_cloud_color.split(":"); + if(s0.length != 3) myDragon.effect_cloud_color_R = -1; + else{ + try{ + myDragon.effect_cloud_color_R = Integer.parseInt(s0[0]); + myDragon.effect_cloud_color_G = Integer.parseInt(s0[1]); + myDragon.effect_cloud_color_B = Integer.parseInt(s0[2]); + } + catch (NumberFormatException e){ + Lang.error("Wrong effect_cloud_color format!"); + myDragon.effect_cloud_color_R = -1; + } + } + List stringList2 = f.getStringList("effect_cloud.potion"); + List effectCloudPotions = new ArrayList<>(); + for(String string : stringList2){ + String[] s = string.split(" "); + if(s.length != 3) continue; + PotionEffectType type = PotionEffectType.getByName(s[0].toUpperCase()); + if(type == null){ + Lang.error("Unknown potion type: " + s[0]); + continue; + } + int duration = -1; + try { + duration = Integer.parseInt(s[1]); + } catch (NumberFormatException ex){ + Lang.error("Wrong number format: " + s[1]); + } + if(duration == -1) continue; + int level = -1; + try { + level = Integer.parseInt(s[2]); + } catch (NumberFormatException ex){ + Lang.error("Wrong number format: " + s[2]); + } + if(level == -1) continue; + PotionEffect potionEffect = new PotionEffect(type,duration*20,level-1); + effectCloudPotions.add(potionEffect); + } + myDragon.effect_cloud_potion = effectCloudPotions; + myDragon.reward_dist = RewardDist.parse(f.getConfigurationSection("reward_dist")); + dragons.add(myDragon); + mp.put(myDragon.unique_name,myDragon); + dragon_names.add(myDragon.unique_name); + sum += edge; + } + public static void disable(){ + dragons.clear(); + mp.clear(); + dragon_names.clear(); + } + + public static void setAttribute(final EnderDragon dragon,final Attribute attribute, double amount){ + AttributeInstance instance = dragon.getAttribute(attribute); + assert instance != null; + instance.setBaseValue(amount); + } + public static void modifyAttribute(final EnderDragon dragon,final Attribute attribute, double amount){ + AttributeInstance instance = dragon.getAttribute(attribute); + assert instance != null; + instance.addModifier(new AttributeModifier("EnderDragon",amount,AttributeModifier.Operation.ADD_NUMBER)); + } + + public void initiateRespawn(final Player p){ + DragonRespawnResult res = initiateRespawn(p.getWorld()); + if(res == DragonRespawnResult.success) Lang.broadcastMSG(Lang.dragon_auto_respawn); + else Lang.sendFeedback(p,"§c"+res.getMessage()); + } + public void initiateRespawn(final CommandSender sender,final String world_name){ + DragonRespawnResult res = initiateRespawn(Bukkit.getWorld(world_name)); + if(res == DragonRespawnResult.success) Lang.broadcastMSG(Lang.dragon_auto_respawn); + else Lang.sendFeedback(sender,"§c"+res.getMessage()); + } + public void initiateRespawn(final String world_name){ + DragonRespawnResult res = initiateRespawn(Bukkit.getWorld(world_name)); + if(res == DragonRespawnResult.success) Lang.broadcastMSG(Lang.dragon_auto_respawn); + else Lang.error(res.getMessage()); + } + public boolean canRespawn(final String world_name){ + return canRespawn(Bukkit.getWorld(world_name)); + } + public boolean canRespawn(final World world){ + if(world == null) return false; + if(world.getEnvironment() != World.Environment.THE_END) return false; + if(Version.mcMainVersion >= 16){//executes 1e5 times within 27ms + DragonBattle battle = world.getEnderDragonBattle(); + if(battle == null) return false; + if(battle.getEnderDragon() != null) return false; + if(battle.getRespawnPhase() != DragonBattle.RespawnPhase.NONE) return false; + Location cen = battle.getEndPortalLocation(); + if(cen == null) { + battle.initiateRespawn(); + cen = battle.getEndPortalLocation(); + if(cen == null){ + return false; + } + } + return true; + } + try {//executes 1e5 times within 76ms + Object battle = getInstance().getNMSManager().getEnderDragonBattle(world); + if(battle == null) return false; + Field k = battle.getClass().getDeclaredField("k"); + k.setAccessible(true); + Object isAlive = k.get(battle); + if(!((boolean) isAlive)) return false; + Field p = battle.getClass().getDeclaredField("p"); + p.setAccessible(true); + Object phase = p.get(battle); + if(phase != null) return false; + Field field = battle.getClass().getDeclaredField("o"); + field.setAccessible(true); + Object BlockPosition = field.get(battle); + if(BlockPosition == null){ + if (this.DragonBattle_e == null) this.DragonBattle_e = battle.getClass().getMethod("e"); + this.DragonBattle_e.invoke(battle); + BlockPosition = field.get(battle); + if(BlockPosition == null) return false; + } + return true; + } catch (ReflectiveOperationException e) { + return false; + } + } + public boolean isRespawnRunning(final World world){ + if(world == null) return false; + if(world.getEnvironment() != World.Environment.THE_END) return false; + if(Version.mcMainVersion >= 16){ + DragonBattle battle = world.getEnderDragonBattle(); + assert battle != null; + return battle.getRespawnPhase() != DragonBattle.RespawnPhase.NONE; + } + try { + Object battle = getInstance().getNMSManager().getEnderDragonBattle(world); + assert battle != null; + Field p = battle.getClass().getDeclaredField("p"); + p.setAccessible(true); + Object phase = p.get(battle); + return phase != null; + } catch (ReflectiveOperationException e) { + e.printStackTrace(); + return false; + } + } + public void refresh_respawn(final World world){ + if(world == null) return; + if(world.getEnvironment() != World.Environment.THE_END) return; + if(Version.mcMainVersion >= 16){ + DragonBattle battle = world.getEnderDragonBattle(); + assert battle != null; + battle.initiateRespawn(); + return; + } + try { + Object battle = getInstance().getNMSManager().getEnderDragonBattle(world); + assert battle != null; + if (this.DragonBattle_e == null) this.DragonBattle_e = battle.getClass().getMethod("e"); + this.DragonBattle_e.invoke(battle); + } catch (ReflectiveOperationException e) { + e.printStackTrace(); + } + } + + private DragonRespawnResult initiateRespawn(final World world){ + if(world == null) return DragonRespawnResult.world_not_found; + if(world.getEnvironment() != World.Environment.THE_END) return DragonRespawnResult.world_wrong_env; + if(Version.mcMainVersion >= 16){ + DragonBattle battle = world.getEnderDragonBattle(); + assert battle != null; + if(battle.getEnderDragon() != null) return DragonRespawnResult.dragon_has_existed; + if(battle.getRespawnPhase() != DragonBattle.RespawnPhase.NONE) return DragonRespawnResult.respawn_has_started; + Location cen = battle.getEndPortalLocation(); + if(cen == null) { + battle.initiateRespawn(); + cen = battle.getEndPortalLocation(); + if(cen == null){ + return DragonRespawnResult.world_unloaded;//也可尝试chunk.load() + } + } + placeEndCrystals(world,cen); + battle.initiateRespawn(); + return DragonRespawnResult.success; + } + try { + Object battle = getInstance().getNMSManager().getEnderDragonBattle(world); + assert battle != null; + Field k = battle.getClass().getDeclaredField("k"); + k.setAccessible(true); + Object isAlive = k.get(battle); + if(!((boolean) isAlive)) return DragonRespawnResult.dragon_has_existed; + Field p = battle.getClass().getDeclaredField("p"); + p.setAccessible(true); + Object phase = p.get(battle); + if(phase != null) return DragonRespawnResult.respawn_has_started; + Field field = battle.getClass().getDeclaredField("o"); + field.setAccessible(true); + Object BlockPosition = field.get(battle); + if(BlockPosition == null){ + if (this.DragonBattle_e == null) this.DragonBattle_e = battle.getClass().getMethod("e"); + this.DragonBattle_e.invoke(battle); + BlockPosition = field.get(battle); + if(BlockPosition == null) return DragonRespawnResult.world_unloaded; + } + if(this.getX == null) this.getX = BlockPosition.getClass().getMethod("getX"); + if(this.getY == null) this.getY = BlockPosition.getClass().getMethod("getY"); + if(this.getZ == null) this.getZ = BlockPosition.getClass().getMethod("getZ"); + Location loc = new Location(world,(int)getX.invoke(BlockPosition),(int)this.getY.invoke(BlockPosition),(int)this.getZ.invoke(BlockPosition)); + placeEndCrystals(world, loc); + if (this.DragonBattle_e == null) this.DragonBattle_e = battle.getClass().getMethod("e"); + this.DragonBattle_e.invoke(battle); + return DragonRespawnResult.success; + } catch (ReflectiveOperationException e) { + return DragonRespawnResult.version_not_support; + } + + } + private void placeEndCrystals(final World world,final Location cen){ + cen.add(0.5,1,0.5); + for(int i = 0; i < 4; i++){ + EnderCrystal crystal = (EnderCrystal) world.spawnEntity(cen.clone().add(nxt[i][0],0,nxt[i][1]), EntityType.ENDER_CRYSTAL); + if(Config.crystal_invulnerable) crystal.setInvulnerable(true); + crystal.setShowingBottom(false); + } + } + public enum DragonRespawnResult{ + success, + world_not_found, + world_unloaded, + world_wrong_env, + respawn_has_started, + dragon_has_existed, + version_not_support; + public String getMessage(){ + switch (this){ + case success: return "Success"; + case world_not_found: return "Can't find this world!"; + case world_unloaded: return "The world_the_end is unloaded."; + case world_wrong_env: return "Respawn only can be called in the End."; + case respawn_has_started: return "The respawning has already started."; + case dragon_has_existed: return "There is already a dragon here."; + case version_not_support: return "Your server version (" + Version.getVersion() + ") is not supported!"; + default: return "Unknown error!"; + } + } + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/manager/GlowManager.java b/src/main/java/pers/xanadu/enderdragon/manager/GlowManager.java new file mode 100644 index 0000000..81b377e --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/manager/GlowManager.java @@ -0,0 +1,76 @@ +package pers.xanadu.enderdragon.manager; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; +import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.scoreboard.Team; +import pers.xanadu.enderdragon.util.Version; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; + +public class GlowManager { + public static Set handled = new HashSet<>(); + public static void reload(){ + handled.clear(); + } + public static void setScoreBoard(Player p){ + Scoreboard board = p.getScoreboard(); + if(handled.contains(board)) return; + ChatColor[] colors = ChatColor.values(); + for(ChatColor color : colors){ + String name = "ed-"+color.name(); + if(board.getTeam(name)==null) board.registerNewTeam(name); + Team team = board.getTeam(name); + assert team != null; + if(Version.mcMainVersion >= 13) team.setColor(color); + else team.setPrefix(color.toString()); + } + handled.add(board); + } + public static void addUUID(String uuid,String color){ + Set teams = new HashSet<>(); + Bukkit.getOnlinePlayers().forEach(player -> { + GlowManager.setScoreBoard(player); + Team team = player.getScoreboard().getTeam("ed-"+color.toUpperCase()); + teams.add(team); + }); + teams.forEach(team->{ + team.addEntry(uuid); + }); + } + public static void setGlowingColor(Entity entity, ChatColor color){ + Set teams = new HashSet<>(); + Bukkit.getOnlinePlayers().forEach(player -> { + GlowManager.setScoreBoard(player); + Team team = player.getScoreboard().getTeam("ed-"+color.name()); + teams.add(team); + }); + teams.forEach(team->{ + team.addEntry(entity.getUniqueId().toString()); + entity.setGlowing(true); + }); + } + public static ChatColor getGlowColor(String str){ + ChatColor chatColor; + if(str.equals("RANDOM")) chatColor = randomColor(); + else chatColor = ChatColor.valueOf(str); + return chatColor; + } + public static ChatColor getGlowColor(GlowColor glowColor){ + if(glowColor == GlowColor.NONE) return null; + if(glowColor == GlowColor.RANDOM) return randomColor(); + return ChatColor.valueOf(glowColor.name()); + } + public static ChatColor randomColor(){ + return ChatColor.values()[ThreadLocalRandom.current().nextInt(16)]; + } + public enum GlowColor{ + AQUA,BLACK,BLUE,DARK_AQUA,DARK_BLUE,DARK_GRAY,DARK_GREEN,DARK_PURPLE,DARK_RED,GOLD,GRAY,GREEN,LIGHT_PURPLE,RED,WHITE,YELLOW, + NONE,RANDOM + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/manager/GroovyManager.java b/src/main/java/pers/xanadu/enderdragon/manager/GroovyManager.java new file mode 100644 index 0000000..1cc85f3 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/manager/GroovyManager.java @@ -0,0 +1,105 @@ +package pers.xanadu.enderdragon.manager; + +import groovy.lang.*; +import groovy.util.GroovyScriptEngine; +import io.netty.util.internal.ConcurrentSet; +import org.bukkit.entity.Player; +import org.codehaus.groovy.control.CompilerConfiguration; +import org.codehaus.groovy.control.customizers.ImportCustomizer; +import pers.xanadu.enderdragon.config.Config; +import pers.xanadu.enderdragon.script.Events; +import pers.xanadu.enderdragon.script.tool.ScriptCommand; + +import java.io.File; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.concurrent.ConcurrentHashMap; + +import static pers.xanadu.enderdragon.EnderDragon.plugin; +import static pers.xanadu.enderdragon.config.Lang.error; +import static pers.xanadu.enderdragon.config.Lang.info; + +public class GroovyManager { + private static final File baseDir = new File(plugin.getDataFolder(),"expansion/groovy"); + private static final ConcurrentHashMap script_mp = new ConcurrentHashMap<>(); + public static final ConcurrentSet> event_set = new ConcurrentSet<>(); + public static final ConcurrentSet cmd_set = new ConcurrentSet<>(); + private static final GroovyScriptEngine engine; + private static final CompilerConfiguration compilerConfig; + private static final String lib; + + static { + try { + compilerConfig = new CompilerConfiguration(); + ImportCustomizer importCustomizer = new ImportCustomizer(); + importCustomizer.addImport("Bukkit","org.bukkit.Bukkit"); + importCustomizer.addImport("Player","org.bukkit.entity.Player"); + importCustomizer.addImport("Events","pers.xanadu.enderdragon.script.Events"); + importCustomizer.addImport("Command","pers.xanadu.enderdragon.script.tool.ScriptCommand"); + importCustomizer.addStaticImport("plugin","pers.xanadu.enderdragon.EnderDragon","plugin"); + compilerConfig.addCompilationCustomizers(importCustomizer); + GroovyClassLoader classLoader = new GroovyClassLoader(GroovyManager.class.getClassLoader(),compilerConfig); + engine = new GroovyScriptEngine(new URL[]{baseDir.toURI().toURL()}, classLoader); + InputStream inputStream = plugin.getResource("script/lib.groovy"); + lib = Config.convertInputStreamToString(inputStream); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + + public static void reload() { + event_set.forEach(Events::unregister); + event_set.clear(); + cmd_set.forEach(ScriptCommand::unregister); + cmd_set.clear(); + script_mp.clear(); + loadAllScripts(baseDir); + script_mp.forEach((key,script)->invoke(key,"enable")); + } + public static Object eval(String expression, Player player){ + Binding binding = new Binding(); + binding.setVariable("player",player); + binding.setVariable("itemStack",player.getItemInHand()); + binding.setVariable("world",player.getWorld()); + GroovyShell shell = new GroovyShell(GroovyManager.class.getClassLoader(),binding,compilerConfig); + //Bukkit.broadcastMessage(lib); + return shell.evaluate(lib+expression); + } + + public static Object invoke(String fileName, String function, Object... args) { + Script script = GroovyManager.script_mp.get(fileName); + if (script != null) { + try { + return script.invokeMethod(function, args); + } catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } + + private static void loadAllScripts(File folder) { + if (folder.isDirectory()) { + File[] subFiles = folder.listFiles(); + if(subFiles == null) return; + for (File file : subFiles) { + if(file.isDirectory()) loadAllScripts(file); + else if(file.getName().endsWith(".groovy")) loadGroovyFile(file); + } + } + } + + private static void loadGroovyFile(File file) { + String key = file.getPath().substring(37); + try { + Script script = engine.createScript(key, new Binding()); + //script.evaluate("import org.bukkit.Bukkit"); + script_mp.put(key, script); + info("Successfully load script: "+key); + } catch (Exception e) { + error("Failed to load script: "+key); + e.printStackTrace(); + } + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/manager/GuiManager.java b/src/main/java/pers/xanadu/enderdragon/manager/GuiManager.java new file mode 100644 index 0000000..1c8f50e --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/manager/GuiManager.java @@ -0,0 +1,76 @@ +package pers.xanadu.enderdragon.manager; + +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.gui.GUIWrapper; + +import java.io.File; +import java.util.HashMap; +import java.util.Iterator; + +import static pers.xanadu.enderdragon.EnderDragon.plugin; + +public class GuiManager { + private static HashMap f = new HashMap<>(); + public static void loadGui(){ + new BukkitRunnable(){ + @Override + public void run(){ + File folder = new File(plugin.getDataFolder(),"gui"); + if(!folder.exists()) return; + File[] files = folder.listFiles(); + if(files == null) return; + for(File file : files){ + if(!file.getName().endsWith(".yml")) continue; + Lang.info(Lang.plugin_read_file + file.getName()); + FileConfiguration fileConfiguration = YamlConfiguration.loadConfiguration(file); + Iterator it = fileConfiguration.getKeys(false).iterator(); + while (it.hasNext()){ + String name = (String) it.next(); + ConfigurationSection section = fileConfiguration.getConfigurationSection(name); + GUIWrapper guiWrapper = new GUIWrapper(section); + f.put(name, guiWrapper); + } + } + } + }.runTaskAsynchronously(plugin); + } + public static void disable(){ + f.clear(); + } + public static void openGui(Player player, String name, boolean editor) { + if (!f.containsKey(name)) { + Lang.sendFeedback(player,Lang.gui_not_found); + return; + } + player.openInventory(new GUIWrapper(f.get(name),name,editor).current()); + } + public static void openGui(Player player,String style,String key, boolean editor){ + if (!f.containsKey(style)) { + Lang.sendFeedback(player,Lang.gui_not_found); + return; + } + player.openInventory(new GUIWrapper(f.get(style),key,editor).current()); + } + + @Deprecated + public static void openGui(Player player, String name) { + if (!f.containsKey(name)) { + Lang.sendFeedback(player,Lang.gui_not_found); + return; + } + player.openInventory(new GUIWrapper(f.get(name),name,false).current()); + } + @Deprecated + public static void openGui(Player player,String style,String key){ + if (!f.containsKey(style)) { + Lang.sendFeedback(player,Lang.gui_not_found); + return; + } + player.openInventory(new GUIWrapper(f.get(style),key,false).current()); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/manager/ItemManager.java b/src/main/java/pers/xanadu/enderdragon/manager/ItemManager.java new file mode 100644 index 0000000..1415029 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/manager/ItemManager.java @@ -0,0 +1,431 @@ +package pers.xanadu.enderdragon.manager; + +import org.bukkit.Material; +import org.bukkit.attribute.Attribute; +import org.bukkit.attribute.AttributeModifier; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.Repairable; +import org.bukkit.persistence.PersistentDataContainer; +import pers.xanadu.enderdragon.EnderDragon; +import pers.xanadu.enderdragon.config.Config; +import pers.xanadu.enderdragon.reward.Reward; +import pers.xanadu.enderdragon.reward.Chance; +import pers.xanadu.enderdragon.util.Version; + +import java.util.*; + +public class ItemManager { + public static String write(Reward reward){ + Chance chance = reward.getChance(); + return write(reward.getItem(),chance.getValue(),chance.getStr(),reward.getName()); + } + public static String write(ItemStack item,double value,String str,String name){ + YamlConfiguration yaml = new YamlConfiguration(); + if(Config.advanced_setting_backslash_split_reward) yaml.options().pathSeparator('\\'); + if(name == null){ + ItemMeta meta = item.getItemMeta(); + if(meta != null) { + String displayName = meta.getDisplayName(); + if("".equals(displayName) || displayName == null){ + name = item.getType().name().toLowerCase() + "(" + TaskManager.getCurrentTimeWithSpecialFormat() + ")"; + } + else name = meta.getDisplayName(); + } + else name = item.getType().name().toLowerCase() + "(" + TaskManager.getCurrentTimeWithSpecialFormat() + ")"; + } + ConfigurationSection section = yaml.createSection(name); + switch(Config.item_format_reward){ + case "nbt" : { + section.set("data_type","nbt"); + section.set("data",EnderDragon.getInstance().getNMSManager().getNBT(item)); + break; + } + case "advanced" : { + section.set("data_type","advanced"); + ConfigurationSection section_data = section.createSection("data"); + //type + String type = item.getType().name(); + section_data.set("type",type); + if("AIR".equals(type)) break; + //amount + int amount = item.getAmount(); + section_data.set("amount",amount); + //damage + int damage = item.getDurability(); + if(damage != 0) section_data.set("damage",damage); + ItemMeta meta = item.getItemMeta(); + if(meta == null) break; + //DisplayName + String display_name = meta.getDisplayName(); + if(!"".equals(display_name)) section_data.set("display_name",display_name); + //LocalizedName + if(meta.hasLocalizedName()){ + section_data.set("localized_name",meta.getLocalizedName()); + } + //lore + List lores = meta.getLore(); + if(lores != null) section_data.set("lore",lores); + //Enchantments + if(meta.hasEnchants()){ + ConfigurationSection enchants = section_data.createSection("enchants"); + Map mp = meta.getEnchants(); + mp.forEach((enchantment,level) -> enchants.set(enchantment.getName(),level)); + } + if(Version.mcMainVersion>=14 || "v1_13_R2".equals(Version.getVersion())){ + //AttributeModifiers + if(meta.hasAttributeModifiers()){ + ConfigurationSection attributes = section_data.createSection("AttributeModifiers"); + meta.getAttributeModifiers().forEach((attribute,modifier)->{ + attributes.set(attribute.name(),modifier); + }); + } + } + if(Version.mcMainVersion>=14){ + //CustomModelData + if(meta.hasCustomModelData()) { + section_data.set("CustomModelData",meta.getCustomModelData());//int + } + //PersistentDataContainer + PersistentDataContainer dataContainer = meta.getPersistentDataContainer(); + if(!dataContainer.isEmpty()){ + ConfigurationSection dataContainer_section = section_data.createSection("PersistentDataContainer"); + String cpd = EnderDragon.getInstance().getNMSManager().PDCtoString(dataContainer); + dataContainer_section.set("data_type","nbt"); + dataContainer_section.set("data",cpd); + } + } + //RepairCost + if(meta instanceof Repairable){ + Repairable repairable = (Repairable) meta; + section_data.set("RepairCost",repairable.getRepairCost()); + } + //ItemFlags + Set flags = meta.getItemFlags(); + if(!flags.isEmpty()){ + List list = new ArrayList<>(); + flags.forEach(flag ->{ + list.add(flag.name()); + }); + section_data.set("ItemFlags",list); + } + //Unbreakable + section_data.set("unbreakable",meta.isUnbreakable()); + //internal + Object cpd = EnderDragon.getInstance().getNMSManager().getCPD(item); + Map mp = EnderDragon.getInstance().getNMSManager().cpdToMap(cpd); + if(mp.containsKey("tag")){ + cpd = mp.get("tag"); + mp = EnderDragon.getInstance().getNMSManager().cpdToMap(cpd); + mp.remove("Damage"); + if(mp.containsKey("display")){ + Object display = mp.get("display"); + Map display_mp = EnderDragon.getInstance().getNMSManager().cpdToMap(display); + display_mp.remove("Name"); + display_mp.remove("LocName"); + display_mp.remove("Lore"); + Object new_display = EnderDragon.getInstance().getNMSManager().getNBTTagCompound(display_mp); + mp.put("display",new_display); + } + //mp.remove("display");//Name, LocName, Lore, color + mp.remove("Enchantments"); + mp.remove("AttributeModifiers"); + mp.remove("CustomModelData"); + mp.remove("PublicBukkitValues");//PersistentDataContainer + mp.remove("RepairCost"); + mp.remove("HideFlags");//ItemFlags + mp.remove("Unbreakable"); + //CanDestroy, CanPlaceOn + Object new_cpd = EnderDragon.getInstance().getNMSManager().getNBTTagCompound(mp); + ConfigurationSection internal = section_data.createSection("internal"); + internal.set("data_type","nbt"); + internal.set("data",new_cpd.toString()); + } +// Map mp = EnderDragon.getInstance().getNMSManager().getUnhandledTags(meta); +// if(mp != null){ +// ConfigurationSection internal = section_data.createSection("internal"); +// saveUnhandledTags(internal,mp); +// } + + break; + } + default : { + section.set("data_type","default"); + section.set("data", item); + } + } + ConfigurationSection drop_section = section.createSection("drop_chance"); + drop_section.set("value",value); + drop_section.set("format",str); + return yaml.saveToString(); + } + public static Reward readAsReward(ConfigurationSection section){ + Set strings = section.getKeys(false); + String name = strings.iterator().next(); + ConfigurationSection section0 = section.getConfigurationSection(name); + if(section0 == null) return null; + String data_type = section0.getString("data_type"); + //data_type may be null + ItemStack item; + if("nbt".equals(data_type)) item = readFromNBT(section0,"data"); + else if("advanced".equals(data_type)) item = readFromAdvData(section0, "data"); + else item = readFromBukkit(section0,"data"); + ConfigurationSection chance_section = section0.getConfigurationSection("drop_chance"); + if(chance_section == null) return null; + double d0 = chance_section.getDouble("value"); + String str = chance_section.getString("format"); + return new Reward(item,new Chance(d0, str)); + } + public static ItemStack readFromAdvData(ConfigurationSection section, String path){ + ConfigurationSection data = section.getConfigurationSection(path); + if(data == null) return new ItemStack(Material.AIR); + String type = data.getString("type"); + if(type == null || "AIR".equals(type)) return new ItemStack(Material.AIR); + int amount = data.getInt("amount"); + Material material = Material.getMaterial(type); + if(material == null) return new ItemStack(Material.AIR); + ItemStack item = new ItemStack(material,amount); + //internal + if(data.contains("internal")){ + ConfigurationSection internal_section = data.getConfigurationSection("internal"); + if(internal_section!=null){ + if("nbt".equals(internal_section.getString("data_type"))){ + String nbt = internal_section.getString("data"); + Object cpd = EnderDragon.getInstance().getNMSManager().getCPD(nbt); + Map mp_tag = new HashMap<>(); + mp_tag.put("tag",cpd); + Object full_cpd = EnderDragon.getInstance().getNMSManager().getNBTTagCompound(mp_tag); + item = EnderDragon.getInstance().getNMSManager().mergeItemCPD(item,full_cpd); + } +// else{ +// Map mp = getUnhandledTags(internal_section); +// EnderDragon.getInstance().getNMSManager().setUnhandledTags(meta,mp); +// } +// Map mp = new HashMap<>(); +// internal_section.getKeys(false).forEach(key->{ +// Object obj = internal_section.get(key);//obj instanceof String +// Object nbt_base = EnderDragon.getInstance().getNMSItemManager().readAsNBTBase((String) obj); +// mp.put(key,nbt_base); +// }); +// Map mp = getUnhandledTags(internal_section); +// NBTTagCompound cpd = getNBTTagCompound(mp); +// net.minecraft.world.item.ItemStack ei = CraftItemStack.asNMSCopy(item); +// ei.c(cpd); +// item = CraftItemStack.asBukkitCopy(ei); + //EnderDragon.getInstance().getNMSManager().setUnhandledTags(meta,mp); + } + } + //damage + if(data.contains("damage")){ + int damage = data.getInt("damage"); + item.setDurability((short) damage); + } + ItemMeta meta = item.getItemMeta(); + if(meta == null) return item; + //DisplayName + String display_name = data.getString("display_name"); + if(display_name != null) meta.setDisplayName(display_name); + //LocalizedName + if(data.contains("localized_name")){ + String LocalizedName = data.getString("localized_name"); + if(LocalizedName != null) meta.setLocalizedName(LocalizedName); + } + //lore + if(data.contains("lore")){ + List lores = data.getStringList("lore"); + if(!lores.isEmpty()) meta.setLore(lores); + } + //Enchantments + if(data.contains("enchants")){ + ConfigurationSection enchants = data.getConfigurationSection("enchants"); + if(enchants != null){ + //Map mp = new HashMap<>(); + enchants.getKeys(false).forEach(key->{ + Enchantment enchantment = Enchantment.getByName(key); + int level = enchants.getInt(key); + if(enchantment != null && level>0){ + meta.addEnchant(enchantment,level,true); + } + }); + } + } + //CustomModelData + if(data.contains("CustomModelData")){ + int CustomModelData = data.getInt("CustomModelData"); + meta.setCustomModelData(CustomModelData); + } + //AttributeModifiers + if(data.contains("AttributeModifiers")){ + ConfigurationSection attributes = data.getConfigurationSection("AttributeModifiers"); + if(attributes != null){ + attributes.getKeys(false).forEach(name->{ + Attribute attribute = Attribute.valueOf(name); + AttributeModifier modifier = (AttributeModifier) attributes.get(name); + if(modifier != null){ + meta.addAttributeModifier(attribute,modifier); + } + }); + } + } + //RepairCost + if(data.contains("RepairCost")){ + int cost = data.getInt("RepairCost"); + if(meta instanceof Repairable){ + ((Repairable)meta).setRepairCost(cost); + } + } + //ItemFlags + if(data.contains("ItemFlags")){ + List names = data.getStringList("ItemFlags"); + names.forEach(name->meta.addItemFlags(ItemFlag.valueOf(name))); + } + //Unbreakable + if(data.contains("unbreakable") && data.getBoolean("unbreakable")) meta.setUnbreakable(true); + //PersistentDataContainer + if(data.contains("PersistentDataContainer")){ + ConfigurationSection dataContainer_section = data.getConfigurationSection("PersistentDataContainer"); + if(dataContainer_section != null){ + if("nbt".equals(dataContainer_section.getString("data_type"))){ + String nbt = dataContainer_section.getString("data"); + Object cpd = EnderDragon.getInstance().getNMSManager().getCPD(nbt); + PersistentDataContainer container = meta.getPersistentDataContainer(); + EnderDragon.getInstance().getNMSManager().setPersistentDataContainer(container, cpd); + } + } + } + item.setItemMeta(meta); + return item; + } + public static ItemStack readFromNBT(ConfigurationSection section, String path){ + String nbt = section.getString(path); + if (nbt == null) return new ItemStack(Material.AIR); + return EnderDragon.getInstance().getNMSItemManager().readAsItem(nbt); + } + public static ItemStack readFromBukkit(ConfigurationSection section, String path){ + String nbt = section.getString(path); + if (nbt == null) return new ItemStack(Material.AIR); + return section.getItemStack(path); + } + public static ItemStack readFromString(String str){ + YamlConfiguration yml = new YamlConfiguration(); + if(Config.advanced_setting_backslash_split_reward) yml.options().pathSeparator('\\'); + yml.set("test",str); + return yml.getItemStack("test"); + } + public static void addLoreFront(ItemStack item, String lore){ + ItemMeta meta = item.getItemMeta(); + if(meta != null) { + List lores = meta.getLore(); + if (lores != null) { + lores.add(0,lore); + meta.setLore(lores); + } + else { + meta.setLore(Collections.singletonList(lore)); + } + item.setItemMeta(meta); + } + } + public static void addLoreBack(ItemStack item, String lore){ + ItemMeta meta = item.getItemMeta(); + if(meta != null) { + List lores = meta.getLore(); + if (lores != null) { + lores.add(lore); + meta.setLore(lores); + } + else { + meta.setLore(Collections.singletonList(lore)); + } + item.setItemMeta(meta); + } + } + public static boolean isEmpty(ItemStack item){ + if(item == null) return true; + if(item.getType() == Material.AIR) return true; + return false; + } + private static void saveUnhandledTags(ConfigurationSection section, Map mp){ + mp.forEach((k,v)->{ + //Bukkit.broadcastMessage(k+": "+v.getClass().toString()); + if(v instanceof Map){ + saveUnhandledTags(section.createSection(k), (Map) v); + } + else section.set(k,v.toString()); + }); + } +/** + private static void saveUnhandledTags(ConfigurationSection section, Map mp){ + mp.forEach((k,v)->{ + Object obj = v; + //Bukkit.broadcastMessage(obj.getClass().toString()); + try{ + obj = EnderDragon.getInstance().getNMSItemManager().parseNBT(v); + }catch (Throwable ignored){ + + } + if(obj instanceof Map){ + saveUnhandledTags(section.createSection(k), (Map) obj); + } + else section.set(k,obj); + }); + }**/ + private static Map getUnhandledTags(ConfigurationSection section){ + Map res = new HashMap<>(); + section.getKeys(false).forEach(key->{ + Object obj = section.get(key); + if(obj instanceof ConfigurationSection){ + ConfigurationSection subSection = section.getConfigurationSection(key); + if(subSection != null){ + obj = getUnhandledTags(subSection); +// Object mp = getUnhandledTags(subSection); +// Bukkit.getLogger().info(mp.getClass().toString()); +// try{ +// obj = EnderDragon.getInstance().getNMSItemManager().getNBTBase(mp); +// }catch (Throwable throwable){ +// +// } + } + } + else obj = EnderDragon.getInstance().getNMSManager().getCPD((String) obj); + //else obj = EnderDragon.getInstance().getNMSItemManager().readAsNBTBase((String) obj); + res.put(key,obj); + }); + return res; + } + +// private static Object dfs(ConfigurationSection section){ +// section.getKeys(false).forEach(key->{ +// Object obj = section.get(key); +// if(obj instanceof ConfigurationSection){ +// ConfigurationSection subSection = section.getConfigurationSection(key); +// if(subSection != null) obj = dfs(subSection); +// } +// else obj = EnderDragon.getInstance().getNMSItemManager().readAsNBTBase((String) obj); +// +// }); +// return +// } + +// //internal +// Map mp = EnderDragon.getInstance().getNMSManager().getUnhandledTags(meta); +// if(mp != null){ +// ConfigurationSection internal = section_data.createSection("internal"); +// mp.forEach((k,v)->{ +// Object obj = EnderDragon.getInstance().getNMSItemManager().parseNBT(v); +// +// if(obj instanceof Map) obj = obj.toString(); +// else if(obj instanceof List) obj = obj.toString(); +// +// internal.set(k,obj); +// }); +// } + + + + +} diff --git a/src/main/java/pers/xanadu/enderdragon/manager/RewardManager.java b/src/main/java/pers/xanadu/enderdragon/manager/RewardManager.java new file mode 100644 index 0000000..44b00d8 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/manager/RewardManager.java @@ -0,0 +1,133 @@ +package pers.xanadu.enderdragon.manager; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; +import pers.xanadu.enderdragon.config.Config; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.reward.Reward; +import pers.xanadu.enderdragon.reward.Chance; +import pers.xanadu.enderdragon.util.MyDragon; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.List; +import java.util.logging.Level; + +import static pers.xanadu.enderdragon.EnderDragon.*; + +public class RewardManager { + + public static void reload(){ + for(MyDragon dragon : DragonManager.dragons){ + dragon.datum.clear(); + File file = getRewardFile(dragon.unique_name); + if(file == null) return; + FileConfiguration data = loadConfiguration(file); + String path = "list"; + List list = data.getStringList(path); + // if list == null ? + for(String str : list){ + YamlConfiguration yml = new YamlConfiguration(); + if(Config.advanced_setting_backslash_split_reward) yml.options().pathSeparator('\\'); + try{ + yml.loadFromString(str); + Reward reward = ItemManager.readAsReward(yml); + dragon.datum.add(reward); + }catch (InvalidConfigurationException e){ + Lang.error(Lang.plugin_item_read_error + str); + } + } + } + } + public static void addItem(String key,Reward reward){ + addItem(key,reward.getItem(),reward.getChance()); + } + public static void addItem(String key, ItemStack item, Chance chance){ + MyDragon dragon = DragonManager.mp.get(key); + if(dragon == null) return; + File file = getRewardFile(dragon.unique_name); + if(file == null) return; + FileConfiguration data = loadConfiguration(file); + String path = "list"; + List list = data.getStringList(path); + Reward reward = new Reward(item,chance); + list.add(reward.toString()); + data.set(path,list); + try { + data.save(file); + } catch (IOException e) { + throw new RuntimeException(e); + } + dragon.datum.add(reward); + } + public static void clearItem(String key){ + MyDragon dragon = DragonManager.mp.get(key); + if(dragon == null) return; + File file = getRewardFile(dragon.unique_name); + if(file == null) return; + FileConfiguration data = loadConfiguration(file); + String path = "list"; + data.set(path,""); + try { + data.save(file); + } catch (IOException e) { + throw new RuntimeException(e); + } + dragon.datum.clear(); + } + public static boolean removeItem(String key,int idx){ + MyDragon dragon = DragonManager.mp.get(key); + if(dragon == null) return false; + File file = getRewardFile(dragon.unique_name); + if(file == null) return false; + FileConfiguration data = loadConfiguration(file); + String path = "list"; + List list = data.getStringList(path); + try{ + list.remove(idx); + data.set(path,list); + data.save(file); + dragon.datum.remove(idx); + return true; + }catch (IndexOutOfBoundsException e){ + Lang.error("Index out of bound!"); + }catch (IOException e) { + throw new RuntimeException(e); + } + return false; + } + private static File getRewardFile(String key){ + String file_path = "reward/" + key + ".yml"; + File file = new File(plugin.getDataFolder(),file_path); + if(!file.exists()) { + try{ + YamlConfiguration yml = new YamlConfiguration(); + if(Config.advanced_setting_backslash_split_reward) yml.options().pathSeparator('\\'); + yml.set("version","2.1.0"); + yml.set("list",""); + yml.save(file); + }catch (IOException e){ + Lang.error("Not Found "+file_path+" ,skipped it."); + return null; + } + } + return new File(plugin.getDataFolder(),file_path); + } + private static YamlConfiguration loadConfiguration(@NotNull File file) { + YamlConfiguration config = new YamlConfiguration(); + if(Config.advanced_setting_backslash_split_reward) config.options().pathSeparator('\\'); + try { + config.load(file); + } catch (FileNotFoundException ex) { + } catch (IOException | InvalidConfigurationException ex) { + Bukkit.getLogger().log(Level.SEVERE, "Cannot load " + file, ex); + } + return config; + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/manager/SkillManager.java b/src/main/java/pers/xanadu/enderdragon/manager/SkillManager.java new file mode 100644 index 0000000..c02876d --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/manager/SkillManager.java @@ -0,0 +1,81 @@ +package pers.xanadu.enderdragon.manager; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.entity.*; +import pers.xanadu.enderdragon.util.MathUtil; + +import java.util.concurrent.ThreadLocalRandom; + +public class SkillManager { + //离开祭坛 + //向指定位置发射末影龙火球 + //在玩家附近召唤愤怒的末影人 + //立刻飞向玩家并近战攻击 + //在当前位置吐龙息 + + public static void leaveEndPortal(final EnderDragon dragon){ + dragon.setPhase(EnderDragon.Phase.LEAVE_PORTAL); + } + public static void launchDragonFireball(final EnderDragon dragon, final Location target){ + Location loc1 = dragon.getLocation(); + World world = loc1.getWorld(); + if(world == null) return; + double dx = target.getX() - loc1.getX(); + double dy = target.getY() - loc1.getY(); + double dz = target.getZ() - loc1.getZ(); + double yaw = Math.toDegrees(-Math.atan2(dx, dz)); + double horizontalDistance = Math.sqrt(dx * dx + dz * dz); + double pitch = Math.toDegrees(-Math.atan2(dy, horizontalDistance)); + yaw = normalizeAngle(yaw, -180, 180); + pitch = normalizeAngle(pitch, -90, 90); + Location loc = new Location(world,loc1.getX(),loc1.getY(),loc1.getZ(), (float) yaw, (float) pitch); + Projectile projectile = world.spawn(loc, DragonFireball.class); + projectile.setShooter(dragon); + + //Projectile projectile2 = loc1.getWorld().spawn(loc, DragonFireball.class); + //projectile2.setShooter(dragon); + //projectile2.setVelocity(new Vector(-dx,-dy,-dz).normalize()); + } + public static void callEnderManReinforce(final Player p,int num){ + if(num <= 0) return; + ThreadLocalRandom random = ThreadLocalRandom.current(); + Location loc = p.getLocation(); + World world = loc.getWorld(); + assert world != null; + int i = MathUtil.floor(loc.getX()); + int j = MathUtil.floor(loc.getY()); + int k = MathUtil.floor(loc.getZ()); + int i1=10,j1,k1=10; + for (int l = 0; l < 50; l++) { + i1 = i + (random.nextInt(7, 41) * random.nextInt(-1, 2)); + j1 = j + (random.nextInt(7, 41) * random.nextInt(-1, 2)); + k1 = k + (random.nextInt(7, 41) * random.nextInt(-1, 2)); + Block block = world.getBlockAt(i1,j1-1,k1); + if(block.isLiquid() || block.isEmpty()) continue; + if(!world.getBlockAt(i1,j1,k1).isEmpty()) continue; + if(!world.getBlockAt(i1,j1+1,k1).isEmpty()) continue; + if(!world.getBlockAt(i1,j1+2,k1).isEmpty()) continue; + Enderman enderman = (Enderman) world.spawnEntity(new Location(world,i1,j1,k1),EntityType.ENDERMAN); + enderman.setTarget(p); + --num; + if(num == 0) return; + } + loc = world.getHighestBlockAt(i1,k1).getLocation().add(0,1,0); + while (num>0){ + --num; + Enderman enderman = (Enderman) world.spawnEntity(loc,EntityType.ENDERMAN); + enderman.setTarget(p); + } + } + + private static double normalizeAngle(double angle, double min, double max) { + if (angle < min) { + angle = min; + } else if (angle > max) { + angle = max; + } + return angle; + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/manager/TaskManager.java b/src/main/java/pers/xanadu/enderdragon/manager/TaskManager.java new file mode 100644 index 0000000..46b4bf8 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/manager/TaskManager.java @@ -0,0 +1,103 @@ +package pers.xanadu.enderdragon.manager; + +import org.bukkit.configuration.ConfigurationSection; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.task.DragonRespawnRunnable; +import pers.xanadu.enderdragon.task.type.*; +import pers.xanadu.enderdragon.task.Task; +import pers.xanadu.enderdragon.task.TaskType; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Date; +import java.util.concurrent.ConcurrentHashMap; + +import static pers.xanadu.enderdragon.EnderDragon.*; + +public class TaskManager { + public static final ConcurrentHashMap mp = new ConcurrentHashMap<>(); + private static final DateTimeFormatter RoundTimeFormat_hm = DateTimeFormatter.ofPattern("HH:mm"); + private static final DateTimeFormatter RoundTimeFormat_all = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"); + + public static Task parse(String unique_name,String world_name,String string){ + String[] str = string.split(":",2); + TaskType taskType = TaskType.getByName(str[0]); + switch (taskType){ + case minute : { + return new Minute(TaskType.minute,unique_name,world_name,str[1]); + } + case hour : { + return new Hour(TaskType.hour,unique_name,world_name,str[1]); + } + case day : { + return new Day(TaskType.day,unique_name,world_name,str[1]); + } + case week : { + return new Week(TaskType.week,unique_name,world_name,str[1]); + } + case month : { + return new Month(TaskType.month,unique_name,world_name,str[1]); + } + case year : { + return new Year(TaskType.year,unique_name,world_name,str[1]); + } + default : { + return null; + } + } + } + public static void reload(){ + mp.forEach((key,runnable)->runnable.cancel()); + mp.clear(); + ConfigurationSection section = plugin.getConfig().getConfigurationSection("auto_respawn"); + if(section==null) return; + int cnt = 0; + for (String key : section.getKeys(false)) { + ConfigurationSection sub = section.getConfigurationSection(key); + if(sub == null) continue; + boolean enable = sub.getBoolean("enable"); + String world_name = sub.getString("world_name"); + String task_string = sub.getString("respawn_time"); + if(!enable || task_string == null || world_name == null) continue; + DragonRespawnRunnable runnable = new DragonRespawnRunnable(parse(key,world_name,task_string)); + runnable.start(); + mp.put(key,runnable); + ++cnt; + } + Lang.info(String.format("%d auto_respawn task(s) started to run...",cnt)); + } + public static LocalTime getRoundTime(String str){ + try { + return LocalTime.parse(str, RoundTimeFormat_hm); + }catch (DateTimeParseException e){ + Lang.error("\"respawn_time\" in config.yml error!The format of time should be HH:mm."); + } + return null; + } + public static String getRoundTimeStr(LocalDateTime time){ + return time.format(RoundTimeFormat_all); + } + public static LocalDateTime getLocalDateTime(String str){ + if(isValidTime(str)) return LocalDateTime.parse(str, RoundTimeFormat_all); + return null; + } + public static boolean isValidTime(String str){ + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + try{ + df.parse(str); + } catch (ParseException e) { + Lang.error("\"next_respawn_time\" in data.yml error!The format of time should be HH:mm."); + return false; + } + return true; + } + public static String getCurrentTimeWithSpecialFormat(){ + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH∶mm∶ss");//这里的∶是特殊字符 + return df.format(new Date()); + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/manager/TimerManager.java b/src/main/java/pers/xanadu/enderdragon/manager/TimerManager.java new file mode 100644 index 0000000..b5f4154 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/manager/TimerManager.java @@ -0,0 +1,76 @@ +package pers.xanadu.enderdragon.manager; + +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.task.DragonRespawnTimer; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; + +import static pers.xanadu.enderdragon.EnderDragon.plugin; + +public class TimerManager { + private static final HashMap mp = new HashMap<>(); + public static void enable(){ + File file = new File(plugin.getDataFolder(),"respawn_cd.yml"); + if(file.exists()){ + FileConfiguration fc = YamlConfiguration.loadConfiguration(file); + ConfigurationSection section = fc.getConfigurationSection("respawn_cd"); + if(section == null) return; + section.getKeys(false).forEach(name->{ + int set_time = section.getInt(name+".setTime"); + int rest_time = section.getInt(name+".remainTime"); + if(set_time>0){ + boolean run = section.getBoolean(name+".isRunning"); + DragonRespawnTimer timer = new DragonRespawnTimer(name,set_time,rest_time); + if(run) timer.run(); + TimerManager.mp.put(name,timer); + } + }); + } + } + public static void save(){ + YamlConfiguration yml = new YamlConfiguration(); + char split = yml.options().pathSeparator(); + mp.forEach((k,v)->{ + ConfigurationSection section = yml.createSection("respawn_cd"+split+k); + if(v.getRestTime()>0){ + //section.set("world_name",k); + section.set("setTime",v.getSetTime()); + section.set("remainTime",v.getRestTime()); + section.set("isRunning",v.isRunning()); + } + }); + try{ + yml.save(new File(plugin.getDataFolder(),"respawn_cd.yml")); + }catch (IOException e){ + Lang.error("Failed to save respawn_cd.yml!"); + } + } + public static void startTimer(String world_name){ + DragonRespawnTimer timer = mp.get(world_name); + if(timer != null){ + timer.run(); + } + } + public static void setTimer(String world_name, DragonRespawnTimer timer){ + DragonRespawnTimer timer_old = mp.get(world_name); + if(timer_old != null) timer_old.del(); + mp.put(world_name,timer); + } + public static DragonRespawnTimer getTimer(String world_name){ + return mp.get(world_name); + } + public static void removeTimer(String world_name){ + DragonRespawnTimer timer_old = mp.get(world_name); + if(timer_old != null) timer_old.del(); + mp.remove(world_name); + } + public static void removeAll(){ + mp.values().forEach(DragonRespawnTimer::del); + mp.clear(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/manager/WorldManager.java b/src/main/java/pers/xanadu/enderdragon/manager/WorldManager.java new file mode 100644 index 0000000..d8fde3f --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/manager/WorldManager.java @@ -0,0 +1,196 @@ +package pers.xanadu.enderdragon.manager; + +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.Entity; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.util.Version; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +import static java.lang.Math.sqrt; +import static pers.xanadu.enderdragon.EnderDragon.getInstance; +import static pers.xanadu.enderdragon.util.MathUtil.*; + +public class WorldManager { + public static final List worlds = new ArrayList<>(); + private Field dimension; + private Field world_provider; + private Method getDimensionID; + + public static void reload(){ + worlds.clear(); + Bukkit.getWorlds().forEach(world -> worlds.add(world.getName())); + } + + public static Collection getExplosionDragon(float power, Location loc){ + World world = loc.getWorld(); + if(world == null) return Collections.EMPTY_LIST; + return getExplosionDragon(loc.getWorld(),power,loc.getX()+0.5d,loc.getY()+0.5d,loc.getZ()+0.5d); + } + public static Collection getExplosionDragon(World world,float power,double x,double y,double z){ + float f = power * 2.0F; + int x1 = floor(x - (double)f - 1.0); + int x2 = floor(x + (double)f + 1.0); + int y1 = floor(y - (double)f - 1.0); + int y2 = floor(y + (double)f + 1.0); + int z1 = floor(z - (double)f - 1.0); + int z2 = floor(z + (double)f + 1.0); +// Collection list = world.getNearbyEntities(new BoundingBox(x1, y1, z1, x2, y2, z2)); + Location cen = new Location(world,(x1+x2)/2d,(y1+y2)/2d,(z1+z2)/2d); + double rx = (x2-x1)/2d; + double ry = (y2-y1)/2d; + double rz = (z2-z1)/2d; + Collection list = world.getNearbyEntities(cen,rx,ry,rz); + List res = new ArrayList<>(); + for (Entity entity : list) { + if(entity instanceof EnderDragon){ + double d0 = sqrt(c(entity,x, y, z)) / f; + if (d0 <= 1.0) { + Location loc = entity.getLocation(); + double dx = loc.getX() - x; + double dy = loc.getY() + 6.8d - y; + double dz = loc.getZ() - z; + double d1 = sqrt(dx * dx + dy * dy + dz * dz); + if (d1 != 0.0) { + res.add((EnderDragon) entity); + } + } + } + } + return res; + } +// public static float a(Vector endPos, Entity entity) { +// BoundingBox bb = entity.getBoundingBox(); +// double d0 = 1.0 / ((bb.getMaxX() - bb.getMinX()) * 2.0 + 1.0); +// double d1 = 1.0 / ((bb.getMaxY() - bb.getMinY()) * 2.0 + 1.0); +// double d2 = 1.0 / ((bb.getMaxZ() - bb.getMinZ()) * 2.0 + 1.0); +// double d3 = (1.0 - Math.floor(1.0 / d0) * d0) / 2.0; +// double d4 = (1.0 - Math.floor(1.0 / d2) * d2) / 2.0; +// if (d0 >= 0.0 && d1 >= 0.0 && d2 >= 0.0) { +// int i = 0; +// int j = 0; +// +// for(float f = 0.0F; f <= 1.0F; f = (float)((double)f + d0)) { +// for(float f1 = 0.0F; f1 <= 1.0F; f1 = (float)((double)f1 + d1)) { +// for(float f2 = 0.0F; f2 <= 1.0F; f2 = (float)((double)f2 + d2)) { +// double d5 = d(f, bb.getMinX(), bb.getMaxX()); +// double d6 = d(f1, bb.getMinY(), bb.getMaxY()); +// double d7 = d(f2, bb.getMinZ(), bb.getMaxZ()); +// //Vec3D vec3d1 = new Vec3D(d5 + d3, d6, d7 + d4); +// Location start = new Location(entity.getWorld(),d5 + d3, d6, d7 + d4); +// Vector dir = new Vector(endPos.getX()-start.getX(),endPos.getY()-start.getY(),endPos.getZ()-start.getZ()); +// double maxDistance = dir.length(); +// RayTraceResult result = entity.getWorld().rayTraceBlocks(start,dir,maxDistance, FluidCollisionMode.NEVER,false); +// if(result == null) ++i; +//// if (entity.getWorld().rayTrace(new RayTrace(vec3d1, endPos, RayTrace.BlockCollisionOption.OUTLINE, RayTrace.FluidCollisionOption.NONE, entity)).getType() == MovingObjectPosition.EnumMovingObjectType.MISS) { +//// ++i; +//// } +// ++j; +// } +// } +// } +// return (float)i / (float)j; +// } else { +// return 0.0F; +// } +// } + + public void fixWorldEnvironment(){ + Bukkit.getWorlds().forEach(world -> { + try{ + if(isTheEnd(world)) getInstance().getNMSManager().setEnvironment(world, World.Environment.THE_END); + }catch(ReflectiveOperationException e){ + e.printStackTrace(); + } + }); + } + private boolean isTheEnd(World world) throws ReflectiveOperationException { + String version = Version.getVersion(); + switch (version) { + case "v1_12_R1" : + case "v1_13_R1" : { + Object world_server = getInstance().getNMSManager().getWorldServer(world); + if(dimension == null) dimension = world_server.getClass().getDeclaredField("dimension"); + int dimen = (int) dimension.get(world_server); + return dimen == 1; + } + case "v1_13_R2" : { + Object world_server = getInstance().getNMSManager().getWorldServer(world); + if(dimension == null) dimension = world_server.getClass().getField("dimension"); + Object DimensionManager = dimension.get(world_server); + if(getDimensionID == null) getDimensionID = DimensionManager.getClass().getMethod("getDimensionID"); + int dimen = (int) getDimensionID.invoke(DimensionManager); + return dimen == 1; + } + case "v1_14_R1" : + case "v1_15_R1" : { + Object world_server = getInstance().getNMSManager().getWorldServer(world); + if(world_provider == null) world_provider = world_server.getClass().getField("worldProvider"); + Object worldProvider = world_provider.get(world_server); + if(dimension == null) dimension = getInstance().getNMSManager().getWorldProviderClass().getDeclaredField("f"); + dimension.setAccessible(true); + Object DimensionManager = dimension.get(worldProvider); + if(getDimensionID == null) getDimensionID = DimensionManager.getClass().getMethod("getDimensionID"); + int dimen = (int) getDimensionID.invoke(DimensionManager); + return dimen == 1; + } + case "v1_16_R1" : + case "v1_16_R2" : + case "v1_16_R3" : + case "v1_17_R1" : { + Object world_server = getInstance().getNMSManager().getWorldServer(world); + if(getDimensionID == null) getDimensionID = getInstance().getNMSManager().getWorldClass().getMethod("getDimensionKey"); + Object world_type = getDimensionID.invoke(world_server); + return world_type.toString().contains("minecraft:the_end"); + } + default : { + if(Version.mcMainVersion < 12){ + Lang.warn("Your server version (" + version + ") is not supported!"); + return false; + } + Object world_server = getInstance().getNMSManager().getWorldServer(world); + if(getDimensionID == null) getDimensionID = world_server.getClass().getMethod("getTypeKey"); + Object world_type = getDimensionID.invoke(world_server); + return world_type.toString().contains("minecraft:the_end"); + } + } + /* + try{ + //>=1.18 建议使用WorldServer::getTypeKey + Object world_server = getInstance().getNMSManager().getWorldServer(world); + Class World_Class = Class.forName("net.minecraft.server."+ Version.getVersion()+".World");//<=1.16.5 + Object world_type = World_Class.getDeclaredMethod("getDimensionKey").invoke(world_server);//<=1.17.1 + + String string_type = world_type.toString(); + Bukkit.broadcastMessage(string_type); + + Class ResourceKey_Class = Class.forName("net.minecraft.server."+Version.getVersion()+".ResourceKey"); + Object ResourceKey = ResourceKey_Class.cast(world_type); + Object MinecraftKey = ResourceKey_Class.getDeclaredMethod("a").invoke(ResourceKey); + Class MinecraftKey_Class = Class.forName("net.minecraft.server."+Version.getVersion()+".MinecraftKey"); + String string_type2 = (String) MinecraftKey_Class.getDeclaredMethod("getKey").invoke(MinecraftKey); + Bukkit.broadcastMessage(string_type2); + + + + +// Object world_c = getCraftWorld(world); +// Object envi = CraftWorldClass.getDeclaredMethod("getEnvironment").invoke(world_c); +// World.Environment environment = (World.Environment) envi; +// Bukkit.broadcastMessage(environment.toString()); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + */ + } + +} + diff --git a/src/main/java/pers/xanadu/enderdragon/maven/Dependency.java b/src/main/java/pers/xanadu/enderdragon/maven/Dependency.java new file mode 100644 index 0000000..0e516e8 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/maven/Dependency.java @@ -0,0 +1,144 @@ +package pers.xanadu.enderdragon.maven; + +import me.lucko.jarrelocator.JarRelocator; +import me.lucko.jarrelocator.Relocation; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +import static pers.xanadu.enderdragon.maven.DependencyManager.*; + +public class Dependency { + protected final String groupId; + protected final String artifactId; + protected final String version; + private final String repository; + private final AlgorithmType algorithm; + protected final String path; + private final List relocate_rules_str; + private final List rules = new ArrayList<>(); + public Dependency(String groupId, String artifactId, String version){ + this(groupId,artifactId,version,"https://repo1.maven.org/maven2/",AlgorithmType.SHA_1, Collections.emptyList()); + } + public Dependency(String groupId,String artifactId,String version,String repository,AlgorithmType algo,List relocate_rules){ + this.groupId = groupId; + this.artifactId = artifactId; + this.version = version; + this.repository = repository.endsWith("/")?repository:repository+"/"; + this.algorithm = algo; + this.relocate_rules_str = relocate_rules; + this.path = groupId.replaceAll("\\.","/") + "/" + + artifactId.replaceAll("\\.","/") + "/" + + version; + int rule_size = relocate_rules.size()/2; + for(int i=0;i dependency_set = new TreeSet<>(); + private static final Logger logger = Bukkit.getLogger(); + private static boolean dep_groovy = false; + public static void onEnable(){ + dependency_set.clear(); + List rules = Collections.emptyList(); +// List rules = Arrays.asList( +// "groovy","xanadu.groovy", +// "org.apache.groovy","xanadu.org.apache.groovy" +// ); + Dependency groovy = new Dependency("org.apache.groovy","groovy","4.0.10","https://repo1.maven.org/maven2/", Dependency.AlgorithmType.SHA_256,rules); + boolean f = groovy.load(); + if(f) dep_groovy = true; + else err("Failed to load library: "+groovy.getName()); + + //addDependency("org.jetbrains.kotlin","kotlin-stdlib","1.7.20"); + //addDependency("com.fasterxml.jackson.core","jackson-databind","2.14.2"); + //loadAllDependency(); + } + @TestOnly + private static void loadAllDependency(){ + dependency_set.forEach(key->{ + String[] splits = key.split("\\$",3); + new Dependency(splits[0],splits[1],splits[2]).load(); + }); + } + @TestOnly + public static void addDependency(String groupId, String artifactId, String version,String... exclusion){ + dependency_set.add(groupId+"$"+artifactId+"$"+version); + if(exclusion!=null && exclusion.length!=0 && "*$*".equals(exclusion[0])) return; + String pom_url = "https://repo1.maven.org/maven2/" + + groupId.replaceAll("\\.", "/") + "/" + + artifactId.replaceAll("\\.","/") + "/" + + version + "/" + artifactId + "-" + version + ".pom"; + String baseDir = "libs\\" + + groupId.replaceAll("\\.", "\\\\") + "\\" + + artifactId.replaceAll("\\.","\\\\") + "\\" + + version; + File folder = new File(baseDir); + folder.mkdirs(); + String filePath = baseDir + "\\" + artifactId + "-" + version + ".pom"; + DependencyManager.downloadFile(pom_url,filePath); + File file = new File(filePath); + try{ + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + DocumentBuilder builder = factory.newDocumentBuilder(); + Document doc = builder.parse(file); + Element root = doc.getDocumentElement(); + Element dependenciesElement = XMLParser.getElement(root,"dependencies"); + if(dependenciesElement == null) return; + NodeList dependencyList = dependenciesElement.getElementsByTagName("dependency"); + for (int i = 0; i < dependencyList.getLength(); i++) { + Element dependencyElement = (Element) dependencyList.item(i); + String nxt_groupId = XMLParser.getString(dependencyElement,"groupId"); + String nxt_artifactId = XMLParser.getString(dependencyElement,"artifactId"); + String nxt_version = XMLParser.getString(dependencyElement,"version"); + if(nxt_groupId==null || nxt_artifactId==null || nxt_version==null){ + return; + } + String scope = XMLParser.getString(dependencyElement,"scope"); + String optional = XMLParser.getString(dependencyElement,"optional"); + //${xxx}如何处理? + //获取不到版本怎么办? + //if(scope.matches("${}")) + if(isRequired(scope,optional)) { + String[] nxt_exclusions = getExclusions(dependencyElement); + String id = nxt_groupId + "$" + nxt_artifactId; + String parent_id = nxt_groupId + "$*"; + if(exclusion!=null){ + boolean add = true; + for(int j=0;j loader) { + try { + return loader.getDeclaredField("ucp"); + } catch (NoSuchFieldError | NoSuchFieldException e2) { + Class superclass = loader.getSuperclass(); + if (superclass == Object.class) { + return null; + } + return ucp(superclass); + } + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/maven/XMLParser.java b/src/main/java/pers/xanadu/enderdragon/maven/XMLParser.java new file mode 100644 index 0000000..1964d69 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/maven/XMLParser.java @@ -0,0 +1,15 @@ +package pers.xanadu.enderdragon.maven; + +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +public class XMLParser { + public static String getString(Element element,String tag){ + Element element_section = getElement(element,tag); + return element_section==null?null:element_section.getTextContent(); + } + public static Element getElement(Element element,String tag){ + NodeList nodeList = element.getElementsByTagName(tag); + return (Element) nodeList.item(0); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/metrics/Metrics.java b/src/main/java/pers/xanadu/enderdragon/metrics/Metrics.java new file mode 100644 index 0000000..c8b9726 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/metrics/Metrics.java @@ -0,0 +1,849 @@ +package pers.xanadu.enderdragon.metrics; + +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.zip.GZIPOutputStream; +import javax.net.ssl.HttpsURLConnection; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; + +public class Metrics { + + private final Plugin plugin; + + private final MetricsBase metricsBase; + + /** + * Creates a new Metrics instance. + * + * @param plugin Your plugin instance. + * @param serviceId The id of the service. It can be found at What is my plugin id? + */ + public Metrics(JavaPlugin plugin, int serviceId) { + this.plugin = plugin; + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + if (!config.isSet("serverUuid")) { + config.addDefault("enabled", true); + config.addDefault("serverUuid", UUID.randomUUID().toString()); + config.addDefault("logFailedRequests", false); + config.addDefault("logSentData", false); + config.addDefault("logResponseStatusText", false); + // Inform the server owners about bStats + config + .options() + .header( + "bStats (https://bStats.org) collects some basic information for plugin authors, like how\n" + + "many people use their plugin and their total player count. It's recommended to keep bStats\n" + + "enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n" + + "performance penalty associated with having metrics enabled, and data sent to bStats is fully\n" + + "anonymous.") + .copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { + } + } + // Load the data + boolean enabled = plugin.getConfig().getBoolean("bStats.enabled", true); + String serverUUID = config.getString("serverUuid"); + boolean logErrors = config.getBoolean("logFailedRequests", false); + boolean logSentData = config.getBoolean("logSentData", false); + boolean logResponseStatusText = config.getBoolean("logResponseStatusText", false); + metricsBase = + new MetricsBase( + "bukkit", + serverUUID, + serviceId, + enabled, + this::appendPlatformData, + this::appendServiceData, + submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask), + plugin::isEnabled, + (message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error), + (message) -> this.plugin.getLogger().log(Level.INFO, message), + logErrors, + logSentData, + logResponseStatusText); + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + metricsBase.addCustomChart(chart); + } + + private void appendPlatformData(JsonObjectBuilder builder) { + builder.appendField("playerAmount", getPlayerAmount()); + builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0); + builder.appendField("bukkitVersion", Bukkit.getVersion()); + builder.appendField("bukkitName", Bukkit.getName()); + builder.appendField("javaVersion", System.getProperty("java.version")); + builder.appendField("osName", System.getProperty("os.name")); + builder.appendField("osArch", System.getProperty("os.arch")); + builder.appendField("osVersion", System.getProperty("os.version")); + builder.appendField("coreCount", Runtime.getRuntime().availableProcessors()); + } + + private void appendServiceData(JsonObjectBuilder builder) { + builder.appendField("pluginVersion", plugin.getDescription().getVersion()); + } + + private int getPlayerAmount() { + try { + // Around MC 1.8 the return type was changed from an array to a collection, + // This fixes java.lang.NoSuchMethodError: + // org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + return onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + // Just use the new method if the reflection failed + return Bukkit.getOnlinePlayers().size(); + } + } + + public static class MetricsBase { + + /** The version of the Metrics class. */ + public static final String METRICS_VERSION = "3.0.0"; + + private static final ScheduledExecutorService scheduler = + Executors.newScheduledThreadPool(1, task -> new Thread(task, "bStats-Metrics")); + + private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s"; + + private final String platform; + + private final String serverUuid; + + private final int serviceId; + + private final Consumer appendPlatformDataConsumer; + + private final Consumer appendServiceDataConsumer; + + private final Consumer submitTaskConsumer; + + private final Supplier checkServiceEnabledSupplier; + + private final BiConsumer errorLogger; + + private final Consumer infoLogger; + + private final boolean logErrors; + + private final boolean logSentData; + + private final boolean logResponseStatusText; + + private final Set customCharts = new HashSet<>(); + + private final boolean enabled; + + /** + * Creates a new MetricsBase class instance. + * + * @param platform The platform of the service. + * @param serviceId The id of the service. + * @param serverUuid The server uuid. + * @param enabled Whether or not data sending is enabled. + * @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all platform-specific data. + * @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all service-specific data. + * @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be + * used to delegate the data collection to a another thread to prevent errors caused by + * concurrency. Can be {@code null}. + * @param checkServiceEnabledSupplier A supplier to check if the service is still enabled. + * @param errorLogger A consumer that accepts log message and an error. + * @param infoLogger A consumer that accepts info log messages. + * @param logErrors Whether or not errors should be logged. + * @param logSentData Whether or not the sent data should be logged. + * @param logResponseStatusText Whether or not the response status text should be logged. + */ + public MetricsBase( + String platform, + String serverUuid, + int serviceId, + boolean enabled, + Consumer appendPlatformDataConsumer, + Consumer appendServiceDataConsumer, + Consumer submitTaskConsumer, + Supplier checkServiceEnabledSupplier, + BiConsumer errorLogger, + Consumer infoLogger, + boolean logErrors, + boolean logSentData, + boolean logResponseStatusText) { + this.platform = platform; + this.serverUuid = serverUuid; + this.serviceId = serviceId; + this.enabled = enabled; + this.appendPlatformDataConsumer = appendPlatformDataConsumer; + this.appendServiceDataConsumer = appendServiceDataConsumer; + this.submitTaskConsumer = submitTaskConsumer; + this.checkServiceEnabledSupplier = checkServiceEnabledSupplier; + this.errorLogger = errorLogger; + this.infoLogger = infoLogger; + this.logErrors = logErrors; + this.logSentData = logSentData; + this.logResponseStatusText = logResponseStatusText; + checkRelocation(); + if (enabled) { + // WARNING: Removing the option to opt-out will get your plugin banned from bStats + startSubmitting(); + } + } + + public void addCustomChart(CustomChart chart) { + this.customCharts.add(chart); + } + + private void startSubmitting() { + final Runnable submitTask = + () -> { + if (!enabled || !checkServiceEnabledSupplier.get()) { + // Submitting data or service is disabled + scheduler.shutdown(); + return; + } + if (submitTaskConsumer != null) { + submitTaskConsumer.accept(this::submitData); + } else { + this.submitData(); + } + }; + // Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution + // of requests on the + // bStats backend. To circumvent this problem, we introduce some randomness into the initial + // and second delay. + // WARNING: You must not modify and part of this Metrics class, including the submit delay or + // frequency! + // WARNING: Modifying this code will get your plugin banned on bStats. Just don't do it! + long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3)); + long secondDelay = (long) (1000 * 60 * (Math.random() * 30)); + scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS); + scheduler.scheduleAtFixedRate( + submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS); + } + + private void submitData() { + final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder(); + appendPlatformDataConsumer.accept(baseJsonBuilder); + final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder(); + appendServiceDataConsumer.accept(serviceJsonBuilder); + JsonObjectBuilder.JsonObject[] chartData = + customCharts.stream() + .map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors)) + .filter(Objects::nonNull) + .toArray(JsonObjectBuilder.JsonObject[]::new); + serviceJsonBuilder.appendField("id", serviceId); + serviceJsonBuilder.appendField("customCharts", chartData); + baseJsonBuilder.appendField("service", serviceJsonBuilder.build()); + baseJsonBuilder.appendField("serverUUID", serverUuid); + baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION); + JsonObjectBuilder.JsonObject data = baseJsonBuilder.build(); + scheduler.execute( + () -> { + try { + // Send the data + sendData(data); + } catch (Exception e) { + // Something went wrong! :( + if (logErrors) { + errorLogger.accept("Could not submit bStats metrics data", e); + } + } + }); + } + + private void sendData(JsonObjectBuilder.JsonObject data) throws Exception { + if (logSentData) { + infoLogger.accept("Sent bStats metrics data: " + data.toString()); + } + String url = String.format(REPORT_URL, platform); + HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection(); + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("User-Agent", "Metrics-Service/1"); + connection.setDoOutput(true); + try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { + outputStream.write(compressedData); + } + StringBuilder builder = new StringBuilder(); + try (BufferedReader bufferedReader = + new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + } + if (logResponseStatusText) { + infoLogger.accept("Sent data to bStats and received response: " + builder); + } + } + + /** Checks that the class was properly relocated. */ + private void checkRelocation() { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null + || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this little + // "trick" ... :D + final String defaultPackage = + new String(new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'}); + final String examplePackage = + new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure no one just copy & pastes the example and uses the wrong package + // names + if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage) + || MetricsBase.class.getPackage().getName().startsWith(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + /** + * Gzips the given string. + * + * @param str The string to gzip. + * @return The gzipped string. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + } + return outputStream.toByteArray(); + } + } + + public static class DrilldownPie extends CustomChart { + + private final Callable>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie(String chartId, Callable>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); + } + } + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class AdvancedPie extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()}); + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public abstract static class CustomChart { + + private final String chartId; + + protected CustomChart(String chartId) { + if (chartId == null) { + throw new IllegalArgumentException("chartId must not be null"); + } + this.chartId = chartId; + } + + public JsonObjectBuilder.JsonObject getRequestJsonObject( + BiConsumer errorLogger, boolean logErrors) { + JsonObjectBuilder builder = new JsonObjectBuilder(); + builder.appendField("chartId", chartId); + try { + JsonObjectBuilder.JsonObject data = getChartData(); + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + builder.appendField("data", data); + } catch (Throwable t) { + if (logErrors) { + errorLogger.accept("Failed to get data for custom chart with id " + chartId, t); + } + return null; + } + return builder.build(); + } + + protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception; + } + + public static class SimplePie extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + String value = callable.call(); + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + public static class AdvancedBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + /** + * An extremely simple JSON builder. + * + *

While this class is neither feature-rich nor the most performant one, it's sufficient enough + * for its use-case. + */ + public static class JsonObjectBuilder { + + private StringBuilder builder = new StringBuilder(); + + private boolean hasAtLeastOneField = false; + + public JsonObjectBuilder() { + builder.append("{"); + } + + /** + * Appends a null field to the JSON. + * + * @param key The key of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendNull(String key) { + appendFieldUnescaped(key, "null"); + return this; + } + + /** + * Appends a string field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String value) { + if (value == null) { + throw new IllegalArgumentException("JSON value must not be null"); + } + appendFieldUnescaped(key, "\"" + escape(value) + "\""); + return this; + } + + /** + * Appends an integer field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int value) { + appendFieldUnescaped(key, String.valueOf(value)); + return this; + } + + /** + * Appends an object to the JSON. + * + * @param key The key of the field. + * @param object The object. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject object) { + if (object == null) { + throw new IllegalArgumentException("JSON object must not be null"); + } + appendFieldUnescaped(key, object.toString()); + return this; + } + + /** + * Appends a string array to the JSON. + * + * @param key The key of the field. + * @param values The string array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values) + .map(value -> "\"" + escape(value) + "\"") + .collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an integer array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an object array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends a field to the object. + * + * @param key The key of the field. + * @param escapedValue The escaped value of the field. + */ + private void appendFieldUnescaped(String key, String escapedValue) { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + if (key == null) { + throw new IllegalArgumentException("JSON key must not be null"); + } + if (hasAtLeastOneField) { + builder.append(","); + } + builder.append("\"").append(escape(key)).append("\":").append(escapedValue); + hasAtLeastOneField = true; + } + + /** + * Builds the JSON string and invalidates this builder. + * + * @return The built JSON string. + */ + public JsonObject build() { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + JsonObject object = new JsonObject(builder.append("}").toString()); + builder = null; + return object; + } + + /** + * Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt. + * + *

This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'. + * Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n"). + * + * @param value The value to escape. + * @return The escaped value. + */ + private static String escape(String value) { + final StringBuilder builder = new StringBuilder(); + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if (c == '"') { + builder.append("\\\""); + } else if (c == '\\') { + builder.append("\\\\"); + } else if (c <= '\u000F') { + builder.append("\\u000").append(Integer.toHexString(c)); + } else if (c <= '\u001F') { + builder.append("\\u00").append(Integer.toHexString(c)); + } else { + builder.append(c); + } + } + return builder.toString(); + } + + /** + * A super simple representation of a JSON object. + * + *

This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not + * allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String, + * JsonObject)}. + */ + public static class JsonObject { + + private final String value; + + private JsonObject(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + } +} \ No newline at end of file diff --git a/src/main/java/pers/xanadu/enderdragon/nms/BossBar/I_BossBarManager.java b/src/main/java/pers/xanadu/enderdragon/nms/BossBar/I_BossBarManager.java new file mode 100644 index 0000000..7968aee --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/BossBar/I_BossBarManager.java @@ -0,0 +1,11 @@ +package pers.xanadu.enderdragon.nms.BossBar; + +import org.bukkit.World; + +import java.util.List; + +public interface I_BossBarManager { + void saveBossBarData(List worlds); + void loadBossBarData(List worlds); + void setBossBar(World world,String title,String color,String style); +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/BossBar/v1_12_R1/BossBarManager.java b/src/main/java/pers/xanadu/enderdragon/nms/BossBar/v1_12_R1/BossBarManager.java new file mode 100644 index 0000000..51171d5 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/BossBar/v1_12_R1/BossBarManager.java @@ -0,0 +1,105 @@ +package pers.xanadu.enderdragon.nms.BossBar.v1_12_R1; + +import net.minecraft.server.v1_12_R1.BossBattle; +import net.minecraft.server.v1_12_R1.BossBattleServer; +import org.bukkit.World; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.craftbukkit.v1_12_R1.util.CraftChatMessage; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.nms.BossBar.I_BossBarManager; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.List; + +import static pers.xanadu.enderdragon.EnderDragon.getInstance; +import static pers.xanadu.enderdragon.EnderDragon.plugin; + +public class BossBarManager implements I_BossBarManager { + private Field BossBattleServer = null; + public void saveBossBarData(List worlds){ + File file = new File(plugin.getDataFolder(),"world_data.yml"); + YamlConfiguration yml = new YamlConfiguration(); + worlds.forEach(world -> { + try{ + Object edb = getInstance().getNMSManager().getEnderDragonBattle(world); + if(BossBattleServer == null) BossBattleServer = edb.getClass().getDeclaredField("c"); + BossBattleServer.setAccessible(true); + BossBattleServer bbs = (BossBattleServer) BossBattleServer.get(edb); + String path = world.getName()+yml.options().pathSeparator(); + yml.set(path+"title",bbs.title.getText()); + yml.set(path+"color",bbs.color.name()); + yml.set(path+"style",bbs.style.name()); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + }); + try{ + yml.save(file); + Lang.info("BossBar data has been saved!"); + }catch (IOException e){ + Lang.error("Failed to save world_data!"); + } + } + public void loadBossBarData(List worlds){ + File file = new File(plugin.getDataFolder(),"world_data.yml"); + if(!file.exists()) return; + Lang.info("Enabling BossBar fix..."); + YamlConfiguration yml = new YamlConfiguration(); + try{ + yml.load(file); + }catch (InvalidConfigurationException | IOException e) { + Lang.error("Failed to load world_data!"); + return; + } + worlds.forEach(world -> { + try{ + Object edb = getInstance().getNMSManager().getEnderDragonBattle(world); + if(BossBattleServer == null) BossBattleServer = edb.getClass().getDeclaredField("c"); + BossBattleServer.setAccessible(true); + BossBattleServer bbs = (BossBattleServer) BossBattleServer.get(edb); + String path = world.getName()+"."; + bbs.title = CraftChatMessage.fromString(yml.getString(path+"title"), true)[0]; + bbs.color = BossBattle.BarColor.valueOf(yml.getString(path+"color")); + bbs.style = BossBattle.BarStyle.valueOf(yml.getString(path+"style")); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + }); + } + public void setBossBar(World world,String title,String color,String style){ + BossBattleServer bbs = new BossBattleServer( + CraftChatMessage.fromString(title, true)[0], + convertColor(color), + convertStyle(style) + ); + bbs.setCreateFog(true); + bbs.setDarkenSky(true); + bbs.setPlayMusic(true); + try{ + Object edb = getInstance().getNMSManager().getEnderDragonBattle(world); + if(BossBattleServer == null) BossBattleServer = edb.getClass().getDeclaredField("c"); + BossBattleServer.setAccessible(true); + BossBattleServer.set(edb,bbs); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + } + private BossBattle.BarColor convertColor(String color) { + return BossBattle.BarColor.valueOf(color); + } + private BossBattle.BarStyle convertStyle(String style) { + switch (style) { + case "SOLID": + default: return net.minecraft.server.v1_12_R1.BossBattle.BarStyle.PROGRESS; + case "SEGMENTED_6": return net.minecraft.server.v1_12_R1.BossBattle.BarStyle.NOTCHED_6; + case "SEGMENTED_10": return net.minecraft.server.v1_12_R1.BossBattle.BarStyle.NOTCHED_10; + case "SEGMENTED_12": return net.minecraft.server.v1_12_R1.BossBattle.BarStyle.NOTCHED_12; + case "SEGMENTED_20": return net.minecraft.server.v1_12_R1.BossBattle.BarStyle.NOTCHED_20; + } + } + + +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/BossBar/v1_13_R1/BossBarManager.java b/src/main/java/pers/xanadu/enderdragon/nms/BossBar/v1_13_R1/BossBarManager.java new file mode 100644 index 0000000..9e268c9 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/BossBar/v1_13_R1/BossBarManager.java @@ -0,0 +1,103 @@ +package pers.xanadu.enderdragon.nms.BossBar.v1_13_R1; + +import net.minecraft.server.v1_13_R1.BossBattle; +import net.minecraft.server.v1_13_R1.BossBattleServer; +import org.bukkit.World; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.craftbukkit.v1_13_R1.util.CraftChatMessage; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.nms.BossBar.I_BossBarManager; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.List; + +import static pers.xanadu.enderdragon.EnderDragon.getInstance; +import static pers.xanadu.enderdragon.EnderDragon.plugin; + +public class BossBarManager implements I_BossBarManager { + private Field BossBattleServer = null; + public void saveBossBarData(List worlds){ + File file = new File(plugin.getDataFolder(),"world_data.yml"); + YamlConfiguration yml = new YamlConfiguration(); + worlds.forEach(world -> { + try{ + Object edb = getInstance().getNMSManager().getEnderDragonBattle(world); + if(BossBattleServer == null) BossBattleServer = edb.getClass().getDeclaredField("c"); + BossBattleServer.setAccessible(true); + BossBattleServer bbs = (BossBattleServer) BossBattleServer.get(edb); + String path = world.getName() + yml.options().pathSeparator(); + yml.set(path+"title",bbs.title.getText()); + yml.set(path+"color",bbs.color.name()); + yml.set(path+"style",bbs.style.name()); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + }); + try{ + yml.save(file); + Lang.info("BossBar data has been saved!"); + }catch (IOException e){ + Lang.error("Failed to save world_data!"); + } + } + public void loadBossBarData(List worlds){ + File file = new File(plugin.getDataFolder(),"world_data.yml"); + if(!file.exists()) return; + Lang.info("Enabling BossBar fix..."); + YamlConfiguration yml = new YamlConfiguration(); + try{ + yml.load(file); + }catch (InvalidConfigurationException | IOException e) { + Lang.error("Failed to load world_data!"); + return; + } + worlds.forEach(world -> { + try{ + Object edb = getInstance().getNMSManager().getEnderDragonBattle(world); + if(BossBattleServer == null) BossBattleServer = edb.getClass().getDeclaredField("c"); + BossBattleServer.setAccessible(true); + BossBattleServer bbs = (BossBattleServer) BossBattleServer.get(edb); + String path = world.getName()+"."; + bbs.title = CraftChatMessage.fromString(yml.getString(path+"title"), true)[0]; + bbs.color = BossBattle.BarColor.valueOf(yml.getString(path+"color")); + bbs.style = BossBattle.BarStyle.valueOf(yml.getString(path+"style")); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + }); + } + public void setBossBar(World world,String title,String color,String style){ + BossBattleServer bbs = new BossBattleServer( + CraftChatMessage.fromString(title, true)[0], + convertColor(color), + convertStyle(style) + ); + bbs.setCreateFog(true); + bbs.setDarkenSky(true); + bbs.setPlayMusic(true); + try{ + Object edb = getInstance().getNMSManager().getEnderDragonBattle(world); + if(BossBattleServer == null) BossBattleServer = edb.getClass().getDeclaredField("c"); + BossBattleServer.setAccessible(true); + BossBattleServer.set(edb,bbs); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + } + private BossBattle.BarColor convertColor(String color) { + return BossBattle.BarColor.valueOf(color); + } + private BossBattle.BarStyle convertStyle(String style) { + switch (style) { + case "SOLID": + default: return net.minecraft.server.v1_13_R1.BossBattle.BarStyle.PROGRESS; + case "SEGMENTED_6": return net.minecraft.server.v1_13_R1.BossBattle.BarStyle.NOTCHED_6; + case "SEGMENTED_10": return net.minecraft.server.v1_13_R1.BossBattle.BarStyle.NOTCHED_10; + case "SEGMENTED_12": return net.minecraft.server.v1_13_R1.BossBattle.BarStyle.NOTCHED_12; + case "SEGMENTED_20": return net.minecraft.server.v1_13_R1.BossBattle.BarStyle.NOTCHED_20; + } + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/BossBar/v1_13_R2/BossBarManager.java b/src/main/java/pers/xanadu/enderdragon/nms/BossBar/v1_13_R2/BossBarManager.java new file mode 100644 index 0000000..940f624 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/BossBar/v1_13_R2/BossBarManager.java @@ -0,0 +1,103 @@ +package pers.xanadu.enderdragon.nms.BossBar.v1_13_R2; + +import net.minecraft.server.v1_13_R2.BossBattle; +import net.minecraft.server.v1_13_R2.BossBattleServer; +import org.bukkit.World; +import org.bukkit.configuration.InvalidConfigurationException; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.craftbukkit.v1_13_R2.util.CraftChatMessage; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.nms.BossBar.I_BossBarManager; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.List; + +import static pers.xanadu.enderdragon.EnderDragon.getInstance; +import static pers.xanadu.enderdragon.EnderDragon.plugin; + +public class BossBarManager implements I_BossBarManager { + private Field BossBattleServer = null; + public void saveBossBarData(List worlds){ + File file = new File(plugin.getDataFolder(),"world_data.yml"); + YamlConfiguration yml = new YamlConfiguration(); + worlds.forEach(world -> { + try{ + Object edb = getInstance().getNMSManager().getEnderDragonBattle(world); + if(BossBattleServer == null) BossBattleServer = edb.getClass().getDeclaredField("bossBattle"); + BossBattleServer.setAccessible(true); + BossBattleServer bbs = (BossBattleServer) BossBattleServer.get(edb); + String path = world.getName() + yml.options().pathSeparator(); + yml.set(path+"title",bbs.title.getText()); + yml.set(path+"color",bbs.color.name()); + yml.set(path+"style",bbs.style.name()); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + }); + try{ + yml.save(file); + Lang.info("BossBar data has been saved!"); + }catch (IOException e){ + Lang.error("Failed to save world_data!"); + } + } + public void loadBossBarData(List worlds){ + File file = new File(plugin.getDataFolder(),"world_data.yml"); + if(!file.exists()) return; + Lang.info("Enabling BossBar fix..."); + YamlConfiguration yml = new YamlConfiguration(); + try{ + yml.load(file); + }catch (InvalidConfigurationException | IOException e) { + Lang.error("Failed to load world_data!"); + return; + } + worlds.forEach(world -> { + try{ + Object edb = getInstance().getNMSManager().getEnderDragonBattle(world); + if(BossBattleServer == null) BossBattleServer = edb.getClass().getDeclaredField("bossBattle"); + BossBattleServer.setAccessible(true); + BossBattleServer bbs = (BossBattleServer) BossBattleServer.get(edb); + String path = world.getName() + yml.options().pathSeparator(); + bbs.title = CraftChatMessage.fromString(yml.getString(path+"title"), true)[0]; + bbs.color = BossBattle.BarColor.valueOf(yml.getString(path+"color")); + bbs.style = BossBattle.BarStyle.valueOf(yml.getString(path+"style")); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + }); + } + public void setBossBar(World world,String title,String color,String style){ + BossBattleServer bbs = new BossBattleServer( + CraftChatMessage.fromString(title, true)[0], + convertColor(color), + convertStyle(style) + ); + bbs.setCreateFog(true); + bbs.setDarkenSky(true); + bbs.setPlayMusic(true); + try{ + Object edb = getInstance().getNMSManager().getEnderDragonBattle(world); + if(BossBattleServer == null) BossBattleServer = edb.getClass().getField("bossBattle"); + BossBattleServer.setAccessible(true); + BossBattleServer.set(edb,bbs); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + } + private BossBattle.BarColor convertColor(String color) { + return BossBattle.BarColor.valueOf(color); + } + private BossBattle.BarStyle convertStyle(String style) { + switch (style) { + case "SOLID": + default: return net.minecraft.server.v1_13_R2.BossBattle.BarStyle.PROGRESS; + case "SEGMENTED_6": return net.minecraft.server.v1_13_R2.BossBattle.BarStyle.NOTCHED_6; + case "SEGMENTED_10": return net.minecraft.server.v1_13_R2.BossBattle.BarStyle.NOTCHED_10; + case "SEGMENTED_12": return net.minecraft.server.v1_13_R2.BossBattle.BarStyle.NOTCHED_12; + case "SEGMENTED_20": return net.minecraft.server.v1_13_R2.BossBattle.BarStyle.NOTCHED_20; + } + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/I_NMSItemManager.java b/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/I_NMSItemManager.java new file mode 100644 index 0000000..d1704c4 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/I_NMSItemManager.java @@ -0,0 +1,11 @@ +package pers.xanadu.enderdragon.nms.NMSItem; + +import org.bukkit.inventory.ItemStack; + +public interface I_NMSItemManager { + ItemStack readAsItem(String nbt); + ItemStack cpdToItem(Object cpd); + Object parseNBT(Object nbt_base); + Object readAsNBTBase(String raw); + Object getNBTBase(Object obj); +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_12_R1/CraftNBTTagConfigSerializer.java b/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_12_R1/CraftNBTTagConfigSerializer.java new file mode 100644 index 0000000..ce86e30 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_12_R1/CraftNBTTagConfigSerializer.java @@ -0,0 +1,146 @@ +package pers.xanadu.enderdragon.nms.NMSItem.v1_12_R1; + +import net.minecraft.server.v1_12_R1.*; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.*; +import java.util.regex.Pattern; + +public class CraftNBTTagConfigSerializer { + private static final Pattern ARRAY = Pattern.compile("^\\[.*]"); + private static final Pattern INTEGER = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)?i", 2); + private static final Pattern DOUBLE = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?d", 2); + private static final Pattern byte_format = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)b", 2); + private static final Pattern short_format = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)s", 2); + private static final Pattern integer_format = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)"); + private static final Pattern long_format = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)l", 2); + private static final Pattern float_format = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?f", 2); + private static final Pattern double_format = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?d", 2); + private static final Pattern double_format2 = Pattern.compile("[-+]?(?:[0-9]+[.]|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?", 2); + + + public CraftNBTTagConfigSerializer() { + } + + public static Object serialize(NBTBase base) { + if (base instanceof NBTTagCompound) { + Map innerMap = new HashMap(); + + for (String key : ((NBTTagCompound) base).c()) { + innerMap.put(key, serialize(((NBTTagCompound) base).get(key))); + } + + return innerMap; + } + if (base instanceof NBTTagString) { + return ((NBTTagString) base).c_(); + } + else { + return base instanceof NBTTagInt ? base + "i" : base.toString(); + } + + } + + public static NBTBase deserialize(Object object) { + if (object instanceof Map) { + NBTTagCompound compound = new NBTTagCompound(); + for (Object obj : ((Map) object).entrySet()) { + Map.Entry entry = (Map.Entry) obj; + compound.set(entry.getKey(), deserialize(entry.getValue())); + } + return compound; + } else if (!(object instanceof List)) { + if (object instanceof String) { + String string = (String)object; + if (ARRAY.matcher(string).matches()) { + try { + Constructor constructor = MojangsonParser.class.getDeclaredConstructor(String.class); + MojangsonParser parser = constructor.newInstance(string); + Method parseArray = MojangsonParser.class.getDeclaredMethod("k"); + parseArray.setAccessible(true); + return (NBTBase) parseArray.invoke(parser); + } catch (Throwable e) { + throw new RuntimeException("Could not deserialize found list ", e); + } + } else if (INTEGER.matcher(string).matches()) { + return new NBTTagInt(Integer.parseInt(string.substring(0, string.length() - 1))); + } else if (DOUBLE.matcher(string).matches()) { + return new NBTTagDouble(Double.parseDouble(string.substring(0, string.length() - 1))); + } else { + try{ + Constructor constructor = MojangsonParser.class.getDeclaredConstructor(String.class); + MojangsonParser parser = constructor.newInstance(""); + Method parseLiteral = MojangsonParser.class.getDeclaredMethod("c", String.class); + parseLiteral.setAccessible(true); + NBTBase nbtBase = (NBTBase) parseLiteral.invoke(parser,string); + if (nbtBase instanceof NBTTagInt) { + return new NBTTagString(nbtBase.toString()); + } else { + return (nbtBase instanceof NBTTagDouble ? new NBTTagString(String.valueOf(((NBTTagDouble)nbtBase).asDouble())) : nbtBase); + } + }catch (ReflectiveOperationException e){ + throw new RuntimeException("Could not deserialize NBTBase"); + } + + } + } else { + throw new RuntimeException("Could not deserialize NBTBase"); + } + } else { + List list = (List)object; + if (list.isEmpty()) { + return new NBTTagList(); + } + else { + NBTTagList tagList = new NBTTagList(); + for (Object tag : list) { + tagList.add(deserialize(tag)); + } + return tagList; + } + } + } + public static NBTBase v1_12_R1_c(String raw) { + try { + if (float_format.matcher(raw).matches()) { + return new NBTTagFloat(Float.parseFloat(raw.substring(0, raw.length() - 1))); + } + + if (byte_format.matcher(raw).matches()) { + return new NBTTagByte(Byte.parseByte(raw.substring(0, raw.length() - 1))); + } + + if (long_format.matcher(raw).matches()) { + return new NBTTagLong(Long.parseLong(raw.substring(0, raw.length() - 1))); + } + + if (short_format.matcher(raw).matches()) { + return new NBTTagShort(Short.parseShort(raw.substring(0, raw.length() - 1))); + } + + if (integer_format.matcher(raw).matches()) { + return new NBTTagInt(Integer.parseInt(raw)); + } + + if (double_format.matcher(raw).matches()) { + return new NBTTagDouble(Double.parseDouble(raw.substring(0, raw.length() - 1))); + } + + if (double_format2.matcher(raw).matches()) { + return new NBTTagDouble(Double.parseDouble(raw)); + } + + if ("true".equalsIgnoreCase(raw)) { + return new NBTTagByte((byte)1); + } + + if ("false".equalsIgnoreCase(raw)) { + return new NBTTagByte((byte)0); + } + } catch (NumberFormatException e) { + e.printStackTrace(); + } + return new NBTTagString(raw); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_12_R1/NMSItemManager.java b/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_12_R1/NMSItemManager.java new file mode 100644 index 0000000..7eaffea --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_12_R1/NMSItemManager.java @@ -0,0 +1,35 @@ +package pers.xanadu.enderdragon.nms.NMSItem.v1_12_R1; + +import net.minecraft.server.v1_12_R1.*; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_12_R1.inventory.CraftItemStack; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.nms.NMSItem.I_NMSItemManager; + +public class NMSItemManager implements I_NMSItemManager { + + public org.bukkit.inventory.ItemStack readAsItem(String nbt){ + try { + NBTTagCompound cpd = MojangsonParser.parse(nbt); + ItemStack ei = new ItemStack(cpd); + return CraftItemStack.asBukkitCopy(ei); + } catch (MojangsonParseException e) { + Lang.error("Wrong item nbt format:"+nbt); + return new org.bukkit.inventory.ItemStack(Material.AIR); + } + } + public org.bukkit.inventory.ItemStack cpdToItem(Object cpd){ + ItemStack ei = new ItemStack((NBTTagCompound) cpd); + return CraftItemStack.asBukkitCopy(ei); + } + public Object parseNBT(Object nbt_base){ + return CraftNBTTagConfigSerializer.serialize((NBTBase) nbt_base); + } + public Object readAsNBTBase(String raw){ + return CraftNBTTagConfigSerializer.v1_12_R1_c(raw); + } + public Object getNBTBase(Object obj){ + return CraftNBTTagConfigSerializer.deserialize(obj); + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_13_R1/CraftNBTTagConfigSerializer.java b/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_13_R1/CraftNBTTagConfigSerializer.java new file mode 100644 index 0000000..d0b6947 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_13_R1/CraftNBTTagConfigSerializer.java @@ -0,0 +1,151 @@ +package pers.xanadu.enderdragon.nms.NMSItem.v1_13_R1; + +import com.mojang.brigadier.StringReader; +import net.minecraft.server.v1_13_R1.*; + +import java.lang.reflect.Method; +import java.util.*; +import java.util.regex.Pattern; + +public class CraftNBTTagConfigSerializer { + private static final Pattern ARRAY = Pattern.compile("^\\[.*]"); + private static final Pattern INTEGER = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)?i", 2); + private static final Pattern DOUBLE = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?d", 2); + public static final MojangsonParser MOJANGSON_PARSER = new MojangsonParser(new StringReader("")); + private static final Pattern byte_format = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)b", 2); + private static final Pattern short_format = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)s", 2); + private static final Pattern integer_format = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)"); + private static final Pattern long_format = Pattern.compile("[-+]?(?:0|[1-9][0-9]*)l", 2); + private static final Pattern float_format = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?f", 2); + private static final Pattern double_format = Pattern.compile("[-+]?(?:[0-9]+[.]?|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?d", 2); + private static final Pattern double_format_2 = Pattern.compile("[-+]?(?:[0-9]+[.]|[0-9]*[.][0-9]+)(?:e[-+]?[0-9]+)?", 2); + + public CraftNBTTagConfigSerializer() { + } + + public static Object serialize(NBTBase base) { + if (base instanceof NBTTagCompound) { + Map innerMap = new HashMap(); + Iterator var3 = ((NBTTagCompound)base).getKeys().iterator(); + + while(var3.hasNext()) { + String key = (String)var3.next(); + innerMap.put(key, serialize(((NBTTagCompound)base).get(key))); + } + + return innerMap; + } else if (!(base instanceof NBTTagList)) { + if (base instanceof NBTTagString) { + return base.b_(); + } else { + return base instanceof NBTTagInt ? base + "i" : base.toString(); + } + } else { + List baseList = new ArrayList(); + + for(int i = 0; i < ((NBTList)base).size(); ++i) { + baseList.add(serialize(((NBTList)base).get(i))); + } + + return baseList; + } + } + + public static NBTBase v1_13_R1_b(String str) { + try { + if (float_format.matcher(str).matches()) { + return new NBTTagFloat(Float.parseFloat(str.substring(0, str.length() - 1))); + } + + if (byte_format.matcher(str).matches()) { + return new NBTTagByte(Byte.parseByte(str.substring(0, str.length() - 1))); + } + + if (long_format.matcher(str).matches()) { + return new NBTTagLong(Long.parseLong(str.substring(0, str.length() - 1))); + } + + if (short_format.matcher(str).matches()) { + return new NBTTagShort(Short.parseShort(str.substring(0, str.length() - 1))); + } + + if (integer_format.matcher(str).matches()) { + return new NBTTagInt(Integer.parseInt(str)); + } + + if (double_format.matcher(str).matches()) { + return new NBTTagDouble(Double.parseDouble(str.substring(0, str.length() - 1))); + } + + if (double_format_2.matcher(str).matches()) { + return new NBTTagDouble(Double.parseDouble(str)); + } + + if ("true".equalsIgnoreCase(str)) { + return new NBTTagByte((byte)1); + } + + if ("false".equalsIgnoreCase(str)) { + return new NBTTagByte((byte)0); + } + } catch (NumberFormatException e) { + e.printStackTrace(); + } + return new NBTTagString(str); + } + + public static NBTBase deserialize(Object object) { + if (object instanceof Map) { + NBTTagCompound compound = new NBTTagCompound(); + for (Object obj : ((Map) object).entrySet()) { + Map.Entry entry = (Map.Entry) obj; + compound.set(entry.getKey(), deserialize(entry.getValue())); + } + return compound; + } else if (!(object instanceof List)) { + if (object instanceof String) { + String string = (String)object; + if (ARRAY.matcher(string).matches()) { + try { + Method parseArray = MojangsonParser.class.getDeclaredMethod("h"); + parseArray.setAccessible(true); + MojangsonParser parser = new MojangsonParser(new StringReader(string)); + return (NBTBase) parseArray.invoke(parser); + } catch (Throwable e) { + throw new RuntimeException("Could not deserialize found list ", e); + } + } else if (INTEGER.matcher(string).matches()) { + return new NBTTagInt(Integer.parseInt(string.substring(0, string.length() - 1))); + } else if (DOUBLE.matcher(string).matches()) { + return new NBTTagDouble(Double.parseDouble(string.substring(0, string.length() - 1))); + } else { + try{ + Method parseLiteral = MojangsonParser.class.getDeclaredMethod("b", String.class); + parseLiteral.setAccessible(true); + NBTBase nbtBase = (NBTBase) parseLiteral.invoke(MOJANGSON_PARSER,string); + if (nbtBase instanceof NBTTagInt) { + return new NBTTagString(nbtBase.b_()); + } else { + return (nbtBase instanceof NBTTagDouble ? new NBTTagString(String.valueOf(((NBTTagDouble)nbtBase).asDouble())) : nbtBase); + } + }catch (ReflectiveOperationException e){ + throw new RuntimeException("Could not deserialize NBTBase"); + } + } + } else { + throw new RuntimeException("Could not deserialize NBTBase"); + } + } else { + List list = (List)object; + if (list.isEmpty()) { + return new NBTTagList(); + } else { + NBTTagList tagList = new NBTTagList(); + for (Object tag : list) { + tagList.add(deserialize(tag)); + } + return tagList; + } + } + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_13_R1/NMSItemManager.java b/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_13_R1/NMSItemManager.java new file mode 100644 index 0000000..1642a4e --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_13_R1/NMSItemManager.java @@ -0,0 +1,37 @@ +package pers.xanadu.enderdragon.nms.NMSItem.v1_13_R1; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.server.v1_13_R1.ItemStack; +import net.minecraft.server.v1_13_R1.MojangsonParser; +import net.minecraft.server.v1_13_R1.NBTBase; +import net.minecraft.server.v1_13_R1.NBTTagCompound; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_13_R1.inventory.CraftItemStack; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.nms.NMSItem.I_NMSItemManager; + +public class NMSItemManager implements I_NMSItemManager { + public org.bukkit.inventory.ItemStack readAsItem(String nbt){ + try { + NBTTagCompound cpd = MojangsonParser.parse(nbt); + ItemStack ei = ItemStack.a(cpd); + return CraftItemStack.asBukkitCopy(ei); + } catch (CommandSyntaxException e) { + Lang.error("Wrong item nbt format:"+nbt); + return new org.bukkit.inventory.ItemStack(Material.AIR); + } + } + public org.bukkit.inventory.ItemStack cpdToItem(Object cpd){ + ItemStack ei = ItemStack.a((NBTTagCompound) cpd); + return CraftItemStack.asBukkitCopy(ei); + } + public Object parseNBT(Object nbt_base){ + return CraftNBTTagConfigSerializer.serialize((NBTBase) nbt_base); + } + public Object readAsNBTBase(String raw){ + return CraftNBTTagConfigSerializer.v1_13_R1_b(raw); + } + public Object getNBTBase(Object obj){ + return CraftNBTTagConfigSerializer.deserialize(obj); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_13_R2_above/NMSItemManager.java b/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_13_R2_above/NMSItemManager.java new file mode 100644 index 0000000..90e1b63 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/NMSItem/v1_13_R2_above/NMSItemManager.java @@ -0,0 +1,30 @@ +package pers.xanadu.enderdragon.nms.NMSItem.v1_13_R2_above; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import pers.xanadu.enderdragon.EnderDragon; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.nms.NMSItem.I_NMSItemManager; + +public class NMSItemManager implements I_NMSItemManager { + public ItemStack readAsItem(String nbt){ + try { + return EnderDragon.getInstance().getNMSManager().getItemStack(nbt); + } catch (Throwable e) { + Lang.error("Wrong item nbt format:"+nbt); + return new org.bukkit.inventory.ItemStack(Material.AIR); + } + } + public ItemStack cpdToItem(Object cpd){ + return EnderDragon.getInstance().getNMSManager().getItemStack(cpd); + } + public Object parseNBT(Object nbt_base){ + return EnderDragon.getInstance().getNMSManager().serializeNBTBase(nbt_base); + } + public Object readAsNBTBase(String raw){ + return EnderDragon.getInstance().getNMSManager().StringParseLiteral(raw); + } + public Object getNBTBase(Object obj){ + return EnderDragon.getInstance().getNMSManager().deserializeObject(obj); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/I_RespawnAnchorManager.java b/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/I_RespawnAnchorManager.java new file mode 100644 index 0000000..98ec9f9 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/I_RespawnAnchorManager.java @@ -0,0 +1,7 @@ +package pers.xanadu.enderdragon.nms.RespawnAnchor; + +import org.bukkit.World; + +public interface I_RespawnAnchorManager { + boolean isRespawnAnchorWorks(World world); +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_16_R1/RespawnAnchorManager.java b/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_16_R1/RespawnAnchorManager.java new file mode 100644 index 0000000..214724f --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_16_R1/RespawnAnchorManager.java @@ -0,0 +1,15 @@ +package pers.xanadu.enderdragon.nms.RespawnAnchor.v1_16_R1; + +import net.minecraft.server.v1_16_R1.DimensionManager; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_16_R1.CraftWorld; +import pers.xanadu.enderdragon.nms.RespawnAnchor.I_RespawnAnchorManager; + +public class RespawnAnchorManager implements I_RespawnAnchorManager { + public boolean isRespawnAnchorWorks(World world){ + CraftWorld cw = (CraftWorld) world; + net.minecraft.server.v1_16_R1.World ew = cw.getHandle(); + DimensionManager dm = ew.getDimensionManager(); + return dm.isRespawnAnchorWorks(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_16_R2/RespawnAnchorManager.java b/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_16_R2/RespawnAnchorManager.java new file mode 100644 index 0000000..3493704 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_16_R2/RespawnAnchorManager.java @@ -0,0 +1,15 @@ +package pers.xanadu.enderdragon.nms.RespawnAnchor.v1_16_R2; + +import net.minecraft.server.v1_16_R2.DimensionManager; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_16_R2.CraftWorld; +import pers.xanadu.enderdragon.nms.RespawnAnchor.I_RespawnAnchorManager; + +public class RespawnAnchorManager implements I_RespawnAnchorManager { + public boolean isRespawnAnchorWorks(World world){ + CraftWorld cw = (CraftWorld) world; + net.minecraft.server.v1_16_R2.World ew = cw.getHandle(); + DimensionManager dm = ew.getDimensionManager(); + return dm.isRespawnAnchorWorks(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_16_R3/RespawnAnchorManager.java b/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_16_R3/RespawnAnchorManager.java new file mode 100644 index 0000000..8956c12 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_16_R3/RespawnAnchorManager.java @@ -0,0 +1,15 @@ +package pers.xanadu.enderdragon.nms.RespawnAnchor.v1_16_R3; + +import net.minecraft.server.v1_16_R3.DimensionManager; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; +import pers.xanadu.enderdragon.nms.RespawnAnchor.I_RespawnAnchorManager; + +public class RespawnAnchorManager implements I_RespawnAnchorManager { + public boolean isRespawnAnchorWorks(World world){ + CraftWorld cw = (CraftWorld) world; + net.minecraft.server.v1_16_R3.World ew = cw.getHandle(); + DimensionManager dm = ew.getDimensionManager(); + return dm.isRespawnAnchorWorks(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_17_R1/RespawnAnchorManager.java b/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_17_R1/RespawnAnchorManager.java new file mode 100644 index 0000000..04f8c40 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_17_R1/RespawnAnchorManager.java @@ -0,0 +1,15 @@ +package pers.xanadu.enderdragon.nms.RespawnAnchor.v1_17_R1; + +import net.minecraft.world.level.dimension.DimensionManager; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; +import pers.xanadu.enderdragon.nms.RespawnAnchor.I_RespawnAnchorManager; + +public class RespawnAnchorManager implements I_RespawnAnchorManager { + public boolean isRespawnAnchorWorks(World world){ + CraftWorld cw = (CraftWorld) world; + net.minecraft.world.level.World ew = cw.getHandle(); + DimensionManager dm = ew.getDimensionManager(); + return dm.isRespawnAnchorWorks(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_18_above/RespawnAnchorManager.java b/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_18_above/RespawnAnchorManager.java new file mode 100644 index 0000000..3ef57e2 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/RespawnAnchor/v1_18_above/RespawnAnchorManager.java @@ -0,0 +1,10 @@ +package pers.xanadu.enderdragon.nms.RespawnAnchor.v1_18_above; + +import org.bukkit.World; +import pers.xanadu.enderdragon.nms.RespawnAnchor.I_RespawnAnchorManager; + +public class RespawnAnchorManager implements I_RespawnAnchorManager { + public boolean isRespawnAnchorWorks(World world){ + return world.isRespawnAnchorWorks(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/WorldData/I_WorldDataManager.java b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/I_WorldDataManager.java new file mode 100644 index 0000000..187b97a --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/I_WorldDataManager.java @@ -0,0 +1,7 @@ +package pers.xanadu.enderdragon.nms.WorldData; + +import org.bukkit.World; + +public interface I_WorldDataManager { + long getGameTime(World world); +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_12_R1/WorldDataManager.java b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_12_R1/WorldDataManager.java new file mode 100644 index 0000000..67f1795 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_12_R1/WorldDataManager.java @@ -0,0 +1,14 @@ +package pers.xanadu.enderdragon.nms.WorldData.v1_12_R1; + +import net.minecraft.server.v1_12_R1.WorldServer; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; +import pers.xanadu.enderdragon.nms.WorldData.I_WorldDataManager; + +public class WorldDataManager implements I_WorldDataManager { + public long getGameTime(World world){ + CraftWorld cw = (CraftWorld) world; + WorldServer ws = cw.getHandle(); + return ws.getTime(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_13_R1/WorldDataManager.java b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_13_R1/WorldDataManager.java new file mode 100644 index 0000000..8b41385 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_13_R1/WorldDataManager.java @@ -0,0 +1,14 @@ +package pers.xanadu.enderdragon.nms.WorldData.v1_13_R1; + +import net.minecraft.server.v1_13_R1.WorldServer; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_13_R1.CraftWorld; +import pers.xanadu.enderdragon.nms.WorldData.I_WorldDataManager; + +public class WorldDataManager implements I_WorldDataManager { + public long getGameTime(World world){ + CraftWorld cw = (CraftWorld) world; + WorldServer ws = cw.getHandle(); + return ws.getTime(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_13_R2/WorldDataManager.java b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_13_R2/WorldDataManager.java new file mode 100644 index 0000000..e76ef5c --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_13_R2/WorldDataManager.java @@ -0,0 +1,14 @@ +package pers.xanadu.enderdragon.nms.WorldData.v1_13_R2; + +import net.minecraft.server.v1_13_R2.WorldServer; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; +import pers.xanadu.enderdragon.nms.WorldData.I_WorldDataManager; + +public class WorldDataManager implements I_WorldDataManager { + public long getGameTime(World world){ + CraftWorld cw = (CraftWorld) world; + WorldServer ws = cw.getHandle(); + return ws.getTime(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_14_R1/WorldDataManager.java b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_14_R1/WorldDataManager.java new file mode 100644 index 0000000..b0fd469 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_14_R1/WorldDataManager.java @@ -0,0 +1,14 @@ +package pers.xanadu.enderdragon.nms.WorldData.v1_14_R1; + +import net.minecraft.server.v1_14_R1.WorldServer; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; +import pers.xanadu.enderdragon.nms.WorldData.I_WorldDataManager; + +public class WorldDataManager implements I_WorldDataManager { + public long getGameTime(World world){ + CraftWorld cw = (CraftWorld) world; + WorldServer ws = cw.getHandle(); + return ws.getTime(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_15_R1/WorldDataManager.java b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_15_R1/WorldDataManager.java new file mode 100644 index 0000000..f2e35f9 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_15_R1/WorldDataManager.java @@ -0,0 +1,14 @@ +package pers.xanadu.enderdragon.nms.WorldData.v1_15_R1; + +import net.minecraft.server.v1_15_R1.WorldServer; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; +import pers.xanadu.enderdragon.nms.WorldData.I_WorldDataManager; + +public class WorldDataManager implements I_WorldDataManager { + public long getGameTime(World world){ + CraftWorld cw = (CraftWorld) world; + WorldServer ws = cw.getHandle(); + return ws.getTime(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_16_R1/WorldDataManager.java b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_16_R1/WorldDataManager.java new file mode 100644 index 0000000..235f80a --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_16_R1/WorldDataManager.java @@ -0,0 +1,14 @@ +package pers.xanadu.enderdragon.nms.WorldData.v1_16_R1; + +import net.minecraft.server.v1_16_R1.WorldServer; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_16_R1.CraftWorld; +import pers.xanadu.enderdragon.nms.WorldData.I_WorldDataManager; + +public class WorldDataManager implements I_WorldDataManager { + public long getGameTime(World world){ + CraftWorld cw = (CraftWorld) world; + WorldServer ws = cw.getHandle(); + return ws.getTime(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_16_R2/WorldDataManager.java b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_16_R2/WorldDataManager.java new file mode 100644 index 0000000..1fc537c --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_16_R2/WorldDataManager.java @@ -0,0 +1,14 @@ +package pers.xanadu.enderdragon.nms.WorldData.v1_16_R2; + +import net.minecraft.server.v1_16_R2.WorldServer; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_16_R2.CraftWorld; +import pers.xanadu.enderdragon.nms.WorldData.I_WorldDataManager; + +public class WorldDataManager implements I_WorldDataManager { + public long getGameTime(World world){ + CraftWorld cw = (CraftWorld) world; + WorldServer ws = cw.getHandle(); + return ws.getTime(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_16_R3/WorldDataManager.java b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_16_R3/WorldDataManager.java new file mode 100644 index 0000000..0a4b223 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_16_R3/WorldDataManager.java @@ -0,0 +1,14 @@ +package pers.xanadu.enderdragon.nms.WorldData.v1_16_R3; + +import net.minecraft.server.v1_16_R3.WorldServer; +import org.bukkit.World; +import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; +import pers.xanadu.enderdragon.nms.WorldData.I_WorldDataManager; + +public class WorldDataManager implements I_WorldDataManager { + public long getGameTime(World world){ + CraftWorld cw = (CraftWorld) world; + WorldServer ws = cw.getHandle(); + return ws.getTime(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_17_above/WorldDataManager.java b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_17_above/WorldDataManager.java new file mode 100644 index 0000000..fcd0f86 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/nms/WorldData/v1_17_above/WorldDataManager.java @@ -0,0 +1,10 @@ +package pers.xanadu.enderdragon.nms.WorldData.v1_17_above; + +import org.bukkit.World; +import pers.xanadu.enderdragon.nms.WorldData.I_WorldDataManager; + +public class WorldDataManager implements I_WorldDataManager { + public long getGameTime(World world){ + return world.getGameTime(); + } +}