From a8662dc2f3b8f31dfd3f1fe6f8550dc62d521118 Mon Sep 17 00:00:00 2001 From: AMinecraftDev Date: Sat, 3 Nov 2018 21:51:08 +0800 Subject: [PATCH] 1.0.0-SNAPSHOT-U38 + Finished working on the Targeting system and fully implemented it into the boss spawning system + Added the targeting option to the bosses.json --- .../Core/resources-json/bosses.json | 1 + plugin-modules/Core/resources-yml/config.yml | 1 + .../com/songoda/epicbosses/CustomBosses.java | 3 + .../songoda/epicbosses/entity/BossEntity.java | 2 +- .../epicbosses/holder/ActiveBossHolder.java | 9 +++ .../listeners/after/BossDeathListener.java | 3 +- .../listeners/pre/BossSpawnListener.java | 10 ++- .../managers/BossTargetManager.java | 64 ++++++++++++++++ .../epicbosses/targetting/ITarget.java | 16 ++++ .../epicbosses/targetting/TargetHandler.java | 74 +++++++++++++++++++ .../types/ClosestTargetHandler.java | 37 ++++++++++ .../types/NotDamagedNearbyTargetHandler.java | 31 ++++++++ .../types/RandomNearbyTargetHandler.java | 28 +++++++ .../types/TopDamagerTargetHandler.java | 39 ++++++++++ .../songoda/epicbosses/utils/MapUtils.java | 31 ++++++++ pom.xml | 2 +- 16 files changed, 344 insertions(+), 7 deletions(-) create mode 100644 plugin-modules/Core/src/com/songoda/epicbosses/managers/BossTargetManager.java create mode 100644 plugin-modules/Core/src/com/songoda/epicbosses/targetting/ITarget.java create mode 100644 plugin-modules/Core/src/com/songoda/epicbosses/targetting/TargetHandler.java create mode 100644 plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/ClosestTargetHandler.java create mode 100644 plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/NotDamagedNearbyTargetHandler.java create mode 100644 plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/RandomNearbyTargetHandler.java create mode 100644 plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/TopDamagerTargetHandler.java create mode 100644 plugin-modules/Core/src/com/songoda/epicbosses/utils/MapUtils.java diff --git a/plugin-modules/Core/resources-json/bosses.json b/plugin-modules/Core/resources-json/bosses.json index 4893fc7..761e828 100644 --- a/plugin-modules/Core/resources-json/bosses.json +++ b/plugin-modules/Core/resources-json/bosses.json @@ -2,6 +2,7 @@ "SkeletonKing": { "editing": true, "spawnItem": "SKSpawnItem", + "targeting": "RandomNearby", "entityStats": [ { "mainStats": { diff --git a/plugin-modules/Core/resources-yml/config.yml b/plugin-modules/Core/resources-yml/config.yml index e91b185..3c63eb9 100644 --- a/plugin-modules/Core/resources-yml/config.yml +++ b/plugin-modules/Core/resources-yml/config.yml @@ -1,5 +1,6 @@ Settings: debug: false + bossTargetRange: 50.0 BlockedWorlds: enabled: false diff --git a/plugin-modules/Core/src/com/songoda/epicbosses/CustomBosses.java b/plugin-modules/Core/src/com/songoda/epicbosses/CustomBosses.java index 1e315af..9f26816 100644 --- a/plugin-modules/Core/src/com/songoda/epicbosses/CustomBosses.java +++ b/plugin-modules/Core/src/com/songoda/epicbosses/CustomBosses.java @@ -1,5 +1,6 @@ package com.songoda.epicbosses; +import com.songoda.epicbosses.targetting.TargetHandler; import lombok.Getter; import com.songoda.epicbosses.api.BossAPI; import com.songoda.epicbosses.commands.BossCmd; @@ -41,6 +42,7 @@ public class CustomBosses extends JavaPlugin implements IReloadable { @Getter private BossListenerManager bossListenerManager; @Getter private BossCommandManager bossCommandManager; @Getter private BossEntityManager bossEntityManager; + @Getter private BossTargetManager bossTargetManager; @Getter private BossPanelManager bossPanelManager; @Getter private BossHookManager bossHookManager; @Getter private VersionHandler versionHandler; @@ -62,6 +64,7 @@ public class CustomBosses extends JavaPlugin implements IReloadable { this.debugManager = new DebugManager(); this.versionHandler = new VersionHandler(); + this.bossTargetManager = new BossTargetManager(this); this.bossEntityContainer = new BossEntityContainer(); this.bossMechanicManager = new BossMechanicManager(this); this.bossHookManager = new BossHookManager(this); diff --git a/plugin-modules/Core/src/com/songoda/epicbosses/entity/BossEntity.java b/plugin-modules/Core/src/com/songoda/epicbosses/entity/BossEntity.java index e815a33..3df49ed 100644 --- a/plugin-modules/Core/src/com/songoda/epicbosses/entity/BossEntity.java +++ b/plugin-modules/Core/src/com/songoda/epicbosses/entity/BossEntity.java @@ -21,8 +21,8 @@ public class BossEntity { @Expose @Getter private final SkillsElement skills; @Expose @Getter private final DropsElement drops; - @Expose @Getter @Setter private String spawnItem; @Expose @Getter @Setter private boolean editing; + @Expose @Getter @Setter private String spawnItem, targeting; public BossEntity(boolean editing, String spawnItem, List entityStats, SkillsElement skills, DropsElement drops, MessagesElement messages, CommandsElement commands) { this.editing = editing; diff --git a/plugin-modules/Core/src/com/songoda/epicbosses/holder/ActiveBossHolder.java b/plugin-modules/Core/src/com/songoda/epicbosses/holder/ActiveBossHolder.java index 85fb13f..46a285e 100644 --- a/plugin-modules/Core/src/com/songoda/epicbosses/holder/ActiveBossHolder.java +++ b/plugin-modules/Core/src/com/songoda/epicbosses/holder/ActiveBossHolder.java @@ -1,6 +1,8 @@ package com.songoda.epicbosses.holder; import lombok.Getter; +import lombok.Setter; +import com.songoda.epicbosses.targetting.TargetHandler; import com.songoda.epicbosses.entity.BossEntity; import com.songoda.epicbosses.exception.AlreadySetException; import org.bukkit.Location; @@ -24,6 +26,9 @@ public class ActiveBossHolder { @Getter private Map livingEntityMap = new HashMap<>(); @Getter private Map mapOfDamagingUsers = new HashMap<>(); + @Getter @Setter private TargetHandler targetHandler = null; + @Getter @Setter private boolean isDead = false; + public ActiveBossHolder(BossEntity bossEntity, Location spawnLocation, String name) { this.location = spawnLocation; this.bossEntity = bossEntity; @@ -37,4 +42,8 @@ public class ActiveBossHolder { this.livingEntityMap.put(position, livingEntity); } } + + public boolean hasAttacked(UUID uuid) { + return this.mapOfDamagingUsers.containsKey(uuid); + } } diff --git a/plugin-modules/Core/src/com/songoda/epicbosses/listeners/after/BossDeathListener.java b/plugin-modules/Core/src/com/songoda/epicbosses/listeners/after/BossDeathListener.java index 0b108db..22b6a41 100644 --- a/plugin-modules/Core/src/com/songoda/epicbosses/listeners/after/BossDeathListener.java +++ b/plugin-modules/Core/src/com/songoda/epicbosses/listeners/after/BossDeathListener.java @@ -55,6 +55,7 @@ public class BossDeathListener implements Listener { if(this.bossEntityManager.isAllEntitiesDead(activeBossHolder)) { PreBossDeathEvent preBossDeathEvent = new PreBossDeathEvent(activeBossHolder, location); + activeBossHolder.setDead(true); ServerUtils.get().callEvent(preBossDeathEvent); } } @@ -129,7 +130,7 @@ public class BossDeathListener implements Listener { Bukkit.getOnlinePlayers().forEach(onlinePlayer -> { if(onlinePlayer.getWorld().getName().equals(location.getWorld().getName())) { if(onlinePlayer.getLocation().distanceSquared(location) <= messageRadius) { - finalMessage.forEach(s -> onlinePlayer.sendMessage(s)); + finalMessage.forEach(onlinePlayer::sendMessage); } } }); diff --git a/plugin-modules/Core/src/com/songoda/epicbosses/listeners/pre/BossSpawnListener.java b/plugin-modules/Core/src/com/songoda/epicbosses/listeners/pre/BossSpawnListener.java index b90464e..f55fb2a 100644 --- a/plugin-modules/Core/src/com/songoda/epicbosses/listeners/pre/BossSpawnListener.java +++ b/plugin-modules/Core/src/com/songoda/epicbosses/listeners/pre/BossSpawnListener.java @@ -9,6 +9,7 @@ import com.songoda.epicbosses.events.PreBossSpawnEvent; import com.songoda.epicbosses.holder.ActiveBossHolder; import com.songoda.epicbosses.managers.BossEntityManager; import com.songoda.epicbosses.managers.BossLocationManager; +import com.songoda.epicbosses.managers.BossTargetManager; import com.songoda.epicbosses.utils.Debug; import com.songoda.epicbosses.utils.Message; import com.songoda.epicbosses.utils.ServerUtils; @@ -38,12 +39,14 @@ import java.util.Map; public class BossSpawnListener implements Listener { private BossLocationManager bossLocationManager; + private BossTargetManager bossTargetManager; private BossEntityManager bossEntityManager; private VersionHandler versionHandler; public BossSpawnListener(CustomBosses customBosses) { this.versionHandler = customBosses.getVersionHandler(); this.bossEntityManager = customBosses.getBossEntityManager(); + this.bossTargetManager = customBosses.getBossTargetManager(); this.bossLocationManager = customBosses.getBossLocationManager(); } @@ -99,10 +102,9 @@ public class BossSpawnListener implements Listener { return; } - //TODO: Set TargetHandler to the boss - PreBossSpawnEvent preBossSpawnEvent = new PreBossSpawnEvent(activeBossHolder, player, itemStack); + this.bossTargetManager.initializeTargetHandler(activeBossHolder); ServerUtils.get().callEvent(preBossSpawnEvent); } @@ -136,14 +138,14 @@ public class BossSpawnListener implements Listener { Bukkit.getOnlinePlayers().forEach(onlinePlayer -> { if(onlinePlayer.getWorld().getName().equals(location.getWorld().getName())) { if(onlinePlayer.getLocation().distanceSquared(location) <= messagesRadius) { - messages.forEach(s -> onlinePlayer.sendMessage(s)); + messages.forEach(onlinePlayer::sendMessage); } } }); } } - //TODO: Create AutoTarget for TargetHandler + activeBossHolder.getTargetHandler().runTargetCycle(); //TODO: Handle Taunts BossSpawnEvent bossSpawnEvent = new BossSpawnEvent(activeBossHolder); diff --git a/plugin-modules/Core/src/com/songoda/epicbosses/managers/BossTargetManager.java b/plugin-modules/Core/src/com/songoda/epicbosses/managers/BossTargetManager.java new file mode 100644 index 0000000..b895ac2 --- /dev/null +++ b/plugin-modules/Core/src/com/songoda/epicbosses/managers/BossTargetManager.java @@ -0,0 +1,64 @@ +package com.songoda.epicbosses.managers; + +import com.songoda.epicbosses.CustomBosses; +import com.songoda.epicbosses.entity.BossEntity; +import com.songoda.epicbosses.holder.ActiveBossHolder; +import com.songoda.epicbosses.targetting.TargetHandler; +import com.songoda.epicbosses.targetting.types.ClosestTargetHandler; +import com.songoda.epicbosses.targetting.types.NotDamagedNearbyTargetHandler; +import com.songoda.epicbosses.targetting.types.RandomNearbyTargetHandler; +import com.songoda.epicbosses.targetting.types.TopDamagerTargetHandler; +import lombok.Getter; + +/** + * @author Charles Cullen + * @version 1.0.0 + * @since 03-Nov-18 + */ +public class BossTargetManager { + + @Getter private final CustomBosses plugin; + + public BossTargetManager(CustomBosses plugin) { + this.plugin = plugin; + } + + public double getTargetRadius() { + return this.plugin.getConfig().getDouble("Settings.bossTargetRange", 50.0); + } + + public void initializeTargetHandler(ActiveBossHolder activeBossHolder) { + BossEntity bossEntity = activeBossHolder.getBossEntity(); + String targeting = bossEntity.getTargeting(); + TargetHandler targetHandler; + + if(targeting.equalsIgnoreCase("RandomNearby")) { + targetHandler = getRandomNearbyTargetHandler(activeBossHolder); + } else if(targeting.equalsIgnoreCase("TopDamager")) { + targetHandler = getTopDamagerTargetHandler(activeBossHolder); + } else if(targeting.equalsIgnoreCase("NotDamagedNearby")) { + targetHandler = getNotDamagedNearbyTargetHandler(activeBossHolder); + } else { + targetHandler = getClosestTargetHandler(activeBossHolder); + } + + activeBossHolder.setTargetHandler(targetHandler); + } + + private TargetHandler getClosestTargetHandler(ActiveBossHolder activeBossHolder) { + return new ClosestTargetHandler(activeBossHolder, this); + } + + private TargetHandler getNotDamagedNearbyTargetHandler(ActiveBossHolder activeBossHolder) { + return new NotDamagedNearbyTargetHandler(activeBossHolder, this); + } + + private TargetHandler getRandomNearbyTargetHandler(ActiveBossHolder activeBossHolder) { + return new RandomNearbyTargetHandler(activeBossHolder, this); + } + + private TargetHandler getTopDamagerTargetHandler(ActiveBossHolder activeBossHolder) { + return new TopDamagerTargetHandler(activeBossHolder, this); + } + +} diff --git a/plugin-modules/Core/src/com/songoda/epicbosses/targetting/ITarget.java b/plugin-modules/Core/src/com/songoda/epicbosses/targetting/ITarget.java new file mode 100644 index 0000000..cca334b --- /dev/null +++ b/plugin-modules/Core/src/com/songoda/epicbosses/targetting/ITarget.java @@ -0,0 +1,16 @@ +package com.songoda.epicbosses.targetting; + +import org.bukkit.entity.LivingEntity; + +import java.util.List; + +/** + * @author Charles Cullen + * @version 1.0.0 + * @since 30-Oct-18 + */ +public interface ITarget { + + LivingEntity selectTarget(List nearbyEntities); + +} diff --git a/plugin-modules/Core/src/com/songoda/epicbosses/targetting/TargetHandler.java b/plugin-modules/Core/src/com/songoda/epicbosses/targetting/TargetHandler.java new file mode 100644 index 0000000..720edbc --- /dev/null +++ b/plugin-modules/Core/src/com/songoda/epicbosses/targetting/TargetHandler.java @@ -0,0 +1,74 @@ +package com.songoda.epicbosses.targetting; + +import com.songoda.epicbosses.CustomBosses; +import com.songoda.epicbosses.holder.ActiveBossHolder; +import com.songoda.epicbosses.managers.BossTargetManager; +import com.songoda.epicbosses.utils.ServerUtils; +import lombok.Getter; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Charles Cullen + * @version 1.0.0 + * @since 30-Oct-18 + */ +public abstract class TargetHandler implements ITarget { + + @Getter protected final BossTargetManager bossTargetManager; + @Getter protected final ActiveBossHolder activeBossHolder; + + public TargetHandler(ActiveBossHolder activeBossHolder, BossTargetManager bossTargetManager) { + this.activeBossHolder = activeBossHolder; + this.bossTargetManager = bossTargetManager; + } + + public void runTargetCycle() { + ServerUtils.get().runLaterAsync(100L, () -> { + updateTarget(); + + if(!getActiveBossHolder().isDead()) runTargetCycle(); + }); + } + + protected LivingEntity getBossEntity() { + for(LivingEntity livingEntity : this.activeBossHolder.getLivingEntityMap().values()) { + if(livingEntity != null && !livingEntity.isDead()) return livingEntity; + } + + return null; + } + + private void updateTarget() { + LivingEntity boss = getBossEntity(); + double radius = this.bossTargetManager.getTargetRadius(); + + if(boss == null) return; + + List nearbyEntities = new ArrayList<>(); + + for(Entity entity : boss.getNearbyEntities(radius, radius, radius)) { + if(!(entity instanceof Player)) continue; + + LivingEntity livingEntity = (LivingEntity) entity; + + nearbyEntities.add(livingEntity); + } + + updateBoss(selectTarget(nearbyEntities)); + } + + private void updateBoss(LivingEntity newTarget) { + this.activeBossHolder.getLivingEntityMap().values().forEach(livingEntity -> { + if(livingEntity != null && !livingEntity.isDead()) { + ((Creature) livingEntity).setTarget(newTarget); + } + }); + } + +} diff --git a/plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/ClosestTargetHandler.java b/plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/ClosestTargetHandler.java new file mode 100644 index 0000000..84b57e8 --- /dev/null +++ b/plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/ClosestTargetHandler.java @@ -0,0 +1,37 @@ +package com.songoda.epicbosses.targetting.types; + +import com.songoda.epicbosses.holder.ActiveBossHolder; +import com.songoda.epicbosses.managers.BossTargetManager; +import com.songoda.epicbosses.targetting.TargetHandler; +import org.bukkit.entity.LivingEntity; + +import java.util.List; + +/** + * @author Charles Cullen + * @version 1.0.0 + * @since 30-Oct-18 + */ +public class ClosestTargetHandler extends TargetHandler { + + public ClosestTargetHandler(ActiveBossHolder activeBossHolder, BossTargetManager bossTargetManager) { + super(activeBossHolder, bossTargetManager); + } + + @Override + public LivingEntity selectTarget(List nearbyEntities) { + LivingEntity boss = getBossEntity(); + double radius = this.bossTargetManager.getTargetRadius(); + double closestDistance = (radius * radius); + LivingEntity nearestTarget = null; + + for(LivingEntity livingEntity : nearbyEntities) { + if(livingEntity.getLocation().distanceSquared(boss.getLocation()) > closestDistance) continue; + + closestDistance = livingEntity.getLocation().distanceSquared(boss.getLocation()); + nearestTarget = livingEntity; + } + + return nearestTarget; + } +} diff --git a/plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/NotDamagedNearbyTargetHandler.java b/plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/NotDamagedNearbyTargetHandler.java new file mode 100644 index 0000000..3b6c6bb --- /dev/null +++ b/plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/NotDamagedNearbyTargetHandler.java @@ -0,0 +1,31 @@ +package com.songoda.epicbosses.targetting.types; + +import com.songoda.epicbosses.holder.ActiveBossHolder; +import com.songoda.epicbosses.managers.BossTargetManager; +import com.songoda.epicbosses.targetting.TargetHandler; +import org.bukkit.entity.LivingEntity; + +import java.util.List; + +/** + * @author Charles Cullen + * @version 1.0.0 + * @since 02-Nov-18 + */ +public class NotDamagedNearbyTargetHandler extends TargetHandler { + + public NotDamagedNearbyTargetHandler(ActiveBossHolder activeBossHolder, BossTargetManager bossTargetManager) { + super(activeBossHolder, bossTargetManager); + } + + @Override + public LivingEntity selectTarget(List nearbyEntities) { + for(LivingEntity livingEntity : nearbyEntities) { + if(getActiveBossHolder().hasAttacked(livingEntity.getUniqueId())) continue; + + return livingEntity; + } + + return null; + } +} diff --git a/plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/RandomNearbyTargetHandler.java b/plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/RandomNearbyTargetHandler.java new file mode 100644 index 0000000..81140f9 --- /dev/null +++ b/plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/RandomNearbyTargetHandler.java @@ -0,0 +1,28 @@ +package com.songoda.epicbosses.targetting.types; + +import com.songoda.epicbosses.holder.ActiveBossHolder; +import com.songoda.epicbosses.managers.BossTargetManager; +import com.songoda.epicbosses.targetting.TargetHandler; +import org.bukkit.entity.LivingEntity; + +import java.util.Collections; +import java.util.List; + +/** + * @author Charles Cullen + * @version 1.0.0 + * @since 30-Oct-18 + */ +public class RandomNearbyTargetHandler extends TargetHandler { + + public RandomNearbyTargetHandler(ActiveBossHolder activeBossHolder, BossTargetManager bossTargetManager) { + super(activeBossHolder, bossTargetManager); + } + + @Override + public LivingEntity selectTarget(List nearbyEntities) { + Collections.shuffle(nearbyEntities); + + return nearbyEntities.stream().findFirst().orElse(null); + } +} diff --git a/plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/TopDamagerTargetHandler.java b/plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/TopDamagerTargetHandler.java new file mode 100644 index 0000000..3a688aa --- /dev/null +++ b/plugin-modules/Core/src/com/songoda/epicbosses/targetting/types/TopDamagerTargetHandler.java @@ -0,0 +1,39 @@ +package com.songoda.epicbosses.targetting.types; + +import com.songoda.epicbosses.holder.ActiveBossHolder; +import com.songoda.epicbosses.managers.BossTargetManager; +import com.songoda.epicbosses.targetting.TargetHandler; +import com.songoda.epicbosses.utils.MapUtils; +import org.bukkit.entity.LivingEntity; + +import java.util.*; + +/** + * @author Charles Cullen + * @version 1.0.0 + * @since 30-Oct-18 + */ +public class TopDamagerTargetHandler extends TargetHandler { + + public TopDamagerTargetHandler(ActiveBossHolder activeBossHolder, BossTargetManager bossTargetManager) { + super(activeBossHolder, bossTargetManager); + } + + @Override + public LivingEntity selectTarget(List nearbyEntities) { + Map nearbyDamages = new HashMap<>(); + Map mapOfDamages = getActiveBossHolder().getMapOfDamagingUsers(); + + nearbyEntities.forEach(livingEntity -> { + UUID uuid = livingEntity.getUniqueId(); + + if(mapOfDamages.containsKey(uuid)) { + nearbyDamages.put(livingEntity, mapOfDamages.get(uuid)); + } + }); + + Map sortedMap = MapUtils.get().sortByValue(nearbyDamages); + + return sortedMap.keySet().stream().filter(livingEntity1 -> livingEntity1 != null && livingEntity1.isDead()).findFirst().orElse(null); + } +} diff --git a/plugin-modules/Core/src/com/songoda/epicbosses/utils/MapUtils.java b/plugin-modules/Core/src/com/songoda/epicbosses/utils/MapUtils.java new file mode 100644 index 0000000..80d17ce --- /dev/null +++ b/plugin-modules/Core/src/com/songoda/epicbosses/utils/MapUtils.java @@ -0,0 +1,31 @@ +package com.songoda.epicbosses.utils; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * @author Charles Cullen + * @version 1.0.0 + * @since 03-Nov-18 + */ +public class MapUtils { + + private static MapUtils INSTANCE = new MapUtils(); + + public > Map sortByValue(Map map) { + List> list = new ArrayList<>(map.entrySet()); + Map resultMap = new LinkedHashMap<>(); + + list.sort(Map.Entry.comparingByValue()); + list.forEach(entry -> resultMap.put(entry.getKey(), entry.getValue())); + + return resultMap; + } + + public static MapUtils get() { + return INSTANCE; + } + +} diff --git a/pom.xml b/pom.xml index baeef52..dcbb56b 100644 --- a/pom.xml +++ b/pom.xml @@ -19,7 +19,7 @@ - 1.0.0-SNAPSHOT-U36 + 1.0.0-SNAPSHOT-U38 EpicBosses com.songoda.epicbosses.CustomBosses AMinecraftDev