diff --git a/src/main/java/pers/xanadu/enderdragon/reward/Chance.java b/src/main/java/pers/xanadu/enderdragon/reward/Chance.java new file mode 100644 index 0000000..e9a8ccb --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/reward/Chance.java @@ -0,0 +1,22 @@ +package pers.xanadu.enderdragon.reward; + + +public class Chance { + private double value; + private String str; + public Chance(Chance chance){ + str = chance.str; + value = chance.value; + } + public Chance(double d0,String str){ + this.str = str; + this.value = d0; + } + public double getValue(){ + return value; + } + public String getStr(){ + return str; + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/reward/DistType.java b/src/main/java/pers/xanadu/enderdragon/reward/DistType.java new file mode 100644 index 0000000..f8d72a8 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/reward/DistType.java @@ -0,0 +1,28 @@ +package pers.xanadu.enderdragon.reward; + +import java.util.Map; +import java.util.TreeMap; + +public enum DistType { + killer, + drop,//glow? + all, + rank,//num + pack,//num + termwise, + unknown; + + private static final Map mp = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + + public static DistType getByName(String str){ + //if(str == null) return drop; + return mp.getOrDefault(str,unknown); + } + static { + DistType[] values = DistType.values(); + for (DistType type : values) { + String name = type.name(); + mp.put(name, type); + } + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/reward/Reward.java b/src/main/java/pers/xanadu/enderdragon/reward/Reward.java new file mode 100644 index 0000000..6bc6cf6 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/reward/Reward.java @@ -0,0 +1,50 @@ +package pers.xanadu.enderdragon.reward; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import pers.xanadu.enderdragon.manager.ItemManager; + + +public class Reward extends ItemStack { + protected String name; + protected Chance chance; + private ItemStack item; + + @Override + public String toString(){ + return ItemManager.write(this); + } + + public String getName() { + return this.name; + } +// +// @Override +// public int hashCode() { +// return this.name.hashCode(); +// } + + public ItemStack getItem() { + if(item == null) return new ItemStack(Material.AIR); + return item.clone(); + } + public Chance getChance(){ + return this.chance; + } + + + + protected Reward(ItemStack item,String chance) { + this.item = item; + + } + public Reward(ItemStack item, Chance chance){ + this.item = item; + this.chance = chance; + } + public Reward(ItemStack item){ + this.item = item; + this.chance = null; + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/reward/RewardDist.java b/src/main/java/pers/xanadu/enderdragon/reward/RewardDist.java new file mode 100644 index 0000000..2b41a98 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/reward/RewardDist.java @@ -0,0 +1,59 @@ +package pers.xanadu.enderdragon.reward; + +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.reward.dist.*; +import pers.xanadu.enderdragon.util.MyDragon; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +public abstract class RewardDist { + public static RewardDist parse(ConfigurationSection section){ + if(section == null) return new Dist_Drop(); + String type_name = section.getString("type"); + DistType type = DistType.getByName(type_name); + switch (type){ + case all : { + return new Dist_All(); + } + case drop : { + return new Dist_Drop(section.getConfigurationSection("drop")); + } + case killer : { + return new Dist_Killer(); + } + case pack : { + return new Dist_Pack(section.getConfigurationSection("pack")); + } + case rank : { + return new Dist_Rank(section.getConfigurationSection("rank")); + } + case termwise : { + return new Dist_Termwise(); + } + default : { + Lang.error("Unknown reward_dist type: "+type_name); + return new Dist_Drop(); + } + } + } + public List getDropReward(MyDragon myDragon){ + List list = new ArrayList<>(); + for(Reward reward : myDragon.datum){ + double chance = reward.getChance().getValue(); + if(chance > ThreadLocalRandom.current().nextDouble(100)){ + list.add(reward.getItem()); + } + } + return list; + } + public void handle_dist(final MyDragon myDragon,final EnderDragon dragon,final Player killer){ + + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_All.java b/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_All.java new file mode 100644 index 0000000..47abdd3 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_All.java @@ -0,0 +1,36 @@ +package pers.xanadu.enderdragon.reward.dist; + +import org.bukkit.Bukkit; +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.manager.DamageManager; +import pers.xanadu.enderdragon.reward.RewardDist; +import pers.xanadu.enderdragon.util.MyDragon; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +public class Dist_All extends RewardDist { + @Override + public void handle_dist(final MyDragon myDragon,final EnderDragon dragon,final Player killer){ + ConcurrentHashMap damage_data = DamageManager.data.get(dragon.getUniqueId()); + if(damage_data == null) return; + List items = getDropReward(myDragon); + if(items.isEmpty()) return; + Bukkit.getOnlinePlayers().forEach(p->{ + if(damage_data.containsKey(p.getName())){ + boolean full = false; + for(ItemStack item : items){ + if(full || p.getInventory().firstEmpty() == -1){ + p.getWorld().dropItem(p.getLocation(),item); + full = true; + } + else p.getInventory().addItem(item); + } + if(full) Lang.sendFeedback(p, Lang.dragon_player_inv_full); + } + }); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Drop.java b/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Drop.java new file mode 100644 index 0000000..8cb1ce3 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Drop.java @@ -0,0 +1,53 @@ +package pers.xanadu.enderdragon.reward.dist; + +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.Item; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; +import pers.xanadu.enderdragon.manager.GlowManager; +import pers.xanadu.enderdragon.reward.RewardDist; +import pers.xanadu.enderdragon.util.MyDragon; + +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +import static pers.xanadu.enderdragon.manager.GlowManager.setGlowingColor; + +public class Dist_Drop extends RewardDist { + private final GlowManager.GlowColor color; + public Dist_Drop(ConfigurationSection section){ + if(section == null) color = GlowManager.GlowColor.NONE; + else { + String color = section.getString("glow","NONE").toUpperCase(); + this.color = GlowManager.GlowColor.valueOf(color); + } + } + public Dist_Drop(){ + color = GlowManager.GlowColor.NONE; + } + @Override + public void handle_dist(final MyDragon myDragon, final EnderDragon dragon, final Player killer){ + List items = getDropReward(myDragon); + if(items.isEmpty()) return; + World world = dragon.getWorld(); + Location loc = dragon.getLocation(); + items.forEach(item->{ + Item entity_item = world.dropItemNaturally(loc,item); + ChatColor color = getGlowColor(); + if(color!=null) setGlowingColor(entity_item,color); + double x = ThreadLocalRandom.current().nextDouble(0.25); + double y = ThreadLocalRandom.current().nextDouble(0.25); + double z = ThreadLocalRandom.current().nextDouble(0.25); + entity_item.setVelocity(new Vector(x,y,z)); + }); + } + + public ChatColor getGlowColor(){ + return GlowManager.getGlowColor(color); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Killer.java b/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Killer.java new file mode 100644 index 0000000..f442e38 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Killer.java @@ -0,0 +1,29 @@ +package pers.xanadu.enderdragon.reward.dist; + +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.reward.RewardDist; +import pers.xanadu.enderdragon.util.MyDragon; + +import java.util.List; + +public class Dist_Killer extends RewardDist { + @Override + public void handle_dist(final MyDragon myDragon,final EnderDragon dragon,final Player p){ + List items = getDropReward(myDragon); + if(items.isEmpty()) return; + if(p != null){ + boolean full = false; + for(ItemStack item : items){ + if(full || p.getInventory().firstEmpty() == -1){ + p.getWorld().dropItem(p.getLocation(),item); + full = true; + } + else p.getInventory().addItem(item); + } + if(full) Lang.sendFeedback(p, Lang.dragon_player_inv_full); + } + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Pack.java b/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Pack.java new file mode 100644 index 0000000..a443c3f --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Pack.java @@ -0,0 +1,53 @@ +package pers.xanadu.enderdragon.reward.dist; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.manager.DamageManager; +import pers.xanadu.enderdragon.reward.RewardDist; +import pers.xanadu.enderdragon.util.AExpJ; +import pers.xanadu.enderdragon.util.MyDragon; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +public class Dist_Pack extends RewardDist { + private final int max_num; + public Dist_Pack(ConfigurationSection section){ + if(section == null) max_num = 1; + else max_num = section.getInt("max_num",1); + } + + @Override + public void handle_dist(final MyDragon myDragon,final EnderDragon dragon,final Player killer){ + ConcurrentHashMap damage_data = DamageManager.data.get(dragon.getUniqueId()); + if(damage_data == null) return; + List items = getDropReward(myDragon); + if(items.isEmpty()) return; + int m = Math.min(max_num,damage_data.size()); + if(m<=0) return; + List receivers = AExpJ.sample(damage_data,m); + receivers.forEach(receiver->{ + Player p = Bukkit.getPlayer(receiver); + if(p != null){ + boolean full = false; + for(ItemStack item : items){ + if(full || p.getInventory().firstEmpty() == -1){ + p.getWorld().dropItem(p.getLocation(),item); + full = true; + } + else p.getInventory().addItem(item); + } + if(full) Lang.sendFeedback(p, Lang.dragon_player_inv_full); + } + }); + } + + public int getMax_num(){ + return max_num; + } +} + diff --git a/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Rank.java b/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Rank.java new file mode 100644 index 0000000..d17fb95 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Rank.java @@ -0,0 +1,57 @@ +package pers.xanadu.enderdragon.reward.dist; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.manager.DamageManager; +import pers.xanadu.enderdragon.reward.RewardDist; +import pers.xanadu.enderdragon.util.MyDragon; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + +public class Dist_Rank extends RewardDist { + private final int max_num; + public Dist_Rank(ConfigurationSection section){ + if(section == null) max_num = 1; + else max_num = section.getInt("max_num",1); + } + public int getMax_num(){ + return max_num; + } + @Override + public void handle_dist(final MyDragon myDragon,final EnderDragon dragon,final Player killer){ + ConcurrentHashMap damage_data = DamageManager.data.get(dragon.getUniqueId()); + if(damage_data == null) return; + List items = getDropReward(myDragon); + if(items.isEmpty()) return; + int m = Math.min(max_num,damage_data.size()); + if(m<=0) return; + List> list = damage_data.entrySet().stream().sorted(Dist_Rank::sortByDamage).collect(Collectors.toList()); + for(int i=0;i int sortByDamage(Map.Entry e1,Map.Entry e2){ + if(e2.getValue()>e1.getValue()) return 1; + if(e2.getValue().equals(e1.getValue())) return 0; + return -1; + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Termwise.java b/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Termwise.java new file mode 100644 index 0000000..65bdc1d --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/reward/dist/Dist_Termwise.java @@ -0,0 +1,39 @@ +package pers.xanadu.enderdragon.reward.dist; + +import org.bukkit.Bukkit; +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.manager.DamageManager; +import pers.xanadu.enderdragon.reward.RewardDist; +import pers.xanadu.enderdragon.util.AliasSample; +import pers.xanadu.enderdragon.util.MyDragon; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +public class Dist_Termwise extends RewardDist { + @Override + public void handle_dist(final MyDragon myDragon,final EnderDragon dragon,final Player killer){ + ConcurrentHashMap damage_data = DamageManager.data.get(dragon.getUniqueId()); + if(damage_data == null) return; + List items = getDropReward(myDragon); + if(items.isEmpty()) return; + AliasSample alias = new AliasSample(new ArrayList<>(damage_data.values())); + List list = new ArrayList<>(damage_data.keySet()); + items.forEach(item->{ + int idx = alias.next(); + String receiver = list.get(idx); + Player p = Bukkit.getPlayer(receiver); + if(p != null){ + if(p.getInventory().firstEmpty() == -1){ + p.getWorld().dropItem(p.getLocation(),item); + Lang.sendFeedback(p, Lang.dragon_player_inv_full); + } + else p.getInventory().addItem(item); + } + }); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/script/Events.java b/src/main/java/pers/xanadu/enderdragon/script/Events.java new file mode 100644 index 0000000..4b47847 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/script/Events.java @@ -0,0 +1,101 @@ +package pers.xanadu.enderdragon.script; + +import java.lang.reflect.Method; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Consumer; +import org.bukkit.Bukkit; +import org.bukkit.event.Event; +import org.bukkit.event.EventPriority; +import org.bukkit.event.HandlerList; +import org.bukkit.event.Listener; +import org.bukkit.plugin.EventExecutor; +import org.jetbrains.annotations.NotNull; +import pers.xanadu.enderdragon.manager.GroovyManager; + +import static pers.xanadu.enderdragon.EnderDragon.plugin; + +public class Events implements Listener, EventExecutor { + private final Consumer consumer; + private final Class clazz; + private boolean disabled; + private final AtomicLong expireTime; + public Events(Class clazz, Consumer consumer) { + this.clazz = clazz; + this.consumer = consumer; + this.expireTime = new AtomicLong(-1L); + this.disabled = false; + } + + public void unregister() { + if (!this.disabled) { + try { + Method method = this.clazz.getMethod("getHandlerList"); + HandlerList handlerList = (HandlerList) method.invoke(null); + if (Bukkit.isPrimaryThread()) { + handlerList.unregister(this); + } + else { + Bukkit.getScheduler().runTask(plugin, () -> handlerList.unregister(this)); + } + } catch (Exception e) { + e.printStackTrace(); + } + this.disabled = true; + } + } + public static Events registerPersistently(Class clazz, Consumer consumer) { + return Events.registerPersistently(clazz, EventPriority.NORMAL, false, consumer); + } + public static Events registerPersistently(Class clazz, EventPriority priority, boolean ignoreCancelled, Consumer consumer) { + Events tmp = new Events<>(clazz, consumer); + if (Bukkit.isPrimaryThread()) { + Bukkit.getPluginManager().registerEvent(clazz,tmp,priority,tmp,plugin,ignoreCancelled); + } + else { + Bukkit.getScheduler().runTask(plugin, () -> Bukkit.getPluginManager().registerEvent(clazz,tmp,priority,tmp,plugin,ignoreCancelled)); + } + return tmp; + } + public static Events register(Class clazz, Consumer consumer) { + return Events.register(clazz, EventPriority.NORMAL, false, consumer); + } + public static Events register(Class clazz, EventPriority priority, boolean ignoreCancelled, Consumer consumer) { + Events tmp = new Events<>(clazz, consumer); + if (Bukkit.isPrimaryThread()) { + Bukkit.getPluginManager().registerEvent(clazz,tmp,priority,tmp,plugin,ignoreCancelled); + } + else { + Bukkit.getScheduler().runTask(plugin, () -> Bukkit.getPluginManager().registerEvent(clazz,tmp,priority,tmp,plugin,ignoreCancelled)); + } + GroovyManager.event_set.add(tmp); + return tmp; + } +// private static void register(Class clazz, Events event, EventPriority priority, boolean ignoreCancelled) { +// Bukkit.getPluginManager().registerEvent(clazz,event,priority,event,plugin,ignoreCancelled); +// } + + @Override + public void execute(@NotNull Listener listener, @NotNull Event event) { + if (this.expireTime.get() > 0L && System.currentTimeMillis() > this.expireTime.get()) { + Bukkit.getScheduler().runTask(plugin, this::unregister); + return; + } + if (this.clazz.isInstance(event)) { + this.consumer.accept((T) event); + } + } + public Events withTime(long time) { + this.expireTime.set(time); + return this; + } + + public boolean cancelIfExpired() { + if (this.expireTime.get() > 0L && System.currentTimeMillis() > this.expireTime.get()) { + this.unregister(); + return true; + } + return false; + } + +} + diff --git a/src/main/java/pers/xanadu/enderdragon/task/DragonRespawnRunnable.java b/src/main/java/pers/xanadu/enderdragon/task/DragonRespawnRunnable.java new file mode 100644 index 0000000..27f2ebb --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/task/DragonRespawnRunnable.java @@ -0,0 +1,37 @@ +package pers.xanadu.enderdragon.task; + +import org.bukkit.scheduler.BukkitRunnable; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.EnderDragon; + +import static pers.xanadu.enderdragon.EnderDragon.*; + +public class DragonRespawnRunnable extends BukkitRunnable { + private final Task task; + public DragonRespawnRunnable(Task task){ + this.task = task; + } + @Override + public void run(){ + if(task == null) { + this.cancel(); + Lang.error("The config of auto-respawn errors!Task has been disabled..."); + return; + } + if(task.isTimeUp()){ + new BukkitRunnable(){ + @Override + public void run(){ + EnderDragon.getInstance().getDragonManager().initiateRespawn(task.world_name); + task.updateTime(); + task.saveFile(); + } + }.runTask(plugin); + } + } + public void start(){ + this.runTaskTimerAsynchronously(plugin,0,200L); + } + + +} diff --git a/src/main/java/pers/xanadu/enderdragon/task/DragonRespawnTimer.java b/src/main/java/pers/xanadu/enderdragon/task/DragonRespawnTimer.java new file mode 100644 index 0000000..ade7165 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/task/DragonRespawnTimer.java @@ -0,0 +1,82 @@ +package pers.xanadu.enderdragon.task; + +import org.bukkit.Bukkit; +import org.bukkit.scheduler.BukkitRunnable; +import pers.xanadu.enderdragon.EnderDragon; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.util.MathUtil; + +import static pers.xanadu.enderdragon.EnderDragon.plugin; + +public class DragonRespawnTimer { + private final String world_name; + private final int delay; + private BukkitRunnable runnable; + private int remainSecond; + private boolean isRunning; + public DragonRespawnTimer(String WorldName,int second){ + this(WorldName,second,second); + } + public DragonRespawnTimer(String WorldName,int second,int rest_second){ + this.world_name = WorldName; + this.delay = second; + this.remainSecond = rest_second; + this.isRunning = false; + resetRunnable(); + } + public void run(){ + if(!isRunning) runnable.runTaskTimerAsynchronously(plugin,0L,20L); + isRunning = true; + } + public void update(){ + remainSecond = delay; + runnable.cancel(); + isRunning = false; + resetRunnable(); + } + public void del(){ + if(isRunning) runnable.cancel(); + } + public String getWorld_name(){ + return this.world_name; + } + public int getSetTime(){ + return this.delay; + } + public int getRestTime(){ + return this.remainSecond; + } + public boolean isRunning(){ + return isRunning; + } + public double getProgress(){ + return 1d*remainSecond/delay; + } + @Override + public String toString(){ + return "(" + world_name + ") " + + "remain:" + MathUtil.formatDuration(remainSecond) + + ", set:" + MathUtil.formatDuration(delay); + } + private void resetRunnable(){ + this.runnable = new BukkitRunnable() { + @Override + public void run() { + remainSecond--; + if(remainSecond <= 0){ + Bukkit.getScheduler().runTask(plugin,() -> { + if(EnderDragon.getInstance().getDragonManager().canRespawn(world_name)){ + EnderDragon.getInstance().getDragonManager().initiateRespawn(world_name); + update(); + } + else { + remainSecond = delay; + Lang.error(Lang.command_respawn_cd_retry); + } + }); + } + } + }; + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/task/Task.java b/src/main/java/pers/xanadu/enderdragon/task/Task.java new file mode 100644 index 0000000..71c494c --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/task/Task.java @@ -0,0 +1,94 @@ +package pers.xanadu.enderdragon.task; + +import pers.xanadu.enderdragon.EnderDragon; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.manager.TaskManager; + +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.LocalTime; + +import static pers.xanadu.enderdragon.EnderDragon.data; +import static pers.xanadu.enderdragon.EnderDragon.dataF; +import static pers.xanadu.enderdragon.manager.TaskManager.getRoundTimeStr; + +public abstract class Task { + protected int period; + protected int day; + private final TaskType type; + protected abstract LocalDateTime initNextTime(LocalDateTime cur); + public abstract void updateTime(); + protected LocalDateTime nextTime; + protected final String world_name; + protected final String unique_name; + protected Task(TaskType type, String unique_name,String world_name,String str){ + this.type = type; + this.unique_name = unique_name; + this.world_name = world_name; + switch (type){ + case minute : + case hour : { + this.period = Integer.parseInt(str); + break; + } + case day : { + this.period = Integer.parseInt(str.split(",")[0]); + break; + } + case week : + case month : + case year : { + this.day = Integer.parseInt(str.split(",")[0]); + break; + } + } + char split = data.options().pathSeparator(); + String next_time = EnderDragon.data.getString("auto_respawn"+split+unique_name+split+"next_respawn_time"); + if(next_time == null){ + switch (type){ + case minute : + case hour : { + this.nextTime = this.initNextTime(LocalDateTime.now().withSecond(0)); + break; + } + case day : + case week : + case month : + case year : { + calcNextTime(str); + break; + } + } + this.saveFile(); + } + else this.nextTime = TaskManager.getLocalDateTime(next_time); + } + private void calcNextTime(String str){ + LocalTime time = TaskManager.getRoundTime(str.split(",")[1]); + if(time != null) this.nextTime = this.initNextTime(LocalDateTime.now().withSecond(0).with(time)); + else this.nextTime = this.initNextTime(LocalDateTime.now().withSecond(0)); + } + public boolean isTimeUp(){ + LocalDateTime now = LocalDateTime.now().plusSeconds(1); + if(now.isAfter(nextTime)){ + return true; + } + return false; + } + public void saveFile(){ + char split = data.options().pathSeparator(); + String path = "auto_respawn"+split+unique_name+split; + data.set(path+"world_name",world_name); + data.set(path+"next_respawn_time",getRoundTimeStr(nextTime)); + try{ + data.save(dataF); + }catch (IOException ex){ + Lang.error(Lang.plugin_file_save_error.replaceAll("\\{file_name}",dataF.getName())); + } + } + + public TaskType getType(){ + return this.type; + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/task/TaskType.java b/src/main/java/pers/xanadu/enderdragon/task/TaskType.java new file mode 100644 index 0000000..0a30096 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/task/TaskType.java @@ -0,0 +1,26 @@ +package pers.xanadu.enderdragon.task; + +import java.util.Map; +import java.util.TreeMap; + +public enum TaskType { + minute, + hour, + day, + week, + month, + year, + unknown; + private static final Map mp = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); + public static TaskType getByName(String str){ + if(str == null) return unknown; + return mp.getOrDefault(str,unknown); + } + static{ + TaskType[] values = values(); + for (TaskType taskType : values) { + String name = taskType.name(); + mp.put(name, taskType); + } + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/task/type/Day.java b/src/main/java/pers/xanadu/enderdragon/task/type/Day.java new file mode 100644 index 0000000..f32fe7f --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/task/type/Day.java @@ -0,0 +1,21 @@ +package pers.xanadu.enderdragon.task.type; + +import pers.xanadu.enderdragon.task.Task; +import pers.xanadu.enderdragon.task.TaskType; + +import java.time.LocalDateTime; + +public class Day extends Task { + + @Override + public LocalDateTime initNextTime(LocalDateTime cur) { + return cur.plusDays(period); + } + @Override + public void updateTime(){ + this.nextTime = LocalDateTime.now().withSecond(0).plusDays(period); + } + public Day(TaskType type, String unique_name,String world_name,String str){ + super(type,unique_name,world_name,str); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/task/type/Hour.java b/src/main/java/pers/xanadu/enderdragon/task/type/Hour.java new file mode 100644 index 0000000..5862cbe --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/task/type/Hour.java @@ -0,0 +1,20 @@ +package pers.xanadu.enderdragon.task.type; + +import pers.xanadu.enderdragon.task.Task; +import pers.xanadu.enderdragon.task.TaskType; + +import java.time.LocalDateTime; + +public class Hour extends Task { + @Override + public LocalDateTime initNextTime(LocalDateTime cur) { + return cur.plusHours(period); + } + @Override + public void updateTime(){ + this.nextTime = LocalDateTime.now().withSecond(0).plusHours(period); + } + public Hour(TaskType type, String unique_name,String world_name,String str){ + super(type,unique_name,world_name,str); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/task/type/Minute.java b/src/main/java/pers/xanadu/enderdragon/task/type/Minute.java new file mode 100644 index 0000000..a68d6df --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/task/type/Minute.java @@ -0,0 +1,22 @@ +package pers.xanadu.enderdragon.task.type; + +import pers.xanadu.enderdragon.task.Task; +import pers.xanadu.enderdragon.task.TaskType; + +import java.time.LocalDateTime; + +public class Minute extends Task { + + @Override + public LocalDateTime initNextTime(LocalDateTime cur) { + return cur.plusMinutes(period); + } + @Override + public void updateTime(){ + this.nextTime = LocalDateTime.now().withSecond(0).plusMinutes(period); + } + + public Minute(TaskType type, String unique_name,String world_name,String str){ + super(type,unique_name,world_name,str); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/task/type/Month.java b/src/main/java/pers/xanadu/enderdragon/task/type/Month.java new file mode 100644 index 0000000..f66e3ff --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/task/type/Month.java @@ -0,0 +1,21 @@ +package pers.xanadu.enderdragon.task.type; + +import pers.xanadu.enderdragon.task.Task; +import pers.xanadu.enderdragon.task.TaskType; + +import java.time.LocalDateTime; + +public class Month extends Task { + @Override + public LocalDateTime initNextTime(LocalDateTime cur) { + return cur.plusMonths(1).withDayOfMonth(day); + } + @Override + public void updateTime(){ + this.nextTime = LocalDateTime.now().withSecond(0).plusMonths(1).withDayOfMonth(day); + } + public Month(TaskType type, String unique_name,String world_name,String str){ + super(type,unique_name,world_name,str); + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/task/type/Week.java b/src/main/java/pers/xanadu/enderdragon/task/type/Week.java new file mode 100644 index 0000000..a1c7d17 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/task/type/Week.java @@ -0,0 +1,22 @@ +package pers.xanadu.enderdragon.task.type; + +import pers.xanadu.enderdragon.task.Task; +import pers.xanadu.enderdragon.task.TaskType; + +import java.time.DayOfWeek; +import java.time.LocalDateTime; + +public class Week extends Task { + + @Override + public LocalDateTime initNextTime(LocalDateTime cur) { + return cur.with(DayOfWeek.of(day)).plusDays(7); + } + @Override + public void updateTime(){ + this.nextTime = LocalDateTime.now().withSecond(0).plusDays(7); + } + public Week(TaskType type, String unique_name,String world_name,String str){ + super(type,unique_name,world_name,str); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/task/type/Year.java b/src/main/java/pers/xanadu/enderdragon/task/type/Year.java new file mode 100644 index 0000000..f0b7523 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/task/type/Year.java @@ -0,0 +1,20 @@ +package pers.xanadu.enderdragon.task.type; + +import pers.xanadu.enderdragon.task.Task; +import pers.xanadu.enderdragon.task.TaskType; + +import java.time.LocalDateTime; + +public class Year extends Task { + @Override + public LocalDateTime initNextTime(LocalDateTime cur) { + return cur.plusYears(1).withDayOfMonth(day); + } + @Override + public void updateTime(){ + this.nextTime = LocalDateTime.now().withSecond(0).plusYears(1); + } + public Year(TaskType type, String unique_name,String world_name,String str){ + super(type,unique_name,world_name,str); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/util/AExpJ.java b/src/main/java/pers/xanadu/enderdragon/util/AExpJ.java new file mode 100644 index 0000000..102f28e --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/util/AExpJ.java @@ -0,0 +1,63 @@ +package pers.xanadu.enderdragon.util; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ThreadLocalRandom; + +public final class AExpJ { + public static List sample(final ConcurrentHashMap mp,int m){ + List> list = new ArrayList<>(); + mp.forEach((k,v)->list.add(new Pair<>(k,v))); + return sample(list,m); + } + public static List sample(final List> samples, int m) { + PriorityQueue> heap = new PriorityQueue<>(Comparator.comparingDouble(p -> p.second)); + double Xw = 0.0; + double Tw = 0.0; + double w_acc = 0.0; + for (Pair sample : samples) { + if (heap.size() < m) { + double wi = sample.second; + double ui = ThreadLocalRandom.current().nextDouble(); + double ki = Math.pow(ui, 1 / wi); + heap.offer(new Pair<>(sample.first, ki)); + continue; + } + if (w_acc == 0) { + if (heap.isEmpty()) break; + Tw = heap.peek().second; + double r = ThreadLocalRandom.current().nextDouble(); + Xw = Math.log(r) / Math.log(Tw); + } + double wi = sample.second; + if (w_acc + wi < Xw) { + w_acc += wi; + continue; + } + else w_acc = 0; + double tw = Math.pow(Tw, wi); + double r2 = ThreadLocalRandom.current().nextDouble() * (1 - tw) + tw; + double ki = Math.pow(r2, 1 / wi); + heap.poll(); + heap.offer(new Pair<>(sample.first, ki)); + } + List res = new ArrayList<>(); + for (Pair pair : heap) { + res.add(pair.first); + } + return res; + } + +// public static void main(String[] args) { +// List> samples = new ArrayList<>(); +// samples.add(new Pair<>("item1", 0.8)); +// samples.add(new Pair<>("item2", 0.4)); +// samples.add(new Pair<>("item3", 0.2)); +// Map mp = new HashMap<>(); +// for(int i=0;i<1e5;i++){ +// List result = sample(samples, 1); +// mp.compute(result.get(0), (k, v)->v==null?1:v+1); +// } +// System.out.println(mp); +// } +} diff --git a/src/main/java/pers/xanadu/enderdragon/util/AliasSample.java b/src/main/java/pers/xanadu/enderdragon/util/AliasSample.java new file mode 100644 index 0000000..6a8a4f4 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/util/AliasSample.java @@ -0,0 +1,42 @@ +package pers.xanadu.enderdragon.util; + +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; + +public final class AliasSample { + private final int[] alias; + private final double[] probability; + public AliasSample(List probabilities) { + if (probabilities == null) throw new NullPointerException(); + if (probabilities.size() == 0) + throw new IllegalArgumentException("Probability vector can't be empty."); + this.probability = new double[probabilities.size()]; + this.alias = new int[probabilities.size()]; + final double average = 1.0 / probabilities.size(); + probabilities = new ArrayList<>(probabilities);//make a copy of list, avoid modifying the param + Deque small = new ArrayDeque<>(); + Deque large = new ArrayDeque<>(); + for (int i = 0; i < probabilities.size(); ++i) { + if (probabilities.get(i) >= average) large.add(i); + else small.add(i); + } + while (!small.isEmpty() && !large.isEmpty()) { + int less = small.removeLast(); + int more = large.removeLast(); + probability[less] = probabilities.get(less) * probabilities.size(); + alias[less] = more; + probabilities.set(more, (probabilities.get(more) + probabilities.get(less)) - average); + if (probabilities.get(more) >= 1.0 / probabilities.size()) large.add(more); + else small.add(more); + } + while (!small.isEmpty()) probability[small.removeLast()] = 1.0; + while (!large.isEmpty()) probability[large.removeLast()] = 1.0; + } + + public int next() { + int column = ThreadLocalRandom.current().nextInt(probability.length); + boolean coinToss = ThreadLocalRandom.current().nextDouble() < probability[column]; + return coinToss ? column : alias[column]; + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/util/ColorUtil.java b/src/main/java/pers/xanadu/enderdragon/util/ColorUtil.java new file mode 100644 index 0000000..1cbb5b7 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/util/ColorUtil.java @@ -0,0 +1,69 @@ +package pers.xanadu.enderdragon.util; + +import net.md_5.bungee.api.ChatColor; + +import java.awt.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static pers.xanadu.enderdragon.util.Version.mcMainVersion; + +public class ColorUtil { + + public static Pattern hex_code = Pattern.compile("&#([0-9A-Fa-f]{6})"); + public static Pattern gradient = Pattern.compile("&\\[#([0-9a-fA-F]{6})-#([0-9a-fA-F]{6})(.+)]"); + public static String parse(String str){ + if(mcMainVersion >= 16){ + return org.bukkit.ChatColor.translateAlternateColorCodes('&',transGradient(str)); + } + else{ + return org.bukkit.ChatColor.translateAlternateColorCodes('&',str); + } + } + private static String translateHexCodes(String str) { + Matcher matcher = hex_code.matcher(str); + StringBuffer buffer = new StringBuffer(); + while(matcher.find()) { + matcher.appendReplacement(buffer, ChatColor.of("#" + matcher.group(1)).toString()); + } + return ChatColor.translateAlternateColorCodes('&', matcher.appendTail(buffer).toString()); + } + private static String transGradient(String str) { + if (str.contains("&[#")&&str.contains("]")) { + Matcher matcher = gradient.matcher(str); + StringBuffer buffer = new StringBuffer(); + while (matcher.find()) { + String text = matcher.group(3); + int[] colors = gradient(matcher.group(1),matcher.group(2),text.length()); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < text.length(); i++) { + Color c = new Color(colors[i]); + builder.append(ChatColor.of(c)).append(text.charAt(i)); + } + matcher.appendReplacement(buffer, builder.toString()); + } + matcher.appendTail(buffer); + return buffer.toString(); + } + return translateHexCodes(str); + } + private static int[] gradient(String start,String end,int length){ + int[] color = new int[length]; + int[] rgb1 = MathUtil.hexToInt(start); + int[] rgb2 = MathUtil.hexToInt(end); + if(length==0){return color;} + if(length==1){ + for(int j=0;j<3;j++){ + color[0] = color[0]*256+rgb1[j]; + } + return color; + } + for(int i=0;i0){ + duration.append(days).append("d"); + f = true; + } + if(f||hours>0){ + duration.append(hours).append("h"); + f = true; + } + if(f||minutes>0){ + duration.append(minutes).append("m"); + } + duration.append(remainingSeconds).append("s"); + return duration.toString(); + } + public static int[] getDate(int seconds){ + if (seconds < 0) throw new IllegalArgumentException("Duration must be a positive number."); + int days = seconds / (24 * 3600); + int hours = (seconds % (24 * 3600)) / 3600; + int minutes = ((seconds % (24 * 3600)) % 3600) / 60; + int remainingSeconds = ((seconds % (24 * 3600)) % 3600) % 60; + return new int[]{days,hours,minutes,remainingSeconds}; + } + @Deprecated + public static K getByWeight(final ConcurrentHashMap mp){ + double sum = mp.values().stream().mapToDouble(Double::doubleValue).sum(); + double rand = ThreadLocalRandom.current().nextDouble(sum); + final AtomicReference cur = new AtomicReference<>(0d); + final AtomicReference res = new AtomicReference<>(); + mp.forEach((k,v)->{ + Double value = cur.get(); + if(value<=rand && value+v>rand) { + res.set(k); + return; + } + cur.updateAndGet(v1 -> v1 + v); + }); + return res.get(); + } +} diff --git a/src/main/java/pers/xanadu/enderdragon/util/MyDragon.java b/src/main/java/pers/xanadu/enderdragon/util/MyDragon.java new file mode 100644 index 0000000..65dbf20 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/util/MyDragon.java @@ -0,0 +1,62 @@ +package pers.xanadu.enderdragon.util; + +import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; +import pers.xanadu.enderdragon.reward.Reward; +import pers.xanadu.enderdragon.reward.RewardDist; + +import java.util.ArrayList; +import java.util.List; + +public class MyDragon implements Comparable{ + public ItemStack icon; + public String unique_name; + public String display_name; + public String drop_gui; + public int edge; + public int priority; + public double spawn_chance; + public int max_health; + public int spawn_health; + public int no_damage_tick; + public int exp_drop; + public int dragon_egg_spawn_delay; + public int dragon_egg_spawn_x; + public int dragon_egg_spawn_y; + public int dragon_egg_spawn_z; + public double dragon_egg_spawn_chance; + public double attack_damage_modify; + //public double move_speed_modify; + public double armor_modify; + public double armor_toughness_modify; + public double crystal_heal_speed; + public boolean suck_blood_enable; + public double suck_blood_rate; + public double suck_blood_base_amount; + public boolean suck_blood_only_player; + public List attack_potion_effect; + public List attack_extra_effect; + public List spawn_cmd; + public List death_cmd; + public List spawn_broadcast_msg; + public List death_broadcast_msg; + public List msg_to_killer; + public String glow_color; + public String bossbar_color; + public String bossbar_style; + public double effect_cloud_original_radius; + public double effect_cloud_expand_speed; + public int effect_cloud_duration; + public int effect_cloud_color_R; + public int effect_cloud_color_G; + public int effect_cloud_color_B; + public List effect_cloud_potion; + public List datum = new ArrayList<>(); + public RewardDist reward_dist; + + @Override + public int compareTo(final MyDragon o) { + return o.priority - this.priority;//降序 + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/util/NMSUtil.java b/src/main/java/pers/xanadu/enderdragon/util/NMSUtil.java new file mode 100644 index 0000000..94c2062 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/util/NMSUtil.java @@ -0,0 +1,453 @@ +package pers.xanadu.enderdragon.util; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.persistence.PersistentDataContainer; +import pers.xanadu.enderdragon.EnderDragon; +import pers.xanadu.enderdragon.config.Config; +import pers.xanadu.enderdragon.config.Lang; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Map; + +import static pers.xanadu.enderdragon.EnderDragon.getInstance; + +public class NMSUtil { + private String getEDB_base; + private Method getNMSWord; + private Method asNMSCopy; + private Method copyNMSStack; + private Method asBukkitCopy; + private Method asCraftMirror; + private Method asCraftCopy; + private Method NMSItemStack_save; + private Method NMSItemStack_setTag; + private Method cpdToEi; + private Method stringToCPD; + private Method stringToNBTBase; + private Method serializeNBTBase; + private Method deserializeObject; + private Method PDCtoCPD; + private Method PersistentDataContainer_putAll; + private Method NBTTagCompound_set; + private Field unhandledTags; + private Field internalTag; + private Field MOJANGSON_PARSER; + private Field world_c_environment; + private Field NBTTagCompound_map; + private Class WorldClass; + private Class CraftWorldClass; + private Class WorldProviderClass; + private Class WorldProviderTheEndClass; + private Class CraftItemStackClass; + private Class CraftMetaItemClass; + private Class NMSItemStackClass; + private Class CraftEntityClass; + private Class NBTTagCompoundClass; + private Class NBTBaseClass; + private Class MojangsonParserClass; + private Class CraftNBTTagConfigSerializerClass; + private Class CraftPersistentDataContainerClass; + + public void init(){ + String version = Version.getVersion(); + try{ + this.CraftWorldClass = Class.forName("org.bukkit.craftbukkit." + version + ".CraftWorld"); + this.getNMSWord = CraftWorldClass.getDeclaredMethod("getHandle"); + this.WorldClass = this.getNMSWord.getReturnType().getSuperclass(); + this.world_c_environment = CraftWorldClass.getDeclaredField("environment"); + this.world_c_environment.setAccessible(true); + if(Version.mcMainVersion>=12 && Version.mcMainVersion<16){ + this.WorldProviderClass = Class.forName("net.minecraft.server."+version+".WorldProvider"); + this.WorldProviderTheEndClass = Class.forName("net.minecraft.server."+version+".WorldProviderTheEnd"); + } + this.CraftItemStackClass = Class.forName("org.bukkit.craftbukkit." + version + ".inventory.CraftItemStack"); + this.CraftMetaItemClass = Class.forName("org.bukkit.craftbukkit." + version + ".inventory.CraftMetaItem"); + this.unhandledTags = CraftMetaItemClass.getDeclaredField("unhandledTags"); + unhandledTags.setAccessible(true); + this.internalTag = CraftMetaItemClass.getDeclaredField("internalTag"); + internalTag.setAccessible(true); + this.NMSItemStackClass = CraftItemStackClass.getDeclaredField("handle").getType(); + this.CraftEntityClass = Class.forName("org.bukkit.craftbukkit."+version+".entity.CraftEntity"); + init_NBTTagCompoundClass(); + init_NBTBaseClass(); + init_NBTTagCompound_map(); + this.NBTTagCompound_set = NBTTagCompoundClass.getMethod(getMethodName(ReflectiveMethod.NBTTagCompound_set),String.class,NBTBaseClass); + this.asNMSCopy = CraftItemStackClass.getMethod("asNMSCopy",ItemStack.class); + this.copyNMSStack = CraftItemStackClass.getMethod("copyNMSStack",NMSItemStackClass,int.class); + this.asBukkitCopy = CraftItemStackClass.getMethod("asBukkitCopy",NMSItemStackClass); + this.asCraftMirror = CraftItemStackClass.getMethod("asCraftMirror",NMSItemStackClass); + this.asCraftCopy = CraftItemStackClass.getMethod("asCraftCopy",ItemStack.class); + this.NMSItemStack_save = NMSItemStackClass.getMethod(getMethodName(ReflectiveMethod.NMSItemStack_save),NBTTagCompoundClass); + this.NMSItemStack_setTag = NMSItemStackClass.getMethod(getMethodName(ReflectiveMethod.NMSItemStack_setTag),NBTTagCompoundClass); + if(Version.mcMainVersion>=13) this.cpdToEi = NMSItemStackClass.getMethod("a",NBTTagCompoundClass); + + if(Version.mcMainVersion<=16) this.MojangsonParserClass = Class.forName("net.minecraft.server."+version+".MojangsonParser"); + else this.MojangsonParserClass = Class.forName("net.minecraft.nbt.MojangsonParser"); + this.stringToCPD = MojangsonParserClass.getMethod(getMethodName(ReflectiveMethod.MojangsonParser_parse),String.class); + this.stringToNBTBase = MojangsonParserClass.getDeclaredMethod(getMethodName(ReflectiveMethod.MojangsonParser_parseLiteral),String.class); + stringToNBTBase.setAccessible(true); + + if(Version.mcMainVersion>13 || "v1_13_R2".equals(Version.getVersion())){ + this.CraftNBTTagConfigSerializerClass = Class.forName("org.bukkit.craftbukkit." + version + ".util.CraftNBTTagConfigSerializer"); + this.serializeNBTBase = CraftNBTTagConfigSerializerClass.getMethods()[0]; + this.deserializeObject = CraftNBTTagConfigSerializerClass.getMethod("deserialize",Object.class); + this.MOJANGSON_PARSER = CraftNBTTagConfigSerializerClass.getDeclaredField("MOJANGSON_PARSER"); + MOJANGSON_PARSER.setAccessible(true); + } + if(Version.mcMainVersion>=14){ + this.CraftPersistentDataContainerClass = Class.forName("org.bukkit.craftbukkit." + version + ".persistence.CraftPersistentDataContainer"); + this.PDCtoCPD = CraftPersistentDataContainerClass.getDeclaredMethod("toTagCompound"); + this.PersistentDataContainer_putAll = CraftPersistentDataContainerClass.getDeclaredMethod("putAll",NBTTagCompoundClass); + } + + + + }catch(ReflectiveOperationException e){ + e.printStackTrace(); + } + switch (version) { + case "v1_12_R1" : { + getEDB_base = "t"; + break; + } + case "v1_13_R1" : + case "v1_13_R2" : { + getEDB_base = "r"; + break; + } + case "v1_14_R1" : { + getEDB_base = "q"; + break; + } + case "v1_15_R1" : { + getEDB_base = "o"; + break; + } + default : getEDB_base = null; + } + if(Config.debug) check(); + } + public void check(){ + try{ + Field[] fields = NMSUtil.class.getDeclaredFields(); + for(Field field : fields){ + Bukkit.getLogger().info(field.getName()+"->"+field.get(this)); + } + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + } +// public Object getMetaCPD(ItemMeta meta){ +// try{ +// Object craft_meta = CraftMetaItemClass.cast(meta); +// Object internalTag = this.internalTag.get(craft_meta); +// return internalTag; +// }catch (ReflectiveOperationException e){ +// e.printStackTrace(); +// return null; +// } +// } + + /** + * 只保留物品type和amount + * nbt深合并需要遍历每一层 + */ + @Deprecated + public ItemStack mergeItemCPD(final ItemStack item,final Object cpd){ + Map self = cpdToMap(getCPD(item)); + Map rhs = cpdToMap(cpd); + self.putAll(rhs); + Object new_cpd = getNBTTagCompound(self); + return EnderDragon.getInstance().getNMSItemManager().cpdToItem(new_cpd); + } + public Map cpdToMap(final Object cpd){ + try{ + return (Map) NBTTagCompound_map.get(cpd); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + return null; + } + } + public Object getNBTTagCompound(final Map mp){ + try{ + Object cpd = NBTTagCompoundClass.newInstance(); + mp.forEach((key,value)->{ + Object res; + if(value instanceof Map){ + res = getNBTTagCompound((Map) value); + } + else res = value; + try{ + NBTTagCompound_set.invoke(cpd,key,res); + }catch (ReflectiveOperationException e){ + throw new RuntimeException("Reflective error!"); + } + }); + return cpd; + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + return null; + } + } + public Object StringParseLiteral(final String str){ + try{ + return stringToNBTBase.invoke(MOJANGSON_PARSER.get(null),str); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + return null; + } + } + public void setPersistentDataContainer(final PersistentDataContainer dataContainer,final Object cpd){ + try{ + Object PDC = CraftPersistentDataContainerClass.cast(dataContainer); + PersistentDataContainer_putAll.invoke(PDC,cpd); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + } + public String PDCtoString(final PersistentDataContainer dataContainer){ + try{ + Object PDC = CraftPersistentDataContainerClass.cast(dataContainer); + return PDCtoCPD.invoke(PDC).toString(); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + return null; + } + } + + public Object deserializeObject(final Object object){ + try{ + return deserializeObject.invoke(null,object); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + return null; + } + } + public Object serializeNBTBase(final Object nbt_base){ + try{ + return serializeNBTBase.invoke(null, nbt_base); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + return null; + } + } + public void setUnhandledTags(final ItemMeta meta, Map unhandledTags){ + try{ + Object craft_meta = CraftMetaItemClass.cast(meta); + this.unhandledTags.set(craft_meta, unhandledTags); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + } + public Map getUnhandledTags(final ItemMeta meta){ + try{ + Object craft_meta = CraftMetaItemClass.cast(meta); + Object unhandledTags = this.unhandledTags.get(craft_meta); + return (Map) unhandledTags; + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + return null; + } + } + public ItemStack applyItemTag(final ItemStack item,final Object cpd){ + try{ + Object ei = asNMSCopy.invoke(null,item); + NMSItemStack_setTag.invoke(ei,cpd); + return (ItemStack) asBukkitCopy.invoke(null,ei); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + return new ItemStack(Material.AIR); + } + } + public String getNBT(final ItemStack item){ + try{ + Object ci = CraftItemStackClass.isInstance(item)?CraftItemStackClass.cast(item):asCraftCopy.invoke(null,item); + Object ei = asNMSCopy.invoke(null, ci); + Object cpd = NMSItemStack_save.invoke(ei, NBTTagCompoundClass.newInstance()); + return cpd.toString(); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + return "{id:\"minecraft:air\"}"; + } + } + public Object getCPD(final ItemStack item){ + try{ + Object ci = CraftItemStackClass.isInstance(item)?CraftItemStackClass.cast(item):asCraftCopy.invoke(null,item); + Object ei = asNMSCopy.invoke(null, ci); + return NMSItemStack_save.invoke(ei, NBTTagCompoundClass.newInstance()); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + return null; + } + } + public Object getCPD(final String nbt){ + try{ + return stringToCPD.invoke(null,nbt); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + return null; + } + } + /** + * 仅1.13+可用 + */ + public ItemStack getItemStack(final Object cpd){ + try{ + Object ei = cpdToEi.invoke(null,cpd); + Object ci = asBukkitCopy.invoke(null,ei); + return (ItemStack) ci; + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + return null; + } + } + /** + * 仅1.13+可用 + */ + public ItemStack getItemStack(final String nbt){ + try{ + Object cpd = stringToCPD.invoke(null,nbt); + Object ei = cpdToEi.invoke(null,cpd); + Object ci = asBukkitCopy.invoke(null,ei); + return (ItemStack) ci; + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + return null; + } + } + public void setEnvironment(final World world,final World.Environment env){ + Object world_c = getCraftWorld(world); + try{ + //Object old_env = world_c_environment.get(world_c); + world_c_environment.set(world_c,env); + }catch (ReflectiveOperationException e){ + e.printStackTrace(); + } + } + public Object getEnderDragonBattle(final World world){ + String version = Version.getVersion(); + if (Version.mcMainVersion>=12 && Version.mcMainVersion<16) { + try { + Object worldServer = getInstance().getNMSManager().getWorldServer(world); + assert worldServer != null; + Field field = worldServer.getClass().getField("worldProvider"); + Object worldProvider = field.get(worldServer); + Object WorldProviderTheEnd = WorldProviderTheEndClass.cast(worldProvider); + String method_name = getInstance().getNMSManager().getEDB_base; + if(method_name == null) return null; + Method method = WorldProviderTheEnd.getClass().getDeclaredMethod(method_name); + return method.invoke(WorldProviderTheEnd); + } catch (ReflectiveOperationException e) { + Lang.warn("Your server version (" + version + ") is not supported!"); + e.printStackTrace(); + } + } + Lang.warn("Your server version (" + version + ") is not supported!"); + return null; + } + public Object getWorldServer(final World ThisWorld) { + try { + Object castClass = getCraftWorld(ThisWorld); + return this.CraftWorldClass.getDeclaredMethod("getHandle").invoke(castClass); + } catch (ReflectiveOperationException e) { + e.printStackTrace(); + } + return null; + } + public Object getCraftWorld(final World ThisWorld) { + if (this.CraftWorldClass.isInstance(ThisWorld)) return this.CraftWorldClass.cast(ThisWorld); + return null; + } + public Object getWorld_e(final World world){ + try { + Object world_c = getCraftWorld(world); + return this.getNMSWord.invoke(world_c); + } catch (ReflectiveOperationException e) { + e.printStackTrace(); + } + return null; + } + public Class getNBTBaseClass(){ + return this.NBTBaseClass; + } + public Class getNBTTagCompoundClass(){ + return this.NBTTagCompoundClass; + } + public Class getWorldClass(){ + return this.WorldClass; + } + public Class getWorldProviderClass(){ + return this.WorldProviderClass; + } + private String getMethodName(final ReflectiveMethod method){ + switch (method){ + case NMSItemStack_save: { + if(Version.mcMainVersion<=17) return "save"; + return "b"; + } + case NMSItemStack_setTag: { + if(Version.mcMainVersion<=17) return "setTag"; + return "c"; + } + case MojangsonParser_parse: { + if(Version.mcMainVersion<=17) return "parse"; + return "a"; + } + case MojangsonParser_parseLiteral: { + if(Version.mcMainVersion==12) return "c"; + else if("v1_13_R1".equals(Version.getVersion())) return "b"; + else if(Version.mcMainVersion<=17) return "parseLiteral"; + else return "b"; + } + case NBTTagCompound_set: { + if(Version.mcMainVersion<=17) return "set"; + return "a"; + } + default: return "unreachable"; + } + } + private void init_NBTTagCompoundClass(){ + try{ + Class CraftMetaBlockStateClass = Class.forName("org.bukkit.craftbukkit."+Version.getVersion()+".inventory.CraftMetaBlockState"); + Field field = CraftMetaBlockStateClass.getDeclaredField("blockEntityTag"); + this.NBTTagCompoundClass = field.getType(); + return; + }catch (ReflectiveOperationException ignored){} + + Method[] methods = CraftEntityClass.getDeclaredMethods(); + for (Method method : methods) { + if ("save".equals(method.getName())) this.NBTTagCompoundClass = method.getReturnType(); + } + } + private void init_NBTTagCompound_map(){ + Field[] fields = NBTTagCompoundClass.getDeclaredFields(); + for(Field field : fields){ + if(field.getType() == this.unhandledTags.getType()){ + this.NBTTagCompound_map = field; + break; + } + } + this.NBTTagCompound_map.setAccessible(true); + } + private void init_NBTBaseClass(){ + try{ + //在mohist端使用getPackage()喜提null + this.NBTBaseClass = Class.forName(this.NBTTagCompoundClass.getName().replace(".NBTTagCompound",".NBTBase")); + }catch (ClassNotFoundException e){ + e.printStackTrace(); + } + } + private static enum ReflectiveMethod { + NMSItemStack_save, + NMSItemStack_setTag, + MojangsonParser_parse, + MojangsonParser_parseLiteral, + NBTTagCompound_set + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/util/Pair.java b/src/main/java/pers/xanadu/enderdragon/util/Pair.java new file mode 100644 index 0000000..e3fea87 --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/util/Pair.java @@ -0,0 +1,11 @@ +package pers.xanadu.enderdragon.util; + +public class Pair { + public P1 first; + public P2 second; + public Pair(P1 first, P2 second) { + this.first = first; + this.second = second; + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/util/UpdateChecker.java b/src/main/java/pers/xanadu/enderdragon/util/UpdateChecker.java new file mode 100644 index 0000000..75c45ed --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/util/UpdateChecker.java @@ -0,0 +1,48 @@ +package pers.xanadu.enderdragon.util; + +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.scheduler.BukkitRunnable; +import pers.xanadu.enderdragon.EnderDragon; +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.script.Events; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; + +public class UpdateChecker { + public static void checkUpdate(){ + Lang.info(Lang.plugin_checking_update); + new BukkitRunnable(){ + @Override + public void run(){ + try { + URLConnection conn = new URL("https://api.github.com/repos/iXanadu13/EnderDragon/releases/latest").openConnection(); + conn.setConnectTimeout(20000); + conn.setReadTimeout(60000); + InputStream is = conn.getInputStream(); + String line = new BufferedReader(new InputStreamReader(is)).readLine(); + is.close(); + String newVer = line.substring(line.indexOf("\"tag_name\"") + 13, line.indexOf("\"target_commitish\"") - 2); + String localVer = EnderDragon.plugin.getDescription().getVersion(); + if (!localVer.equals(newVer)) { + Lang.warn(Lang.plugin_out_of_date.replace("{0}",localVer).replace("{1}",newVer)); + Events.registerPersistently(PlayerJoinEvent.class,e->{ + if(e.getPlayer().hasPermission("ed.update.notify")) { + e.getPlayer().sendMessage("§3An update for §bEnderDragon §r(v" + newVer + ")§3 is available at", "§7§nhttps://www.spigotmc.org/resources/enderdragon.101583/"); + } + }); + } + else{ + Lang.info(Lang.plugin_up_to_date.replace("{1}",newVer)); + } + } catch (Exception e) { + Lang.warn(Lang.plugin_check_update_fail); + } + } + }.runTaskAsynchronously(EnderDragon.plugin); + } + +} diff --git a/src/main/java/pers/xanadu/enderdragon/util/Version.java b/src/main/java/pers/xanadu/enderdragon/util/Version.java new file mode 100644 index 0000000..dd29c5e --- /dev/null +++ b/src/main/java/pers/xanadu/enderdragon/util/Version.java @@ -0,0 +1,87 @@ +package pers.xanadu.enderdragon.util; + +import pers.xanadu.enderdragon.config.Lang; +import pers.xanadu.enderdragon.nms.BossBar.I_BossBarManager; +import pers.xanadu.enderdragon.nms.NMSItem.I_NMSItemManager; +import pers.xanadu.enderdragon.nms.RespawnAnchor.I_RespawnAnchorManager; +import pers.xanadu.enderdragon.nms.WorldData.I_WorldDataManager; + +import static org.bukkit.Bukkit.getServer; + +public class Version { + public static final String setting_dragon = "2.2.0"; + public static final String lang = "2.2.0"; + public static final String config = "2.2.0"; + public static final String data = "2.2.0"; + public static int mcMainVersion; + public static int mcPatchVersion; + private static String version = "no version found"; + private static boolean isMohist = false; + public static void init(){ + try { + version = getServer().getClass().getPackage().getName().split("\\.")[3]; + String[] mc_version = getServer().getBukkitVersion().split("-")[0].split("\\."); + mcMainVersion = Integer.parseInt(mc_version[1]); + if(mc_version.length<=2) mcPatchVersion = 0; + else mcPatchVersion = Integer.parseInt(mc_version[2]); + } catch (Throwable throwable) { + throwable.printStackTrace(); + Lang.warn("Failed to get nms-version!"); + } + Lang.info("Found version: " + version); + try{ + Class.forName("net.minecraftforge.server.ServerMain"); + isMohist = true; + }catch(ReflectiveOperationException ignored){} + + } + public static I_NMSItemManager getNMSItemManager(){ + switch (version){ + case "v1_12_R1" : return new pers.xanadu.enderdragon.nms.NMSItem.v1_12_R1.NMSItemManager(); + case "v1_13_R1" : return new pers.xanadu.enderdragon.nms.NMSItem.v1_13_R1.NMSItemManager(); + default: return new pers.xanadu.enderdragon.nms.NMSItem.v1_13_R2_above.NMSItemManager(); + } + } + public static I_BossBarManager getBossBarManager(){ + switch(version){ + case "v1_12_R1" : return new pers.xanadu.enderdragon.nms.BossBar.v1_12_R1.BossBarManager(); + case "v1_13_R1" : return new pers.xanadu.enderdragon.nms.BossBar.v1_13_R1.BossBarManager(); + case "v1_13_R2" : return new pers.xanadu.enderdragon.nms.BossBar.v1_13_R2.BossBarManager(); + default: return null; + } + } + public static I_WorldDataManager getWorldDataManager(){ + switch (version){ + case "v1_12_R1" : return new pers.xanadu.enderdragon.nms.WorldData.v1_12_R1.WorldDataManager(); + case "v1_13_R1" : return new pers.xanadu.enderdragon.nms.WorldData.v1_13_R1.WorldDataManager(); + case "v1_13_R2" : return new pers.xanadu.enderdragon.nms.WorldData.v1_13_R2.WorldDataManager(); + case "v1_14_R1" : return new pers.xanadu.enderdragon.nms.WorldData.v1_14_R1.WorldDataManager(); + case "v1_15_R1" : return new pers.xanadu.enderdragon.nms.WorldData.v1_15_R1.WorldDataManager(); + case "v1_16_R1" : return new pers.xanadu.enderdragon.nms.WorldData.v1_16_R1.WorldDataManager(); + case "v1_16_R2" : return new pers.xanadu.enderdragon.nms.WorldData.v1_16_R2.WorldDataManager(); + case "v1_16_R3" : return new pers.xanadu.enderdragon.nms.WorldData.v1_16_R3.WorldDataManager(); + default : return new pers.xanadu.enderdragon.nms.WorldData.v1_17_above.WorldDataManager(); + } + } + public static I_RespawnAnchorManager getRespawnAnchorManager(){ + switch (version){ + case "v1_12_R1" : + case "v1_13_R1" : + case "v1_14_R1" : + case "v1_13_R2" : + case "v1_15_R1" : return null; + case "v1_16_R1" : return new pers.xanadu.enderdragon.nms.RespawnAnchor.v1_16_R1.RespawnAnchorManager(); + case "v1_16_R2" : return new pers.xanadu.enderdragon.nms.RespawnAnchor.v1_16_R2.RespawnAnchorManager(); + case "v1_16_R3" : return new pers.xanadu.enderdragon.nms.RespawnAnchor.v1_16_R3.RespawnAnchorManager(); + case "v1_17_R1" : return new pers.xanadu.enderdragon.nms.RespawnAnchor.v1_17_R1.RespawnAnchorManager(); + default: return new pers.xanadu.enderdragon.nms.RespawnAnchor.v1_18_above.RespawnAnchorManager(); + } + } + public static String getVersion() { + return version; + } + public static boolean isMohist(){ + return isMohist; + } + +}