mirror of
https://gitlab.com/phoenix-dvpmt/mmocore.git
synced 2025-11-18 06:24:17 +01:00
More display options for skill, class skill tree node/paths icons
This commit is contained in:
parent
2aa78c4f2b
commit
d93f0d7062
@ -4,6 +4,7 @@ import io.lumine.mythic.lib.MythicLib;
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.api.MMOLineConfig;
|
||||
import io.lumine.mythic.lib.api.player.EquipmentSlot;
|
||||
import io.lumine.mythic.lib.gui.util.IconOptions;
|
||||
import io.lumine.mythic.lib.player.modifier.ModifierSource;
|
||||
import io.lumine.mythic.lib.player.skill.PassiveSkill;
|
||||
import io.lumine.mythic.lib.script.Script;
|
||||
@ -33,15 +34,12 @@ import net.Indyuce.mmocore.skill.ClassSkill;
|
||||
import net.Indyuce.mmocore.skill.RegisteredSkill;
|
||||
import net.Indyuce.mmocore.skill.binding.SkillSlot;
|
||||
import net.Indyuce.mmocore.skill.cast.ComboMap;
|
||||
import net.Indyuce.mmocore.util.Icon;
|
||||
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.SkullMeta;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@ -51,7 +49,7 @@ import java.util.logging.Level;
|
||||
public class PlayerClass implements ExperienceObject, PreloadedObject {
|
||||
private final String name, id, actionBarFormat;
|
||||
private final List<String> description = new ArrayList<>(), attrDescription = new ArrayList<>();
|
||||
private final ItemStack icon;
|
||||
private final IconOptions icon;
|
||||
private final Map<ClassOption, Boolean> options = new HashMap<>();
|
||||
private final int maxLevel, displayOrder;
|
||||
|
||||
@ -101,13 +99,7 @@ public class PlayerClass implements ExperienceObject, PreloadedObject {
|
||||
this.id = UtilityMethods.enumName(id);
|
||||
|
||||
name = MythicLib.plugin.parseColors(config.getString("display.name", "INVALID DISPLAY NAME"));
|
||||
icon = Icon.from(config.get("display.item", "BARRIER")).toItem();
|
||||
|
||||
if (config.contains("display.texture") && icon.getType() == Material.PLAYER_HEAD) {
|
||||
ItemMeta meta = icon.getItemMeta();
|
||||
UtilityMethods.setTextureValue((SkullMeta) meta, config.getString("display.texture"));
|
||||
icon.setItemMeta(meta);
|
||||
}
|
||||
icon = IconOptions.from(config.get("display.item"));
|
||||
|
||||
for (String string : config.getStringList("display.lore"))
|
||||
description.add(ChatColor.GRAY + MythicLib.plugin.parseColors(string));
|
||||
@ -141,7 +133,7 @@ public class PlayerClass implements ExperienceObject, PreloadedObject {
|
||||
try {
|
||||
skillTrees.add(MMOCore.plugin.skillTreeManager.get(str));
|
||||
} catch (Exception e) {
|
||||
MMOCore.log(Level.WARNING, "Could not find skill tree with ID: " + str);
|
||||
MMOCore.log(Level.WARNING, "Skill tree '" + str + "' not found for player class " + getId());
|
||||
}
|
||||
|
||||
// Class-specific scripts
|
||||
@ -276,7 +268,7 @@ public class PlayerClass implements ExperienceObject, PreloadedObject {
|
||||
comboMap = null;
|
||||
castParticle = new CastingParticle(VParticle.INSTANT_EFFECT.get());
|
||||
actionBarFormat = "";
|
||||
this.icon = new ItemStack(material);
|
||||
this.icon = new IconOptions(material);
|
||||
setOption(ClassOption.DISPLAY, false);
|
||||
setOption(ClassOption.DEFAULT, false);
|
||||
for (PlayerResource resource : PlayerResource.values())
|
||||
@ -336,8 +328,14 @@ public class PlayerClass implements ExperienceObject, PreloadedObject {
|
||||
return expTable != null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public IconOptions getRawIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ItemStack getIcon() {
|
||||
return icon.clone();
|
||||
return icon.toItemStack();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@ -61,7 +61,7 @@ public class MMOCoreUtils {
|
||||
* @param current Current value of resource
|
||||
* @param maxStat Maximum value of resource
|
||||
* @return Clamped resource value. If the provided current value is 0,
|
||||
* this function will return the maximum resource value.
|
||||
* this function will return the maximum resource value.
|
||||
*/
|
||||
public static double fixResource(double current, double maxStat) {
|
||||
return current == 0 ? maxStat : Math.max(0, Math.min(current, maxStat));
|
||||
@ -82,6 +82,11 @@ public class MMOCoreUtils {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see UtilityMethods#kebabCase(Enum)
|
||||
* @see UtilityMethods#kebabCase(String)
|
||||
*/
|
||||
@Deprecated
|
||||
public static String ymlName(String str) {
|
||||
return str.toLowerCase().replace("_", "-").replace(" ", "-");
|
||||
}
|
||||
|
||||
@ -55,8 +55,8 @@ public abstract class AbstractClassSelect extends EditableInventory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack getDisplayedItem(T inv, int n) {
|
||||
ItemOptions options = n == 0 ? ItemOptions.item(n, playerClass.getIcon()) : ItemOptions.index(n);
|
||||
public ItemStack getDisplayedItem(@NotNull T inv, int n) {
|
||||
ItemOptions options = n == 0 ? new ItemOptions(n, playerClass.getRawIcon()) : ItemOptions.index(n);
|
||||
return super.getDisplayedItem(inv, options);
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package net.Indyuce.mmocore.gui;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.gui.Navigator;
|
||||
import io.lumine.mythic.lib.gui.editable.item.InventoryItem;
|
||||
import net.Indyuce.mmocore.MMOCore;
|
||||
@ -63,7 +64,7 @@ public class ClassSelect extends AbstractClassSelect {
|
||||
|
||||
inv.getNavigator().unblockClosing();
|
||||
final PlayerClass playerClass = findDeepestSubclass(inv.playerData, this.playerClass);
|
||||
InventoryManager.CLASS_CONFIRM.get(MMOCoreUtils.ymlName(playerClass.getId())).newInventory(inv, inv.profileCallback != null).open();
|
||||
InventoryManager.CLASS_CONFIRM.get(UtilityMethods.kebabCase(playerClass.getId())).newInventory(inv, inv.profileCallback != null).open();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -150,7 +150,7 @@ public class SkillList extends EditableInventory {
|
||||
public ItemStack getDisplayedItem(SkillViewerInventory inv, int n) {
|
||||
if (inv.selected == null) return new ItemStack(Material.AIR);
|
||||
|
||||
return getDisplayedItem(inv, inv.selected.getSkill().getRawIcon().toItemOptions(n));
|
||||
return getDisplayedItem(inv, new ItemOptions(n, inv.selected.getSkill().getRawIcon()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -269,7 +269,7 @@ public class SkillList extends EditableInventory {
|
||||
if (skillSlot == null || !inv.playerData.hasUnlocked(skillSlot)) return new ItemStack(Material.AIR);
|
||||
|
||||
final @Nullable ClassSkill boundSkill = inv.playerData.getBoundSkill(n + 1);
|
||||
final ItemOptions options = boundSkill == null ? ItemOptions.index(n) : filledItem == null ? boundSkill.getSkill().getRawIcon().toItemOptions(n) : ItemOptions.model(n, filledItem, filledCMD);
|
||||
final ItemOptions options = boundSkill == null ? ItemOptions.index(n) : filledItem == null ? new ItemOptions(n, boundSkill.getSkill().getRawIcon()) : ItemOptions.model(n, filledItem, filledCMD);
|
||||
return super.getDisplayedItem(inv, options);
|
||||
}
|
||||
|
||||
@ -395,7 +395,7 @@ public class SkillList extends EditableInventory {
|
||||
if (index >= inv.skills.size()) return new ItemStack(Material.AIR);
|
||||
|
||||
ClassSkill skill = inv.skills.get(index);
|
||||
return getDisplayedItem(inv, skill.getSkill().getRawIcon().toItemOptions(n));
|
||||
return getDisplayedItem(inv, new ItemOptions(n, skill.getSkill().getRawIcon()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -9,18 +9,19 @@ import io.lumine.mythic.lib.gui.editable.item.ItemOptions;
|
||||
import io.lumine.mythic.lib.gui.editable.item.PhysicalItem;
|
||||
import io.lumine.mythic.lib.gui.editable.item.SimpleItem;
|
||||
import io.lumine.mythic.lib.gui.editable.placeholder.Placeholders;
|
||||
import io.lumine.mythic.lib.gui.util.IconOptions;
|
||||
import net.Indyuce.mmocore.MMOCore;
|
||||
import net.Indyuce.mmocore.api.ConfigMessage;
|
||||
import net.Indyuce.mmocore.api.SoundEvent;
|
||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
|
||||
import net.Indyuce.mmocore.skilltree.*;
|
||||
import net.Indyuce.mmocore.skilltree.display.DisplayInfo;
|
||||
import net.Indyuce.mmocore.skilltree.IntegerCoordinates;
|
||||
import net.Indyuce.mmocore.skilltree.NodeState;
|
||||
import net.Indyuce.mmocore.skilltree.ParentType;
|
||||
import net.Indyuce.mmocore.skilltree.SkillTreeNode;
|
||||
import net.Indyuce.mmocore.skilltree.display.DisplayMap;
|
||||
import net.Indyuce.mmocore.skilltree.display.NodeDisplayInfo;
|
||||
import net.Indyuce.mmocore.skilltree.display.PathDisplayInfo;
|
||||
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
|
||||
import net.Indyuce.mmocore.util.Icon;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.NamespacedKey;
|
||||
@ -37,10 +38,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class SkillTreeViewer extends EditableInventory {
|
||||
protected final Map<DisplayInfo, Icon> icons = new HashMap<>();
|
||||
protected DisplayMap icons;
|
||||
protected final Map<NodeState, String> statusNames = new HashMap<>();
|
||||
|
||||
/**
|
||||
@ -64,31 +64,11 @@ public class SkillTreeViewer extends EditableInventory {
|
||||
public void reload(@NotNull JavaPlugin plugin, @NotNull ConfigurationSection config) {
|
||||
super.reload(plugin, config);
|
||||
|
||||
if (config.contains("status-names"))
|
||||
for (NodeState nodeState : NodeState.values())
|
||||
statusNames.put(nodeState, config.getString("status-names." + UtilityMethods.ymlName(nodeState.name()), nodeState.name()));
|
||||
if (config.contains("status-names")) for (NodeState nodeState : NodeState.values())
|
||||
statusNames.put(nodeState, config.getString("status-names." + UtilityMethods.ymlName(nodeState.name()), nodeState.name()));
|
||||
|
||||
// Loads all the pathDisplayInfo
|
||||
for (NodeState status : NodeState.values())
|
||||
for (PathType pathType : PathType.values()) {
|
||||
final String configPath = "display.paths." + MMOCoreUtils.ymlName(status.name()) + "." + MMOCoreUtils.ymlName(pathType.name());
|
||||
if (!config.contains(configPath)) {
|
||||
MMOCore.log(Level.WARNING, "An error occurred while loading skill tree GUI: Missing path type: " + MMOCoreUtils.ymlName(pathType.name()) + " for status: " + MMOCoreUtils.ymlName(status.name()));
|
||||
continue;
|
||||
}
|
||||
icons.put(new PathDisplayInfo(pathType, status), Icon.from(config.get(configPath)));
|
||||
}
|
||||
|
||||
// Loads all the nodeDisplayInfo
|
||||
for (NodeState status : NodeState.values())
|
||||
for (NodeType nodeType : NodeType.values()) {
|
||||
final String configPath = "display.nodes." + MMOCoreUtils.ymlName(status.name()) + "." + MMOCoreUtils.ymlName(nodeType.name());
|
||||
if (!config.contains(configPath)) {
|
||||
MMOCore.log(Level.WARNING, "An error occurred while loading skill tree GUI: Missing node type: " + MMOCoreUtils.ymlName(nodeType.name()) + " for status: " + MMOCoreUtils.ymlName(status.name()));
|
||||
continue;
|
||||
}
|
||||
icons.put(new NodeDisplayInfo(nodeType, status), Icon.from(config.get(configPath)));
|
||||
}
|
||||
// Loads display info
|
||||
icons = DisplayMap.from(config.getConfigurationSection("display"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -268,8 +248,7 @@ public class SkillTreeViewer extends EditableInventory {
|
||||
|
||||
@Override
|
||||
public void onClick(@NotNull SkillTreeInventory inv, @NotNull InventoryClickEvent event) {
|
||||
String id = event.getCurrentItem().getItemMeta().getPersistentDataContainer().get(
|
||||
new NamespacedKey(MMOCore.plugin, "skill-tree-id"), PersistentDataType.STRING);
|
||||
String id = event.getCurrentItem().getItemMeta().getPersistentDataContainer().get(new NamespacedKey(MMOCore.plugin, "skill-tree-id"), PersistentDataType.STRING);
|
||||
MMOCore.plugin.soundManager.getSound(SoundEvent.CHANGE_SKILL_TREE).playTo(inv.getPlayer());
|
||||
inv.skillTree = MMOCore.plugin.skillTreeManager.get(id);
|
||||
inv.open();
|
||||
@ -317,8 +296,7 @@ public class SkillTreeViewer extends EditableInventory {
|
||||
public SkillTreeNodeItem(ConfigurationSection config) {
|
||||
super(config);
|
||||
|
||||
if (config.isList("path-lore"))
|
||||
pathLore.addAll(config.getStringList("path-lore"));
|
||||
if (config.isList("path-lore")) pathLore.addAll(config.getStringList("path-lore"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -373,8 +351,8 @@ public class SkillTreeViewer extends EditableInventory {
|
||||
IntegerCoordinates coordinates = inv.getCoordinates(n);
|
||||
if (!inv.getSkillTree().isPathOrNode(coordinates)) return new ItemStack(Material.AIR);
|
||||
|
||||
Icon icon = inv.getIcon(coordinates);
|
||||
ItemStack item = super.getDisplayedItem(inv, icon.toItemOptions(n));
|
||||
IconOptions icon = inv.getIcon(coordinates);
|
||||
ItemStack item = super.getDisplayedItem(inv, new ItemOptions(n, icon));
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
|
||||
// Make sure name is not null
|
||||
@ -513,17 +491,14 @@ public class SkillTreeViewer extends EditableInventory {
|
||||
this.skillTree = skillTree == null ? skillTrees.get(0) : skillTree;
|
||||
if (skillTree == null)
|
||||
maxTreeListPage = (skillTrees.size() - 1) / SkillTreeViewer.this.getByFunction("skill-tree").getSlots().size();
|
||||
else
|
||||
maxTreeListPage = 0;
|
||||
else maxTreeListPage = 0;
|
||||
//We get the width and height of the GUI(corresponding to the slots given)
|
||||
slots = SkillTreeViewer.this.getByFunction("skill-tree-node").getSlots();
|
||||
minSlot = 64;
|
||||
maxSlot = 0;
|
||||
for (int slot : slots) {
|
||||
if (slot < minSlot)
|
||||
minSlot = slot;
|
||||
if (slot > maxSlot)
|
||||
maxSlot = slot;
|
||||
if (slot < minSlot) minSlot = slot;
|
||||
if (slot > maxSlot) maxSlot = slot;
|
||||
}
|
||||
width = (maxSlot - minSlot) % 9;
|
||||
height = (maxSlot - minSlot) / 9;
|
||||
@ -551,32 +526,30 @@ public class SkillTreeViewer extends EditableInventory {
|
||||
return playerData;
|
||||
}
|
||||
|
||||
public Icon getIcon(IntegerCoordinates coordinates) {
|
||||
public IconOptions getIcon(@NotNull IntegerCoordinates coordinates) {
|
||||
if (skillTree.isNode(coordinates)) {
|
||||
SkillTreeNode node = skillTree.getNode(coordinates);
|
||||
NodeType nodeType = node.getNodeType();
|
||||
NodeState nodeState = playerData.getNodeState(node);
|
||||
//If the node has its own display, it will be shown.
|
||||
if (node.hasIcon(nodeState))
|
||||
return node.getIcon(nodeState);
|
||||
DisplayInfo displayInfo = new NodeDisplayInfo(nodeType, nodeState);
|
||||
//Takes the display defined in the skill tree config if it exists.
|
||||
if (skillTree.hasIcon(displayInfo))
|
||||
return skillTree.getIcon(displayInfo);
|
||||
var node = skillTree.getNode(coordinates);
|
||||
var nodeShape = node.getNodeType();
|
||||
var nodeState = playerData.getNodeState(node);
|
||||
var displayInfo = new NodeDisplayInfo(nodeShape, nodeState);
|
||||
|
||||
// Node > skill tree > skill tree UI
|
||||
var icon = DisplayMap.getIcon(displayInfo, node.getIcons(), skillTree.getIcons(), icons);
|
||||
if (icon == null) icon = DisplayMap.DEFAULT_ICON;
|
||||
//Validate.notNull(icon, "Node " + node.getFullId() + " has no icon for shape " + nodeShape + " and state " + nodeState);
|
||||
|
||||
Icon icon = icons.get(displayInfo);
|
||||
Validate.notNull(icon, "The node " + node.getFullId() + " has no icon for the type " + nodeType + " and the status " + nodeState);
|
||||
return icon;
|
||||
} else {
|
||||
SkillTreePath path = skillTree.getPath(coordinates);
|
||||
PathType pathType = path.getPathType();
|
||||
NodeState pathStatus = path.getStatus(playerData);
|
||||
DisplayInfo displayInfo = new PathDisplayInfo(pathType, pathStatus);
|
||||
//Takes the display defined in the skill tree config if it exists.
|
||||
if (skillTree.hasIcon(displayInfo))
|
||||
return skillTree.getIcon(displayInfo);
|
||||
Icon icon = icons.get(displayInfo);
|
||||
Validate.notNull(icon, "There is no icon for the path type " + pathType + " and the status " + pathStatus);
|
||||
var path = skillTree.getPath(coordinates);
|
||||
var pathShape = path.getPathType();
|
||||
var pathStatus = path.getStatus(playerData);
|
||||
var displayInfo = new PathDisplayInfo(pathShape, pathStatus);
|
||||
|
||||
// Skill tree > Skill tree UI
|
||||
var icon = DisplayMap.getIcon(displayInfo, skillTree.getIcons(), icons);
|
||||
if (icon == null) icon = DisplayMap.DEFAULT_ICON;
|
||||
//Validate.notNull(icon, "No icon for path shape " + pathShape + " and state " + pathStatus);
|
||||
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,7 +69,12 @@ public class InventoryManager {
|
||||
final var specificUi = invType.provider.apply(id, !configFile.exists());
|
||||
|
||||
((Map) invType.inventories).put(formattedId, specificUi);
|
||||
specificUi.reload(MMOCore.plugin, new ConfigFile("/gui/" + invType.name, specificUi.getId()).getConfig());
|
||||
|
||||
// try {
|
||||
specificUi.reload(MMOCore.plugin, new ConfigFile("/gui/" + invType.name, specificUi.getId()).getConfig());
|
||||
/* } catch (Exception exception) {
|
||||
MMOCore.log(Level.WARNING, "Could not load inventory 'gui/" + invType.name + "/" + invType.name + "-default" + "': " + exception.getMessage());
|
||||
} */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2,12 +2,12 @@ package net.Indyuce.mmocore.skill;
|
||||
|
||||
import io.lumine.mythic.lib.MythicLib;
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.gui.util.IconOptions;
|
||||
import io.lumine.mythic.lib.skill.handler.SkillHandler;
|
||||
import io.lumine.mythic.lib.skill.trigger.TriggerType;
|
||||
import io.lumine.mythic.lib.util.formula.BooleanExpression;
|
||||
import net.Indyuce.mmocore.api.util.math.formula.IntegerLinearValue;
|
||||
import net.Indyuce.mmocore.api.util.math.formula.LinearValue;
|
||||
import net.Indyuce.mmocore.util.Icon;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@ -23,7 +23,7 @@ public class RegisteredSkill {
|
||||
|
||||
private final Map<String, DecimalFormat> parameterDecimalFormats = new HashMap<>();
|
||||
|
||||
private final Icon icon;
|
||||
private final IconOptions icon;
|
||||
private final List<String> lore;
|
||||
private final List<String> categories;
|
||||
private final TriggerType triggerType;
|
||||
@ -32,7 +32,7 @@ public class RegisteredSkill {
|
||||
this.handler = handler;
|
||||
|
||||
name = Objects.requireNonNull(config.getString("name"), "Could not find skill name");
|
||||
icon = Icon.from(config.get("material"));
|
||||
icon = IconOptions.from(config.get("material"));
|
||||
lore = Objects.requireNonNull(config.getStringList("lore"), "Could not find skill lore");
|
||||
|
||||
// Trigger type
|
||||
@ -46,7 +46,6 @@ public class RegisteredSkill {
|
||||
else
|
||||
categories.add("ACTIVE");
|
||||
|
||||
|
||||
// Load default modifier formulas
|
||||
for (String param : handler.getParameters()) {
|
||||
if (config.contains(param + ".decimal-format"))
|
||||
@ -62,15 +61,20 @@ public class RegisteredSkill {
|
||||
defaultParameters.put("level", new IntegerLinearValue(0, 1));
|
||||
}
|
||||
|
||||
public RegisteredSkill(SkillHandler<?> handler, String name, ItemStack icon, List<String> lore, @Nullable TriggerType triggerType) {
|
||||
public RegisteredSkill(SkillHandler<?> handler, String name, IconOptions icon, List<String> lore, @Nullable TriggerType triggerType) {
|
||||
this.handler = handler;
|
||||
this.name = name;
|
||||
this.icon = Icon.fromItem(icon);
|
||||
this.icon = IconOptions.from(icon);
|
||||
this.lore = lore;
|
||||
this.triggerType = triggerType;
|
||||
this.categories = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public RegisteredSkill(SkillHandler<?> handler, String name, ItemStack icon, List<String> lore, @Nullable TriggerType triggerType) {
|
||||
this(handler, name, IconOptions.from(icon), lore, triggerType);
|
||||
}
|
||||
|
||||
public SkillHandler<?> getHandler() {
|
||||
return handler;
|
||||
}
|
||||
@ -89,11 +93,11 @@ public class RegisteredSkill {
|
||||
|
||||
@Deprecated
|
||||
public ItemStack getIcon() {
|
||||
return icon.toItem();
|
||||
return icon.toItemStack();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Icon getRawIcon() {
|
||||
public IconOptions getRawIcon() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
|
||||
@ -5,8 +5,7 @@ import net.Indyuce.mmocore.api.player.PlayerData;
|
||||
/**
|
||||
* State of one skill tree node, or path between nodes.
|
||||
*
|
||||
* @see PlayerData#getNodeState(SkillTreeNode)
|
||||
* @see SkillTreePath#getStatus(PlayerData)
|
||||
* @see PlayerData#getNodeState(SkillTreeNode)
|
||||
*/
|
||||
public enum NodeState {
|
||||
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
package net.Indyuce.mmocore.skilltree;
|
||||
|
||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||
|
||||
/**
|
||||
* @see SkillTreePath#getStatus(PlayerData)
|
||||
*/
|
||||
public enum PathState {
|
||||
|
||||
/**
|
||||
* The player has purchased and unlocked the skill tree node.
|
||||
*/
|
||||
UNLOCKED,
|
||||
|
||||
/**
|
||||
* The player has instant access to but has not unlocked the node.
|
||||
*/
|
||||
UNLOCKABLE,
|
||||
|
||||
/**
|
||||
* The player does not have access to this skill node but it
|
||||
* remains a possibility to access it.
|
||||
*/
|
||||
LOCKED,
|
||||
|
||||
/**
|
||||
* The player made a choice making it now impossible to reach this
|
||||
* node given its skill tree exploration. The player needs to
|
||||
* re-spec to unlock that node.
|
||||
*/
|
||||
FULLY_LOCKED
|
||||
}
|
||||
@ -2,14 +2,16 @@ package net.Indyuce.mmocore.skilltree;
|
||||
|
||||
import io.lumine.mythic.lib.MythicLib;
|
||||
import io.lumine.mythic.lib.gui.editable.placeholder.Placeholders;
|
||||
import io.lumine.mythic.lib.gui.util.IconOptions;
|
||||
import net.Indyuce.mmocore.MMOCore;
|
||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
|
||||
import net.Indyuce.mmocore.experience.EXPSource;
|
||||
import net.Indyuce.mmocore.experience.ExpCurve;
|
||||
import net.Indyuce.mmocore.experience.ExperienceObject;
|
||||
import net.Indyuce.mmocore.experience.droptable.ExperienceTable;
|
||||
import net.Indyuce.mmocore.util.Icon;
|
||||
import net.Indyuce.mmocore.skilltree.display.DisplayMap;
|
||||
import net.Indyuce.mmocore.skilltree.display.NodeDisplayInfo;
|
||||
import net.Indyuce.mmocore.skilltree.display.NodeShape;
|
||||
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Location;
|
||||
@ -26,7 +28,7 @@ public class SkillTreeNode implements ExperienceObject {
|
||||
private final String name, id;
|
||||
private final String permissionRequired;
|
||||
private final int pointConsumption;
|
||||
private final Map<NodeState, Icon> icons = new HashMap<>();
|
||||
private final DisplayMap icons;
|
||||
private final IntegerCoordinates coordinates;
|
||||
private final int maxLevel, maxChildren;
|
||||
private final ExperienceTable experienceTable;
|
||||
@ -42,13 +44,7 @@ public class SkillTreeNode implements ExperienceObject {
|
||||
this.tree = tree;
|
||||
|
||||
// Load icons for node states
|
||||
if (config.isConfigurationSection("display")) for (NodeState state : NodeState.values()) {
|
||||
final String ymlStatus = MMOCoreUtils.ymlName(state.name());
|
||||
if (config.isConfigurationSection("display." + ymlStatus))
|
||||
icons.put(state, Icon.from(config.get("display." + MMOCoreUtils.ymlName(state.name()))));
|
||||
else
|
||||
MMOCore.log("Could not find node display for state " + ymlStatus + " of node " + id + " in tree " + tree.getId() + ". Using default display.");
|
||||
}
|
||||
this.icons = DisplayMap.from(config.getConfigurationSection("display"));
|
||||
|
||||
name = Objects.requireNonNull(config.getString("name"), "Could not find node name");
|
||||
root = config.getBoolean("root", config.getBoolean("is-root")); // backwards compatibility
|
||||
@ -81,14 +77,6 @@ public class SkillTreeNode implements ExperienceObject {
|
||||
return tree;
|
||||
}
|
||||
|
||||
public boolean hasIcon(NodeState status) {
|
||||
return icons.containsKey(status);
|
||||
}
|
||||
|
||||
public Icon getIcon(NodeState status) {
|
||||
return icons.get(status);
|
||||
}
|
||||
|
||||
public boolean isRoot() {
|
||||
return root;
|
||||
}
|
||||
@ -167,7 +155,7 @@ public class SkillTreeNode implements ExperienceObject {
|
||||
|
||||
/**
|
||||
* @return Full node identifier, containing both the node identifier AND
|
||||
* the skill tree identifier, like "combat_extra_strength"
|
||||
* the skill tree identifier, like "combat_extra_strength"
|
||||
*/
|
||||
@NotNull
|
||||
public String getFullId() {
|
||||
@ -184,6 +172,11 @@ public class SkillTreeNode implements ExperienceObject {
|
||||
return coordinates;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public DisplayMap getIcons() {
|
||||
return icons;
|
||||
}
|
||||
|
||||
public static final String KEY_PREFIX = "node";
|
||||
|
||||
@Override
|
||||
@ -202,28 +195,28 @@ public class SkillTreeNode implements ExperienceObject {
|
||||
return experienceTable != null;
|
||||
}
|
||||
|
||||
public NodeType getNodeType() {
|
||||
public NodeShape getNodeType() {
|
||||
boolean up = tree.isPathOrNode(new IntegerCoordinates(coordinates.getX(), coordinates.getY() - 1));
|
||||
boolean down = tree.isPathOrNode(new IntegerCoordinates(coordinates.getX(), coordinates.getY() + 1));
|
||||
boolean right = tree.isPathOrNode(new IntegerCoordinates(coordinates.getX() + 1, coordinates.getY()));
|
||||
boolean left = tree.isPathOrNode(new IntegerCoordinates(coordinates.getX() - 1, coordinates.getY()));
|
||||
|
||||
if (up && right && down && left) return NodeType.UP_RIGHT_DOWN_LEFT;
|
||||
else if (up && right && down) return NodeType.UP_RIGHT_DOWN;
|
||||
else if (up && right && left) return NodeType.UP_RIGHT_LEFT;
|
||||
else if (up && down && left) return NodeType.UP_DOWN_LEFT;
|
||||
else if (down && right && left) return NodeType.DOWN_RIGHT_LEFT;
|
||||
else if (up && right) return NodeType.UP_RIGHT;
|
||||
else if (up && down) return NodeType.UP_DOWN;
|
||||
else if (up && left) return NodeType.UP_LEFT;
|
||||
else if (down && right) return NodeType.DOWN_RIGHT;
|
||||
else if (down && left) return NodeType.DOWN_LEFT;
|
||||
else if (right && left) return NodeType.RIGHT_LEFT;
|
||||
else if (up) return NodeType.UP;
|
||||
else if (down) return NodeType.DOWN;
|
||||
else if (right) return NodeType.RIGHT;
|
||||
else if (left) return NodeType.LEFT;
|
||||
return NodeType.NO_PATH;
|
||||
if (up && right && down && left) return NodeShape.UP_RIGHT_DOWN_LEFT;
|
||||
else if (up && right && down) return NodeShape.UP_RIGHT_DOWN;
|
||||
else if (up && right && left) return NodeShape.UP_RIGHT_LEFT;
|
||||
else if (up && down && left) return NodeShape.UP_DOWN_LEFT;
|
||||
else if (down && right && left) return NodeShape.DOWN_RIGHT_LEFT;
|
||||
else if (up && right) return NodeShape.UP_RIGHT;
|
||||
else if (up && down) return NodeShape.UP_DOWN;
|
||||
else if (up && left) return NodeShape.UP_LEFT;
|
||||
else if (down && right) return NodeShape.DOWN_RIGHT;
|
||||
else if (down && left) return NodeShape.DOWN_LEFT;
|
||||
else if (right && left) return NodeShape.RIGHT_LEFT;
|
||||
else if (up) return NodeShape.UP;
|
||||
else if (down) return NodeShape.DOWN;
|
||||
else if (right) return NodeShape.RIGHT;
|
||||
else if (left) return NodeShape.LEFT;
|
||||
return NodeShape.NO_PATH;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -281,4 +274,23 @@ public class SkillTreeNode implements ExperienceObject {
|
||||
public ExpCurve getExpCurve() {
|
||||
throw new RuntimeException("Skill trees don't have experience");
|
||||
}
|
||||
|
||||
//region Deprecated
|
||||
|
||||
@Deprecated
|
||||
public boolean hasIcon(NodeState status) {
|
||||
return getIcon(status) != null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Nullable
|
||||
public IconOptions getIcon(NodeState status) {
|
||||
for (var shape : NodeShape.values()) {
|
||||
var found = DisplayMap.getIcon(new NodeDisplayInfo(shape, status), icons);
|
||||
if (found != null) return found;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
//endregion
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package net.Indyuce.mmocore.skilltree;
|
||||
|
||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||
import net.Indyuce.mmocore.skilltree.display.PathShape;
|
||||
import net.Indyuce.mmocore.skilltree.tree.SkillTree;
|
||||
|
||||
public class SkillTreePath {
|
||||
@ -20,25 +21,25 @@ public class SkillTreePath {
|
||||
* Defines the status of a path between two nodes, which is determined
|
||||
* by the pair of states of the two nodes.
|
||||
*/
|
||||
public NodeState getStatus(PlayerData playerData) {
|
||||
public PathState getStatus(PlayerData playerData) {
|
||||
var from = playerData.getNodeState(this.from);
|
||||
var to = playerData.getNodeState(this.to);
|
||||
|
||||
// Either one is fully locked => gray out path
|
||||
if (from == NodeState.FULLY_LOCKED || to == NodeState.FULLY_LOCKED) return NodeState.FULLY_LOCKED;
|
||||
if (from == NodeState.FULLY_LOCKED || to == NodeState.FULLY_LOCKED) return PathState.FULLY_LOCKED;
|
||||
|
||||
// Both are unlocked => path is taken, unlocked
|
||||
if (from.isUnlocked() && to.isUnlocked()) return NodeState.UNLOCKED;
|
||||
if (from.isUnlocked() && to.isUnlocked()) return PathState.UNLOCKED;
|
||||
|
||||
// One of them is unlocked, other one is unlockable => path is not taken yet, but can be
|
||||
if ((from == NodeState.UNLOCKABLE && to.isUnlocked()) || (from.isUnlocked() && to == NodeState.UNLOCKABLE))
|
||||
return NodeState.UNLOCKABLE;
|
||||
return PathState.UNLOCKABLE;
|
||||
|
||||
// Otherwise, locked path
|
||||
return NodeState.LOCKED;
|
||||
return PathState.LOCKED;
|
||||
}
|
||||
|
||||
public PathType getPathType() {
|
||||
public PathShape getPathType() {
|
||||
IntegerCoordinates upCoor = new IntegerCoordinates(coordinates.getX(), coordinates.getY() - 1);
|
||||
IntegerCoordinates downCoor = new IntegerCoordinates(coordinates.getX(), coordinates.getY() + 1);
|
||||
IntegerCoordinates rightCoor = new IntegerCoordinates(coordinates.getX() + 1, coordinates.getY());
|
||||
@ -49,18 +50,18 @@ public class SkillTreePath {
|
||||
boolean hasLeft = tree.isPath(leftCoor) || leftCoor.equals(from.getCoordinates()) || leftCoor.equals(to.getCoordinates());
|
||||
|
||||
if ((hasUp || hasDown) && !hasLeft && !hasRight) {
|
||||
return PathType.UP;
|
||||
return PathShape.UP;
|
||||
} else if ((hasRight || hasLeft) && !hasUp && !hasDown) {
|
||||
return PathType.RIGHT;
|
||||
return PathShape.RIGHT;
|
||||
} else if (hasUp && hasRight) {
|
||||
return PathType.UP_RIGHT;
|
||||
return PathShape.UP_RIGHT;
|
||||
} else if (hasUp && hasLeft) {
|
||||
return PathType.UP_LEFT;
|
||||
return PathShape.UP_LEFT;
|
||||
} else if (hasDown && hasRight) {
|
||||
return PathType.DOWN_RIGHT;
|
||||
return PathShape.DOWN_RIGHT;
|
||||
} else if (hasDown && hasLeft) {
|
||||
return PathType.DOWN_LEFT;
|
||||
return PathShape.DOWN_LEFT;
|
||||
}
|
||||
return PathType.DEFAULT;
|
||||
return PathShape.DEFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
package net.Indyuce.mmocore.skilltree.display;
|
||||
|
||||
import net.Indyuce.mmocore.skilltree.NodeState;
|
||||
|
||||
/**
|
||||
* The information needed to determine the display of a node/path depending on its context.
|
||||
*/
|
||||
public abstract class DisplayInfo {
|
||||
protected final NodeState state;
|
||||
|
||||
protected DisplayInfo(NodeState state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public NodeState getState() {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,96 @@
|
||||
package net.Indyuce.mmocore.skilltree.display;
|
||||
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.gui.util.IconOptions;
|
||||
import net.Indyuce.mmocore.skilltree.NodeState;
|
||||
import net.Indyuce.mmocore.skilltree.PathState;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class DisplayMap {
|
||||
public final Map<Object, IconOptions> icons = new HashMap<>();
|
||||
|
||||
public static final IconOptions DEFAULT_ICON = new IconOptions(Material.BARRIER, 0);
|
||||
public static final DisplayMap EMPTY = new DisplayMap(YamlConfiguration.loadConfiguration(new StringReader("")));
|
||||
|
||||
private DisplayMap(@NotNull ConfigurationSection config) {
|
||||
|
||||
// Loads all the pathDisplayInfo
|
||||
if (config.contains("paths")) for (var status : PathState.values())
|
||||
for (PathShape pathShape : PathShape.values())
|
||||
try {
|
||||
final String configPath = "paths." + UtilityMethods.kebabCase(status.name() + "." + pathShape.name());
|
||||
icons.put(new PathDisplayInfo(pathShape, status), IconOptions.from(config.get(configPath)));
|
||||
} catch (Exception exception) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
// Loads all the nodeDisplayInfo
|
||||
var nodeConfig = getNodeConfig(config);
|
||||
if (nodeConfig != null) for (var state : NodeState.values()) {
|
||||
final var statusConfig = nodeConfig.get(UtilityMethods.kebabCase(state.name()));
|
||||
if (statusConfig == null) continue;
|
||||
|
||||
// Check if it depends on state
|
||||
if (statusConfig instanceof ConfigurationSection && UtilityMethods.containsOneKey((ConfigurationSection) statusConfig, NodeShape.values(), UtilityMethods::kebabCase))
|
||||
for (var shape : NodeShape.values()) {
|
||||
try {
|
||||
final var configPath = "nodes." + UtilityMethods.kebabCase(state.name() + "." + shape.name());
|
||||
icons.put(new NodeDisplayInfo(shape, state), IconOptions.from(nodeConfig.get(configPath)));
|
||||
} catch (Exception exception) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
// Depends on node type
|
||||
else {
|
||||
var iconFound = IconOptions.from(statusConfig);
|
||||
for (var shape : NodeShape.values())
|
||||
icons.put(new NodeDisplayInfo(shape, state), iconFound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ConfigurationSection getNodeConfig(@Nullable ConfigurationSection config) {
|
||||
|
||||
// Null to null
|
||||
if (config == null) return null;
|
||||
|
||||
// 'nodes' subconfig
|
||||
var subconfig = config.getConfigurationSection("nodes");
|
||||
if (subconfig != null) return subconfig;
|
||||
|
||||
// Validate at least one state
|
||||
// Not strictly necessary.
|
||||
if (UtilityMethods.containsOneKey(config, NodeState.values(), UtilityMethods::kebabCase)) return config;
|
||||
|
||||
// Wrong syntax..
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param nodeInfo Either a {@link NodeDisplayInfo} or {@link PathDisplayInfo}
|
||||
* @return Icon/texture mapping of node/path display info
|
||||
*/
|
||||
@Nullable
|
||||
public static IconOptions getIcon(Object nodeInfo, @NotNull DisplayMap... maps) {
|
||||
int i = 0;
|
||||
IconOptions found = null;
|
||||
while (found == null && i < maps.length) found = maps[i++].icons.get(nodeInfo);
|
||||
return found;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static DisplayMap from(@Nullable ConfigurationSection config) {
|
||||
if (config == null) return EMPTY;
|
||||
return new DisplayMap(config);
|
||||
}
|
||||
}
|
||||
@ -1,22 +1,27 @@
|
||||
package net.Indyuce.mmocore.skilltree.display;
|
||||
|
||||
import net.Indyuce.mmocore.skilltree.NodeType;
|
||||
import net.Indyuce.mmocore.skilltree.NodeState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class NodeDisplayInfo extends DisplayInfo {
|
||||
private final NodeType type;
|
||||
public class NodeDisplayInfo {
|
||||
private final NodeShape shape;
|
||||
private final NodeState state;
|
||||
|
||||
public NodeDisplayInfo(@NotNull NodeType type, @NotNull NodeState status) {
|
||||
super(status);
|
||||
|
||||
this.type = type;
|
||||
public NodeDisplayInfo(@NotNull NodeShape shape, @NotNull NodeState status) {
|
||||
this.state = status;
|
||||
this.shape = shape;
|
||||
}
|
||||
|
||||
public NodeType getType() {
|
||||
return type;
|
||||
@NotNull
|
||||
public NodeState getStatus() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public NodeShape getShape() {
|
||||
return shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -24,16 +29,16 @@ public class NodeDisplayInfo extends DisplayInfo {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
NodeDisplayInfo that = (NodeDisplayInfo) o;
|
||||
return state == that.state && type == that.type;
|
||||
return state == that.state && shape == that.shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(state, type);
|
||||
return Objects.hash(state, shape);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NodeDisplayInfo{" + "status=" + state + ", type=" + type + '}';
|
||||
return "NodeDisplayInfo{" + "status=" + state + ", type=" + shape + '}';
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
package net.Indyuce.mmocore.skilltree;
|
||||
package net.Indyuce.mmocore.skilltree.display;
|
||||
|
||||
/**
|
||||
* TODO docs
|
||||
*/
|
||||
public enum NodeType {
|
||||
public enum NodeShape {
|
||||
UP_RIGHT_DOWN_LEFT,
|
||||
UP_RIGHT_DOWN,
|
||||
UP_RIGHT_LEFT,
|
||||
@ -1,30 +1,32 @@
|
||||
package net.Indyuce.mmocore.skilltree.display;
|
||||
|
||||
import net.Indyuce.mmocore.skilltree.PathType;
|
||||
import net.Indyuce.mmocore.skilltree.NodeState;
|
||||
import net.Indyuce.mmocore.skilltree.PathState;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class PathDisplayInfo extends DisplayInfo {
|
||||
private final PathType type;
|
||||
public class PathDisplayInfo {
|
||||
private final PathShape shape;
|
||||
private final PathState state;
|
||||
|
||||
public PathDisplayInfo(PathType type, NodeState status) {
|
||||
super(status);
|
||||
|
||||
this.type = type;
|
||||
public PathDisplayInfo(@NotNull PathShape shape, @NotNull PathState status) {
|
||||
this.state = status;
|
||||
this.shape = shape;
|
||||
}
|
||||
|
||||
public PathType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public NodeState getStatus() {
|
||||
@NotNull
|
||||
public PathState getStatus() {
|
||||
return state;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public PathShape getShape() {
|
||||
return shape;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(type, state);
|
||||
return Objects.hash(shape, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -32,11 +34,11 @@ public class PathDisplayInfo extends DisplayInfo {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
PathDisplayInfo that = (PathDisplayInfo) o;
|
||||
return type == that.type && state == that.state;
|
||||
return shape == that.shape && state == that.state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "PathDisplayInfo{" + "type=" + type + ", status=" + state + '}';
|
||||
return "PathDisplayInfo{" + "type=" + shape + ", status=" + state + '}';
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
package net.Indyuce.mmocore.skilltree;
|
||||
package net.Indyuce.mmocore.skilltree.display;
|
||||
|
||||
/**
|
||||
* These are the different textures that a path between
|
||||
* two nodes can have, just like a redstone wire which can take
|
||||
* turns, go straight, or be a one node path on its own.
|
||||
*/
|
||||
public enum PathType {
|
||||
public enum PathShape {
|
||||
|
||||
/**
|
||||
* │ up, down
|
||||
@ -2,15 +2,12 @@ package net.Indyuce.mmocore.skilltree.tree;
|
||||
|
||||
import io.lumine.mythic.lib.MythicLib;
|
||||
import io.lumine.mythic.lib.UtilityMethods;
|
||||
import io.lumine.mythic.lib.gui.util.IconOptions;
|
||||
import net.Indyuce.mmocore.MMOCore;
|
||||
import net.Indyuce.mmocore.api.player.PlayerData;
|
||||
import net.Indyuce.mmocore.api.util.MMOCoreUtils;
|
||||
import net.Indyuce.mmocore.manager.registry.RegisteredObject;
|
||||
import net.Indyuce.mmocore.skilltree.*;
|
||||
import net.Indyuce.mmocore.skilltree.display.DisplayInfo;
|
||||
import net.Indyuce.mmocore.skilltree.display.NodeDisplayInfo;
|
||||
import net.Indyuce.mmocore.skilltree.display.PathDisplayInfo;
|
||||
import net.Indyuce.mmocore.util.Icon;
|
||||
import net.Indyuce.mmocore.skilltree.display.DisplayMap;
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
@ -42,7 +39,7 @@ public abstract class SkillTree implements RegisteredObject {
|
||||
protected final Map<String, SkillTreeNode> nodes = new HashMap<>();
|
||||
protected final int maxPointSpent;
|
||||
protected final List<SkillTreeNode> roots = new ArrayList<>();
|
||||
protected final Map<DisplayInfo, Icon> icons = new HashMap<>();
|
||||
protected final DisplayMap icons;
|
||||
|
||||
protected final Map<IntegerCoordinates, SkillTreeNode> coordNodes = new HashMap<>();
|
||||
protected final Map<IntegerCoordinates, SkillTreePath> coordPaths = new HashMap<>();
|
||||
@ -87,33 +84,8 @@ public abstract class SkillTree implements RegisteredObject {
|
||||
}
|
||||
}
|
||||
|
||||
// Loads all the pathDisplayInfo
|
||||
for (NodeState status : NodeState.values())
|
||||
for (PathType pathType : PathType.values())
|
||||
try {
|
||||
final String configPath = "display.paths." + MMOCoreUtils.ymlName(status.name()) + "." + MMOCoreUtils.ymlName(pathType.name());
|
||||
icons.put(new PathDisplayInfo(pathType, status), Icon.from(config.get(configPath)));
|
||||
} catch (Exception exception) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
// Loads all the nodeDisplayInfo
|
||||
for (var status : NodeState.values()) {
|
||||
final var anyType = config.get("display.nodes." + MMOCoreUtils.ymlName(status.name()));
|
||||
|
||||
// Does not depend on node type.
|
||||
if (anyType != null) for (var nodeType : NodeType.values())
|
||||
icons.put(new NodeDisplayInfo(nodeType, status), Icon.from(anyType));
|
||||
|
||||
// Depends on node type
|
||||
else for (var nodeType : NodeType.values())
|
||||
try {
|
||||
final var configPath = "display.nodes." + MMOCoreUtils.ymlName(status.name()) + "." + MMOCoreUtils.ymlName(nodeType.name());
|
||||
icons.put(new NodeDisplayInfo(nodeType, status), Icon.from(config.get(configPath)));
|
||||
} catch (Exception exception) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
// Load icons
|
||||
this.icons = DisplayMap.from(config.getConfigurationSection("display"));
|
||||
|
||||
// Setup children and parents for each node
|
||||
for (SkillTreeNode node : nodes.values())
|
||||
@ -149,11 +121,6 @@ public abstract class SkillTree implements RegisteredObject {
|
||||
return customModelData;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static SkillTree loadSkillTree(ConfigurationSection config) {
|
||||
return MMOCore.plugin.skillTreeManager.loadSkillTree(config);
|
||||
}
|
||||
|
||||
public void addRoot(@NotNull SkillTreeNode node) {
|
||||
roots.add(node);
|
||||
}
|
||||
@ -366,12 +333,9 @@ public abstract class SkillTree implements RegisteredObject {
|
||||
return Objects.requireNonNull(nodes.get(name), "Could not find node in tree '" + id + "' with name '" + name + "'");
|
||||
}
|
||||
|
||||
public boolean hasIcon(DisplayInfo displayInfo) {
|
||||
return icons.containsKey(displayInfo);
|
||||
}
|
||||
|
||||
public Icon getIcon(DisplayInfo displayInfo) {
|
||||
return icons.get(displayInfo);
|
||||
@NotNull
|
||||
public DisplayMap getIcons() {
|
||||
return icons;
|
||||
}
|
||||
|
||||
public boolean isNode(String name) {
|
||||
@ -390,4 +354,23 @@ public abstract class SkillTree implements RegisteredObject {
|
||||
public int hashCode() {
|
||||
return Objects.hash(id);
|
||||
}
|
||||
|
||||
//region Deprecated
|
||||
|
||||
@Deprecated
|
||||
public static SkillTree loadSkillTree(ConfigurationSection config) {
|
||||
return MMOCore.plugin.skillTreeManager.loadSkillTree(config);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public boolean hasIcon(Object displayInfo) {
|
||||
return DisplayMap.getIcon(displayInfo, icons) != null;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public IconOptions getIcon(Object displayInfo) {
|
||||
return DisplayMap.getIcon(displayInfo, icons);
|
||||
}
|
||||
|
||||
//endregion
|
||||
}
|
||||
|
||||
@ -14,7 +14,11 @@ import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The material and custom model-data of a node
|
||||
*
|
||||
* @see io.lumine.mythic.lib.gui.util.IconOptions
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public class Icon {
|
||||
private final Material material;
|
||||
private final int modelData;
|
||||
@ -77,7 +81,7 @@ public class Icon {
|
||||
|
||||
if (object instanceof ConfigurationSection) {
|
||||
final ConfigurationSection config = (ConfigurationSection) object;
|
||||
final Material material = Material.valueOf(UtilityMethods.enumName(((ConfigurationSection) object).getString("item")));
|
||||
final Material material = Material.valueOf(UtilityMethods.enumName(((ConfigurationSection) object).getString("item", "none")));
|
||||
final int modelData = config.getInt("model-data", config.getInt("custom-model-data")); // Backwards compatibility
|
||||
return new Icon(material, modelData);
|
||||
}
|
||||
|
||||
@ -5,6 +5,13 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @param <L> Left-hand side type
|
||||
* @param <R> Right-hand side type
|
||||
* @see io.lumine.mythic.lib.util.Pair
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public class Pair<L, R> {
|
||||
private final L left;
|
||||
private final R right;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
package net.Indyuce.mmocore.waypoint;
|
||||
|
||||
import io.lumine.mythic.lib.util.Pair;
|
||||
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;
|
||||
|
||||
|
||||
@ -13,6 +13,8 @@
|
||||
|
||||
<build>
|
||||
|
||||
<finalName>MMOCore-${project.version}</finalName>
|
||||
|
||||
<!--
|
||||
Includes default files in the Bukkit module
|
||||
-->
|
||||
@ -34,7 +36,6 @@
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<configuration>
|
||||
<finalName>MMOCore-${project.version}</finalName>
|
||||
<outputDirectory>../target/</outputDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
@ -4,13 +4,16 @@
|
||||
display:
|
||||
name: 'Human'
|
||||
|
||||
# This is the default class which players have when
|
||||
# joining the server. They can level it up, but they
|
||||
# cannot choose this class again after changing their
|
||||
# class because it is not displayed in /class
|
||||
# No need for an item since the default class is not displayed
|
||||
# anywhere by default.
|
||||
#item: LEATHER_CHESTPLATE
|
||||
|
||||
# This is the default class granted to players when joining the server.
|
||||
# They may level it up, but they cannot choose this class again
|
||||
# after switching class, since it is not displayed in /class
|
||||
options:
|
||||
default: true
|
||||
display: false
|
||||
default: true # Default class when joining the server for the first time
|
||||
display: false # Does not display in the class UI
|
||||
needs-permission: false # False by default
|
||||
|
||||
# Only regens when out of combat
|
||||
|
||||
@ -26,7 +26,15 @@ display:
|
||||
- '&7 Max Mana: &930 &7(+&91.3&7)'
|
||||
- '&7 Health Regen: &90.13 &7(+&90&7)'
|
||||
- '&7 Mana Regen: &90.2 &7(+&90.04&7)'
|
||||
item: BLAZE_POWDER:1 # Supports custom model data/texture by durability
|
||||
|
||||
item: 'BLAZE_POWDER:1' # Syntax: '<ITEM>:<custom_model_data_int>'
|
||||
# Alternate syntax for string custom model data, item model....
|
||||
#item:
|
||||
# item: BLAZE_POWDER
|
||||
# custom-model-data: 10
|
||||
# custom-model-data-string: 'whatever'
|
||||
# item-model: 'minecraft:dirt'
|
||||
# texture: '' # Skull texture (set 'item' to 'PLAYER_HEAD')
|
||||
|
||||
# Must match an existing exp curve filename from the 'expcurves' folder
|
||||
exp-curve: levels
|
||||
|
||||
@ -24,7 +24,17 @@ display:
|
||||
- '&7 Max Mana: &927 &7(+&91.2&7)'
|
||||
- '&7 Health Regen: &90.13 &7(+&90&7)'
|
||||
- '&7 Mana Regen: &90.2 &7(+&90.04&7)'
|
||||
|
||||
item: BLAZE_POWDER
|
||||
# Alternate syntax for custom model data
|
||||
#item: 'BLAZE_POWDER:10'
|
||||
# Alternate syntax for custom model data, item model....
|
||||
#item:
|
||||
# item: BLAZE_POWDER
|
||||
# custom-model-data: 10
|
||||
# custom-model-data-string: 'whatever'
|
||||
# item-model: 'minecraft:dirt'
|
||||
# texture: '' # Skull texture (set 'item' to 'PLAYER_HEAD')
|
||||
|
||||
# Must match an existing exp curve filename from the 'expcurves' folder
|
||||
exp-curve: levels
|
||||
|
||||
@ -23,7 +23,17 @@ display:
|
||||
- '&7 Max Mana: &920 &7(+&90&7)'
|
||||
- '&7 Health Regen: &90.1 &7(+&90&7)'
|
||||
- '&7 Mana Regen: &90.166 &7(+&90&7)'
|
||||
|
||||
item: BOW
|
||||
# Alternate syntax for custom model data
|
||||
#item: 'BOW:10'
|
||||
# Alternate syntax for custom model data, item model....
|
||||
#item:
|
||||
# item: BOW
|
||||
# custom-model-data: 10
|
||||
# custom-model-data-string: 'whatever'
|
||||
# item-model: 'minecraft:dirt'
|
||||
# texture: '' # Skull texture (set 'item' to 'PLAYER_HEAD')
|
||||
|
||||
# Must match an existing exp curve filename from the 'expcurves' folder
|
||||
exp-curve: levels
|
||||
|
||||
@ -25,7 +25,15 @@ display:
|
||||
- '&7 Max Mana: &920 &7(+&90&7)'
|
||||
- '&7 Health Regen: &90.1 &7(+&90&7)'
|
||||
- '&7 Mana Regen: &90.166 &7(+&90&7)'
|
||||
item: ENCHANTED_GOLDEN_APPLE:0 # Supports custom model data/texture by durability
|
||||
|
||||
item: 'ENCHANTED_GOLDEN_APPLE:100'
|
||||
# Alternate syntax for custom model data, item model....
|
||||
#item:
|
||||
# item: ENCHANTED_GOLDEN_APPLE
|
||||
# custom-model-data: 10
|
||||
# custom-model-data-string: 'whatever'
|
||||
# item-model: 'minecraft:dirt'
|
||||
# texture: '' # Skull texture (set 'item' to 'PLAYER_HEAD')
|
||||
|
||||
# Must match an existing exp curve filename from the 'expcurves' folder
|
||||
exp-curve: levels
|
||||
|
||||
@ -23,7 +23,18 @@ display:
|
||||
- '&7 Max Mana: &920 &7(+&90&7)'
|
||||
- '&7 Health Regen: &90.1 &7(+&90&7)'
|
||||
- '&7 Mana Regen: &90.166 &7(+&90&7)'
|
||||
|
||||
# Change class icon here
|
||||
item: LEATHER_BOOTS
|
||||
# Alternate syntax for custom model data
|
||||
#item: 'LEATHER_BOOTS:10'
|
||||
# Alternate syntax for custom model data, item model....
|
||||
#item:
|
||||
# item: IRON_SWORD
|
||||
# custom-model-data: 10
|
||||
# custom-model-data-string: 'whatever'
|
||||
# item-model: 'minecraft:dirt'
|
||||
# texture: '' # Skull texture (set 'item' to 'PLAYER_HEAD')
|
||||
|
||||
# Must match an existing exp curve filename from the 'expcurves' folder
|
||||
exp-curve: levels
|
||||
|
||||
@ -28,7 +28,16 @@ display:
|
||||
- '&7 Max Rage: &c20 &7(+&c1&7)'
|
||||
- '&7 Health Regen: &90.1 &7(+&90&7)'
|
||||
- '&7 Rage Degeneration: &9-0.5&7/s'
|
||||
item: IRON_SWORD:0 # Supports custom model data/texture by durability
|
||||
|
||||
# Change class icon here
|
||||
item: 'IRON_SWORD:0' # Syntax: '<ITEM>:<custom_model_data_int>'
|
||||
# Alternate syntax for custom model data, item model....
|
||||
#item:
|
||||
# item: IRON_SWORD
|
||||
# custom-model-data: 10
|
||||
# custom-model-data-string: 'whatever'
|
||||
# item-model: 'minecraft:dirt'
|
||||
# texture: '' # Skull texture (set 'item' to 'PLAYER_HEAD')
|
||||
|
||||
# Must match an existing exp curve filename from the 'expcurves' folder
|
||||
exp-curve: levels
|
||||
|
||||
@ -210,54 +210,22 @@ display:
|
||||
custom-model-data: 0
|
||||
nodes:
|
||||
unlocked:
|
||||
up-right-down-left:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
up-right-down:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
up-right-left:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
up-down-left:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
down-right-left:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
up-right:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
up-down:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
up-left:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
down-right:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
down-left:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
right-left:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
right:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
left:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
up:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
down:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
no-path:
|
||||
item: "WHITE_CONCRETE"
|
||||
custom-model-data: 0
|
||||
up-right-down-left: "WHITE_CONCRETE:0"
|
||||
up-right-down: "WHITE_CONCRETE:0"
|
||||
up-right-left: "WHITE_CONCRETE:0"
|
||||
up-down-left: "WHITE_CONCRETE:0"
|
||||
down-right-left: "WHITE_CONCRETE:0"
|
||||
up-right: "WHITE_CONCRETE:0"
|
||||
up-down: "WHITE_CONCRETE:0"
|
||||
up-left: "WHITE_CONCRETE:0"
|
||||
down-right: "WHITE_CONCRETE:0"
|
||||
down-left: "WHITE_CONCRETE:0"
|
||||
right-left: "WHITE_CONCRETE:0"
|
||||
right: "WHITE_CONCRETE:0"
|
||||
left: "WHITE_CONCRETE:0"
|
||||
up: "WHITE_CONCRETE:0"
|
||||
down: "WHITE_CONCRETE:0"
|
||||
no-path: "WHITE_CONCRETE:0"
|
||||
locked:
|
||||
up-right-down-left:
|
||||
item: "GRAY_CONCRETE"
|
||||
|
||||
@ -81,7 +81,15 @@ status-names:
|
||||
locked: 'Locked'
|
||||
fully-locked: 'Fully Locked'
|
||||
|
||||
|
||||
# This section is to change display options for nodes and paths depending on:
|
||||
# - their shape: each path has a shape given its neighboring connections (left + up, )... kind of like a vanilla redstone wire.
|
||||
# - their state: is the node/path unlocked, locked, maxed out... ?
|
||||
#
|
||||
# All of this is to "hide" the grid pattern of the chest inventory UI and give the
|
||||
# impression of a clean 2D skill tree UI.
|
||||
#
|
||||
# Please refer to skill-tree/combat.yml for syntax examples.
|
||||
#####################
|
||||
display:
|
||||
paths:
|
||||
unlocked:
|
||||
|
||||
@ -430,15 +430,19 @@ nodes:
|
||||
1:
|
||||
- "&eAdditional on-hit weapon damage in +%4"
|
||||
|
||||
# This section is to have a specific display for the skill tree in the GUI.
|
||||
# It is optional as if you don't fill it the config in gui/skill-tree.yml will be used.
|
||||
# For each node it will first look if the node has a specific display, if not it will look if
|
||||
# the display is defined in this section. If not it will use the default display in gui/skill-tree.yml.
|
||||
# This section is to change display options for nodes and paths depending on:
|
||||
# - their shape: each path has a shape given its neighboring connections (left + up, )... kind of like a vanilla redstone wire.
|
||||
# - their state: is the node/path unlocked, locked, maxed out... ?
|
||||
#
|
||||
# All of this is to "hide" the grid pattern of the chest inventory UI and give the
|
||||
# impression of a clean 2D skill tree UI.
|
||||
#
|
||||
# This config section is optional; if you do not provide it the one provided in the skill tree CUSTOM GUI CONFIG will be used.
|
||||
#######################
|
||||
#display:
|
||||
# paths:
|
||||
# unlocked:
|
||||
# up: 'WHITE_DYE:0'
|
||||
# up: 'WHITE_DYE:0' # Syntax is 'MATERIAL:INT_CUSTOM_MODEL_DATA'
|
||||
# up-right: 'WHITE_DYE:0'
|
||||
# up-left: 'WHITE_DYE:0'
|
||||
# down-right: 'WHITE_DYE:0'
|
||||
@ -556,15 +560,39 @@ nodes:
|
||||
# down: 'BLACK_CONCRETE:0'
|
||||
# no-path: 'BLACK_CONCRETE:0'
|
||||
|
||||
# The following syntax works too, it applies the same texture
|
||||
# no matter the neighboring paths.
|
||||
#
|
||||
# The following syntax shows how to use an item model, int custom model data
|
||||
# or string custom model data. This works on both nodes and paths.
|
||||
#######################
|
||||
#display:
|
||||
# paths:
|
||||
# unlocked:
|
||||
# up:
|
||||
# item: DIAMOND
|
||||
# item-model: 'minecraft:dirt'
|
||||
# custom-model-data: 10
|
||||
# custom-model-data-string: 'whatever'
|
||||
# ........
|
||||
# ......
|
||||
# nodes:
|
||||
# unlocked:
|
||||
# up-right-down-left:
|
||||
# item: DIAMOND
|
||||
# item-model: 'minecraft:dirt'
|
||||
# custom-model-data: 10
|
||||
# custom-model-data-string: 'whatever'
|
||||
# .......
|
||||
# .......
|
||||
|
||||
# To make your configs lighter, you can have the node textures
|
||||
# only depend on their state (locked, unlocked...) and not shape.
|
||||
#######################
|
||||
#display:
|
||||
# paths:
|
||||
# .......
|
||||
# nodes:
|
||||
# unlocked: 'WHITE_CONCRETE:0'
|
||||
# maxed-out: 'GREEN_CONCRETE:0'
|
||||
# locked: 'GRAY_CONCRETE:0'
|
||||
# unlockable: 'BLUE_CONCRETE:0'
|
||||
# fully-locked: 'BLACK_CONCRETE:0'
|
||||
# unlocked: # No shape, only state!
|
||||
# item: DIAMOND
|
||||
# item-model: 'minecraft:dirt'
|
||||
# custom-model-data: 10
|
||||
# custom-model-data-string: 'whatever'
|
||||
# ....
|
||||
|
||||
@ -426,141 +426,22 @@ nodes:
|
||||
1:
|
||||
- "Additional magic skill damage in +%3"
|
||||
|
||||
# This section is to have a specific display for the skill tree in the GUI.
|
||||
# It is optional as if you don't fill it the config in gui/skill-tree.yml will be used.
|
||||
# For each node it will first look if the node has a specific display, if not it will look if
|
||||
# the display is defined in this section. If not it will use the default display in gui/skill-tree.yml.
|
||||
# This section is to change display options for nodes and paths depending on:
|
||||
# - their shape: each path has a shape given its neighboring connections (left + up, )... kind of like a vanilla redstone wire.
|
||||
# - their state: is the node/path unlocked, locked, maxed out... ?
|
||||
#
|
||||
# All of this is to "hide" the grid pattern of the chest inventory UI and give the
|
||||
# impression of a clean 2D skill tree UI.
|
||||
#
|
||||
# This config section is optional; if you do not provide it the one provided in the skill tree CUSTOM GUI CONFIG will be used.
|
||||
#
|
||||
# Please refer to the default config file 'combat.yml' for syntax examples and explanations.
|
||||
#########################
|
||||
#display:
|
||||
# paths:
|
||||
# unlocked:
|
||||
# up: 'WHITE_DYE:0'
|
||||
# up-right: 'WHITE_DYE:0'
|
||||
# up-left: 'WHITE_DYE:0'
|
||||
# down-right: 'WHITE_DYE:0'
|
||||
# down-left: 'WHITE_DYE:0'
|
||||
# right: 'WHITE_DYE:0'
|
||||
# default: 'WHITE_DYE:0'
|
||||
# unlockable:
|
||||
# up: 'BLUE_DYE:0'
|
||||
# up-right: 'BLUE_DYE:0'
|
||||
# up-left: 'BLUE_DYE:0'
|
||||
# down-right: 'BLUE_DYE:0'
|
||||
# down-left: 'BLUE_DYE:0'
|
||||
# right: 'BLUE_DYE:0'
|
||||
# default: 'BLUE_DYE:0'
|
||||
# locked:
|
||||
# up: 'GRAY_DYE:0'
|
||||
# up-right: 'GRAY_DYE:0'
|
||||
# up-left: 'GRAY_DYE:0'
|
||||
# down-right: 'GRAY_DYE:0'
|
||||
# down-left: 'GRAY_DYE:0'
|
||||
# right: 'GRAY_DYE:0'
|
||||
# default: 'GRAY_DYE:0'
|
||||
# fully-locked:
|
||||
# up: 'BLACK_DYE:0'
|
||||
# up-right: 'BLACK_DYE:0'
|
||||
# up-left: 'BLACK_DYE:0'
|
||||
# down-right: 'BLACK_DYE:0'
|
||||
# down-left: 'BLACK_DYE:0'
|
||||
# right: 'BLACK_DYE:0'
|
||||
# default: 'BLACK_DYE:0'
|
||||
# ....
|
||||
# ...
|
||||
# nodes:
|
||||
# unlocked:
|
||||
# up-right-down-left: 'WHITE_CONCRETE:0'
|
||||
# up-right-down: 'WHITE_CONCRETE:0'
|
||||
# up-right-left: 'WHITE_CONCRETE:0'
|
||||
# up-down-left: 'WHITE_CONCRETE:0'
|
||||
# down-right-left: 'WHITE_CONCRETE:0'
|
||||
# up-right: 'WHITE_CONCRETE:0'
|
||||
# up-down: 'WHITE_CONCRETE:0'
|
||||
# up-left: 'WHITE_CONCRETE:0'
|
||||
# down-right: 'WHITE_CONCRETE:0'
|
||||
# down-left: 'WHITE_CONCRETE:0'
|
||||
# right-left: 'WHITE_CONCRETE:0'
|
||||
# right: 'WHITE_CONCRETE:0'
|
||||
# left: 'WHITE_CONCRETE:0'
|
||||
# up: 'WHITE_CONCRETE:0'
|
||||
# down: 'WHITE_CONCRETE:0'
|
||||
# no-path: 'WHITE_CONCRETE:0'
|
||||
# maxed-out:
|
||||
# up-right-down-left: 'GREEN_CONCRETE:0'
|
||||
# up-right-down: 'GREEN_CONCRETE:0'
|
||||
# up-right-left: 'GREEN_CONCRETE:0'
|
||||
# up-down-left: 'GREEN_CONCRETE:0'
|
||||
# down-right-left: 'GREEN_CONCRETE:0'
|
||||
# up-right: 'GREEN_CONCRETE:0'
|
||||
# up-down: 'GREEN_CONCRETE:0'
|
||||
# up-left: 'GREEN_CONCRETE:0'
|
||||
# down-right: 'GREEN_CONCRETE:0'
|
||||
# down-left: 'GREEN_CONCRETE:0'
|
||||
# right-left: 'GREEN_CONCRETE:0'
|
||||
# right: 'GREEN_CONCRETE:0'
|
||||
# left: 'GREEN_CONCRETE:0'
|
||||
# up: 'GREEN_CONCRETE:0'
|
||||
# down: 'GREEN_CONCRETE:0'
|
||||
# no-path: 'GREEN_CONCRETE:0'
|
||||
# locked:
|
||||
# up-right-down-left: 'GRAY_CONCRETE:0'
|
||||
# up-right-down: 'GRAY_CONCRETE:0'
|
||||
# up-right-left: 'GRAY_CONCRETE:0'
|
||||
# up-down-left: 'GRAY_CONCRETE:0'
|
||||
# down-right-left: 'GRAY_CONCRETE:0'
|
||||
# up-right: 'GRAY_CONCRETE:0'
|
||||
# up-down: 'GRAY_CONCRETE:0'
|
||||
# up-left: 'GRAY_CONCRETE:0'
|
||||
# down-right: 'GRAY_CONCRETE:0'
|
||||
# down-left: 'GRAY_CONCRETE:0'
|
||||
# right-left: 'GRAY_CONCRETE:0'
|
||||
# right: 'GRAY_CONCRETE:0'
|
||||
# left: 'GRAY_CONCRETE:0'
|
||||
# up: 'GRAY_CONCRETE:0'
|
||||
# down: 'GRAY_CONCRETE:0'
|
||||
# no-path: 'GRAY_CONCRETE:0'
|
||||
# unlockable:
|
||||
# up-right-down-left: 'BLUE_CONCRETE:0'
|
||||
# up-right-down: 'BLUE_CONCRETE:0'
|
||||
# up-right-left: 'BLUE_CONCRETE:0'
|
||||
# up-down-left: 'BLUE_CONCRETE:0'
|
||||
# down-right-left: 'BLUE_CONCRETE:0'
|
||||
# up-right: 'BLUE_CONCRETE:0'
|
||||
# up-down: 'BLUE_CONCRETE:0'
|
||||
# up-left: 'BLUE_CONCRETE:0'
|
||||
# down-right: 'BLUE_CONCRETE:0'
|
||||
# down-left: 'BLUE_CONCRETE:0'
|
||||
# right-left: 'BLUE_CONCRETE:0'
|
||||
# right: 'BLUE_CONCRETE:0'
|
||||
# left: 'BLUE_CONCRETE:0'
|
||||
# up: 'BLUE_CONCRETE:0'
|
||||
# down: 'BLUE_CONCRETE:0'
|
||||
# no-path: 'BLUE_CONCRETE:0'
|
||||
# fully-locked:
|
||||
# up-right-down-left: 'BLACK_CONCRETE:0'
|
||||
# up-right-down: 'BLACK_CONCRETE:0'
|
||||
# up-right-left: 'BLACK_CONCRETE:0'
|
||||
# up-down-left: 'BLACK_CONCRETE:0'
|
||||
# down-right-left: 'BLACK_CONCRETE:0'
|
||||
# up-right: 'BLACK_CONCRETE:0'
|
||||
# up-down: 'BLACK_CONCRETE:0'
|
||||
# up-left: 'BLACK_CONCRETE:0'
|
||||
# down-right: 'BLACK_CONCRETE:0'
|
||||
# down-left: 'BLACK_CONCRETE:0'
|
||||
# right-left: 'BLACK_CONCRETE:0'
|
||||
# right: 'BLACK_CONCRETE:0'
|
||||
# left: 'BLACK_CONCRETE:0'
|
||||
# up: 'BLACK_CONCRETE:0'
|
||||
# down: 'BLACK_CONCRETE:0'
|
||||
# no-path: 'BLACK_CONCRETE:0'
|
||||
|
||||
# The following syntax works too, it applies the same texture
|
||||
# no matter the neighboring paths.
|
||||
#
|
||||
#display:
|
||||
# paths:
|
||||
# .......
|
||||
# nodes:
|
||||
# unlocked: 'WHITE_CONCRETE:0'
|
||||
# maxed-out: 'GREEN_CONCRETE:0'
|
||||
# locked: 'GRAY_CONCRETE:0'
|
||||
# unlockable: 'BLUE_CONCRETE:0'
|
||||
# fully-locked: 'BLACK_CONCRETE:0'
|
||||
# ....
|
||||
|
||||
@ -183,3 +183,23 @@ nodes:
|
||||
- "&eLorem ipsum dolor sit amet"
|
||||
|
||||
coordinates: -2,0
|
||||
|
||||
# This section is to change display options for nodes and paths depending on:
|
||||
# - their shape: each path has a shape given its neighboring connections (left + up, )... kind of like a vanilla redstone wire.
|
||||
# - their state: is the node/path unlocked, locked, maxed out... ?
|
||||
#
|
||||
# All of this is to "hide" the grid pattern of the chest inventory UI and give the
|
||||
# impression of a clean 2D skill tree UI.
|
||||
#
|
||||
# This config section is optional; if you do not provide it the one provided in the skill tree CUSTOM GUI CONFIG will be used.
|
||||
#
|
||||
# Please refer to the default config file 'combat.yml' for syntax examples and explanations.
|
||||
#########################
|
||||
#display:
|
||||
# paths:
|
||||
# unlocked:
|
||||
# up: 'WHITE_DYE:0'
|
||||
# ....
|
||||
# ...
|
||||
# nodes:
|
||||
# ....
|
||||
|
||||
@ -422,3 +422,23 @@ nodes:
|
||||
- "&eAdditional magic skill damage in +%2"
|
||||
1:
|
||||
- "&eAdditional magic skill damage in +%2"
|
||||
|
||||
# This section is to change display options for nodes and paths depending on:
|
||||
# - their shape: each path has a shape given its neighboring connections (left + up, )... kind of like a vanilla redstone wire.
|
||||
# - their state: is the node/path unlocked, locked, maxed out... ?
|
||||
#
|
||||
# All of this is to "hide" the grid pattern of the chest inventory UI and give the
|
||||
# impression of a clean 2D skill tree UI.
|
||||
#
|
||||
# This config section is optional; if you do not provide it the one provided in the skill tree CUSTOM GUI CONFIG will be used.
|
||||
#
|
||||
# Please refer to the default config file 'combat.yml' for syntax examples and explanations.
|
||||
#########################
|
||||
#display:
|
||||
# paths:
|
||||
# unlocked:
|
||||
# up: 'WHITE_DYE:0'
|
||||
# ....
|
||||
# ...
|
||||
# nodes:
|
||||
# ....
|
||||
|
||||
@ -422,3 +422,23 @@ nodes:
|
||||
- "&eAdditional skill/weapon projectile damage +%6"
|
||||
1:
|
||||
- "&eAdditional skill/weapon projectile damage +%6"
|
||||
|
||||
# This section is to change display options for nodes and paths depending on:
|
||||
# - their shape: each path has a shape given its neighboring connections (left + up, )... kind of like a vanilla redstone wire.
|
||||
# - their state: is the node/path unlocked, locked, maxed out... ?
|
||||
#
|
||||
# All of this is to "hide" the grid pattern of the chest inventory UI and give the
|
||||
# impression of a clean 2D skill tree UI.
|
||||
#
|
||||
# This config section is optional; if you do not provide it the one provided in the skill tree CUSTOM GUI CONFIG will be used.
|
||||
#
|
||||
# Please refer to the default config file 'combat.yml' for syntax examples and explanations.
|
||||
#########################
|
||||
#display:
|
||||
# paths:
|
||||
# unlocked:
|
||||
# up: 'WHITE_DYE:0'
|
||||
# ....
|
||||
# ...
|
||||
# nodes:
|
||||
# ....
|
||||
|
||||
@ -422,3 +422,23 @@ nodes:
|
||||
- "&eAdditional on-hit weapon damage in +%2."
|
||||
1:
|
||||
- "&eAdditional on-hit weapon damage in +%2."
|
||||
|
||||
# This section is to change display options for nodes and paths depending on:
|
||||
# - their shape: each path has a shape given its neighboring connections (left + up, )... kind of like a vanilla redstone wire.
|
||||
# - their state: is the node/path unlocked, locked, maxed out... ?
|
||||
#
|
||||
# All of this is to "hide" the grid pattern of the chest inventory UI and give the
|
||||
# impression of a clean 2D skill tree UI.
|
||||
#
|
||||
# This config section is optional; if you do not provide it the one provided in the skill tree CUSTOM GUI CONFIG will be used.
|
||||
#
|
||||
# Please refer to the default config file 'combat.yml' for syntax examples and explanations.
|
||||
#########################
|
||||
#display:
|
||||
# paths:
|
||||
# unlocked:
|
||||
# up: 'WHITE_DYE:0'
|
||||
# ....
|
||||
# ...
|
||||
# nodes:
|
||||
# ....
|
||||
|
||||
Loading…
Reference in New Issue
Block a user