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