From e692499e879060e8d4b826538420dc8c66458807 Mon Sep 17 00:00:00 2001
From: Indyuce <cym.peyrat@yahoo.fr>
Date: Sun, 13 Sep 2020 12:44:24 +0200
Subject: [PATCH 1/4] !Last commits cleanup

---
 .../java/net/Indyuce/mmoitems/MMOItems.java   |  93 +++++++++----
 .../Indyuce/mmoitems/ability/Shadow_Veil.java |   3 +-
 .../Indyuce/mmoitems/api/ArrowParticles.java  |   8 +-
 .../net/Indyuce/mmoitems/api/ItemTier.java    |   2 +-
 .../api/crafting/CraftingStation.java         |  21 +--
 .../mmoitems/api/event/CraftMMOItemEvent.java |  23 ++--
 .../api/item/build/ItemStackBuilder.java      |   2 +-
 .../mmoitems/api/item/build/LoreBuilder.java  |  30 ++--
 .../api/item/template/MMOItemTemplate.java    |  10 +-
 .../mmoitems/api/item/util/ConfigItem.java    |  32 +++--
 .../mmoitems/api/util/PostLoadObject.java     |  31 -----
 .../mmoitems/api/util/TemplateMap.java        |  12 ++
 .../placeholders/MMOItemsPlaceholders.java    |  10 +-
 .../listener/DisableInteractions.java         | 128 +++++++++---------
 .../mmoitems/manager/DropTableManager.java    |   4 +-
 .../mmoitems/manager/LayoutManager.java       |  52 ++++---
 .../mmoitems/manager/TemplateManager.java     |  91 +++++++++----
 .../Indyuce/mmoitems/stat/DisplayName.java    |  45 ++----
 18 files changed, 315 insertions(+), 282 deletions(-)
 delete mode 100644 src/main/java/net/Indyuce/mmoitems/api/util/PostLoadObject.java

diff --git a/src/main/java/net/Indyuce/mmoitems/MMOItems.java b/src/main/java/net/Indyuce/mmoitems/MMOItems.java
index 114aa11a..6938cd50 100644
--- a/src/main/java/net/Indyuce/mmoitems/MMOItems.java
+++ b/src/main/java/net/Indyuce/mmoitems/MMOItems.java
@@ -1,5 +1,21 @@
 package net.Indyuce.mmoitems;
 
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+
+import javax.annotation.Nullable;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.plugin.java.JavaPlugin;
+
 import net.Indyuce.mmoitems.api.ConfigFile;
 import net.Indyuce.mmoitems.api.ItemTier;
 import net.Indyuce.mmoitems.api.SoulboundInfo;
@@ -9,13 +25,21 @@ import net.Indyuce.mmoitems.api.player.PlayerData;
 import net.Indyuce.mmoitems.command.MMOItemsCommandTreeRoot;
 import net.Indyuce.mmoitems.command.UpdateItemCommand;
 import net.Indyuce.mmoitems.command.completion.UpdateItemCompletion;
-import net.Indyuce.mmoitems.comp.*;
+import net.Indyuce.mmoitems.comp.AdvancedEnchantmentsHook;
+import net.Indyuce.mmoitems.comp.MMOItemsMetrics;
+import net.Indyuce.mmoitems.comp.MMOItemsRewardTypes;
+import net.Indyuce.mmoitems.comp.RealDualWieldHook;
+import net.Indyuce.mmoitems.comp.WorldEditSupport;
 import net.Indyuce.mmoitems.comp.eco.VaultSupport;
 import net.Indyuce.mmoitems.comp.flags.DefaultFlags;
 import net.Indyuce.mmoitems.comp.flags.FlagPlugin;
 import net.Indyuce.mmoitems.comp.flags.ResidenceFlags;
 import net.Indyuce.mmoitems.comp.flags.WorldGuardFlags;
-import net.Indyuce.mmoitems.comp.holograms.*;
+import net.Indyuce.mmoitems.comp.holograms.CMIPlugin;
+import net.Indyuce.mmoitems.comp.holograms.HologramSupport;
+import net.Indyuce.mmoitems.comp.holograms.HologramsPlugin;
+import net.Indyuce.mmoitems.comp.holograms.HolographicDisplaysPlugin;
+import net.Indyuce.mmoitems.comp.holograms.TrHologramPlugin;
 import net.Indyuce.mmoitems.comp.inventory.DefaultPlayerInventory;
 import net.Indyuce.mmoitems.comp.inventory.OrnamentPlayerInventory;
 import net.Indyuce.mmoitems.comp.inventory.PlayerInventory;
@@ -34,28 +58,38 @@ import net.Indyuce.mmoitems.comp.rpg.DefaultHook;
 import net.Indyuce.mmoitems.comp.rpg.RPGHandler;
 import net.Indyuce.mmoitems.gui.PluginInventory;
 import net.Indyuce.mmoitems.gui.listener.GuiListener;
-import net.Indyuce.mmoitems.listener.*;
-import net.Indyuce.mmoitems.manager.*;
+import net.Indyuce.mmoitems.listener.CraftingListener;
+import net.Indyuce.mmoitems.listener.CustomBlockListener;
+import net.Indyuce.mmoitems.listener.CustomSoundListener;
+import net.Indyuce.mmoitems.listener.DisableInteractions;
+import net.Indyuce.mmoitems.listener.DurabilityListener;
+import net.Indyuce.mmoitems.listener.ElementListener;
+import net.Indyuce.mmoitems.listener.ItemUse;
+import net.Indyuce.mmoitems.listener.PlayerListener;
+import net.Indyuce.mmoitems.manager.AbilityManager;
+import net.Indyuce.mmoitems.manager.BlockManager;
+import net.Indyuce.mmoitems.manager.ConfigManager;
+import net.Indyuce.mmoitems.manager.CraftingManager;
+import net.Indyuce.mmoitems.manager.DropTableManager;
+import net.Indyuce.mmoitems.manager.EntityManager;
+import net.Indyuce.mmoitems.manager.ItemManager;
+import net.Indyuce.mmoitems.manager.LayoutManager;
+import net.Indyuce.mmoitems.manager.PluginUpdateManager;
+import net.Indyuce.mmoitems.manager.RecipeManager;
+import net.Indyuce.mmoitems.manager.SetManager;
+import net.Indyuce.mmoitems.manager.StatManager;
+import net.Indyuce.mmoitems.manager.TemplateManager;
+import net.Indyuce.mmoitems.manager.TierManager;
+import net.Indyuce.mmoitems.manager.TypeManager;
+import net.Indyuce.mmoitems.manager.UpdaterManager;
+import net.Indyuce.mmoitems.manager.UpgradeManager;
+import net.Indyuce.mmoitems.manager.WorldGenManager;
 import net.mmogroup.mmolib.api.player.MMOPlayerData;
 import net.mmogroup.mmolib.version.SpigotPlugin;
-import org.apache.commons.lang.Validate;
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.entity.Player;
-import org.bukkit.event.HandlerList;
-import org.bukkit.event.Listener;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.plugin.java.JavaPlugin;
-
-import javax.annotation.Nullable;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
 
 public class MMOItems extends JavaPlugin {
 	public static MMOItems plugin;
- 
+
 	private final PluginUpdateManager pluginUpdateManager = new PluginUpdateManager();
 	private final CraftingManager stationRecipeManager = new CraftingManager();
 	private final AbilityManager abilityManager = new AbilityManager();
@@ -102,17 +136,17 @@ public class MMOItems extends JavaPlugin {
 				getLogger().log(Level.WARNING, "Could not initialize support with WorldEdit 7: " + exception.getMessage());
 			}
 
-		/*
-		 * stat manager must be initialized before MMOCore compatibility
-		 * initializes so that MMOCore can register its stats
-		 */
-
 		saveDefaultConfig();
+
+		/*
+		 * Stat manager must be initialized before MMOCore compatibility
+		 * initializes so that MMOCore can register its stats. Types and item
+		 * templates are also loaded as soon as MI is loaded so that other
+		 * plugins can load template references
+		 */
 		statManager = new StatManager();
-
 		typeManager.reload();
-
-		templateManager.loadCompatibility(); // explained why in method
+		templateManager.preloadTemplates();
 
 		if (Bukkit.getPluginManager().getPlugin("MMOCore") != null)
 			new MMOCoreMMOLoader();
@@ -137,14 +171,13 @@ public class MMOItems extends JavaPlugin {
 			getLogger().log(Level.INFO, "Hooked onto MMOInventory");
 		}
 
-
 		findRpgPlugin();
 
-		templateManager.reload();
-
 		tierManager = new TierManager();
 		setManager = new SetManager();
 		upgradeManager = new UpgradeManager();
+		templateManager.postload();
+
 		dropTableManager = new DropTableManager();
 		dynamicUpdater = new UpdaterManager();
 		worldGenManager = new WorldGenManager();
diff --git a/src/main/java/net/Indyuce/mmoitems/ability/Shadow_Veil.java b/src/main/java/net/Indyuce/mmoitems/ability/Shadow_Veil.java
index e9c1d448..b3227912 100644
--- a/src/main/java/net/Indyuce/mmoitems/ability/Shadow_Veil.java
+++ b/src/main/java/net/Indyuce/mmoitems/ability/Shadow_Veil.java
@@ -118,8 +118,7 @@ public class Shadow_Veil extends Ability implements Listener {
 
 		@EventHandler
 		public void cancelMobTarget(EntityTargetEvent event) {
-		    // FIXME NPE for some reason, not sure if getTarget or player is null. Doubt its getTarget but you never know. https://git.lumine.io/mythiccraft/mmoitems/-/issues/126
-			if (event.getTarget().equals(player))
+			if (player.equals(event.getTarget()))
 				event.setCancelled(true);
 		}
 	}
diff --git a/src/main/java/net/Indyuce/mmoitems/api/ArrowParticles.java b/src/main/java/net/Indyuce/mmoitems/api/ArrowParticles.java
index 99bd6ac3..761be3a8 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/ArrowParticles.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/ArrowParticles.java
@@ -42,11 +42,9 @@ public class ArrowParticles extends BukkitRunnable {
 			return;
 		}
 
-		if (color != null)
-			if (particle.getDataType() == DustOptions.class)
-				arrow.getWorld().spawnParticle(particle, arrow.getLocation().add(0, .25, 0), amount, offset, offset, offset, new Particle.DustOptions(color, 1));
-			else
-				arrow.getWorld().spawnParticle(particle, arrow.getLocation().add(0, .25, 0), amount, offset, offset, offset, color);
+		if (color != null && particle.getDataType() == DustOptions.class)
+			arrow.getWorld().spawnParticle(particle, arrow.getLocation().add(0, .25, 0), amount, offset, offset, offset,
+					new Particle.DustOptions(color, 1));
 		else
 			arrow.getWorld().spawnParticle(particle, arrow.getLocation().add(0, .25, 0), amount, offset, offset, offset, speed);
 	}
diff --git a/src/main/java/net/Indyuce/mmoitems/api/ItemTier.java b/src/main/java/net/Indyuce/mmoitems/api/ItemTier.java
index cf9d4c50..c135ad76 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/ItemTier.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/ItemTier.java
@@ -36,7 +36,7 @@ public class ItemTier {
 
 	public ItemTier(ConfigurationSection config) {
 		id = config.getName().toUpperCase().replace("-", "_");
-		name = config.getString("name");
+		name = MMOLib.plugin.parseColors(config.getString("name"));
 		deconstruct = config.contains("deconstruct-item") ? new DropTable(config.getConfigurationSection("deconstruct-item")) : null;
 		unidentificationInfo = new UnidentificationInfo(config.getConfigurationSection("unidentification"));
 
diff --git a/src/main/java/net/Indyuce/mmoitems/api/crafting/CraftingStation.java b/src/main/java/net/Indyuce/mmoitems/api/crafting/CraftingStation.java
index 58bfc30b..f9727745 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/crafting/CraftingStation.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/crafting/CraftingStation.java
@@ -1,5 +1,17 @@
 package net.Indyuce.mmoitems.api.crafting;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.Sound;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.configuration.file.FileConfiguration;
+
 import net.Indyuce.mmoitems.MMOItems;
 import net.Indyuce.mmoitems.api.crafting.recipe.CraftingRecipe;
 import net.Indyuce.mmoitems.api.crafting.recipe.Recipe;
@@ -7,15 +19,8 @@ import net.Indyuce.mmoitems.api.crafting.recipe.Recipe.RecipeOption;
 import net.Indyuce.mmoitems.api.crafting.recipe.RecipeInfo;
 import net.Indyuce.mmoitems.api.crafting.recipe.UpgradingRecipe;
 import net.Indyuce.mmoitems.api.player.PlayerData;
-import net.Indyuce.mmoitems.api.util.PostLoadObject;
 import net.mmogroup.mmolib.MMOLib;
-import org.apache.commons.lang.Validate;
-import org.bukkit.Sound;
-import org.bukkit.configuration.ConfigurationSection;
-import org.bukkit.configuration.file.FileConfiguration;
-
-import java.util.*;
-import java.util.logging.Level;
+import net.mmogroup.mmolib.api.util.PostLoadObject;
 
 public class CraftingStation extends PostLoadObject {
 	private final String id, name;
diff --git a/src/main/java/net/Indyuce/mmoitems/api/event/CraftMMOItemEvent.java b/src/main/java/net/Indyuce/mmoitems/api/event/CraftMMOItemEvent.java
index 1dbccc53..97ec75e9 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/event/CraftMMOItemEvent.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/event/CraftMMOItemEvent.java
@@ -8,21 +8,22 @@ import net.Indyuce.mmoitems.api.player.PlayerData;
 public class CraftMMOItemEvent extends PlayerDataEvent {
 	private static final HandlerList handlers = new HandlerList();
 
-	private ItemStack stack;
-	
-	public CraftMMOItemEvent(PlayerData playerData, ItemStack stack) {
+	private ItemStack result;
+
+	public CraftMMOItemEvent(PlayerData playerData, ItemStack result) {
 		super(playerData);
-		this.stack = stack;
-	}
-	
-	public ItemStack getResult() {
-		return stack;
+
+		this.result = result;
 	}
 
-	public void setStack(ItemStack stack) {
-		this.stack = stack;
+	public ItemStack getResult() {
+		return result;
 	}
-	
+
+	public void setResult(ItemStack result) {
+		this.result = result;
+	}
+
 	public HandlerList getHandlers() {
 		return handlers;
 	}
diff --git a/src/main/java/net/Indyuce/mmoitems/api/item/build/ItemStackBuilder.java b/src/main/java/net/Indyuce/mmoitems/api/item/build/ItemStackBuilder.java
index c865bba0..a5c62e60 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/item/build/ItemStackBuilder.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/item/build/ItemStackBuilder.java
@@ -124,7 +124,7 @@ public class ItemStackBuilder {
 			lore.insert("lore", parsed);
 		}
 
-		meta.setLore(lore.build().toStringList());
+		meta.setLore(lore.build());
 
 		/*
 		 * This tag is added to entirely override default vanilla item attribute
diff --git a/src/main/java/net/Indyuce/mmoitems/api/item/build/LoreBuilder.java b/src/main/java/net/Indyuce/mmoitems/api/item/build/LoreBuilder.java
index 4e3aaf7f..48ea2742 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/item/build/LoreBuilder.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/item/build/LoreBuilder.java
@@ -91,7 +91,7 @@ public class LoreBuilder {
 	 *         have been inserted in the lore. It cleans all unused lore format
 	 *         # lines as well as lore bars
 	 */
-	public LoreBuilder build() {
+	public List<String> build() {
 
 		/*
 		 * loops backwards to remove all unused bars in one iteration only,
@@ -114,29 +114,21 @@ public class LoreBuilder {
 		}
 
 		/*
-		 * clear bar codes and parse chat colors only ONCE
-		 * the bars have been successfully calculated
+		 * clear bar codes and parse chat colors only ONCE the bars have been
+		 * successfully calculated
 		 * 
-		 * NEW: also finalize the lore by breaking
-		 * lines with the \n escape character
+		 * NEW: also finalize the lore by breaking lines with the \n escape
+		 * character
 		 */
-		final List<String> finalLore = new ArrayList<>();	
-		for (int i = 0; i < lore.size(); i++) {
-			for(final String s : MMOLib.plugin.parseColors(lore.get(i)
-					.replace("{bar}", "").replace("{sbar}", "")).split("\\\\n"))
-				finalLore.add(s);
-		}
-		
-		lore.clear();
-		lore.addAll(finalLore);
-		return this;
+		final List<String> cleaned = new ArrayList<>();
+		for (int i = 0; i < lore.size(); i++)
+			for (final String s : MMOLib.plugin.parseColors(lore.get(i).replace("{bar}", "").replace("{sbar}", "")).split("\\\\n"))
+				cleaned.add(s);
+
+		return cleaned;
 	}
 
 	private boolean isBar(String str) {
 		return str.startsWith("{bar}") || str.startsWith("{sbar}");
 	}
-
-	public List<String> toStringList() {
-		return lore;
-	}
 }
diff --git a/src/main/java/net/Indyuce/mmoitems/api/item/template/MMOItemTemplate.java b/src/main/java/net/Indyuce/mmoitems/api/item/template/MMOItemTemplate.java
index 551bc1ef..015f8194 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/item/template/MMOItemTemplate.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/item/template/MMOItemTemplate.java
@@ -20,8 +20,9 @@ import net.Indyuce.mmoitems.api.item.build.MMOItemBuilder;
 import net.Indyuce.mmoitems.api.player.RPGPlayer;
 import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
 import net.Indyuce.mmoitems.stat.type.ItemStat;
+import net.mmogroup.mmolib.api.util.PostLoadObject;
 
-public class MMOItemTemplate implements ItemReference {
+public class MMOItemTemplate extends PostLoadObject implements ItemReference {
 	private final Type type;
 	private final String id;
 
@@ -42,6 +43,8 @@ public class MMOItemTemplate implements ItemReference {
 	 *            different item types share the same ID
 	 */
 	public MMOItemTemplate(Type type, String id) {
+		super(null);
+
 		this.type = type;
 		this.id = id;
 	}
@@ -55,11 +58,14 @@ public class MMOItemTemplate implements ItemReference {
 	 *            The config file read to load the template
 	 */
 	public MMOItemTemplate(Type type, ConfigurationSection config) {
-		Validate.notNull(config, "Could not load template config");
+		super(config);
 
 		this.type = type;
 		this.id = config.getName().toUpperCase().replace("-", "_").replace(" ", "_");
+	}
 
+	@Override
+	protected void whenPostLoaded(ConfigurationSection config) {
 		if (config.contains("option"))
 			for (TemplateOption option : TemplateOption.values())
 				if (config.getBoolean("option." + option.name().toLowerCase().replace("_", "-")))
diff --git a/src/main/java/net/Indyuce/mmoitems/api/item/util/ConfigItem.java b/src/main/java/net/Indyuce/mmoitems/api/item/util/ConfigItem.java
index e36c8453..f9a4799e 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/item/util/ConfigItem.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/item/util/ConfigItem.java
@@ -21,7 +21,6 @@ import java.util.List;
 
 public class ConfigItem {
 	private final String id;
-	private final Material material;
 	private final ItemStack icon;
 
 	// updated when the plugin reloads
@@ -33,16 +32,27 @@ public class ConfigItem {
 
 	public static final ConfigItem CONFIRM = new ConfigItem("CONFIRM", VersionMaterial.GREEN_STAINED_GLASS_PANE.toMaterial(), "&aConfirm");
 	public static final ConfigItem FILL = new ConfigItem("FILL", VersionMaterial.GRAY_STAINED_GLASS_PANE.toMaterial(), "&8");
-	public static final CustomSkull PREVIOUS_PAGE = new CustomSkull("PREVIOUS_PAGE", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmQ2OWUwNmU1ZGFkZmQ4NGU1ZjNkMWMyMTA2M2YyNTUzYjJmYTk0NWVlMWQ0ZDcxNTJmZGM1NDI1YmMxMmE5In19fQ==", "&aPrevious Page");
-	public static final CustomSkull NEXT_PAGE = new CustomSkull("NEXT_PAGE", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTliZjMyOTJlMTI2YTEwNWI1NGViYTcxM2FhMWIxNTJkNTQxYTFkODkzODgyOWM1NjM2NGQxNzhlZDIyYmYifX19", "&aNext Page");
-	public static final CustomSkull PREVIOUS_IN_QUEUE = new CustomSkull("PREVIOUS_IN_QUEUE", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmQ2OWUwNmU1ZGFkZmQ4NGU1ZjNkMWMyMTA2M2YyNTUzYjJmYTk0NWVlMWQ0ZDcxNTJmZGM1NDI1YmMxMmE5In19fQ==", "&aPrevious");
-	public static final CustomSkull NEXT_IN_QUEUE = new CustomSkull("NEXT_IN_QUEUE", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTliZjMyOTJlMTI2YTEwNWI1NGViYTcxM2FhMWIxNTJkNTQxYTFkODkzODgyOWM1NjM2NGQxNzhlZDIyYmYifX19", "&aNext");
-	public static final CustomSkull BACK = new CustomSkull("BACK", "eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmQ2OWUwNmU1ZGFkZmQ4NGU1ZjNkMWMyMTA2M2YyNTUzYjJmYTk0NWVlMWQ0ZDcxNTJmZGM1NDI1YmMxMmE5In19fQ==", "&aBack");
+	public static final CustomSkull PREVIOUS_PAGE = new CustomSkull("PREVIOUS_PAGE",
+			"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmQ2OWUwNmU1ZGFkZmQ4NGU1ZjNkMWMyMTA2M2YyNTUzYjJmYTk0NWVlMWQ0ZDcxNTJmZGM1NDI1YmMxMmE5In19fQ==",
+			"&aPrevious Page");
+	public static final CustomSkull NEXT_PAGE = new CustomSkull("NEXT_PAGE",
+			"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTliZjMyOTJlMTI2YTEwNWI1NGViYTcxM2FhMWIxNTJkNTQxYTFkODkzODgyOWM1NjM2NGQxNzhlZDIyYmYifX19",
+			"&aNext Page");
+	public static final CustomSkull PREVIOUS_IN_QUEUE = new CustomSkull("PREVIOUS_IN_QUEUE",
+			"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmQ2OWUwNmU1ZGFkZmQ4NGU1ZjNkMWMyMTA2M2YyNTUzYjJmYTk0NWVlMWQ0ZDcxNTJmZGM1NDI1YmMxMmE5In19fQ==",
+			"&aPrevious");
+	public static final CustomSkull NEXT_IN_QUEUE = new CustomSkull("NEXT_IN_QUEUE",
+			"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvMTliZjMyOTJlMTI2YTEwNWI1NGViYTcxM2FhMWIxNTJkNTQxYTFkODkzODgyOWM1NjM2NGQxNzhlZDIyYmYifX19",
+			"&aNext");
+	public static final CustomSkull BACK = new CustomSkull("BACK",
+			"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvYmQ2OWUwNmU1ZGFkZmQ4NGU1ZjNkMWMyMTA2M2YyNTUzYjJmYTk0NWVlMWQ0ZDcxNTJmZGM1NDI1YmMxMmE5In19fQ==",
+			"&aBack");
 	public static final CraftingRecipeDisplay CRAFTING_RECIPE_DISPLAY = new CraftingRecipeDisplay();
 	public static final UpgradingRecipeDisplay UPGRADING_RECIPE_DISPLAY = new UpgradingRecipeDisplay();
 	public static final QueueItemDisplay QUEUE_ITEM_DISPLAY = new QueueItemDisplay();
 
-	public static final ConfigItem[] values = { CONFIRM, FILL, PREVIOUS_PAGE, NEXT_PAGE, PREVIOUS_IN_QUEUE, NEXT_IN_QUEUE, BACK, CRAFTING_RECIPE_DISPLAY, UPGRADING_RECIPE_DISPLAY, QUEUE_ITEM_DISPLAY };
+	public static final ConfigItem[] values = { CONFIRM, FILL, PREVIOUS_PAGE, NEXT_PAGE, PREVIOUS_IN_QUEUE, NEXT_IN_QUEUE, BACK,
+			CRAFTING_RECIPE_DISPLAY, UPGRADING_RECIPE_DISPLAY, QUEUE_ITEM_DISPLAY };
 
 	public ConfigItem(String id, Material material) {
 		this(id, material, null);
@@ -53,7 +63,6 @@ public class ConfigItem {
 		Validate.notNull(material, "Material cannot be null");
 
 		this.id = id;
-		this.material = material;
 		this.icon = new ItemStack(material);
 		this.name = name;
 		this.lore = Arrays.asList(lore);
@@ -70,7 +79,6 @@ public class ConfigItem {
 
 		icon = MMOUtils.readIcon(config.getString("material"));
 
-		material = icon.getType();
 		name = config.getString("name", "");
 		lore = config.getStringList("lore");
 
@@ -96,7 +104,7 @@ public class ConfigItem {
 
 	public void updateItem() {
 		setItem(icon);
-		if (material == Material.AIR)
+		if (icon.getType() == Material.AIR)
 			return;
 
 		ItemMeta meta = item.getItemMeta();
@@ -113,10 +121,6 @@ public class ConfigItem {
 		item = MMOLib.plugin.getVersion().getWrapper().getNBTItem(item).addTag(new ItemTag("ItemId", id)).toItem();
 	}
 
-	public Material getMaterial() {
-		return material;
-	}
-
 	public String getName() {
 		return name;
 	}
diff --git a/src/main/java/net/Indyuce/mmoitems/api/util/PostLoadObject.java b/src/main/java/net/Indyuce/mmoitems/api/util/PostLoadObject.java
deleted file mode 100644
index 2ac0076d..00000000
--- a/src/main/java/net/Indyuce/mmoitems/api/util/PostLoadObject.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package net.Indyuce.mmoitems.api.util;
-
-import org.bukkit.configuration.ConfigurationSection;
-
-public abstract class PostLoadObject {
-	private ConfigurationSection config;
-
-	/**
-	 * Objects which must load some data afterwards, like quests which must load
-	 * their parent quests after all quests were initialized or classes which
-	 * must load their subclasses
-	 * 
-	 * @param config
-	 *            Configuration section which must be cached during a small
-	 *            period of time till the rest of the data is loaded
-	 */
-	public PostLoadObject(ConfigurationSection config) {
-		this.config = config;
-	}
-
-	public void postLoad() {
-		whenPostLoaded(config);
-
-		/*
-		 * clean config object for garbage collection
-		 */
-		config = null;
-	}
-
-	protected abstract void whenPostLoaded(ConfigurationSection config);
-}
\ No newline at end of file
diff --git a/src/main/java/net/Indyuce/mmoitems/api/util/TemplateMap.java b/src/main/java/net/Indyuce/mmoitems/api/util/TemplateMap.java
index 9a63f8ab..2571be21 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/util/TemplateMap.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/util/TemplateMap.java
@@ -6,6 +6,7 @@ import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Consumer;
 
 import org.apache.commons.lang.Validate;
 
@@ -78,6 +79,17 @@ public class TemplateMap<C> {
 		typeMap.get(type.getId()).idMap.put(id, value);
 	}
 
+	/**
+	 * Applies a specific consumer for every template. This is used to postload
+	 * all templates when MMOItems enables
+	 * 
+	 * @param action
+	 *            Action performed for every registered template
+	 */
+	public void forEach(Consumer<C> action) {
+		typeMap.values().forEach(submap -> submap.idMap.values().forEach(action));
+	}
+
 	/**
 	 * @return Collects all the values registered in this template map.
 	 */
diff --git a/src/main/java/net/Indyuce/mmoitems/comp/parse/placeholders/MMOItemsPlaceholders.java b/src/main/java/net/Indyuce/mmoitems/comp/parse/placeholders/MMOItemsPlaceholders.java
index 9e19f7d2..5d6ee35b 100644
--- a/src/main/java/net/Indyuce/mmoitems/comp/parse/placeholders/MMOItemsPlaceholders.java
+++ b/src/main/java/net/Indyuce/mmoitems/comp/parse/placeholders/MMOItemsPlaceholders.java
@@ -51,11 +51,10 @@ public class MMOItemsPlaceholders extends PlaceholderExpansion {
 	@Override
 	public String onRequest(@Nullable OfflinePlayer player, @NotNull String identifier) {
 		// registering before identifier.startsWith("stat_") to prevent issues
-		// i don't register it in the starts with condition because it will mess with
-		// substring
+		// i don't register it in the starts with condition because it will mess
+		// with substring
 		if (identifier.equals("stat_defense_percent"))
-			return twoDigits.format(
-					new DamageReduction.DefenseCalculator(MMOPlayerData.get(player)).getReductionPercent()) + "%";
+			return twoDigits.format(100 - new DamageReduction.DefenseCalculator(MMOPlayerData.get(player)).getAppliedDamage(100)) + "%";
 		if (identifier.startsWith("stat_")) {
 			ItemStat stat = MMOItems.plugin.getStats().get(identifier.substring(5).toUpperCase());
 			if (stat != null)
@@ -64,8 +63,7 @@ public class MMOItemsPlaceholders extends PlaceholderExpansion {
 
 		if (identifier.startsWith("ability_cd_")) {
 			PlayerData data = PlayerData.get(player);
-			return data.hasCooldownInfo(identifier.substring(11))
-					? oneDigit.format(data.getCooldownInfo(identifier.substring(11)).getRemaining())
+			return data.hasCooldownInfo(identifier.substring(11)) ? oneDigit.format(data.getCooldownInfo(identifier.substring(11)).getRemaining())
 					: "0";
 		}
 
diff --git a/src/main/java/net/Indyuce/mmoitems/listener/DisableInteractions.java b/src/main/java/net/Indyuce/mmoitems/listener/DisableInteractions.java
index 62b0e1a9..a0b55123 100644
--- a/src/main/java/net/Indyuce/mmoitems/listener/DisableInteractions.java
+++ b/src/main/java/net/Indyuce/mmoitems/listener/DisableInteractions.java
@@ -32,45 +32,48 @@ public class DisableInteractions implements Listener {
 			return;
 
 		NBTItem item = NBTItem.get(event.getCurrentItem());
-		if (item.hasType() && (MMOItems.plugin.getConfig().getBoolean("disable-interactions.repair") || item.getBoolean("MMOITEMS_DISABLE_REPAIRING")))
+		if (item.hasType()
+				&& (MMOItems.plugin.getConfig().getBoolean("disable-interactions.repair") || item.getBoolean("MMOITEMS_DISABLE_REPAIRING")))
 			event.setCancelled(true);
 	}
 
-        // grindstone
-        @EventHandler
-        public void b(InventoryClickEvent event) {
-                if (MMOLib.plugin.getVersion().isBelowOrEqual(1, 13))
-                        return;
+	// grindstone
+	@EventHandler
+	public void b(InventoryClickEvent event) {
+		if (MMOLib.plugin.getVersion().isBelowOrEqual(1, 13))
+			return;
 
-                Inventory inv = event.getClickedInventory();
-                if (inv == null || inv.getType() != InventoryType.GRINDSTONE || event.getSlot() != 2)
-                        return;
+		Inventory inv = event.getClickedInventory();
+		if (inv == null || inv.getType() != InventoryType.GRINDSTONE || event.getSlot() != 2)
+			return;
 
-                NBTItem item = NBTItem.get(event.getCurrentItem());
-                if (item.hasType() && (MMOItems.plugin.getConfig().getBoolean("disable-interactions.repair") || item.getBoolean("MMOITEMS_DISABLE_REPAIRING")))
-                        event.setCancelled(true);
-        }
+		NBTItem item = NBTItem.get(event.getCurrentItem());
+		if (item.hasType()
+				&& (MMOItems.plugin.getConfig().getBoolean("disable-interactions.repair") || item.getBoolean("MMOITEMS_DISABLE_REPAIRING")))
+			event.setCancelled(true);
+	}
 
-        // smithing table
-        @EventHandler
-        public void c(InventoryClickEvent event) {
-                if (MMOLib.plugin.getVersion().isBelowOrEqual(1, 15))
-                        return;
+	// smithing table
+	@EventHandler
+	public void c(InventoryClickEvent event) {
+		if (MMOLib.plugin.getVersion().isBelowOrEqual(1, 15))
+			return;
 
-                Inventory inv = event.getClickedInventory();
-                if (inv == null || inv.getType() != InventoryType.SMITHING || event.getSlot() != 2)
-                        return;
+		Inventory inv = event.getClickedInventory();
+		if (inv == null || inv.getType() != InventoryType.SMITHING || event.getSlot() != 2)
+			return;
 
-                NBTItem item = NBTItem.get(event.getCurrentItem());
-                if (item.hasType() && (MMOItems.plugin.getConfig().getBoolean("disable-interactions.smith") || item.getBoolean("MMOITEMS_DISABLE_SMITHING")))
-                        event.setCancelled(true);
-        }
+		NBTItem item = NBTItem.get(event.getCurrentItem());
+		if (item.hasType() && (MMOItems.plugin.getConfig().getBoolean("disable-interactions.smith") || item.getBoolean("MMOITEMS_DISABLE_SMITHING")))
+			event.setCancelled(true);
+	}
 
 	// enchanting tables
 	@EventHandler
 	public void d(EnchantItemEvent event) {
 		NBTItem item = NBTItem.get(event.getItem());
-		if (item.hasType() && (MMOItems.plugin.getConfig().getBoolean("disable-interactions.enchant") || item.getBoolean("MMOITEMS_DISABLE_ENCHANTING")))
+		if (item.hasType()
+				&& (MMOItems.plugin.getConfig().getBoolean("disable-interactions.enchant") || item.getBoolean("MMOITEMS_DISABLE_ENCHANTING")))
 			event.setCancelled(true);
 	}
 
@@ -93,31 +96,33 @@ public class DisableInteractions implements Listener {
 			event.setCancelled(true);
 	}
 
-        // interaction (entity)
-        @EventHandler
-        public void g(PlayerInteractEntityEvent event) {
-                if (event.getRightClicked() instanceof ArmorStand)
-                        return;
-    
-                NBTItem item = NBTItem.get(event.getHand() == EquipmentSlot.OFF_HAND ? event.getPlayer().getInventory().getItemInOffHand() : event.getPlayer().getInventory().getItemInMainHand());
-                if (item.getBoolean("MMOITEMS_DISABLE_INTERACTION"))
-                        event.setCancelled(true);
-        }
-    
-        // interaction (consume)
-        @EventHandler
-        public void h(PlayerItemConsumeEvent event) {
-            NBTItem item = NBTItem.get(event.getItem());
-            if (item.getBoolean("MMOITEMS_DISABLE_INTERACTION"))
-                    event.setCancelled(true);
-        }
+	// interaction (entity)
+	@EventHandler
+	public void g(PlayerInteractEntityEvent event) {
+		if (event.getRightClicked() instanceof ArmorStand)
+			return;
+
+		NBTItem item = NBTItem.get(event.getHand() == EquipmentSlot.OFF_HAND ? event.getPlayer().getInventory().getItemInOffHand()
+				: event.getPlayer().getInventory().getItemInMainHand());
+		if (item.getBoolean("MMOITEMS_DISABLE_INTERACTION"))
+			event.setCancelled(true);
+	}
+
+	// interaction (consume)
+	@EventHandler
+	public void h(PlayerItemConsumeEvent event) {
+		NBTItem item = NBTItem.get(event.getItem());
+		if (item.getBoolean("MMOITEMS_DISABLE_INTERACTION"))
+			event.setCancelled(true);
+	}
 
 	// workbench
 	@EventHandler
 	public void i(CraftItemEvent event) {
-		if(event.getRecipe() instanceof Keyed)
-			if(((Keyed) event.getRecipe()).getKey().getNamespace().equalsIgnoreCase("mmoitems")) return;
-		
+		if (event.getRecipe() instanceof Keyed)
+			if (((Keyed) event.getRecipe()).getKey().getNamespace().equalsIgnoreCase("mmoitems"))
+				return;
+
 		boolean disableCrafting = MMOItems.plugin.getConfig().getBoolean("disable-interactions.craft");
 		for (ItemStack item : event.getInventory().getMatrix()) {
 			NBTItem nbtItem = NBTItem.get(item);
@@ -146,23 +151,24 @@ public class DisableInteractions implements Listener {
 			return;
 
 		NBTItem arrow = NBTItem.get(stack);
-		if (arrow.hasType() && MMOItems.plugin.getConfig().getBoolean("disable-interactions.arrow-shooting") || arrow.getBoolean("MMOITEMS_DISABLE_ARROW_SHOOTING"))
+		if (arrow.hasType() && MMOItems.plugin.getConfig().getBoolean("disable-interactions.arrow-shooting")
+				|| arrow.getBoolean("MMOITEMS_DISABLE_ARROW_SHOOTING"))
 			event.setCancelled(true);
 	}
 
-        private int firstArrow(Player player) {
+	private int firstArrow(Player player) {
 
-                // check offhand first
-                if (player.getInventory().getItemInOffHand() != null && player.getInventory().getItemInOffHand().getType().name().contains("ARROW"))
-                        return 40;
+		// check offhand first
+		if (player.getInventory().getItemInOffHand() != null && player.getInventory().getItemInOffHand().getType().name().contains("ARROW"))
+			return 40;
 
-                // check for every slot
-                ItemStack[] storage = player.getInventory().getStorageContents();
-                for (int j = 0; j < storage.length; j++) {
-                        ItemStack item = storage[j];
-                        if (item != null && item.getType().name().contains("ARROW"))
-                                return j;
-                }
-                return -1;
-        }
+		// check for every slot
+		ItemStack[] storage = player.getInventory().getStorageContents();
+		for (int j = 0; j < storage.length; j++) {
+			ItemStack item = storage[j];
+			if (item != null && item.getType().name().contains("ARROW"))
+				return j;
+		}
+		return -1;
+	}
 }
diff --git a/src/main/java/net/Indyuce/mmoitems/manager/DropTableManager.java b/src/main/java/net/Indyuce/mmoitems/manager/DropTableManager.java
index c4a4accd..ac68d369 100644
--- a/src/main/java/net/Indyuce/mmoitems/manager/DropTableManager.java
+++ b/src/main/java/net/Indyuce/mmoitems/manager/DropTableManager.java
@@ -79,7 +79,7 @@ public class DropTableManager implements Listener {
 	}
 
 	@EventHandler
-	public void blockDrops(EntityDeathEvent event) {
+	public void entityDrops(EntityDeathEvent event) {
 		LivingEntity entity = event.getEntity();
 		Player killer = entity.getKiller();
 		if (killer != null && killer.hasMetadata("NPC"))
@@ -89,7 +89,7 @@ public class DropTableManager implements Listener {
 	}
 
 	@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
-	public void entityDrops(BlockBreakEvent event) {
+	public void blockDrops(BlockBreakEvent event) {
 		Player player = event.getPlayer();
 		if (player == null || player.getGameMode() == GameMode.CREATIVE)
 			return;
diff --git a/src/main/java/net/Indyuce/mmoitems/manager/LayoutManager.java b/src/main/java/net/Indyuce/mmoitems/manager/LayoutManager.java
index 44e9adc2..da1086d7 100644
--- a/src/main/java/net/Indyuce/mmoitems/manager/LayoutManager.java
+++ b/src/main/java/net/Indyuce/mmoitems/manager/LayoutManager.java
@@ -1,41 +1,39 @@
 package net.Indyuce.mmoitems.manager;
 
-import net.Indyuce.mmoitems.MMOItems;
-import net.Indyuce.mmoitems.api.crafting.Layout;
-import org.bukkit.configuration.file.YamlConfiguration;
-
 import java.io.File;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.logging.Level;
 
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import net.Indyuce.mmoitems.MMOItems;
+import net.Indyuce.mmoitems.api.crafting.Layout;
+
 public class LayoutManager {
-    private final Map<String, Layout> layouts = new HashMap<>();
+	private final Map<String, Layout> layouts = new HashMap<>();
 
-    public LayoutManager() {
-    }
+	public void reload() {
+		layouts.clear();
+		for (File file : new File(MMOItems.plugin.getDataFolder() + "/layouts").listFiles())
+			try {
+				Layout layout = new Layout(file.getName().substring(0, file.getName().length() - 4), YamlConfiguration.loadConfiguration(file));
+				layouts.put(layout.getId(), layout);
+			} catch (IllegalArgumentException exception) {
+				MMOItems.plugin.getLogger().log(Level.WARNING, "Could not load layout '" + file.getName() + "': " + exception.getMessage());
+			}
+	}
 
-    public void reload() {
-        layouts.clear();
-        for (File file : new File(MMOItems.plugin.getDataFolder() + "/layouts").listFiles())
-            try {
-                Layout layout = new Layout(file.getName().substring(0, file.getName().length() - 4), YamlConfiguration.loadConfiguration(file));
-                layouts.put(layout.getId(), layout);
-            } catch (IllegalArgumentException exception) {
-                MMOItems.plugin.getLogger().log(Level.WARNING, "Could not load layout '" + file.getName() + "': " + exception.getMessage());
-            }
-    }
+	public boolean hasLayout(String id) {
+		return layouts.containsKey(id);
+	}
 
-    public boolean hasLayout(String id) {
-        return layouts.containsKey(id);
-    }
+	public Collection<Layout> getLayouts() {
+		return layouts.values();
+	}
 
-    public Collection<Layout> getLayouts() {
-        return layouts.values();
-    }
-
-    public Layout getLayout(String id) {
-        return layouts.getOrDefault(id, layouts.get("default"));
-    }
+	public Layout getLayout(String id) {
+		return layouts.getOrDefault(id, layouts.get("default"));
+	}
 }
diff --git a/src/main/java/net/Indyuce/mmoitems/manager/TemplateManager.java b/src/main/java/net/Indyuce/mmoitems/manager/TemplateManager.java
index d2c20b0a..2396b0fc 100644
--- a/src/main/java/net/Indyuce/mmoitems/manager/TemplateManager.java
+++ b/src/main/java/net/Indyuce/mmoitems/manager/TemplateManager.java
@@ -1,5 +1,16 @@
 package net.Indyuce.mmoitems.manager;
 
+import java.io.File;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.logging.Level;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+
 import net.Indyuce.mmoitems.MMOItems;
 import net.Indyuce.mmoitems.api.ConfigFile;
 import net.Indyuce.mmoitems.api.ItemTier;
@@ -7,16 +18,6 @@ import net.Indyuce.mmoitems.api.Type;
 import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
 import net.Indyuce.mmoitems.api.item.template.TemplateModifier;
 import net.Indyuce.mmoitems.api.util.TemplateMap;
-import org.apache.commons.lang.Validate;
-import org.bukkit.configuration.file.FileConfiguration;
-import org.bukkit.configuration.file.YamlConfiguration;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-import java.util.logging.Level;
 
 public class TemplateManager {
 
@@ -184,6 +185,59 @@ public class TemplateManager {
 		return (int) found;
 	}
 
+	/**
+	 * Templates must be loaded whenever MMOItems enables so that other plugins
+	 * like MMOCore can load template references in drop items or other objects.
+	 * Template data is only loaded when MMOItems enables, once sets, tiers..
+	 * are initialized
+	 */
+	public void preloadTemplates() {
+		templates.clear();
+
+		for (Type type : MMOItems.plugin.getTypes().getAll()) {
+			FileConfiguration config = type.getConfigFile().getConfig();
+			for (String key : config.getKeys(false))
+				try {
+					registerTemplate(new MMOItemTemplate(type, key));
+				} catch (IllegalArgumentException exception) {
+					MMOItems.plugin.getLogger().log(Level.INFO, "Could not preload item template '" + key + "': " + exception.getMessage());
+				}
+		}
+	}
+
+	/**
+	 * Loads item generator modifiers and post load item templates.
+	 */
+	public void postload() {
+
+		MMOItems.plugin.getLogger().log(Level.INFO, "Loading template modifiers, please wait..");
+		for (File file : new File(MMOItems.plugin.getDataFolder() + "/modifiers").listFiles()) {
+			FileConfiguration config = YamlConfiguration.loadConfiguration(file);
+			for (String key : config.getKeys(false))
+				try {
+					TemplateModifier modifier = new TemplateModifier(config.getConfigurationSection(key));
+					modifiers.put(modifier.getId(), modifier);
+				} catch (IllegalArgumentException exception) {
+					MMOItems.plugin.getLogger().log(Level.INFO, "Could not load template modifier '" + key + "': " + exception.getMessage());
+				}
+		}
+
+		MMOItems.plugin.getLogger().log(Level.INFO, "Loading item templates, please wait..");
+		templates.forEach(template -> {
+			try {
+				template.postLoad();
+			} catch (IllegalArgumentException exception) {
+				MMOItems.plugin.getLogger().log(Level.INFO, "Could not load item template '" + template.getId() + "': " + exception.getMessage());
+			}
+		});
+	}
+
+	/**
+	 * Reloads the item templates. This is the method used to reload the manager
+	 * when the server is already running. It clears all the maps and loads
+	 * everything again. Template references in other plugins like MMOCore must
+	 * be refreshed afterwards.
+	 */
 	public void reload() {
 		templates.clear();
 		modifiers.clear();
@@ -211,21 +265,4 @@ public class TemplateManager {
 				}
 		}
 	}
-	// this loads dummy items for on load so
-	// plugins that enable before mmoitems that use
-	// items (mmocore) don't error out and need
-	// a reload
-	public void loadCompatibility() {
-		templates.clear();
-
-		for (Type type : MMOItems.plugin.getTypes().getAll()) {
-			FileConfiguration config = type.getConfigFile().getConfig();
-			for (String key : config.getKeys(false))
-				try {
-					registerTemplate(new MMOItemTemplate(type, key));
-				} catch (IllegalArgumentException ignored) {
-
-				}
-		}
-	}
 }
diff --git a/src/main/java/net/Indyuce/mmoitems/stat/DisplayName.java b/src/main/java/net/Indyuce/mmoitems/stat/DisplayName.java
index 779f7207..e81c3be1 100644
--- a/src/main/java/net/Indyuce/mmoitems/stat/DisplayName.java
+++ b/src/main/java/net/Indyuce/mmoitems/stat/DisplayName.java
@@ -1,8 +1,11 @@
 package net.Indyuce.mmoitems.stat;
 
+import org.bukkit.ChatColor;
+import org.bukkit.inventory.ItemStack;
+
 import net.Indyuce.mmoitems.MMOItems;
+import net.Indyuce.mmoitems.api.ItemTier;
 import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
-import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
 import net.Indyuce.mmoitems.api.item.mmoitem.ReadMMOItem;
 import net.Indyuce.mmoitems.stat.data.StringData;
 import net.Indyuce.mmoitems.stat.data.type.StatData;
@@ -10,8 +13,6 @@ import net.Indyuce.mmoitems.stat.type.ItemStat;
 import net.Indyuce.mmoitems.stat.type.StringStat;
 import net.mmogroup.mmolib.MMOLib;
 import net.mmogroup.mmolib.version.VersionMaterial;
-import org.bukkit.ChatColor;
-import org.bukkit.inventory.ItemStack;
 
 public class DisplayName extends StringStat {
 	public DisplayName() {
@@ -21,8 +22,13 @@ public class DisplayName extends StringStat {
 
 	@Override
 	public void whenApplied(ItemStackBuilder item, StatData data) {
-		item.getMeta().setDisplayName(new DisplayNamePlaceholders(data.toString(), item.getMMOItem()).parse());
+		String format = data.toString();
 
+		ItemTier tier = MMOItems.plugin.getTiers().findTier(item.getMMOItem());
+		format = format.replace("<tier-name>", tier != null ? ChatColor.stripColor(tier.getName()) : "");
+		format = format.replace("<tier-color>", tier != null ? ChatColor.getLastColors(tier.getName()) : "&f");
+
+		item.getMeta().setDisplayName(MMOLib.plugin.parseColors(format));
 	}
 
 	@Override
@@ -30,35 +36,4 @@ public class DisplayName extends StringStat {
 		if (mmoitem.getNBT().getItem().getItemMeta().hasDisplayName())
 			mmoitem.setData(ItemStat.NAME, new StringData(mmoitem.getNBT().getItem().getItemMeta().getDisplayName()));
 	}
-
-	private class DisplayNamePlaceholders {
-
-		private String name;
-
-		private final MMOItem mmoitem;
-
-		private DisplayNamePlaceholders(String name, MMOItem mmoitem) {
-			this.name = name;
-			this.mmoitem = mmoitem;
-		}
-
-		private String parse() {
-			name = name.replace("<tier-name>", (mmoitem.hasData(ItemStat.TIER) && MMOItems.plugin.getTiers().findTier(mmoitem) != null)
-					? stripColorCodes(MMOItems.plugin.getTiers().findTier(mmoitem).getName()) : "");
-			name = name.replace("<tier-color>", (mmoitem.hasData(ItemStat.TIER) && MMOItems.plugin.getTiers().findTier(mmoitem) != null)
-					?  stripText(MMOItems.plugin.getTiers().findTier(mmoitem).getName()) : "&f");
-			name = name.replace("<type-name>", (mmoitem.hasData(ItemStat.DISPLAYED_TYPE))
-					?  stripColorCodes(mmoitem.getData(ItemStat.DISPLAYED_TYPE).toString()) : stripColorCodes(mmoitem.getType().getName()));
-			return MMOLib.plugin.parseColors(name);
-		}
-
-		private String stripColorCodes(String message) {
-			return ChatColor.stripColor(MMOLib.plugin.parseColors(message));
-		}
-
-		private String stripText(String message) {
-			return ChatColor.getLastColors(MMOLib.plugin.parseColors(message));
-		}
-	}
-
 }

From 28b0cdd023205da9c48f96f712f27a5feeafa5a0 Mon Sep 17 00:00:00 2001
From: Ethan <ethanhaynes46@gmail.com>
Date: Mon, 14 Sep 2020 00:51:11 -0400
Subject: [PATCH 2/4] !fix indy loading issue

---
 .../java/net/Indyuce/mmoitems/MMOItems.java   | 72 +++++--------------
 1 file changed, 19 insertions(+), 53 deletions(-)

diff --git a/src/main/java/net/Indyuce/mmoitems/MMOItems.java b/src/main/java/net/Indyuce/mmoitems/MMOItems.java
index 6938cd50..4c346fe7 100644
--- a/src/main/java/net/Indyuce/mmoitems/MMOItems.java
+++ b/src/main/java/net/Indyuce/mmoitems/MMOItems.java
@@ -1,21 +1,5 @@
 package net.Indyuce.mmoitems;
 
-import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.logging.Level;
-
-import javax.annotation.Nullable;
-
-import org.apache.commons.lang.Validate;
-import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.entity.Player;
-import org.bukkit.event.HandlerList;
-import org.bukkit.event.Listener;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.plugin.java.JavaPlugin;
-
 import net.Indyuce.mmoitems.api.ConfigFile;
 import net.Indyuce.mmoitems.api.ItemTier;
 import net.Indyuce.mmoitems.api.SoulboundInfo;
@@ -25,21 +9,13 @@ import net.Indyuce.mmoitems.api.player.PlayerData;
 import net.Indyuce.mmoitems.command.MMOItemsCommandTreeRoot;
 import net.Indyuce.mmoitems.command.UpdateItemCommand;
 import net.Indyuce.mmoitems.command.completion.UpdateItemCompletion;
-import net.Indyuce.mmoitems.comp.AdvancedEnchantmentsHook;
-import net.Indyuce.mmoitems.comp.MMOItemsMetrics;
-import net.Indyuce.mmoitems.comp.MMOItemsRewardTypes;
-import net.Indyuce.mmoitems.comp.RealDualWieldHook;
-import net.Indyuce.mmoitems.comp.WorldEditSupport;
+import net.Indyuce.mmoitems.comp.*;
 import net.Indyuce.mmoitems.comp.eco.VaultSupport;
 import net.Indyuce.mmoitems.comp.flags.DefaultFlags;
 import net.Indyuce.mmoitems.comp.flags.FlagPlugin;
 import net.Indyuce.mmoitems.comp.flags.ResidenceFlags;
 import net.Indyuce.mmoitems.comp.flags.WorldGuardFlags;
-import net.Indyuce.mmoitems.comp.holograms.CMIPlugin;
-import net.Indyuce.mmoitems.comp.holograms.HologramSupport;
-import net.Indyuce.mmoitems.comp.holograms.HologramsPlugin;
-import net.Indyuce.mmoitems.comp.holograms.HolographicDisplaysPlugin;
-import net.Indyuce.mmoitems.comp.holograms.TrHologramPlugin;
+import net.Indyuce.mmoitems.comp.holograms.*;
 import net.Indyuce.mmoitems.comp.inventory.DefaultPlayerInventory;
 import net.Indyuce.mmoitems.comp.inventory.OrnamentPlayerInventory;
 import net.Indyuce.mmoitems.comp.inventory.PlayerInventory;
@@ -58,34 +34,24 @@ import net.Indyuce.mmoitems.comp.rpg.DefaultHook;
 import net.Indyuce.mmoitems.comp.rpg.RPGHandler;
 import net.Indyuce.mmoitems.gui.PluginInventory;
 import net.Indyuce.mmoitems.gui.listener.GuiListener;
-import net.Indyuce.mmoitems.listener.CraftingListener;
-import net.Indyuce.mmoitems.listener.CustomBlockListener;
-import net.Indyuce.mmoitems.listener.CustomSoundListener;
-import net.Indyuce.mmoitems.listener.DisableInteractions;
-import net.Indyuce.mmoitems.listener.DurabilityListener;
-import net.Indyuce.mmoitems.listener.ElementListener;
-import net.Indyuce.mmoitems.listener.ItemUse;
-import net.Indyuce.mmoitems.listener.PlayerListener;
-import net.Indyuce.mmoitems.manager.AbilityManager;
-import net.Indyuce.mmoitems.manager.BlockManager;
-import net.Indyuce.mmoitems.manager.ConfigManager;
-import net.Indyuce.mmoitems.manager.CraftingManager;
-import net.Indyuce.mmoitems.manager.DropTableManager;
-import net.Indyuce.mmoitems.manager.EntityManager;
-import net.Indyuce.mmoitems.manager.ItemManager;
-import net.Indyuce.mmoitems.manager.LayoutManager;
-import net.Indyuce.mmoitems.manager.PluginUpdateManager;
-import net.Indyuce.mmoitems.manager.RecipeManager;
-import net.Indyuce.mmoitems.manager.SetManager;
-import net.Indyuce.mmoitems.manager.StatManager;
-import net.Indyuce.mmoitems.manager.TemplateManager;
-import net.Indyuce.mmoitems.manager.TierManager;
-import net.Indyuce.mmoitems.manager.TypeManager;
-import net.Indyuce.mmoitems.manager.UpdaterManager;
-import net.Indyuce.mmoitems.manager.UpgradeManager;
-import net.Indyuce.mmoitems.manager.WorldGenManager;
+import net.Indyuce.mmoitems.listener.*;
+import net.Indyuce.mmoitems.manager.*;
 import net.mmogroup.mmolib.api.player.MMOPlayerData;
 import net.mmogroup.mmolib.version.SpigotPlugin;
+import org.apache.commons.lang.Validate;
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.plugin.java.JavaPlugin;
+
+import javax.annotation.Nullable;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
 
 public class MMOItems extends JavaPlugin {
 	public static MMOItems plugin;
@@ -176,7 +142,7 @@ public class MMOItems extends JavaPlugin {
 		tierManager = new TierManager();
 		setManager = new SetManager();
 		upgradeManager = new UpgradeManager();
-		templateManager.postload();
+		templateManager.reload(); // should be postload()  but it's broken waiting for indy to fix
 
 		dropTableManager = new DropTableManager();
 		dynamicUpdater = new UpdaterManager();

From 4ea4be6ce72880f675536b69774abcead26296ad Mon Sep 17 00:00:00 2001
From: Ethan <ethanhaynes46@gmail.com>
Date: Mon, 14 Sep 2020 01:23:42 -0400
Subject: [PATCH 3/4] !revert

---
 .../mmoitems/manager/TemplateManager.java     | 92 ++++++-------------
 1 file changed, 28 insertions(+), 64 deletions(-)

diff --git a/src/main/java/net/Indyuce/mmoitems/manager/TemplateManager.java b/src/main/java/net/Indyuce/mmoitems/manager/TemplateManager.java
index 2396b0fc..9c975f93 100644
--- a/src/main/java/net/Indyuce/mmoitems/manager/TemplateManager.java
+++ b/src/main/java/net/Indyuce/mmoitems/manager/TemplateManager.java
@@ -1,16 +1,5 @@
 package net.Indyuce.mmoitems.manager;
 
-import java.io.File;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-import java.util.logging.Level;
-
-import org.apache.commons.lang.Validate;
-import org.bukkit.configuration.file.FileConfiguration;
-import org.bukkit.configuration.file.YamlConfiguration;
-
 import net.Indyuce.mmoitems.MMOItems;
 import net.Indyuce.mmoitems.api.ConfigFile;
 import net.Indyuce.mmoitems.api.ItemTier;
@@ -18,6 +7,16 @@ import net.Indyuce.mmoitems.api.Type;
 import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
 import net.Indyuce.mmoitems.api.item.template.TemplateModifier;
 import net.Indyuce.mmoitems.api.util.TemplateMap;
+import org.apache.commons.lang.Validate;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+
+import java.io.File;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.logging.Level;
 
 public class TemplateManager {
 
@@ -185,59 +184,6 @@ public class TemplateManager {
 		return (int) found;
 	}
 
-	/**
-	 * Templates must be loaded whenever MMOItems enables so that other plugins
-	 * like MMOCore can load template references in drop items or other objects.
-	 * Template data is only loaded when MMOItems enables, once sets, tiers..
-	 * are initialized
-	 */
-	public void preloadTemplates() {
-		templates.clear();
-
-		for (Type type : MMOItems.plugin.getTypes().getAll()) {
-			FileConfiguration config = type.getConfigFile().getConfig();
-			for (String key : config.getKeys(false))
-				try {
-					registerTemplate(new MMOItemTemplate(type, key));
-				} catch (IllegalArgumentException exception) {
-					MMOItems.plugin.getLogger().log(Level.INFO, "Could not preload item template '" + key + "': " + exception.getMessage());
-				}
-		}
-	}
-
-	/**
-	 * Loads item generator modifiers and post load item templates.
-	 */
-	public void postload() {
-
-		MMOItems.plugin.getLogger().log(Level.INFO, "Loading template modifiers, please wait..");
-		for (File file : new File(MMOItems.plugin.getDataFolder() + "/modifiers").listFiles()) {
-			FileConfiguration config = YamlConfiguration.loadConfiguration(file);
-			for (String key : config.getKeys(false))
-				try {
-					TemplateModifier modifier = new TemplateModifier(config.getConfigurationSection(key));
-					modifiers.put(modifier.getId(), modifier);
-				} catch (IllegalArgumentException exception) {
-					MMOItems.plugin.getLogger().log(Level.INFO, "Could not load template modifier '" + key + "': " + exception.getMessage());
-				}
-		}
-
-		MMOItems.plugin.getLogger().log(Level.INFO, "Loading item templates, please wait..");
-		templates.forEach(template -> {
-			try {
-				template.postLoad();
-			} catch (IllegalArgumentException exception) {
-				MMOItems.plugin.getLogger().log(Level.INFO, "Could not load item template '" + template.getId() + "': " + exception.getMessage());
-			}
-		});
-	}
-
-	/**
-	 * Reloads the item templates. This is the method used to reload the manager
-	 * when the server is already running. It clears all the maps and loads
-	 * everything again. Template references in other plugins like MMOCore must
-	 * be refreshed afterwards.
-	 */
 	public void reload() {
 		templates.clear();
 		modifiers.clear();
@@ -265,4 +211,22 @@ public class TemplateManager {
 				}
 		}
 	}
+	// this loads dummy items for on load so
+	// plugins that enable before mmoitems that use
+	// items (mmocore) don't error out and need
+	// a reload
+	public void loadCompatibility() {
+
+		templates.clear();
+
+		for (Type type : MMOItems.plugin.getTypes().getAll()) {
+			FileConfiguration config = type.getConfigFile().getConfig();
+			for (String key : config.getKeys(false))
+				try {
+					registerTemplate(new MMOItemTemplate(type, key));
+				} catch (IllegalArgumentException ignored) {
+
+				}
+		}
+	}
 }

From c01f1e578b66cbcb9461431ca14edfc6725bf758 Mon Sep 17 00:00:00 2001
From: Ethan <ethanhaynes46@gmail.com>
Date: Mon, 14 Sep 2020 01:58:12 -0400
Subject: [PATCH 4/4] !test

---
 .../mmoitems/manager/PluginUpdateManager.java |  1 -
 .../mmoitems/manager/TemplateManager.java     | 92 +++++++++++++------
 2 files changed, 64 insertions(+), 29 deletions(-)

diff --git a/src/main/java/net/Indyuce/mmoitems/manager/PluginUpdateManager.java b/src/main/java/net/Indyuce/mmoitems/manager/PluginUpdateManager.java
index 411e2e6d..2ccb680c 100644
--- a/src/main/java/net/Indyuce/mmoitems/manager/PluginUpdateManager.java
+++ b/src/main/java/net/Indyuce/mmoitems/manager/PluginUpdateManager.java
@@ -153,7 +153,6 @@ public class PluginUpdateManager {
 							// simple path changes
 							rename(config.getConfig().getConfigurationSection(id + ".base"), "regeneration", "health-regeneration");
 							rename(config.getConfig().getConfigurationSection(id + ".base"), "element.light", "element.lightness");
-							rename(config.getConfig().getConfigurationSection(id + ".base"), "consume-cooldown", "item-cooldown");
 
 							// sound changes
 							if (config.getConfig().getConfigurationSection(id + ".base").contains("consume-sound")) {
diff --git a/src/main/java/net/Indyuce/mmoitems/manager/TemplateManager.java b/src/main/java/net/Indyuce/mmoitems/manager/TemplateManager.java
index 9c975f93..2396b0fc 100644
--- a/src/main/java/net/Indyuce/mmoitems/manager/TemplateManager.java
+++ b/src/main/java/net/Indyuce/mmoitems/manager/TemplateManager.java
@@ -1,5 +1,16 @@
 package net.Indyuce.mmoitems.manager;
 
+import java.io.File;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+import java.util.logging.Level;
+
+import org.apache.commons.lang.Validate;
+import org.bukkit.configuration.file.FileConfiguration;
+import org.bukkit.configuration.file.YamlConfiguration;
+
 import net.Indyuce.mmoitems.MMOItems;
 import net.Indyuce.mmoitems.api.ConfigFile;
 import net.Indyuce.mmoitems.api.ItemTier;
@@ -7,16 +18,6 @@ import net.Indyuce.mmoitems.api.Type;
 import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
 import net.Indyuce.mmoitems.api.item.template.TemplateModifier;
 import net.Indyuce.mmoitems.api.util.TemplateMap;
-import org.apache.commons.lang.Validate;
-import org.bukkit.configuration.file.FileConfiguration;
-import org.bukkit.configuration.file.YamlConfiguration;
-
-import java.io.File;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-import java.util.logging.Level;
 
 public class TemplateManager {
 
@@ -184,6 +185,59 @@ public class TemplateManager {
 		return (int) found;
 	}
 
+	/**
+	 * Templates must be loaded whenever MMOItems enables so that other plugins
+	 * like MMOCore can load template references in drop items or other objects.
+	 * Template data is only loaded when MMOItems enables, once sets, tiers..
+	 * are initialized
+	 */
+	public void preloadTemplates() {
+		templates.clear();
+
+		for (Type type : MMOItems.plugin.getTypes().getAll()) {
+			FileConfiguration config = type.getConfigFile().getConfig();
+			for (String key : config.getKeys(false))
+				try {
+					registerTemplate(new MMOItemTemplate(type, key));
+				} catch (IllegalArgumentException exception) {
+					MMOItems.plugin.getLogger().log(Level.INFO, "Could not preload item template '" + key + "': " + exception.getMessage());
+				}
+		}
+	}
+
+	/**
+	 * Loads item generator modifiers and post load item templates.
+	 */
+	public void postload() {
+
+		MMOItems.plugin.getLogger().log(Level.INFO, "Loading template modifiers, please wait..");
+		for (File file : new File(MMOItems.plugin.getDataFolder() + "/modifiers").listFiles()) {
+			FileConfiguration config = YamlConfiguration.loadConfiguration(file);
+			for (String key : config.getKeys(false))
+				try {
+					TemplateModifier modifier = new TemplateModifier(config.getConfigurationSection(key));
+					modifiers.put(modifier.getId(), modifier);
+				} catch (IllegalArgumentException exception) {
+					MMOItems.plugin.getLogger().log(Level.INFO, "Could not load template modifier '" + key + "': " + exception.getMessage());
+				}
+		}
+
+		MMOItems.plugin.getLogger().log(Level.INFO, "Loading item templates, please wait..");
+		templates.forEach(template -> {
+			try {
+				template.postLoad();
+			} catch (IllegalArgumentException exception) {
+				MMOItems.plugin.getLogger().log(Level.INFO, "Could not load item template '" + template.getId() + "': " + exception.getMessage());
+			}
+		});
+	}
+
+	/**
+	 * Reloads the item templates. This is the method used to reload the manager
+	 * when the server is already running. It clears all the maps and loads
+	 * everything again. Template references in other plugins like MMOCore must
+	 * be refreshed afterwards.
+	 */
 	public void reload() {
 		templates.clear();
 		modifiers.clear();
@@ -211,22 +265,4 @@ public class TemplateManager {
 				}
 		}
 	}
-	// this loads dummy items for on load so
-	// plugins that enable before mmoitems that use
-	// items (mmocore) don't error out and need
-	// a reload
-	public void loadCompatibility() {
-
-		templates.clear();
-
-		for (Type type : MMOItems.plugin.getTypes().getAll()) {
-			FileConfiguration config = type.getConfigFile().getConfig();
-			for (String key : config.getKeys(false))
-				try {
-					registerTemplate(new MMOItemTemplate(type, key));
-				} catch (IllegalArgumentException ignored) {
-
-				}
-		}
-	}
 }