mirror of
https://gitlab.com/phoenix-dvpmt/mmocore.git
synced 2024-11-26 00:35:17 +01:00
Fixed waypoint path calculation. Option to disable auto waypoint path calculation
This commit is contained in:
parent
f24a1b0a6a
commit
c4ae7bfed3
@ -9,6 +9,7 @@ import io.lumine.mythic.lib.hologram.Hologram;
|
||||
import io.lumine.mythic.lib.version.VEnchantment;
|
||||
import net.Indyuce.mmocore.MMOCore;
|
||||
import net.Indyuce.mmocore.util.Icon;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.attribute.Attribute;
|
||||
import org.bukkit.entity.Entity;
|
||||
@ -218,12 +219,7 @@ public class MMOCoreUtils {
|
||||
return object.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get all entities surrounding a location. This method does not
|
||||
* take every entity in the world but rather takes all the entities from the
|
||||
* 9 chunks around the entity, so even if the location is at the border of a
|
||||
* chunk (worst case border of 4 chunks), the entity will still be included
|
||||
*/
|
||||
@Deprecated
|
||||
public static List<Entity> getNearbyChunkEntities(Location loc) {
|
||||
|
||||
/*
|
||||
@ -301,6 +297,22 @@ public class MMOCoreUtils {
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Location readLocation(String string) {
|
||||
String[] split = string.split(" ");
|
||||
|
||||
World world = Bukkit.getWorld(split[0]);
|
||||
Validate.notNull(world, "Could not find world with name '" + split[0] + "'");
|
||||
|
||||
double x = Double.parseDouble(split[1]);
|
||||
double y = Double.parseDouble(split[2]);
|
||||
double z = Double.parseDouble(split[3]);
|
||||
float yaw = split.length > 4 ? (float) Double.parseDouble(split[4]) : 0;
|
||||
float pitch = split.length > 5 ? (float) Double.parseDouble(split[5]) : 0;
|
||||
|
||||
return new Location(world, x, y, z, yaw, pitch);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Center location of an entity using its bounding box
|
||||
*/
|
||||
|
@ -13,6 +13,7 @@ import net.Indyuce.mmocore.gui.api.item.Placeholders;
|
||||
import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem;
|
||||
import net.Indyuce.mmocore.waypoint.Waypoint;
|
||||
import net.Indyuce.mmocore.waypoint.WaypointPath;
|
||||
import net.Indyuce.mmocore.waypoint.WaypointPathCalculation;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
@ -26,7 +27,6 @@ import org.bukkit.persistence.PersistentDataType;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -72,7 +72,7 @@ public class WaypointViewer extends EditableInventory {
|
||||
|
||||
public class WaypointItem extends SimplePlaceholderItem<WaypointViewerInventory> {
|
||||
private final SimplePlaceholderItem noWaypoint, locked;
|
||||
private final WaypointItemHandler availWaypoint, noStellium, notLinked, notDynamic, currentWayPoint;
|
||||
private final WaypointItemHandler availWaypoint, noStellium, notLinked, currentWayPoint;
|
||||
|
||||
public WaypointItem(ConfigurationSection config) {
|
||||
super(Material.BARRIER, config);
|
||||
@ -80,7 +80,7 @@ public class WaypointViewer extends EditableInventory {
|
||||
Validate.notNull(config.getConfigurationSection("no-waypoint"), "Could not load 'no-waypoint' config");
|
||||
Validate.notNull(config.getConfigurationSection("locked"), "Could not load 'locked' config");
|
||||
Validate.notNull(config.getConfigurationSection("not-a-destination"), "Could not load 'not-a-destination' config");
|
||||
Validate.notNull(config.getConfigurationSection("not-dynamic"), "Could not load 'not-dynamic' config");
|
||||
//Validate.notNull(config.getConfigurationSection("not-dynamic"), "Could not load 'not-dynamic' config");
|
||||
Validate.notNull(config.getConfigurationSection("current-waypoint"), "Could not load 'current-waypoint' config");
|
||||
Validate.notNull(config.getConfigurationSection("not-enough-stellium"), "Could not load 'not-enough-stellium' config");
|
||||
Validate.notNull(config.getConfigurationSection("display"), "Could not load 'display' config");
|
||||
@ -88,7 +88,7 @@ public class WaypointViewer extends EditableInventory {
|
||||
noWaypoint = new SimplePlaceholderItem(config.getConfigurationSection("no-waypoint"));
|
||||
locked = new SimplePlaceholderItem(config.getConfigurationSection("locked"));
|
||||
notLinked = new WaypointItemHandler(config.getConfigurationSection("not-a-destination"), true);
|
||||
notDynamic = new WaypointItemHandler(config.getConfigurationSection("not-dynamic"), true);
|
||||
//notDynamic = new WaypointItemHandler(config.getConfigurationSection("not-dynamic"), true);
|
||||
currentWayPoint = new WaypointItemHandler(config.getConfigurationSection("current-waypoint"), true);
|
||||
noStellium = new WaypointItemHandler(config.getConfigurationSection("not-enough-stellium"), false);
|
||||
availWaypoint = new WaypointItemHandler(config.getConfigurationSection("display"), false);
|
||||
@ -106,22 +106,20 @@ public class WaypointViewer extends EditableInventory {
|
||||
if (index >= inv.waypoints.size())
|
||||
return noWaypoint.display(inv, n);
|
||||
|
||||
// Locked waypoint?
|
||||
Waypoint waypoint = inv.waypoints.get(index);
|
||||
final Waypoint waypoint = inv.waypoints.get(index);
|
||||
|
||||
// Current waypoint
|
||||
if (inv.current != null && inv.current.equals(waypoint))
|
||||
return currentWayPoint.display(inv, n);
|
||||
|
||||
// Locked waypoint
|
||||
if (!inv.getPlayerData().hasWaypoint(waypoint))
|
||||
return locked.display(inv, n);
|
||||
|
||||
// Waypoints are not linked
|
||||
if (inv.current != null && !inv.paths.containsKey(waypoint))
|
||||
if (!inv.paths.containsKey(waypoint))
|
||||
return notLinked.display(inv, n);
|
||||
|
||||
// Not dynamic waypoint
|
||||
if (inv.current == null && !inv.paths.containsKey(waypoint))
|
||||
return notDynamic.display(inv, n);
|
||||
|
||||
// Normal cost
|
||||
if (inv.paths.get(waypoint).getCost() > inv.getPlayerData().getStellium())
|
||||
return noStellium.display(inv, n);
|
||||
@ -132,10 +130,14 @@ public class WaypointViewer extends EditableInventory {
|
||||
|
||||
public class WaypointItemHandler extends InventoryItem<WaypointViewerInventory> {
|
||||
private final boolean onlyName;
|
||||
private final String splitter, none;
|
||||
|
||||
public WaypointItemHandler(ConfigurationSection config, boolean onlyName) {
|
||||
super(config);
|
||||
|
||||
this.onlyName = onlyName;
|
||||
this.splitter = config.getString("format_path.splitter", ", ");
|
||||
this.none = config.getString("format_path.none", "None");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -187,7 +189,7 @@ public class WaypointViewer extends EditableInventory {
|
||||
holders.register("current_cost", inv.paths.get(waypoint).getCost());
|
||||
holders.register("normal_cost", decimal.format(inv.paths.containsKey(waypoint) ? inv.paths.get(waypoint).getCost() : Double.POSITIVE_INFINITY));
|
||||
holders.register("dynamic_cost", decimal.format(waypoint.getDynamicCost()));
|
||||
holders.register("intermediary_waypoints", inv.paths.containsKey(waypoint) ? inv.paths.get(waypoint).displayIntermediaryWayPoints(inv.isDynamicUse()) : "None");
|
||||
holders.register("intermediary_waypoints", inv.paths.containsKey(waypoint) ? inv.paths.get(waypoint).displayIntermediaryWayPoints(splitter, none) : none);
|
||||
}
|
||||
|
||||
return holders;
|
||||
@ -198,7 +200,8 @@ public class WaypointViewer extends EditableInventory {
|
||||
private final List<Waypoint> waypoints = new ArrayList<>(MMOCore.plugin.waypointManager.getAll());
|
||||
@Nullable
|
||||
private final Waypoint current;
|
||||
private final Map<Waypoint, WaypointPath> paths = new HashMap<>();
|
||||
|
||||
private Map<Waypoint, WaypointPath> paths;
|
||||
|
||||
private int page;
|
||||
|
||||
@ -206,29 +209,7 @@ public class WaypointViewer extends EditableInventory {
|
||||
super(playerData, editable);
|
||||
|
||||
this.current = current;
|
||||
if (current != null)
|
||||
for (WaypointPath pathInfo : current.getAllPath())
|
||||
paths.put(pathInfo.getFinalWaypoint(), pathInfo);
|
||||
|
||||
if (current == null) {
|
||||
|
||||
//Iterate through all the dynamic points and find all the points it is linked to and the path
|
||||
HashMap<Waypoint, Double> dynamicPoints = new HashMap<>();
|
||||
//We first check all the dynamic waypoints
|
||||
for (Waypoint waypoint : waypoints) {
|
||||
if (waypoint.mayBeUsedDynamically(playerData.getPlayer())) {
|
||||
paths.put(waypoint, new WaypointPath(waypoint, waypoint.getDynamicCost()));
|
||||
dynamicPoints.put(waypoint, waypoint.getDynamicCost());
|
||||
}
|
||||
}
|
||||
for (Waypoint source : dynamicPoints.keySet()) {
|
||||
for (WaypointPath target : source.getAllPath()) {
|
||||
if (!paths.containsKey(target.getFinalWaypoint()) || paths.get(target.getFinalWaypoint()).getCost() > target.getCost() + dynamicPoints.get(source)) {
|
||||
paths.put(target.getFinalWaypoint(), target.addCost(dynamicPoints.get(source)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
paths = new WaypointPathCalculation(playerData).run(current).getPaths();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -259,11 +240,10 @@ public class WaypointViewer extends EditableInventory {
|
||||
String tag = container.has(new NamespacedKey(MMOCore.plugin, "waypointId"), PersistentDataType.STRING) ?
|
||||
container.get(new NamespacedKey(MMOCore.plugin, "waypointId"), PersistentDataType.STRING) : "";
|
||||
|
||||
if (tag.equals(""))
|
||||
return;
|
||||
if (tag.isEmpty()) return;
|
||||
|
||||
// Locked waypoint?
|
||||
Waypoint waypoint = MMOCore.plugin.waypointManager.get(tag);
|
||||
final Waypoint waypoint = MMOCore.plugin.waypointManager.get(tag);
|
||||
if (!playerData.hasWaypoint(waypoint)) {
|
||||
ConfigMessage.fromKey("not-unlocked-waypoint").send(player);
|
||||
return;
|
||||
@ -275,18 +255,12 @@ public class WaypointViewer extends EditableInventory {
|
||||
return;
|
||||
}
|
||||
|
||||
// Waypoint does not have target as destination
|
||||
if (current != null && current.getPath(waypoint) == null) {
|
||||
// No access to that waypoint
|
||||
if (paths.get(waypoint) == null) {
|
||||
ConfigMessage.fromKey("cannot-teleport-to").send(player);
|
||||
return;
|
||||
}
|
||||
|
||||
// Not dynamic waypoint
|
||||
if (current == null && !paths.containsKey(waypoint)) {
|
||||
ConfigMessage.fromKey("not-dynamic-waypoint").send(player);
|
||||
return;
|
||||
}
|
||||
|
||||
// Stellium cost
|
||||
double withdraw = paths.get(waypoint).getCost();
|
||||
double left = withdraw - playerData.getStellium();
|
||||
@ -300,7 +274,6 @@ public class WaypointViewer extends EditableInventory {
|
||||
|
||||
player.closeInventory();
|
||||
playerData.warp(waypoint, withdraw);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ public class ConfigManager {
|
||||
public final CommandVerbose commandVerbose = new CommandVerbose();
|
||||
|
||||
public boolean overrideVanillaExp, canCreativeCast, passiveSkillsNeedBinding, cobbleGeneratorXP, saveDefaultClassInfo, splitMainExp, splitProfessionExp, disableQuestBossBar,
|
||||
pvpModeEnabled, pvpModeInvulnerabilityCanDamage, forceClassSelection, enableGlobalSkillTreeGUI, enableSpecificSkillTreeGUI;
|
||||
pvpModeEnabled, pvpModeInvulnerabilityCanDamage, forceClassSelection, enableGlobalSkillTreeGUI, enableSpecificSkillTreeGUI, waypointAutoPathCalculation;
|
||||
public String partyChatPrefix, noSkillBoundPlaceholder;
|
||||
public ChatColor staminaFull, staminaHalf, staminaEmpty;
|
||||
public long combatLogTimer, lootChestExpireTime, lootChestPlayerCooldown, globalSkillCooldown;
|
||||
@ -151,6 +151,7 @@ public class ConfigManager {
|
||||
disableQuestBossBar = MMOCore.plugin.getConfig().getBoolean("mmocore-quests.disable-boss-bar");
|
||||
forceClassSelection = MMOCore.plugin.getConfig().getBoolean("force-class-selection");
|
||||
waypointWarpTime = MMOCore.plugin.getConfig().getInt("waypoints.default-warp-time");
|
||||
waypointAutoPathCalculation = MMOCore.plugin.getConfig().getBoolean("waypoints.auto_path_calculation");
|
||||
|
||||
// Combat
|
||||
pvpModeEnabled = config.getBoolean("pvp_mode.enabled");
|
||||
|
47
MMOCore-API/src/main/java/net/Indyuce/mmocore/util/Pair.java
Normal file
47
MMOCore-API/src/main/java/net/Indyuce/mmocore/util/Pair.java
Normal file
@ -0,0 +1,47 @@
|
||||
package net.Indyuce.mmocore.util;
|
||||
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class Pair<L, R> {
|
||||
private final L left;
|
||||
private final R right;
|
||||
|
||||
private Pair(L left, R right) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
||||
public L getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public R getRight() {
|
||||
return right;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String toString() {
|
||||
return "(" + this.getLeft() + ',' + this.getRight() + ')';
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static <L, R> Pair<L, R> of(L left, R right) {
|
||||
return new Pair<>(left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object object) {
|
||||
if (this == object) return true;
|
||||
if (object == null || getClass() != object.getClass()) return false;
|
||||
Pair<?, ?> pair = (Pair<?, ?>) object;
|
||||
return Objects.equals(left, pair.left) && Objects.equals(right, pair.right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(left, right);
|
||||
}
|
||||
}
|
@ -5,17 +5,14 @@ import io.lumine.mythic.lib.util.PostLoadAction;
|
||||
import io.lumine.mythic.lib.util.PreloadedObject;
|
||||
import net.Indyuce.mmocore.MMOCore;
|
||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
|
||||
import net.Indyuce.mmocore.loot.chest.condition.Condition;
|
||||
import net.Indyuce.mmocore.loot.chest.condition.ConditionInstance;
|
||||
import net.Indyuce.mmocore.player.Unlockable;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
@ -59,7 +56,7 @@ public class Waypoint implements Unlockable, PreloadedObject {
|
||||
name = Objects.requireNonNull(config.getString("name"), "Could not load waypoint name");
|
||||
lore = Objects.requireNonNullElse(config.getStringList("lore"), new ArrayList<>());
|
||||
|
||||
loc = readLocation(Objects.requireNonNull(config.getString("location"), "Could not read location"));
|
||||
loc = MMOCoreUtils.readLocation(Objects.requireNonNull(config.getString("location"), "Could not read location"));
|
||||
radiusSquared = Math.pow(config.getDouble("radius"), 2);
|
||||
warpTime = Math.max(0, config.getInt("warp-time", MMOCore.plugin.configManager.waypointWarpTime));
|
||||
|
||||
@ -131,75 +128,13 @@ public class Waypoint implements Unlockable, PreloadedObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Integer.POSITIVE_INFINITY if the way point is not linked
|
||||
* @return Double.POSITIVE_INFINITY if the way point is not linked
|
||||
* If it is, cost of the instant travel between the two waypoints.
|
||||
*/
|
||||
public double getDirectCost(Waypoint waypoint) {
|
||||
public double getDirectCost(@NotNull Waypoint waypoint) {
|
||||
return destinations.isEmpty() ? normalCost : destinations.getOrDefault(waypoint, Double.POSITIVE_INFINITY);
|
||||
}
|
||||
|
||||
public List<WaypointPath> getAllPath() {
|
||||
//All the WayPoints that have been registered
|
||||
List<Waypoint> checkedPoints = new ArrayList<>();
|
||||
//All the path
|
||||
List<WaypointPath> paths = new ArrayList();
|
||||
List<WaypointPath> pointsToCheck = new ArrayList<>();
|
||||
pointsToCheck.add(new WaypointPath(this));
|
||||
|
||||
while (pointsToCheck.size() != 0) {
|
||||
WaypointPath checked = pointsToCheck.get(0);
|
||||
pointsToCheck.remove(0);
|
||||
// If the point has already been checked, pass
|
||||
if (checkedPoints.contains(checked.getFinalWaypoint()))
|
||||
continue;
|
||||
|
||||
paths.add(checked);
|
||||
checkedPoints.add(checked.getFinalWaypoint());
|
||||
|
||||
for (Waypoint toCheck : checked.getFinalWaypoint().destinations.keySet())
|
||||
if (!checkedPoints.contains(toCheck)) {
|
||||
WaypointPath toCheckInfo = checked.addWayPoint(toCheck);
|
||||
// We keep pointsToCheck ordered
|
||||
pointsToCheck = toCheckInfo.addInOrder(pointsToCheck);
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public WaypointPath getPath(Waypoint targetWaypoint) {
|
||||
//All the WayPoints that have been registered
|
||||
List<Waypoint> checkedPoints = new ArrayList<>();
|
||||
//All the path
|
||||
List<WaypointPath> paths = new ArrayList();
|
||||
List<WaypointPath> pointsToCheck = new ArrayList<>();
|
||||
pointsToCheck.add(new WaypointPath(this));
|
||||
|
||||
while (pointsToCheck.size() != 0) {
|
||||
WaypointPath checked = pointsToCheck.get(0);
|
||||
pointsToCheck.remove(0);
|
||||
// If the point has already been checked, pass
|
||||
if (checkedPoints.contains(checked.getFinalWaypoint()))
|
||||
continue;
|
||||
|
||||
paths.add(checked);
|
||||
checkedPoints.add(checked.getFinalWaypoint());
|
||||
|
||||
if (checked.getFinalWaypoint().equals(targetWaypoint))
|
||||
return checked;
|
||||
|
||||
for (Waypoint toCheck : checked.getFinalWaypoint().destinations.keySet())
|
||||
if (!checkedPoints.contains(toCheck)) {
|
||||
WaypointPath toCheckInfo = checked.addWayPoint(toCheck);
|
||||
// We keep pointsToCheck ordered
|
||||
pointsToCheck = toCheckInfo.addInOrder(pointsToCheck);
|
||||
}
|
||||
}
|
||||
|
||||
//If no path has been found we return null
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean hasOption(WaypointOption option) {
|
||||
return options.get(option);
|
||||
}
|
||||
@ -208,6 +143,11 @@ public class Waypoint implements Unlockable, PreloadedObject {
|
||||
return player.getWorld().equals(loc.getWorld()) && player.getLocation().distanceSquared(loc) < radiusSquared;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Map<Waypoint, Double> getDestinations() {
|
||||
return destinations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return id;
|
||||
@ -245,19 +185,4 @@ public class Waypoint implements Unlockable, PreloadedObject {
|
||||
Waypoint waypoint = (Waypoint) o;
|
||||
return id.equals(waypoint.id);
|
||||
}
|
||||
|
||||
private Location readLocation(String string) {
|
||||
String[] split = string.split(" ");
|
||||
|
||||
World world = Bukkit.getWorld(split[0]);
|
||||
Validate.notNull(world, "Could not find world with name '" + split[0] + "'");
|
||||
|
||||
double x = Double.parseDouble(split[1]);
|
||||
double y = Double.parseDouble(split[2]);
|
||||
double z = Double.parseDouble(split[3]);
|
||||
float yaw = split.length > 4 ? (float) Double.parseDouble(split[4]) : 0;
|
||||
float pitch = split.length > 5 ? (float) Double.parseDouble(split[5]) : 0;
|
||||
|
||||
return new Location(world, x, y, z, yaw, pitch);
|
||||
}
|
||||
}
|
@ -1,29 +1,25 @@
|
||||
package net.Indyuce.mmocore.waypoint;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WaypointPath {
|
||||
private final List<Waypoint> waypoints;
|
||||
private double cost;
|
||||
private final List<Waypoint> waypoints = new ArrayList<>();
|
||||
private final double cost;
|
||||
|
||||
public WaypointPath(Waypoint waypoint) {
|
||||
this.waypoints = new ArrayList<>();
|
||||
this.waypoints.add(waypoint);
|
||||
cost = 0;
|
||||
public static final WaypointPath INFINITE = new WaypointPath(Double.POSITIVE_INFINITY);
|
||||
|
||||
public WaypointPath() {
|
||||
this(0);
|
||||
}
|
||||
|
||||
public WaypointPath(Waypoint waypoint, double cost) {
|
||||
this.waypoints = new ArrayList<>();
|
||||
this.waypoints.add(waypoint);
|
||||
this.cost = cost;
|
||||
}
|
||||
|
||||
public WaypointPath(List<Waypoint> waypoints, double cost) {
|
||||
this.waypoints = new ArrayList<>(waypoints);
|
||||
public WaypointPath(double cost) {
|
||||
this.cost = cost;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<Waypoint> getWaypoints() {
|
||||
return waypoints;
|
||||
}
|
||||
@ -32,54 +28,25 @@ public class WaypointPath {
|
||||
return cost;
|
||||
}
|
||||
|
||||
public WaypointPath addCost(double cost) {
|
||||
this.cost += cost;
|
||||
return this;
|
||||
@NotNull
|
||||
public String displayIntermediaryWayPoints(String splitter, String none) {
|
||||
if (waypoints.isEmpty()) return none;
|
||||
|
||||
boolean b = false;
|
||||
final StringBuilder result = new StringBuilder();
|
||||
for (Waypoint waypoint : waypoints) {
|
||||
if (b) result.append(splitter);
|
||||
result.append(waypoint.getName());
|
||||
if (!b) b = true;
|
||||
}
|
||||
|
||||
public List<WaypointPath> addInOrder(List<WaypointPath> pathInfos) {
|
||||
int index = 0;
|
||||
while (index < pathInfos.size()) {
|
||||
if (cost < pathInfos.get(index).cost) {
|
||||
pathInfos.set(index, this);
|
||||
return pathInfos;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
// If index == pathInfos.size() add the waypoint at the end
|
||||
pathInfos.add(this);
|
||||
return pathInfos;
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param dynamic Display the first waypoint if it is dynamic as it is an intermediary point
|
||||
* @return List with all
|
||||
*/
|
||||
public String displayIntermediaryWayPoints(boolean dynamic) {
|
||||
int beginIndex = dynamic ? 0 : 1;
|
||||
if (waypoints.size() <= beginIndex + 1)
|
||||
return "None";
|
||||
|
||||
String result = "";
|
||||
for (int i = beginIndex; i < waypoints.size() - 1; i++)
|
||||
result += waypoints.get(i).getName() + (i != waypoints.size() - 2 ? ", " : "");
|
||||
return result;
|
||||
}
|
||||
|
||||
public WaypointPath addWayPoint(Waypoint waypoint) {
|
||||
List<Waypoint> newWaypoints = new ArrayList<>();
|
||||
newWaypoints.addAll(waypoints);
|
||||
newWaypoints.add(waypoint);
|
||||
double cost = this.cost + getFinalWaypoint().getDirectCost(waypoint);
|
||||
return new WaypointPath(newWaypoints, cost);
|
||||
}
|
||||
|
||||
public Waypoint getInitialWaypoint() {
|
||||
return waypoints.get(0);
|
||||
}
|
||||
|
||||
public Waypoint getFinalWaypoint() {
|
||||
return waypoints.get(waypoints.size() - 1);
|
||||
@NotNull
|
||||
public WaypointPath push(@NotNull Waypoint waypoint, double extraCost) {
|
||||
final WaypointPath clone = new WaypointPath(this.cost + extraCost);
|
||||
clone.waypoints.add(waypoint);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
package net.Indyuce.mmocore.waypoint;
|
||||
|
||||
import net.Indyuce.mmocore.MMOCore;
|
||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||
import net.Indyuce.mmocore.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class WaypointPathCalculation {
|
||||
private final PlayerData playerData;
|
||||
private final Map<Waypoint, WaypointPath> paths = new HashMap<>();
|
||||
|
||||
public WaypointPathCalculation(PlayerData playerData) {
|
||||
this.playerData = playerData;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public WaypointPathCalculation run(@Nullable Waypoint source) {
|
||||
if (MMOCore.plugin.configManager.waypointAutoPathCalculation) runDijkstra(source);
|
||||
else runSimple(source);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void runSimple(@Nullable Waypoint source) {
|
||||
|
||||
// Direct adjacency
|
||||
if (source != null) for (Map.Entry<Waypoint, Double> adjacent : source.getDestinations().entrySet())
|
||||
replaceIfLower(adjacent.getKey(), adjacent.getValue());
|
||||
|
||||
// Dynamic waypoints
|
||||
for (Waypoint waypoint : MMOCore.plugin.waypointManager.getAll())
|
||||
if (waypoint.hasOption(WaypointOption.DYNAMIC)) replaceIfLower(waypoint, waypoint.getDynamicCost());
|
||||
}
|
||||
|
||||
private void replaceIfLower(@NotNull Waypoint adjacent, double cost) {
|
||||
paths.compute(adjacent, (ignored, path) -> path == null || cost < path.getCost() ? new WaypointPath(cost) : path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the Dijkstra algorithm to compute the shortest paths between source and
|
||||
* all available waypoints to a certain player. Paths using locked waypoints
|
||||
* are not computed.
|
||||
*
|
||||
* @param source Source waypoint node
|
||||
*/
|
||||
public void runDijkstra(@Nullable Waypoint source) {
|
||||
|
||||
final PriorityQueue<Pair<Waypoint, Double>> queue = new PriorityQueue<>(Comparator.comparingDouble(Pair::getRight));
|
||||
final Set<Waypoint> visited = new HashSet<>();
|
||||
|
||||
// Initialization
|
||||
for (Waypoint waypoint : MMOCore.plugin.waypointManager.getAll()) // Dynamic waypoints
|
||||
if (waypoint.hasOption(WaypointOption.DYNAMIC) && waypoint.mayBeUsedDynamically(playerData.getPlayer()))
|
||||
init(queue, waypoint, waypoint.getDynamicCost());
|
||||
if (source != null) init(queue, source, 0); // !! After dynamic waypoints !!
|
||||
|
||||
// Run Dijkstra
|
||||
do {
|
||||
final Waypoint currentNode = queue.remove().getLeft();
|
||||
|
||||
// Mark as visited
|
||||
visited.add(currentNode);
|
||||
|
||||
// Iterate over neighbors
|
||||
final WaypointPath nodePath = path(currentNode);
|
||||
for (Map.Entry<Waypoint, Double> adjacentData : currentNode.getDestinations().entrySet()) {
|
||||
|
||||
// Waypoint is usable?
|
||||
final Waypoint adjacentNode = adjacentData.getKey();
|
||||
if (!(adjacentNode.isUnlockedByDefault()
|
||||
|| adjacentNode.isOnWaypoint(playerData.getPlayer())
|
||||
|| playerData.hasWaypoint(adjacentNode)))
|
||||
return;
|
||||
|
||||
final double edgeWeight = adjacentData.getValue();
|
||||
|
||||
// Update distance if necessary
|
||||
final WaypointPath adjacentPath = path(adjacentNode);
|
||||
if (nodePath.getCost() + edgeWeight < adjacentPath.getCost())
|
||||
paths.put(adjacentNode, nodePath.push(currentNode, edgeWeight));
|
||||
|
||||
// Push to queue
|
||||
if (!visited.contains(adjacentNode)) queue.add(Pair.of(adjacentNode, edgeWeight));
|
||||
}
|
||||
|
||||
} while (!queue.isEmpty());
|
||||
}
|
||||
|
||||
private void init(@NotNull PriorityQueue<Pair<Waypoint, Double>> queue, @NotNull Waypoint waypoint, double cost) {
|
||||
queue.add(Pair.of(waypoint, cost));
|
||||
paths.put(waypoint, new WaypointPath(cost));
|
||||
}
|
||||
|
||||
private WaypointPath path(Waypoint waypoint) {
|
||||
return paths.getOrDefault(waypoint, WaypointPath.INFINITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Result of the waypoint path calculation
|
||||
*/
|
||||
@NotNull
|
||||
public Map<Waypoint, WaypointPath> getPaths() {
|
||||
return paths;
|
||||
}
|
||||
}
|
@ -274,6 +274,18 @@ waypoints:
|
||||
# takes to use the waypoint and teleport to target location.
|
||||
default-warp-time: 100
|
||||
|
||||
# By default, MMOCore runs path calculation to enable players
|
||||
# to take shortcuts and directly teleport across distant waypoints.
|
||||
#
|
||||
# Example:
|
||||
# - Player is standing at waypoint A. They want to go to waypoint C.
|
||||
# - Waypoint A is linked to waypoint B, waypoint B is linked to waypoint C
|
||||
# With this option toggled on, since A -> B -> C is a valid connection,
|
||||
# MMOCore tells the player they can directly go to C without having to
|
||||
# first teleport to B. The stellium cost is the sum of the individual
|
||||
# stelium costs. MMOCore always finds the shortest path between two waypoints.
|
||||
auto_path_calculation: true
|
||||
|
||||
# Change this to the name of the color you want for
|
||||
# the different resource bar placeholders
|
||||
resource-bar-colors:
|
||||
|
@ -34,18 +34,7 @@ items:
|
||||
|
||||
lore:
|
||||
- '{lore}'
|
||||
- '&7You cannot teleport as the two waypoints are not linked.'
|
||||
|
||||
|
||||
# When you cannot teleport to a non dynamic waypoint
|
||||
not-dynamic:
|
||||
name: '&a{name}'
|
||||
item: ENDER_PEARL
|
||||
|
||||
lore:
|
||||
- '{lore}'
|
||||
- '&7You cannot teleport as you are not standing on a waypoint.'
|
||||
|
||||
- '&7You do not have access to this waypoint.'
|
||||
|
||||
current-waypoint:
|
||||
name: '&a{name}'
|
||||
@ -53,7 +42,7 @@ items:
|
||||
|
||||
lore:
|
||||
- '{lore}'
|
||||
- '&7The waypoint you are standing at.'
|
||||
- '&7You are here.'
|
||||
|
||||
# When you don't have enough stellium
|
||||
not-enough-stellium:
|
||||
@ -69,6 +58,9 @@ items:
|
||||
display:
|
||||
name: '&a{name}'
|
||||
item: ENDER_EYE
|
||||
path:
|
||||
splitter: ', '
|
||||
none: 'None'
|
||||
lore:
|
||||
- '{lore}'
|
||||
- '&7You can teleport to this waypoint.'
|
||||
|
@ -115,11 +115,10 @@ new-waypoint-book: '%&eYou unlocked the &6{waypoint} &ewaypoint!'
|
||||
not-enough-stellium: '&cYou don''t have enough stellium: you need {more} more.'
|
||||
waypoint-cooldown: '&cPlease wait {cooldown} before using a waypoint again.'
|
||||
not-unlocked-waypoint: '&cYou have not unlocked that waypoint yet.'
|
||||
not-dynamic-waypoint: '&cYou many only teleport to a non-dynamic waypoint while standing on another waypoint.'
|
||||
standing-on-waypoint: '&cYou are already standing on this waypoint.'
|
||||
warping-canceled: '%&cWaypoint warping canceled.'
|
||||
warping-comencing: '%&cDO NOT MOVE!&e You will be warped in {left}sec.'
|
||||
cannot-teleport-to: '&cThe two waypoints are not linked.'
|
||||
warping-comencing: '%&cDO NOT MOVE!&e You will be teleported in {left}sec.'
|
||||
cannot-teleport-to: '&cYou do not have access to this waypoint.'
|
||||
|
||||
# Cash
|
||||
deposit: '&eYou successfully deposited &6{worth}g&e.'
|
||||
|
Loading…
Reference in New Issue
Block a user