!waypoints improvements

This commit is contained in:
Indyuce 2022-02-27 13:24:25 +01:00
parent fff24aa077
commit 09bd1eec3d
18 changed files with 556 additions and 351 deletions

View File

@ -1,91 +0,0 @@
package net.Indyuce.mmocore.api;
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;
public class Waypoint {
private final String id, name;
private final Location loc;
private final double radiusSquared, stellium;
private final boolean def, sneak, dynamic;
public Waypoint(ConfigurationSection section) {
Validate.notNull(section, "Could not load config section");
id = section.getName();
name = section.getString("name");
Validate.notNull(name, "Could not load waypoint name");
String format = section.getString("location");
Validate.notNull(format, "Could not read location");
loc = readLocation(format);
stellium = section.getDouble("stellium");
radiusSquared = Math.pow(section.getDouble("radius"), 2);
def = section.getBoolean("default");
sneak = !section.contains("sneak") || section.getBoolean("sneak");
dynamic = section.getBoolean("dynamic");
}
public Location getLocation() {
return loc;
}
public String getName() {
return name;
}
public double getStelliumCost() {
return stellium;
}
public boolean hasSneakEnabled() {
return sneak;
}
public String getId() {
return id;
}
public boolean isDefault() {
return def;
}
public boolean isDynamic() {
return dynamic;
}
public boolean isOnWaypoint(Player player) {
return player.getWorld().equals(loc.getWorld()) && player.getLocation().distanceSquared(loc) < radiusSquared;
}
@Override
public String toString() {
return id;
}
@Override
public boolean equals(Object object) {
return object instanceof Waypoint && ((Waypoint) object).id.equals(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);
}
}

View File

@ -97,6 +97,11 @@ public class PlayerResourceUpdateEvent extends PlayerDataEvent implements Cancel
*/ */
SKILL_COST, SKILL_COST,
/**
* When consuming stellium to use a waypoint
*/
USE_WAYPOINT,
/** /**
* Used by quests triggers * Used by quests triggers
* - {@link net.Indyuce.mmocore.api.quest.trigger.ManaTrigger} * - {@link net.Indyuce.mmocore.api.quest.trigger.ManaTrigger}

View File

@ -6,7 +6,9 @@ import io.lumine.mythic.lib.player.cooldown.CooldownMap;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.ConfigMessage; import net.Indyuce.mmocore.api.ConfigMessage;
import net.Indyuce.mmocore.api.SoundEvent; import net.Indyuce.mmocore.api.SoundEvent;
import net.Indyuce.mmocore.api.Waypoint; import net.Indyuce.mmocore.player.Unlockable;
import net.Indyuce.mmocore.waypoint.CostType;
import net.Indyuce.mmocore.waypoint.Waypoint;
import net.Indyuce.mmocore.api.event.PlayerExperienceGainEvent; import net.Indyuce.mmocore.api.event.PlayerExperienceGainEvent;
import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent; import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent;
import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent; import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent;
@ -22,7 +24,7 @@ import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.api.quest.PlayerQuests; import net.Indyuce.mmocore.api.quest.PlayerQuests;
import net.Indyuce.mmocore.api.util.Closable; import net.Indyuce.mmocore.api.util.Closable;
import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect; import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect;
import net.Indyuce.mmocore.experience.EXPSource; import net.Indyuce.mmocore.experience.EXPSource;
import net.Indyuce.mmocore.experience.ExperienceObject; import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.ExperienceTableClaimer; import net.Indyuce.mmocore.experience.ExperienceTableClaimer;
@ -35,6 +37,7 @@ import net.Indyuce.mmocore.party.provided.Party;
import net.Indyuce.mmocore.skill.ClassSkill; import net.Indyuce.mmocore.skill.ClassSkill;
import net.Indyuce.mmocore.skill.RegisteredSkill; import net.Indyuce.mmocore.skill.RegisteredSkill;
import net.Indyuce.mmocore.skill.cast.SkillCastingHandler; import net.Indyuce.mmocore.skill.cast.SkillCastingHandler;
import net.Indyuce.mmocore.waypoint.WaypointOption;
import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.chat.TextComponent;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
@ -382,7 +385,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
} }
public boolean hasWaypoint(Waypoint waypoint) { public boolean hasWaypoint(Waypoint waypoint) {
return waypoint.isDefault() || waypoints.contains(waypoint.getId()); return waypoint.hasOption(WaypointOption.DEFAULT) || waypoints.contains(waypoint.getId());
} }
public void unlockWaypoint(Waypoint waypoint) { public void unlockWaypoint(Waypoint waypoint) {
@ -455,9 +458,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
* *
* @param waypoint Target waypoint * @param waypoint Target waypoint
*/ */
public void warp(Waypoint waypoint) { public void warp(Waypoint waypoint, CostType costType) {
if (!isOnline())
return;
/* /*
* This cooldown is only used internally to make sure the player is not * This cooldown is only used internally to make sure the player is not
@ -466,7 +467,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
*/ */
setLastActivity(PlayerActivity.USE_WAYPOINT); setLastActivity(PlayerActivity.USE_WAYPOINT);
giveStellium(-waypoint.getStelliumCost(), PlayerResourceUpdateEvent.UpdateReason.SKILL_COST); giveStellium(-waypoint.getCost(costType), PlayerResourceUpdateEvent.UpdateReason.USE_WAYPOINT);
new BukkitRunnable() { new BukkitRunnable() {
final int x = getPlayer().getLocation().getBlockX(); final int x = getPlayer().getLocation().getBlockX();
@ -481,7 +482,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc
|| getPlayer().getLocation().getBlockZ() != z) { || getPlayer().getLocation().getBlockZ() != z) {
MMOCore.plugin.soundManager.getSound(SoundEvent.WARP_CANCELLED).playTo(getPlayer()); MMOCore.plugin.soundManager.getSound(SoundEvent.WARP_CANCELLED).playTo(getPlayer());
MMOCore.plugin.configManager.getSimpleMessage("warping-canceled").send(getPlayer()); MMOCore.plugin.configManager.getSimpleMessage("warping-canceled").send(getPlayer());
giveStellium(waypoint.getStelliumCost(), PlayerResourceUpdateEvent.UpdateReason.SKILL_REGENERATION); giveStellium(waypoint.getCost(CostType.NORMAL_USE), PlayerResourceUpdateEvent.UpdateReason.SKILL_REGENERATION);
cancel(); cancel();
return; return;
} }

View File

@ -14,7 +14,7 @@ import net.Indyuce.mmocore.api.player.profess.resource.ResourceRegeneration;
import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.formula.LinearValue; import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
import net.Indyuce.mmocore.api.util.math.particle.CastingParticle; import net.Indyuce.mmocore.loot.chest.particle.CastingParticle;
import net.Indyuce.mmocore.experience.ExpCurve; import net.Indyuce.mmocore.experience.ExpCurve;
import net.Indyuce.mmocore.experience.ExperienceObject; import net.Indyuce.mmocore.experience.ExperienceObject;
import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.experience.droptable.ExperienceTable;

View File

@ -12,7 +12,7 @@ import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.MMOCoreUtils;
import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect; import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;

View File

@ -3,7 +3,6 @@ package net.Indyuce.mmocore.gui;
import io.lumine.mythic.lib.api.item.ItemTag; import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.NBTItem; import io.lumine.mythic.lib.api.item.NBTItem;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.Waypoint;
import net.Indyuce.mmocore.api.player.PlayerActivity; import net.Indyuce.mmocore.api.player.PlayerActivity;
import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.gui.api.EditableInventory; import net.Indyuce.mmocore.gui.api.EditableInventory;
@ -11,7 +10,9 @@ import net.Indyuce.mmocore.gui.api.GeneratedInventory;
import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.InventoryItem;
import net.Indyuce.mmocore.gui.api.item.Placeholders; import net.Indyuce.mmocore.gui.api.item.Placeholders;
import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem;
import org.apache.commons.lang.Validate; import net.Indyuce.mmocore.waypoint.CostType;
import net.Indyuce.mmocore.waypoint.Waypoint;
import net.Indyuce.mmocore.waypoint.WaypointOption;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
@ -19,6 +20,7 @@ import org.bukkit.inventory.ItemStack;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
public class WaypointViewer extends EditableInventory { public class WaypointViewer extends EditableInventory {
public WaypointViewer() { public WaypointViewer() {
@ -60,53 +62,20 @@ public class WaypointViewer extends EditableInventory {
return new WaypointViewerInventory(data, this, waypoint); return new WaypointViewerInventory(data, this, waypoint);
} }
public class WaypointDisplayItem extends InventoryItem<WaypointViewerInventory> {
private final Material notReady;
public WaypointDisplayItem(ConfigurationSection config) {
super(config);
Validate.isTrue(config.contains("not-ready"), "Could not read 'not-ready' material");
notReady = Material.valueOf(config.getString("not-ready"));
}
@Override
public ItemStack display(WaypointViewerInventory inv, int n) {
ItemStack disp = super.display(inv, n);
Waypoint waypoint = inv.waypoints.get(inv.page * inv.getEditable().getByFunction("waypoint").getSlots().size() + n);
if (inv.getPlayerData().getStellium() < waypoint.getStelliumCost() || (inv.current == null && !waypoint.isDynamic()))
disp.setType(notReady);
return NBTItem.get(disp).addTag(new ItemTag("waypointId", waypoint.getId())).toItem();
}
@Override
public Placeholders getPlaceholders(WaypointViewerInventory inv, int n) {
Placeholders holders = new Placeholders();
Waypoint waypoint = inv.waypoints.get(inv.page * inv.getByFunction("waypoint").getSlots().size() + n);
holders.register("name", waypoint.getName());
holders.register("stellium", decimal.format(waypoint.getStelliumCost()));
return holders;
}
}
public class WaypointItem extends SimplePlaceholderItem<WaypointViewerInventory> { public class WaypointItem extends SimplePlaceholderItem<WaypointViewerInventory> {
private final SimplePlaceholderItem noWaypoint, locked; private final SimplePlaceholderItem noWaypoint, locked;
private final WaypointDisplayItem availWaypoint; private final WaypointItemHandler availWaypoint, notLinked, notDynamic, noStellium;
public WaypointItem(ConfigurationSection config) { public WaypointItem(ConfigurationSection config) {
super(Material.BARRIER, config); super(Material.BARRIER, config);
Validate.notNull(config.getConfigurationSection("no-waypoint"), "Could not load 'no-waypoint' config"); noWaypoint = new SimplePlaceholderItem(Objects.requireNonNull(config.getConfigurationSection("no-waypoint"), "Could not load 'no-waypoint' config"));
Validate.notNull(config.getConfigurationSection("locked"), "Could not load 'locked' config"); locked = new SimplePlaceholderItem(Objects.requireNonNull(config.getConfigurationSection("locked"), "Could not load 'locked' config"));
Validate.notNull(config.getConfigurationSection("display"), "Could not load 'display' config");
noWaypoint = new SimplePlaceholderItem(config.getConfigurationSection("no-waypoint")); notLinked = new WaypointItemHandler(Objects.requireNonNull(config.getConfigurationSection("not-a-destination"), "Could not load 'not-a-destination' config"));
locked = new SimplePlaceholderItem(config.getConfigurationSection("locked")); notDynamic = new WaypointItemHandler(Objects.requireNonNull(config.getConfigurationSection("not-dynamic"), "Could not load 'not-dynamic' config"));
availWaypoint = new WaypointDisplayItem(config.getConfigurationSection("display")); noStellium = new WaypointItemHandler(Objects.requireNonNull(config.getConfigurationSection("not-enough-stellium"), "Could not load 'not-enough-stellium' config"));
availWaypoint = new WaypointItemHandler(Objects.requireNonNull(config.getConfigurationSection("display"), "Could not load 'display' config"));
} }
@Override @Override
@ -121,14 +90,59 @@ public class WaypointViewer extends EditableInventory {
if (index >= inv.waypoints.size()) if (index >= inv.waypoints.size())
return noWaypoint.display(inv, n); return noWaypoint.display(inv, n);
// Locked waypoint?
Waypoint waypoint = inv.waypoints.get(index); Waypoint waypoint = inv.waypoints.get(index);
return inv.getPlayerData().hasWaypoint(waypoint) ? availWaypoint.display(inv, n) : locked.display(inv); if (!inv.getPlayerData().hasWaypoint(waypoint))
return locked.display(inv, n);
// Waypoints are not linked
if (inv.current != null && !inv.current.hasDestination(waypoint))
return notLinked.display(inv, n);
// Not dynamic waypoint
if (inv.current == null && !waypoint.hasOption(WaypointOption.DYNAMIC))
return notDynamic.display(inv, n);
// Stellium cost
if (waypoint.getCost(inv.current == null ? CostType.DYNAMIC_USE : CostType.NORMAL_USE) > inv.getPlayerData().getStellium())
return noStellium.display(inv, n);
return availWaypoint.display(inv, n);
}
}
public class WaypointItemHandler extends InventoryItem<WaypointViewerInventory> {
public WaypointItemHandler(ConfigurationSection config) {
super(config);
}
@Override
public ItemStack display(WaypointViewerInventory inv, int n) {
ItemStack disp = super.display(inv, n);
// If a player can teleport to another waypoint given his location
Waypoint waypoint = inv.waypoints.get(inv.page * inv.getEditable().getByFunction("waypoint").getSlots().size() + n);
return NBTItem.get(disp).addTag(new ItemTag("waypointId", waypoint.getId())).toItem();
}
@Override
public Placeholders getPlaceholders(WaypointViewerInventory inv, int n) {
Placeholders holders = new Placeholders();
Waypoint waypoint = inv.waypoints.get(inv.page * inv.getByFunction("waypoint").getSlots().size() + n);
holders.register("name", waypoint.getName());
holders.register("current_cost", decimal.format(waypoint.getCost(inv.waypointCostType)));
holders.register("normal_cost", decimal.format(waypoint.getCost(CostType.NORMAL_USE)));
holders.register("dynamic_cost", decimal.format(waypoint.getCost(CostType.DYNAMIC_USE)));
return holders;
} }
} }
public class WaypointViewerInventory extends GeneratedInventory { public class WaypointViewerInventory extends GeneratedInventory {
private final List<Waypoint> waypoints = new ArrayList<>(MMOCore.plugin.waypointManager.getAll()); private final List<Waypoint> waypoints = new ArrayList<>(MMOCore.plugin.waypointManager.getAll());
private final Waypoint current; private final Waypoint current;
private final CostType waypointCostType;
private int page; private int page;
@ -136,6 +150,7 @@ public class WaypointViewer extends EditableInventory {
super(playerData, editable); super(playerData, editable);
this.current = current; this.current = current;
this.waypointCostType = current == null ? CostType.DYNAMIC_USE : CostType.NORMAL_USE;
} }
@Override @Override
@ -162,23 +177,34 @@ public class WaypointViewer extends EditableInventory {
if (tag.equals("")) if (tag.equals(""))
return; return;
// Locked waypoint?
Waypoint waypoint = MMOCore.plugin.waypointManager.get(tag); Waypoint waypoint = MMOCore.plugin.waypointManager.get(tag);
if (!playerData.hasWaypoint(waypoint)) { if (!playerData.hasWaypoint(waypoint)) {
MMOCore.plugin.configManager.getSimpleMessage("not-unlocked-waypoint").send(player); MMOCore.plugin.configManager.getSimpleMessage("not-unlocked-waypoint").send(player);
return; return;
} }
// Cannot teleport to current waypoint
if (waypoint.equals(current)) { if (waypoint.equals(current)) {
MMOCore.plugin.configManager.getSimpleMessage("standing-on-waypoint").send(player); MMOCore.plugin.configManager.getSimpleMessage("standing-on-waypoint").send(player);
return; return;
} }
if (current == null && !waypoint.isDynamic()) { // Waypoint does not have target as destination
if (current != null && !current.hasDestination(waypoint)) {
MMOCore.plugin.configManager.getSimpleMessage("cannot-teleport-to").send(player);
return;
}
// Not dynamic waypoint
if (current == null && !waypoint.hasOption(WaypointOption.DYNAMIC)) {
MMOCore.plugin.configManager.getSimpleMessage("not-dynamic-waypoint").send(player); MMOCore.plugin.configManager.getSimpleMessage("not-dynamic-waypoint").send(player);
return; return;
} }
double left = waypoint.getStelliumCost() - playerData.getStellium(); // Stellium cost
CostType costType = current == null ? CostType.DYNAMIC_USE : CostType.NORMAL_USE;
double left = waypoint.getCost(costType) - playerData.getStellium();
if (left > 0) { if (left > 0) {
MMOCore.plugin.configManager.getSimpleMessage("not-enough-stellium", "more", decimal.format(left)).send(player); MMOCore.plugin.configManager.getSimpleMessage("not-enough-stellium", "more", decimal.format(left)).send(player);
return; return;
@ -188,7 +214,7 @@ public class WaypointViewer extends EditableInventory {
return; return;
player.closeInventory(); player.closeInventory();
playerData.warp(waypoint); playerData.warp(waypoint, costType);
} }
} }
} }

View File

@ -1,32 +1,38 @@
package net.Indyuce.mmocore.listener; package net.Indyuce.mmocore.listener;
import io.lumine.mythic.lib.api.item.NBTItem;
import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.SoundEvent; import net.Indyuce.mmocore.api.SoundEvent;
import net.Indyuce.mmocore.manager.SoundManager; import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect;
import net.Indyuce.mmocore.manager.InventoryManager;
import net.Indyuce.mmocore.waypoint.Waypoint;
import net.Indyuce.mmocore.waypoint.WaypointOption;
import org.bukkit.Particle; import org.bukkit.Particle;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerToggleSneakEvent; import org.bukkit.event.player.PlayerToggleSneakEvent;
import net.Indyuce.mmocore.MMOCore; import java.util.Objects;
import net.Indyuce.mmocore.api.Waypoint;
import net.Indyuce.mmocore.api.player.PlayerData;
import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect;
import net.Indyuce.mmocore.manager.InventoryManager;
public class WaypointsListener implements Listener { public class WaypointsListener implements Listener {
@EventHandler @EventHandler
public void a(PlayerToggleSneakEvent event) { public void interactWithWaypoint(PlayerToggleSneakEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (!event.isSneaking()) if (!event.isSneaking())
return; return;
Waypoint waypoint = MMOCore.plugin.waypointManager.getCurrentWaypoint(player); Waypoint waypoint = MMOCore.plugin.waypointManager.getCurrentWaypoint(player);
if (waypoint == null || !waypoint.hasSneakEnabled()) if (waypoint == null)
return; return;
PlayerData data = PlayerData.get(player); PlayerData data = PlayerData.get(player);
if (!data.hasWaypoint(waypoint)) { if (waypoint.hasOption(WaypointOption.UNLOCKABLE) && !data.hasWaypoint(waypoint)) {
data.unlockWaypoint(waypoint); data.unlockWaypoint(waypoint);
new SmallParticleEffect(player, Particle.SPELL_WITCH); new SmallParticleEffect(player, Particle.SPELL_WITCH);
MMOCore.plugin.configManager.getSimpleMessage("new-waypoint", "waypoint", waypoint.getName()).send(player); MMOCore.plugin.configManager.getSimpleMessage("new-waypoint", "waypoint", waypoint.getName()).send(player);
@ -34,7 +40,19 @@ public class WaypointsListener implements Listener {
return; return;
} }
if (waypoint.hasOption(WaypointOption.ENABLE_MENU)) {
player.setSneaking(false); player.setSneaking(false);
InventoryManager.WAYPOINTS.newInventory(data, waypoint).open(); InventoryManager.WAYPOINTS.newInventory(data, waypoint).open();
} }
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void waypointBook(PlayerInteractEvent event) {
if (!event.hasItem() || (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() != Action.RIGHT_CLICK_BLOCK))
return;
NBTItem nbtItem = NBTItem.get(event.getItem());
if (Objects.equals(nbtItem.getString("MMOCoreItemId"), "WAYPOINT_BOOK"))
InventoryManager.WAYPOINTS.newInventory(PlayerData.get(event.getPlayer())).open();
}
} }

View File

@ -13,7 +13,7 @@ import org.bukkit.potion.PotionEffectType;
import net.Indyuce.mmocore.api.event.CustomBlockMineEvent; import net.Indyuce.mmocore.api.event.CustomBlockMineEvent;
import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.api.player.stats.StatType;
import net.Indyuce.mmocore.api.util.math.particle.SmallParticleEffect; import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect;
import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.MythicLib;
public class PlayerCollectStats implements Listener { public class PlayerCollectStats implements Listener {

View File

@ -9,7 +9,7 @@ import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.MMOCore;
import net.Indyuce.mmocore.api.Waypoint; import net.Indyuce.mmocore.waypoint.Waypoint;
public class WaypointManager { public class WaypointManager {
private final Map<String, Waypoint> waypoints = new LinkedHashMap<>(); private final Map<String, Waypoint> waypoints = new LinkedHashMap<>();

View File

@ -1,4 +1,6 @@
package net.Indyuce.mmocore.api.player; package net.Indyuce.mmocore.player;
import net.Indyuce.mmocore.api.player.PlayerData;
/** /**
* Some item that can be unlocked * Some item that can be unlocked

View File

@ -3,7 +3,7 @@ package net.Indyuce.mmocore.tree;
import io.lumine.mythic.lib.MythicLib; import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.player.modifier.PlayerModifier; import io.lumine.mythic.lib.player.modifier.PlayerModifier;
import io.lumine.mythic.lib.util.configobject.ConfigSectionObject; import io.lumine.mythic.lib.util.configobject.ConfigSectionObject;
import net.Indyuce.mmocore.api.player.Unlockable; import net.Indyuce.mmocore.player.Unlockable;
import org.apache.commons.lang.Validate; import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;

View File

@ -0,0 +1,29 @@
package net.Indyuce.mmocore.waypoint;
public enum CostType {
/**
* When teleporting to this waypoint
*/
NORMAL_USE,
/**
* When dynamically teleporting to this waypoint
*/
DYNAMIC_USE,
/**
* When setting your spawn point to this waypoint.
*/
SET_SPAWNPOINT;
private final String path;
CostType() {
this.path = name().toLowerCase().replace("_", "-");
}
public String getPath() {
return path;
}
}

View File

@ -0,0 +1,121 @@
package net.Indyuce.mmocore.waypoint;
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 java.util.*;
public class Waypoint implements Unlockable {
private final String id, name;
private final Location loc;
private final double radiusSquared;
/**
* Set that saves all the waypoints accessible when in this waypoint.
* This turns the waypoints system into a giant network.
* <p>
* If it's empty it can access any waypoint.
*/
private final Set<String> destinations = new HashSet<>();
/**
* Waypoint options saved here.
*/
private final Map<WaypointOption, Boolean> options = new HashMap<>();
/**
* Stellium cost for each action (0 being the default cost)
*/
private final Map<CostType, Double> costs = new HashMap<>();
public Waypoint(ConfigurationSection config) {
id = Objects.requireNonNull(config, "Could not load config section").getName();
name = Objects.requireNonNull(config.getString("name"), "Could not load waypoint name");
loc = readLocation(Objects.requireNonNull(config.getString("location"), "Could not read location"));
radiusSquared = Math.pow(config.getDouble("radius"), 2);
for (CostType costType : CostType.values())
costs.put(costType, config.getDouble("cost." + costType.getPath()));
for (WaypointOption option : WaypointOption.values())
options.put(option, config.getBoolean("option." + option.getPath(), option.getDefaultValue()));
destinations.addAll(config.getStringList("linked"));
}
public String getId() {
return id;
}
public String getName() {
return name;
}
public Location getLocation() {
return loc;
}
/**
* @param other Another waypoint
* @return If any player standing on that waypoint can teleport to given waypoint
*/
public boolean hasDestination(Waypoint other) {
return destinations.isEmpty() || destinations.contains(other.getId());
}
public double getCost(CostType type) {
return costs.getOrDefault(type, 0d);
}
public boolean hasOption(WaypointOption option) {
return options.get(option);
}
public boolean isOnWaypoint(Player player) {
return player.getWorld().equals(loc.getWorld()) && player.getLocation().distanceSquared(loc) < radiusSquared;
}
@Override
public String toString() {
return id;
}
@Override
public String getUnlockNamespacedKey() {
return "waypoint:" + getId();
}
@Override
public int hashCode() {
return Objects.hash(id);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
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);
}
}

View File

@ -0,0 +1,46 @@
package net.Indyuce.mmocore.waypoint;
public enum WaypointOption {
DEFAULT(false),
/**
* Enable this so make the waypoint auto unlock when you sneak on it.
*/
UNLOCKABLE(true),
/**
* When enabled players can sneak when standing on that waypoint
* to open its menu. This option can be disabled to create waypoints
* that you can only teleport to.
*/
ENABLE_MENU(true),
/**
* By defaut, players must stand into
*/
DYNAMIC(false),
/**
* When set to true, players can choose this waypoint as their spawnpoint.
* This action costs some stellium.
*/
// SPAWNABLE(false)
;
private final String path;
private final boolean defaultValue;
WaypointOption(boolean defaultValue) {
this.path = name().toLowerCase().replace("_", "-");
this.defaultValue = defaultValue;
}
public String getPath() {
return path;
}
public boolean getDefaultValue() {
return defaultValue;
}
}

View File

@ -1,6 +1,6 @@
# GUI display name # GUI display name
name: Waypoints name: Waypoints
name-on-waypoint: 'Waypoint: {waypoint}'
# Number of slots in your inventory. Must be # Number of slots in your inventory. Must be
# between 9 and 54 and must be a multiple of 9. # between 9 and 54 and must be a multiple of 9.
@ -8,44 +8,72 @@ slots: 45
items: items:
waypoint: waypoint:
slots: [10,11,12,13,14,15,16,19,20,21,22,23,24,25,28,29,30,31,32,33,34] slots: [ 10,11,12,13,14,15,16,19,20,21,22,23,24,25,28,29,30,31,32,33,34 ]
function: waypoint function: waypoint
# Displayed when there is no waypoint # Displayed when there is no waypoint
no-waypoint: no-waypoint:
item: GRAY_STAINED_GLASS_PANE item: GRAY_STAINED_GLASS_PANE
name: '&a' name: '&a'
lore: {} lore: { }
# Displayed when the waypoint has not been unlocked yet. # Displayed when the waypoint has not been unlocked yet.
locked: locked:
name: '&c- Locked -' name: '&c- Locked -'
item: GRAY_DYE item: GRAY_DYE
lore: {} lore: { }
# Displayed when the waypoint is unlocked. # When the two waypoints are not linked together
display: not-a-destination:
name: '&a{name}' name: '&a{name}'
item: ENDER_EYE item: ENDER_PEARL
# Material displayed when the waypoint is not # Material displayed when the waypoint is not
# ready (not dynamic, or not enough stellium) # ready (not dynamic, or not enough stellium)
not-ready: ENDER_PEARL not-ready: ENDER_PEARL
lore: lore:
- '&7You have unlocked this waypoint.' - '&7You cannot teleport as the two waypoints are not linked.'
- '&7Click to teleport for &b{stellium} &7stellium.' - '&7Teleporting costs &b&l{normal_cost}&7/&b&l{dynamic_cost} &7Stellium.'
# When you cannot teleport to a non dynamic waypoint
not-dynamic:
name: '&a{name}'
item: ENDER_PEARL
lore:
- '&7You cannot teleport as you are not standing on a waypoint.'
- '&7Teleporting costs &b&l{normal_cost}&7/&b&l{dynamic_cost} &7Stellium.'
# When you cannot teleport to a non dynamic waypoint
not-enough-stellium:
name: '&a{name}'
item: ENDER_PEARL
lore:
- '&7You cannot teleport as you do not have enough Stellium.'
- '&7Teleporting costs &b&l{normal_cost}&7/&b&l{dynamic_cost} &7Stellium.'
# Displayed when the waypoint is unlocked and usable
display:
name: '&a{name}'
item: ENDER_EYE
lore:
- '&7You can teleport to this waypoint.'
- '&7Click to teleport for &b{current_cost} &7Stellium.'
next: next:
slots: [26] slots: [ 26 ]
function: next function: next
item: PLAYER_HEAD item: PLAYER_HEAD
texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTliZjMyOTJlMTI2YTEwNWI1NGViYTcxM2FhMWIxNTJkNTQxYTFkODkzODgyOWM1NjM2NGQxNzhlZDIyYmYifX19 texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTliZjMyOTJlMTI2YTEwNWI1NGViYTcxM2FhMWIxNTJkNTQxYTFkODkzODgyOWM1NjM2NGQxNzhlZDIyYmYifX19
name: '&aNext Page' name: '&aNext Page'
lore: [] lore: [ ]
previous: previous:
slots: [18] slots: [ 18 ]
function: previous function: previous
item: PLAYER_HEAD item: PLAYER_HEAD
texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmQ2OWUwNmU1ZGFkZmQ4NGU1ZjNkMWMyMTA2M2YyNTUzYjJmYTk0NWVlMWQ0ZDcxNTJmZGM1NDI1YmMxMmE5In19fQ== texture: eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmQ2OWUwNmU1ZGFkZmQ4NGU1ZjNkMWMyMTA2M2YyNTUzYjJmYTk0NWVlMWQ0ZDcxNTJmZGM1NDI1YmMxMmE5In19fQ==
name: '&aPrevious Page' name: '&aPrevious Page'
lore: [] lore: [ ]

View File

@ -1,4 +1,3 @@
GOLD_COIN: GOLD_COIN:
item: GOLD_NUGGET item: GOLD_NUGGET
name: '&6Gold Coin' name: '&6Gold Coin'
@ -11,10 +10,17 @@ NOTE:
lore: lore:
- '&eWorth: {worth}g' - '&eWorth: {worth}g'
WAYPOINT_BOOK:
item: ENCHANTED_BOOK
name: '&6Waypoints Book'
lore:
- '&7Waypoints are locations used to save your progress.'
- '&7This book gives you the ability to freely warp between these.'
DEPOSIT_ITEM: DEPOSIT_ITEM:
item: BOOK item: BOOK
name: '&eDeposit {worth}g' name: '&eDeposit {worth}g'
lore: {} lore: { }
GOLD_POUCH: GOLD_POUCH:
item: LEATHER item: LEATHER

View File

@ -73,6 +73,7 @@ not-dynamic-waypoint: '&cYou many only teleport to a non-dynamic waypoint while
standing-on-waypoint: '&cYou are already standing on this waypoint.' standing-on-waypoint: '&cYou are already standing on this waypoint.'
warping-canceled: '%&cWaypoint warping canceled.' warping-canceled: '%&cWaypoint warping canceled.'
warping-comencing: '%&cDO NOT MOVE!&e You will be warped in {left}sec.' warping-comencing: '%&cDO NOT MOVE!&e You will be warped in {left}sec.'
cannot-teleport-to: '&cThe two waypoints are not linked.'
# Cash # Cash
deposit: '&eYou successfully deposited &6{worth}g&e.' deposit: '&eYou successfully deposited &6{worth}g&e.'

View File

@ -1,6 +1,5 @@
# Waypoint identifier, used as reference for admin commands.
# Waypoint ID, used as reference. # Make sure all the waypoints have different identifiers.
# Make sure the waypoints have different IDs.
spawn: spawn:
# Name of waypoint displayed in the waypoint GUI. # Name of waypoint displayed in the waypoint GUI.
@ -11,17 +10,27 @@ spawn:
location: 'world 69 71 136 136 0' location: 'world 69 71 136 136 0'
# Radius of waypoint around the specified location. # Radius of waypoint around the specified location.
radius: 1.5 radius: 2.0
cost:
# Stellium cost in order to use the waypoint. # Stellium cost in order to use the waypoint.
# Stellium is like stamina however it's not used # Stellium is like stamina however it's not used
# by skills and regens much slower than mana. # by skills and regens much slower than mana.
stellium: 3 normal-use: 3
# Cost when not standing on any waypoint.
dynamic-use: 5
option:
# When enabled, players can unlock the waypoint # When enabled, players can unlock the waypoint
# by sneaking on it, and can open the waypoint menu # by sneaking on it (true by default)
# from the specified location (true by default). unlockable: true
sneak: true
# When enabled, players can teleport to other
#waypoints when sneaking (true by default)
enable-menu: true
# Should be waypoint be unlocked by default? # Should be waypoint be unlocked by default?
default: true default: true
@ -29,8 +38,10 @@ spawn:
spawn1: spawn1:
name: Spawn1 name: Spawn1
location: 'world 69 71 136 136 0' location: 'world 69 71 136 136 0'
radius: 1.5 radius: 2.0
stellium: 3 cost:
normal-use: 3
option:
default: false default: false
# Can be teleported to even when not standing # Can be teleported to even when not standing
@ -40,6 +51,8 @@ spawn1:
spawn2: spawn2:
name: Spawn2 name: Spawn2
location: 'world 69 71 136 136 0' location: 'world 69 71 136 136 0'
radius: 1.5 radius: 3.0
stellium: 3 cost:
sneak: false normal-use: 3
option:
enable-menu: false