diff --git a/src/main/java/net/Indyuce/mmoitems/api/ItemSet.java b/src/main/java/net/Indyuce/mmoitems/api/ItemSet.java
index 932e3127..56f0ce5f 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/ItemSet.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/ItemSet.java
@@ -1,11 +1,6 @@
 package net.Indyuce.mmoitems.api;
 
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 import org.apache.commons.lang.Validate;
 import org.bukkit.configuration.ConfigurationSection;
@@ -17,6 +12,7 @@ import net.Indyuce.mmoitems.MMOUtils;
 import net.Indyuce.mmoitems.stat.data.AbilityData;
 import net.Indyuce.mmoitems.stat.data.ParticleData;
 import net.Indyuce.mmoitems.stat.type.ItemStat;
+import org.jetbrains.annotations.NotNull;
 
 public class ItemSet {
 	private final Map<Integer, SetBonuses> bonuses = new HashMap<>();
@@ -39,10 +35,14 @@ public class ItemSet {
 		Validate.isTrue(config.contains("bonuses"), "Could not find item set bonuses");
 
 		for (int j = 2; j <= itemLimit; j++)
-			if (config.getConfigurationSection("bonuses").contains("" + j)) {
+			if (config.getConfigurationSection("bonuses").contains(String.valueOf(j))) {
 				SetBonuses bonuses = new SetBonuses();
 
-				for (String key : config.getConfigurationSection("bonuses." + j).getKeys(false))
+				// Add permissions
+				for (String perm : config.getConfigurationSection("bonuses." + j).getStringList("granted-permissions")) { bonuses.addPermission(perm); }
+
+				for (String key : config.getConfigurationSection("bonuses." + j).getKeys(false)) {
+
 					try {
 						String format = key.toUpperCase().replace("-", "_").replace(" ", "_");
 
@@ -75,6 +75,7 @@ public class ItemSet {
 					} catch (IllegalArgumentException exception) {
 						throw new IllegalArgumentException("Could not load set bonus '" + key + "': " + exception.getMessage());
 					}
+				}
 
 				this.bonuses.put(j, bonuses);
 			}
@@ -105,6 +106,7 @@ public class ItemSet {
 		private final Map<PotionEffectType, PotionEffect> permEffects = new HashMap<>();
 		private final Set<AbilityData> abilities = new HashSet<>();
 		private final Set<ParticleData> particles = new HashSet<>();
+		private final ArrayList<String> permissions = new ArrayList<>();
 
 		public void addStat(ItemStat stat, double value) {
 			stats.put(stat, value);
@@ -122,6 +124,8 @@ public class ItemSet {
 			particles.add(particle);
 		}
 
+		public void addPermission(@NotNull String permission) { permissions.add(permission); }
+
 		public boolean hasStat(ItemStat stat) {
 			return stats.containsKey(stat);
 		}
@@ -146,6 +150,8 @@ public class ItemSet {
 			return abilities;
 		}
 
+		@NotNull public ArrayList<String> getPermissions() { return permissions; }
+
 		public void merge(SetBonuses bonuses) {
 			bonuses.getStats().forEach((stat, value) -> stats.put(stat, (stats.containsKey(stat) ? stats.get(stat) : 0) + value));
 
@@ -154,6 +160,8 @@ public class ItemSet {
 					permEffects.put(effect.getType(), effect);
 
 			abilities.addAll(bonuses.getAbilities());
+
+			permissions.addAll(bonuses.getPermissions());
 		}
 	}
 }
diff --git a/src/main/java/net/Indyuce/mmoitems/api/ReforgeOptions.java b/src/main/java/net/Indyuce/mmoitems/api/ReforgeOptions.java
index f4c8bd03..e17ee411 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/ReforgeOptions.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/ReforgeOptions.java
@@ -1,8 +1,10 @@
 package net.Indyuce.mmoitems.api;
 
+import net.Indyuce.mmoitems.api.util.MMOItemReforger;
 import org.bukkit.ChatColor;
 import org.bukkit.configuration.ConfigurationSection;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.ArrayList;
 
@@ -19,6 +21,7 @@ public class ReforgeOptions {
 	private final boolean keepSoulbind;
 	private final boolean keepExternalSH;
 	private final boolean keepModifications;
+	@Nullable private final Boolean keepTier;
 
 	private final boolean reroll;
 
@@ -78,6 +81,7 @@ public class ReforgeOptions {
 		keepModifications = config.getBoolean("modifications");
 		reroll = config.getBoolean("reroll");
 		keepAdvancedEnchantments = config.getBoolean("advanced-enchantments");
+		keepTier = config.contains("tier") ? config.getBoolean("tier", true) : null;
 	}
 
 	public ReforgeOptions(boolean... values) {
@@ -92,6 +96,7 @@ public class ReforgeOptions {
 		keepModifications = arr(values, 8);
 		keepAdvancedEnchantments = arr(values, 9);
 		keepSkins = arr(values, 10);
+		keepTier = arr(values, 11);
 	}
 
 	boolean arr(@NotNull boolean[] booleans, int idx) {
@@ -104,70 +109,56 @@ public class ReforgeOptions {
 	/**
 	 * Keeps the display name of the item.
 	 */
-	public boolean shouldReroll() {
-		return reroll;
-	}
+	public boolean shouldReroll() { return reroll; }
 
 	/**
 	 * Keeps the display name of the item.
 	 */
-	public boolean shouldKeepName() {
-		return keepName;
-	}
+	public boolean shouldKeepName() { return keepName; }
 
 	/**
 	 * Keeps the modifiers of the item.
 	 */
-	public boolean shouldKeepMods() {
-		return keepModifications;
-	}
+	public boolean shouldKeepMods() { return keepModifications; }
 
 	/**
 	 *  Keeps all lore lines that begin with {@link org.bukkit.ChatColor#GRAY}
 	 */
-	public boolean shouldKeepLore() {
-		return keepLore;
-	}
+	public boolean shouldKeepLore() { return keepLore; }
 
 	/**
 	 *  Keeps skins
 	 */
-	public boolean shouldKeepSkins() {
-		return keepSkins;
+	public boolean shouldKeepSkins() { return keepSkins; }
 
-	}
+	/**
+	 *  Should keep the tier? defaults to {@link MMOItemReforger#keepTiersWhenReroll}
+	 */
+	public boolean shouldKeepTier() { return keepTier == null ? MMOItemReforger.keepTiersWhenReroll : keepTier; }
 
 	/**
 	 * Should this keep the enchantments the player
 	 * manually cast onto this item? (Not from gem
 	 * stones nor upgrades).
 	 */
-	public boolean shouldKeepEnchantments() {
-		return keepEnchantments;
-	}
+	public boolean shouldKeepEnchantments() { return keepEnchantments; }
 
 	/**
 	 * Should this keep the enchantments the player
 	 * manually cast onto this item? (Not from gem
 	 * stones nor upgrades).
 	 */
-	public boolean shouldKeepAdvancedEnchants() {
-		return keepAdvancedEnchantments;
-	}
+	public boolean shouldKeepAdvancedEnchants() { return keepAdvancedEnchantments; }
 
 	/**
 	 * Keep 'extraneous' data registered onto the Stat History
 	 */
-	public boolean shouldKeepExternalSH() {
-		return keepExternalSH;
-	}
+	public boolean shouldKeepExternalSH() { return keepExternalSH; }
 
 	/**
 	 * Retains the upgrade level of the item.
 	 */
-	public boolean shouldKeepUpgrades() {
-		return keepUpgrades;
-	}
+	public boolean shouldKeepUpgrades() { return keepUpgrades; }
 
 	/**
 	 * Retains all gem stones if there are any, removing
@@ -175,14 +166,10 @@ public class ReforgeOptions {
 	 * <p></p>
 	 * Gemstones remember at what upgrade level they were inserted.
 	 */
-	public boolean shouldKeepGemStones() {
-		return keepGemStones;
-	}
+	public boolean shouldKeepGemStones() { return keepGemStones; }
 
 	/**
 	 * Retains the soulbind if it has any.
 	 */
-	public boolean shouldKeepSoulbind() {
-		return keepSoulbind;
-	}
+	public boolean shouldKeepSoulbind() { return keepSoulbind; }
 }
diff --git a/src/main/java/net/Indyuce/mmoitems/api/item/mmoitem/MMOItem.java b/src/main/java/net/Indyuce/mmoitems/api/item/mmoitem/MMOItem.java
index 305dff30..15464388 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/item/mmoitem/MMOItem.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/item/mmoitem/MMOItem.java
@@ -1,23 +1,25 @@
 package net.Indyuce.mmoitems.api.item.mmoitem;
 
+import io.lumine.mythic.lib.api.item.NBTItem;
 import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
 import net.Indyuce.mmoitems.ItemStats;
 import net.Indyuce.mmoitems.MMOItems;
 import net.Indyuce.mmoitems.api.ItemTier;
 import net.Indyuce.mmoitems.api.Type;
 import net.Indyuce.mmoitems.api.UpgradeTemplate;
+import net.Indyuce.mmoitems.api.interaction.util.DurabilityItem;
 import net.Indyuce.mmoitems.api.item.ItemReference;
 import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
+import net.Indyuce.mmoitems.api.util.MMOItemReforger;
 import net.Indyuce.mmoitems.stat.Enchants;
-import net.Indyuce.mmoitems.stat.data.DoubleData;
-import net.Indyuce.mmoitems.stat.data.GemSocketsData;
-import net.Indyuce.mmoitems.stat.data.GemstoneData;
-import net.Indyuce.mmoitems.stat.data.UpgradeData;
+import net.Indyuce.mmoitems.stat.data.*;
 import net.Indyuce.mmoitems.stat.data.type.Mergeable;
 import net.Indyuce.mmoitems.stat.data.type.StatData;
 import net.Indyuce.mmoitems.stat.type.ItemStat;
 import net.Indyuce.mmoitems.stat.type.StatHistory;
 import org.apache.commons.lang.Validate;
+import org.bukkit.Material;
+import org.bukkit.inventory.meta.ItemMeta;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -225,11 +227,25 @@ public class MMOItem implements ItemReference {
 	 */
 	public int getDamage() {
 
-		if (!hasData(ItemStats.ITEM_DAMAGE)) { return 0; }
+		// Does it use MMO Durability?
+		int maxDurability = hasData(ItemStats.MAX_DURABILITY) ? SilentNumbers.round(((DoubleData) getData(ItemStats.MAX_DURABILITY)).getValue()) : -1;
 
-		DoubleData durData = (DoubleData) getData(ItemStats.ITEM_DAMAGE);
+		if (maxDurability > 0) {
 
-		return SilentNumbers.round(durData.getValue());
+			// Apparently we must do this
+			NBTItem nbtItem = newBuilder().buildNBT();
+
+			// Durability
+			int durability = hasData(ItemStats.CUSTOM_DURABILITY) ? SilentNumbers.round(((DoubleData) getData(ItemStats.CUSTOM_DURABILITY)).getValue()) : maxDurability;
+
+			// Damage is the difference between max and current durability
+			return maxDurability - durability;
+
+		} else {
+
+			// Use vanilla durability
+			return hasData(ItemStats.ITEM_DAMAGE) ? SilentNumbers.round(((DoubleData) getData(ItemStats.ITEM_DAMAGE)).getValue()) : 0;
+		}
 	}
 
 	/**
@@ -240,9 +256,33 @@ public class MMOItem implements ItemReference {
 	 */
 	public void setDamage(int damage) {
 
+		// Too powerful
 		if (hasData(ItemStats.UNBREAKABLE)) { return; }
 
-		setData(ItemStats.ITEM_DAMAGE, new DoubleData(damage));
+		// Does it use MMO Durability?
+		int maxDurability = hasData(ItemStats.MAX_DURABILITY) ? SilentNumbers.round(((DoubleData) getData(ItemStats.MAX_DURABILITY)).getValue()) : -1;
+
+		if (maxDurability > 0) {
+
+			// Apparently we must do this
+			NBTItem nbtItem = newBuilder().buildNBT();
+
+			// Durability
+			setData(ItemStats.CUSTOM_DURABILITY, new DoubleData(maxDurability - damage));
+
+			// Scale damage
+			Material mat = hasData(ItemStats.MATERIAL) ? ((MaterialData) getData(ItemStats.MATERIAL)).getMaterial() : Material.GOLD_INGOT;
+			double multiplier = ((double) damage) * ((double) mat.getMaxDurability()) / ((double) maxDurability);
+			if (multiplier == 0) { return; }
+
+			// Set to some decent amount of damage
+			setData(ItemStats.ITEM_DAMAGE, new DoubleData(multiplier));
+
+		} else {
+
+			// Use vanilla durability
+			setData(ItemStats.ITEM_DAMAGE, new DoubleData(damage));
+		}
 	}
 	//endregion
 
@@ -373,6 +413,9 @@ public class MMOItem implements ItemReference {
 		}
 		//XTC//MMOItems.log("\u00a7b   *\u00a77 Regen Size:\u00a79 " + regeneratedGems.values().size());
 
+		// If RevID updating, it basically just regenerates
+		if (MMOItemReforger.gemstonesRevIDWhenUnsocket) { return new ArrayList<>(regeneratedGems.values()); }
+
 		// Identify actual attributes
 		for (ItemStat stat : getStats()) {
 
@@ -421,6 +464,8 @@ public class MMOItem implements ItemReference {
 		// Can we generate?
 		MMOItem restored = MMOItems.plugin.getMMOItem(MMOItems.plugin.getTypes().get(gem.getMMOItemType()), gem.getMMOItemID());
 
+		if (MMOItemReforger.gemstonesRevIDWhenUnsocket) { return restored; }
+
 		// Valid? neat-o
 		if (restored != null) {
 			//XTC//MMOItems.log("\u00a7a   *\u00a73>\u00a77 Valid, regenerated \u00a7e" + restored.getData(ItemStats.NAME));
diff --git a/src/main/java/net/Indyuce/mmoitems/api/player/PlayerData.java b/src/main/java/net/Indyuce/mmoitems/api/player/PlayerData.java
index b763a23e..dc02796f 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/player/PlayerData.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/player/PlayerData.java
@@ -4,6 +4,7 @@ import io.lumine.mythic.lib.MythicLib;
 import io.lumine.mythic.lib.api.item.NBTItem;
 import io.lumine.mythic.lib.api.player.EquipmentSlot;
 import io.lumine.mythic.lib.api.player.MMOPlayerData;
+import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
 import io.lumine.mythic.lib.damage.AttackMetadata;
 import io.lumine.mythic.lib.player.PlayerMetadata;
 import io.lumine.mythic.lib.player.modifier.ModifierSource;
@@ -19,6 +20,7 @@ import net.Indyuce.mmoitems.api.crafting.CraftingStatus;
 import net.Indyuce.mmoitems.api.event.RefreshInventoryEvent;
 import net.Indyuce.mmoitems.api.interaction.Tool;
 import net.Indyuce.mmoitems.api.item.ItemReference;
+import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
 import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
 import net.Indyuce.mmoitems.api.player.inventory.EquippedItem;
 import net.Indyuce.mmoitems.api.player.inventory.EquippedPlayerItem;
@@ -61,6 +63,7 @@ public class PlayerData {
     private final Set<ParticleRunnable> itemParticles = new HashSet<>();
     private ParticleRunnable overridingItemParticles = null;
     private boolean fullHands = false;
+    @Nullable
     private SetBonuses setBonuses = null;
     private final PlayerStats stats;
 
@@ -174,10 +177,7 @@ public class PlayerData {
         overridingItemParticles = null;
         if (MMOItems.plugin.hasPermissions()) {
             Permission perms = MMOItems.plugin.getVault().getPermissions();
-            permissions.forEach(perm -> {
-                if (perms.has(getPlayer(), perm))
-                    perms.playerRemove(getPlayer(), perm);
-            });
+            permissions.forEach(perm -> { if (perms.has(getPlayer(), perm)) { perms.playerRemove(getPlayer(), perm); } });
         }
         permissions.clear();
 
@@ -248,12 +248,10 @@ public class PlayerData {
              * Apply permissions if vault exists
              */
             if (MMOItems.plugin.hasPermissions() && item.hasData(ItemStats.GRANTED_PERMISSIONS)) {
+
                 permissions.addAll(((StringListData) item.getData(ItemStats.GRANTED_PERMISSIONS)).getList());
                 Permission perms = MMOItems.plugin.getVault().getPermissions();
-                permissions.forEach(perm -> {
-                    if (!perms.has(getPlayer(), perm))
-                        perms.playerAdd(getPlayer(), perm);
-                });
+                permissions.forEach(perm -> { if (!perms.has(getPlayer(), perm)) { perms.playerAdd(getPlayer(), perm); } });
             }
         }
 
@@ -261,8 +259,6 @@ public class PlayerData {
          * calculate the player's item set and add the bonus permanent effects /
          * bonus abilities to the playerdata maps
          */
-        int max = 0;
-        ItemSet set = null;
         Map<ItemSet, Integer> sets = new HashMap<>();
         for (EquippedPlayerItem equipped : inventory.getEquipped()) {
             VolatileMMOItem item = equipped.getItem();
@@ -273,14 +269,28 @@ public class PlayerData {
 
             int nextInt = (sets.getOrDefault(itemSet, 0)) + 1;
             sets.put(itemSet, nextInt);
-            if (nextInt >= max) {
-                max = nextInt;
-                set = itemSet;
+        }
+
+        // Reset
+        setBonuses = null;
+        for (Map.Entry<ItemSet,Integer> equippedSetBonus : sets.entrySet()) {
+
+            if (setBonuses == null) {
+
+                // Set set bonuses
+                setBonuses = equippedSetBonus.getKey().getBonuses(equippedSetBonus.getValue());
+
+            } else {
+
+                // Merge bonuses
+                setBonuses.merge(equippedSetBonus.getKey().getBonuses(equippedSetBonus.getValue()));
             }
         }
-        setBonuses = set == null ? null : set.getBonuses(max);
 
-        if (hasSetBonuses()) {
+        if (setBonuses != null) {
+            Permission perms = MMOItems.plugin.getVault().getPermissions();
+            for (String perm : setBonuses.getPermissions())
+                if (!perms.has(getPlayer(), perm)) { perms.playerAdd(getPlayer(), perm); }
             for (AbilityData ability : setBonuses.getAbilities())
                 mmoData.getPassiveSkillMap().addModifier(new PassiveSkill("MMOItemsItem", ability, EquipmentSlot.OTHER, ModifierSource.OTHER));
             for (ParticleData particle : setBonuses.getParticles())
diff --git a/src/main/java/net/Indyuce/mmoitems/api/util/DeathDowngrading.java b/src/main/java/net/Indyuce/mmoitems/api/util/DeathDowngrading.java
new file mode 100644
index 00000000..1942c7b8
--- /dev/null
+++ b/src/main/java/net/Indyuce/mmoitems/api/util/DeathDowngrading.java
@@ -0,0 +1,340 @@
+package net.Indyuce.mmoitems.api.util;
+
+import io.lumine.mythic.lib.api.item.NBTItem;
+import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
+import net.Indyuce.mmoitems.ItemStats;
+import net.Indyuce.mmoitems.api.interaction.util.DurabilityItem;
+import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
+import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
+import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
+import net.Indyuce.mmoitems.api.player.PlayerData;
+import net.Indyuce.mmoitems.api.player.inventory.EditableEquippedItem;
+import net.Indyuce.mmoitems.api.player.inventory.EquippedPlayerItem;
+import net.Indyuce.mmoitems.api.player.inventory.InventoryUpdateHandler;
+import net.Indyuce.mmoitems.api.util.message.Message;
+import net.Indyuce.mmoitems.stat.data.UpgradeData;
+import net.Indyuce.mmoitems.stat.type.NameData;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.Contract;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Random;
+
+public class DeathDowngrading {
+
+    /**
+     * This will go through the following steps:
+     *
+     *  #1 Evaluate the list of equipped items {@link InventoryUpdateHandler#getEquipped()} to
+     *     find those that can be death-downgraded.
+     *
+     *
+     *  #2 Roll for death downgrade chances, downgrading the items
+     *
+     * @param player Player whose inventory is to be death-downgraded.
+     */
+    public static void playerDeathDowngrade(@NotNull Player player) {
+
+        // Get Player
+        PlayerData data = PlayerData.get(player);
+
+        // Get total downgrade chance, anything less than zero is invalid
+        double deathChance = data.getStats().getStat(ItemStats.DOWNGRADE_ON_DEATH_CHANCE);
+        //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Current chance:\u00a7b " + deathChance);
+        if (deathChance <= 0) { return; }
+
+        // Make sure the equipped items list is up to date and retrieve it
+        data.updateInventory();
+        List<EquippedPlayerItem> items = data.getInventory().getEquipped();
+        ArrayList<EditableEquippedItem> equipped = new ArrayList<>();
+
+        // Equipped Player Items yeah...
+        for (EquippedPlayerItem playerItem : items) {
+
+            // Cannot downgrade? skip
+            if (!canDeathDowngrade(playerItem)) { continue; }
+
+            // Okay explore stat
+            equipped.add((EditableEquippedItem) playerItem.getEquipped());
+            //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Yes. \u00a7aAccepted");
+        }
+
+        // Nothing to perform operations? Snooze
+        if (equipped.size() == 0) {
+            //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 No items to downgrade. ");
+            return; }
+
+        // Create random
+        Random random = new Random();
+
+        // Degrade those items!
+        while (deathChance >= 100 && equipped.size() > 0) {
+
+            // Decrease
+            deathChance -= 100;
+
+            // Downgrade random item
+            int deathChosen = random.nextInt(equipped.size());
+
+            /*
+             * The item was chosen, we must downgrade it by one level.
+             */
+            EditableEquippedItem equip = equipped.get(deathChosen);
+
+            // Downgrade and remove from list
+            equip.setItem(downgrade(new LiveMMOItem(equip.getItem()), player));
+            equipped.remove(deathChosen);
+
+            //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Autodegrading\u00a7a " + mmo.getData(ItemStats.NAME));
+        }
+
+        // If there is chance, and there is size, and there is chance success
+        if (deathChance > 0 && equipped.size() > 0 && random.nextInt(100) < deathChance) {
+
+            // Downgrade random item
+            int d = random.nextInt(equipped.size());
+
+            /*
+             * The item was chosen, we must downgrade it by one level.
+             */
+            EditableEquippedItem equip = equipped.get(d);
+
+            // Downgrade and remove from list
+            equip.setItem(downgrade(new LiveMMOItem(equip.getItem()), player));
+            equipped.remove(d);
+
+            //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Chancedegrade\u00a7a " + mmo.getData(ItemStats.NAME));
+        }
+    }
+
+    /**
+     * @param allItems Absolutely all the items equipped by the player. This method will only affect
+     *                 those that (A) can be downgraded, and (B) RNG roll to be downgraded.
+     *
+     * @param player Player whose items are being downgraded.
+     *
+     * @param deathChance Chance of downgrading one item of the list. Overrollable.
+     *
+     * @return The same list of items... but some of them possibly downgraded.
+     */
+    @NotNull ArrayList<ItemStack> downgradeItems(@NotNull List<ItemStack> allItems, @NotNull Player player, double deathChance) {
+
+        // List of result and downgrade
+        ArrayList<ItemStack> result = new ArrayList<>();
+        ArrayList<ItemStack> downgrade = new ArrayList<>();
+
+        // Choose
+        for (ItemStack item : allItems) {
+
+            // ?? Not that
+            if (SilentNumbers.isAir(item)) { continue; }
+
+            // Downgrade yay or nay
+            if (canDeathDowngrade(item)) {
+
+                // On to downgrading
+                downgrade.add(item);
+
+            } else {
+
+                // On to result
+                result.add(item);
+            }
+        }
+
+        // Create random
+        Random random = new Random();
+
+        // Degrade those items!
+        while (deathChance >= 100 && downgrade.size() > 0) {
+
+            // Decrease
+            deathChance -= 100;
+
+            // Downgrade random item
+            int deathChosen = random.nextInt(downgrade.size());
+
+            /*
+             * The item was chosen, we must downgrade it by one level.
+             */
+            ItemStack equip = downgrade.get(deathChosen);
+
+            // Downgrade and remove from list
+            result.add(downgrade(new LiveMMOItem(equip), player));
+
+            // Remove this one item
+            downgrade.remove(deathChosen);
+        }
+
+        // If there is chance, and there is size, and there is chance success
+        if (deathChance > 0 && downgrade.size() > 0 && random.nextInt(100) < deathChance) {
+
+            // Downgrade random item
+            int deathChosen = random.nextInt(downgrade.size());
+
+            /*
+             * The item was chosen, we must downgrade it by one level.
+             */
+            ItemStack equip = downgrade.get(deathChosen);
+
+            // Downgrade and remove from list
+            result.add(downgrade(new LiveMMOItem(equip), player));
+
+            // Remove this one item
+            downgrade.remove(deathChosen);
+        }
+
+        // Those that survived are rejoined
+        result.addAll(downgrade);
+
+        // That's it
+        return result;
+    }
+
+    /**
+     * @param player For some reason I myself dont understand, {@link DurabilityItem} wants
+     *               a non-null player to be able to perform durability operations.
+     *
+     * @param item Item to downgrade, make sure to have checked
+     *             {@link #canDeathDowngrade(ItemStack)} before!
+     *
+     * @return This item but downgraded if it was possible.
+     */
+    @NotNull public static ItemStack downgrade(@NotNull ItemStack item, @NotNull Player player) {
+
+        // No Item Meta I sleep
+        if (SilentNumbers.isAir(item) || !item.getType().isItem()) { return item; }
+
+        // Must be a MMOItem
+        NBTItem asNBT = NBTItem.get(item);
+        if (!asNBT.hasType()) { return item; }
+
+        // Delegate to MMOItem Method
+        return downgrade(new LiveMMOItem(asNBT), player);
+    }
+
+    /**
+     * @param player For some reason I myself dont understand, {@link DurabilityItem} wants
+     *               a non-null player to be able to perform durability operations.
+     *
+     * @param mmo Item to downgrade, make sure to have checked
+     *             {@link #canDeathDowngrade(MMOItem)} before!
+     *
+     * @return This item but downgraded if it was possible.
+     */
+    @NotNull public static ItemStack downgrade(@NotNull LiveMMOItem mmo, @NotNull Player player) {
+
+        mmo.getUpgradeTemplate().upgradeTo(mmo, mmo.getUpgradeLevel() - 1);
+
+        // Build NBT
+        ItemStack bakedItem = mmo.newBuilder().build();
+
+        // Set durability to zero (full repair)
+        DurabilityItem dur = new DurabilityItem(player, mmo.newBuilder().buildNBT());
+
+        // Perform durability operations
+        if (dur.getDurability() != dur.getMaxDurability()) {
+            dur.addDurability(dur.getMaxDurability());
+            bakedItem.setItemMeta(dur.toItem().getItemMeta());}
+
+        // Send downgrading message
+        Message.DEATH_DOWNGRADING.format(ChatColor.RED, "#item#", (mmo.getData(ItemStats.NAME) instanceof NameData) ? mmo.getData(ItemStats.NAME).toString() : SilentNumbers.getItemName(bakedItem, false))
+                .send(player);
+
+        // Uuuuh
+        return bakedItem;
+    }
+
+    /**
+     * @param player Player to check their death downgrade chance
+     *
+     * @return The death downgrade chance of the player
+     */
+    public double getDeathDowngradeChance(@NotNull Player player) {
+
+        // Get Player
+        PlayerData data = PlayerData.get(player);
+
+        // Get total downgrade chance, anything less than zero is invalid
+        return data.getStats().getStat(ItemStats.DOWNGRADE_ON_DEATH_CHANCE);
+    }
+
+    /**
+     * @param playerItem Equipped Item you want to know if it can be death downgraded
+     *
+     * @return If this is an instance of {@link EditableEquippedItem} and meets {@link #canDeathDowngrade(MMOItem)}
+     */
+    @Contract("null->false")
+    public static boolean canDeathDowngrade(@Nullable EquippedPlayerItem playerItem) {
+
+        // Null
+        if (playerItem == null) { return false; }
+        //DET//playerItem.getItem().hasData(ItemStats.NAME);
+        //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Item:\u00a7b " + playerItem.getItem().getData(ItemStats.NAME));
+
+        // Cannot perform operations of items that are uneditable
+        if (!(playerItem.getEquipped() instanceof EditableEquippedItem)) {
+            //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Not equippable. \u00a7cCancel");
+            return false; }
+
+        // Delegate to MMOItem Method
+        return canDeathDowngrade(playerItem.getItem());
+    }
+
+    /**
+     * @param playerItem Item you want to know if it can be death downgraded
+     *
+     * @return If this item is an MMOItem and meets {@link #canDeathDowngrade(MMOItem)}
+     */
+    @Contract("null->false")
+    public static boolean canDeathDowngrade(@Nullable ItemStack playerItem) {
+
+        // Null
+        if (SilentNumbers.isAir(playerItem) || !playerItem.getType().isItem()) { return false; }
+        //DET//playerItem.getItem().hasData(ItemStats.NAME);
+        //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Item:\u00a7b " + playerItem.getItem().getData(ItemStats.NAME));
+
+        // Get NBT
+        NBTItem asNBT = NBTItem.get(playerItem);
+        if (!asNBT.hasType()) { return false; }
+
+        // Delegate to MMOItem Method
+        return canDeathDowngrade(new VolatileMMOItem(asNBT));
+    }
+
+    /**
+     * @param playerItem MMOItem you want to know if it can be death downgraded
+     *
+     * @return If this item has {@link ItemStats#DOWNGRADE_ON_DEATH} enabled, and
+     *         has an upgrade template, and hasnt reached its minimum upgrades.
+     */
+    @Contract("null->false")
+    public static boolean canDeathDowngrade(@Nullable MMOItem playerItem) {
+        if (playerItem == null) { return false; }
+
+        // Not downgradeable on death? Snooze
+        if (!playerItem.hasData(ItemStats.DOWNGRADE_ON_DEATH)) {
+            //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Not Downgradeable. \u00a7cCancel");
+            return false; }
+
+        // No upgrade template no snooze
+        if(!playerItem.hasData(ItemStats.UPGRADE)) {
+            //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Not Upgradeable. \u00a7cCancel");
+            return false; }
+        if (!playerItem.hasUpgradeTemplate()) {
+            //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Null Template. \u00a7cCancel");
+            return false; }
+
+        // If it can be downgraded by one level...
+        UpgradeData upgradeData = (UpgradeData) playerItem.getData(ItemStats.UPGRADE);
+        //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Too downgraded? \u00a7c" + (upgradeData.getLevel() <= upgradeData.getMin()));
+
+        return upgradeData.getLevel() > upgradeData.getMin();
+    }
+}
diff --git a/src/main/java/net/Indyuce/mmoitems/api/util/MMOItemReforger.java b/src/main/java/net/Indyuce/mmoitems/api/util/MMOItemReforger.java
index ad69b54c..40f66195 100644
--- a/src/main/java/net/Indyuce/mmoitems/api/util/MMOItemReforger.java
+++ b/src/main/java/net/Indyuce/mmoitems/api/util/MMOItemReforger.java
@@ -412,11 +412,13 @@ public class MMOItemReforger {
 						: iLevel;
 
 
+
+
 		// Identify tier.
 		ItemTier tier =
 
 				// Does the item have a tier, and it should keep it?
-				(MMOItemReforger.keepTiersWhenReroll && getOldMMOItem().hasData(ItemStats.TIER)) ?
+				(options.shouldKeepTier() && getOldMMOItem().hasData(ItemStats.TIER)) ?
 
 						// The tier will be the current tier
 						MMOItems.plugin.getTiers().get(getOldMMOItem().getData(ItemStats.TIER).toString())
@@ -478,11 +480,13 @@ public class MMOItemReforger {
 	public static int autoSoulbindLevel = 1;
 	public static int defaultItemLevel = -32767;
 	public static boolean keepTiersWhenReroll = true;
+	public static boolean gemstonesRevIDWhenUnsocket = false;
 
 	public static void reload() {
 		autoSoulbindLevel = MMOItems.plugin.getConfig().getInt("soulbound.auto-bind.level", 1);
 		defaultItemLevel = MMOItems.plugin.getConfig().getInt("item-revision.default-item-level", -32767);
 		keepTiersWhenReroll = MMOItems.plugin.getConfig().getBoolean("item-revision.keep-tiers");
+		gemstonesRevIDWhenUnsocket = MMOItems.plugin.getConfig().getBoolean("item-revision.regenerate-gems-when-unsocketed", false);
 	}
 	//endregion
 
diff --git a/src/main/java/net/Indyuce/mmoitems/listener/PlayerListener.java b/src/main/java/net/Indyuce/mmoitems/listener/PlayerListener.java
index b1acdd0b..9dfdbb76 100644
--- a/src/main/java/net/Indyuce/mmoitems/listener/PlayerListener.java
+++ b/src/main/java/net/Indyuce/mmoitems/listener/PlayerListener.java
@@ -21,6 +21,8 @@ import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
 import net.Indyuce.mmoitems.api.player.PlayerData;
 import net.Indyuce.mmoitems.api.player.inventory.EditableEquippedItem;
 import net.Indyuce.mmoitems.api.player.inventory.EquippedPlayerItem;
+import net.Indyuce.mmoitems.api.player.inventory.InventoryUpdateHandler;
+import net.Indyuce.mmoitems.api.util.DeathDowngrading;
 import net.Indyuce.mmoitems.api.util.message.Message;
 import net.Indyuce.mmoitems.skill.RegisteredSkill;
 import net.Indyuce.mmoitems.stat.data.AbilityData;
@@ -39,6 +41,8 @@ import org.bukkit.event.entity.PlayerDeathEvent;
 import org.bukkit.event.entity.ProjectileLaunchEvent;
 import org.bukkit.event.player.*;
 import org.bukkit.inventory.ItemStack;
+import org.bukkit.scheduler.BukkitRunnable;
+import org.jetbrains.annotations.NotNull;
 
 import java.util.*;
 
@@ -57,8 +61,9 @@ public class PlayerListener implements Listener {
     /**
      * If the player dies, its time to roll the death-downgrade stat!
      */
+    @SuppressWarnings("InstanceofIncompatibleInterface")
     @EventHandler(priority = EventPriority.MONITOR)
-    public void onDeathForUpgradeLoss(PlayerDeathEvent event) {
+    public void onDeathForUpgradeLoss(@NotNull PlayerDeathEvent event) {
 
         // No
         if (event instanceof Cancellable) { if (((Cancellable) event).isCancelled()) { return; } }
@@ -66,126 +71,8 @@ public class PlayerListener implements Listener {
         // Supports NPCs
         if (!PlayerData.has(event.getEntity())) return;
 
-        // Get Player
-        PlayerData data = PlayerData.get(event.getEntity());
-
-        // Get total downgrade chance, anything less than zero is invalid
-        double deathChance = data.getStats().getStat(ItemStats.DOWNGRADE_ON_DEATH_CHANCE);
-        //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Current chance:\u00a7b " + deathChance);
-        if (deathChance <= 0) { return; }
-
-        List<EquippedPlayerItem> items = data.getInventory().getEquipped();
-        ArrayList<EditableEquippedItem> equipped = new ArrayList<>();
-
-        // Equipped Player Items yeah...
-        for (EquippedPlayerItem playerItem : items) {
-
-            // Null
-            if (playerItem == null) { continue; }
-            //DET//playerItem.getItem().hasData(ItemStats.NAME);
-            //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Item:\u00a7b " + playerItem.getItem().getData(ItemStats.NAME));
-
-            // Cannot perform operations of items that are uneditable
-            if (!(playerItem.getEquipped() instanceof EditableEquippedItem)) {
-                //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Not equippable. \u00a7cCancel");
-                continue; }
-
-            // Not downgradeable on death? Snooze
-            if (!playerItem.getItem().hasData(ItemStats.DOWNGRADE_ON_DEATH)) {
-                //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Not Downgradeable. \u00a7cCancel");
-                continue; }
-
-            // No upgrade template no snooze
-            if(!playerItem.getItem().hasData(ItemStats.UPGRADE)) {
-                //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Not Upgradeable. \u00a7cCancel");
-                continue; }
-            if (!playerItem.getItem().hasUpgradeTemplate()) {
-                //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Null Template. \u00a7cCancel");
-                continue; }
-
-            // If it can be downgraded by one level...
-            UpgradeData upgradeData = (UpgradeData) playerItem.getItem().getData(ItemStats.UPGRADE);
-            if (upgradeData.getLevel() <= upgradeData.getMin()) {
-                //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Too downgraded. \u00a7cCancel");
-                continue; }
-
-            // Okay explore stat
-            equipped.add((EditableEquippedItem) playerItem.getEquipped());
-            //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Yes. \u00a7aAccepted");
-        }
-
-        // Nothing to perform operations? Snooze
-        if (equipped.size() == 0) {
-            //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 No items to downgrade. ");
-            return; }
-        Random random = new Random();
-
-        // Degrade those items!
-        while (deathChance >= 100 && equipped.size() > 0) {
-
-            // Decrease
-            deathChance -= 100;
-
-            // Downgrade random item
-            int d = random.nextInt(equipped.size());
-
-            /*
-             * The item was chosen, we must downgrade it by one level.
-             */
-            EditableEquippedItem equip = equipped.get(d);
-            LiveMMOItem mmo = new LiveMMOItem(equip.getItem());
-            mmo.getUpgradeTemplate().upgradeTo(mmo, mmo.getUpgradeLevel() - 1);
-
-            // Build NBT
-            ItemStack bakedItem = mmo.newBuilder().build();
-
-            // Set durability to zero (full repair)
-            DurabilityItem dur = new DurabilityItem(event.getEntity(), mmo.newBuilder().buildNBT());
-
-            if (dur.getDurability() != dur.getMaxDurability()) {
-                dur.addDurability(dur.getMaxDurability());
-                bakedItem.setItemMeta(dur.toItem().getItemMeta());}
-
-            // AH
-            equip.setItem(bakedItem);
-            equipped.remove(d);
-
-            Message.DEATH_DOWNGRADING.format(ChatColor.RED, "#item#", SilentNumbers.getItemName(equip.getItem().getItem(), false))
-                    .send(event.getEntity());
-
-            //DET//MMOItems.log("\u00a78DETH \u00a7cDG\u00a77 Autodegrading\u00a7a " + mmo.getData(ItemStats.NAME));
-        }
-
-        // If there is chance, and there is size, and there is chance success
-        if (deathChance > 0 && equipped.size() > 0 && random.nextInt(100) < deathChance) {
-
-            // Downgrade random item
-            int d = random.nextInt(equipped.size());
-
-            /*
-             * The item was chosen, we must downgrade it by one level.
-             */
-            EditableEquippedItem equip = equipped.get(d);
-            LiveMMOItem mmo = new LiveMMOItem(equip.getItem());
-            mmo.getUpgradeTemplate().upgradeTo(mmo, mmo.getUpgradeLevel() - 1);
-
-            // Build NBT
-            ItemStack bakedItem = mmo.newBuilder().build();
-
-            // Set durability to zero (full repair)
-            DurabilityItem dur = new DurabilityItem(event.getEntity(), mmo.newBuilder().buildNBT());
-
-            if (dur.getDurability() != dur.getMaxDurability()) {
-                dur.addDurability(dur.getMaxDurability());
-                bakedItem.setItemMeta(dur.toItem().getItemMeta());}
-
-            // AH
-            equip.setItem(bakedItem);
-            equipped.remove(d);
-
-            Message.DEATH_DOWNGRADING.format(ChatColor.RED, "#item#", SilentNumbers.getItemName(equip.getItem().getItem(), false))
-                    .send(event.getEntity());
-        }
+        // See description of DelayedDeathDowngrade child class for full explanation
+        (new DelayedDeathDowngrade(event)).runTaskLater(MMOItems.plugin, 3L);
     }
 
     /**
@@ -339,4 +226,32 @@ public class PlayerListener implements Listener {
         // Call event for compatibility
         Bukkit.getPluginManager().callEvent(new AbilityUseEvent(playerData, abilityData, target));
     }
+
+    /**
+     * Some plugins like to interfere with dropping items when the
+     * player dies, or whatever of that sort.
+     *
+     * MMOItems would hate to dupe items because of this, as such, we wait
+     * 3 ticks for those plugins to reasonably complete their operations and
+     * then downgrade the items the player still has equipped.
+     *
+     * If a plugin removes items in this time, they will be completely excluded
+     * and no dupes will be caused, and if a plugin adds items, they will be
+     * included and downgraded. I think that's reasonable behaviour.
+     *
+     * @author Gunging
+     */
+    private static class DelayedDeathDowngrade extends BukkitRunnable {
+
+        @NotNull final PlayerDeathEvent event;
+
+        DelayedDeathDowngrade(@NotNull PlayerDeathEvent event) {this.event = event;}
+
+        @Override
+        public void run() {
+
+            // Downgrade player's inventory
+            DeathDowngrading.playerDeathDowngrade(event.getEntity());
+        }
+    }
 }
diff --git a/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepDurability.java b/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepDurability.java
index 4a264b8c..2b42b26a 100644
--- a/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepDurability.java
+++ b/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepDurability.java
@@ -15,7 +15,6 @@ public class RFGKeepDurability implements Listener {
 
     @EventHandler
     public void onReforge(MMOItemReforgeEvent event) {
-        //RFG// MMOItems.log("§8Reforge §4EFG§7 Keeping Durability");
 
         // What was its durability? Transfer it
         event.getNewMMOItem().setDamage(event.getOldMMOItem().getDamage());
diff --git a/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepGems.java b/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepGems.java
index 06ee0cd7..dd3e960b 100644
--- a/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepGems.java
+++ b/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepGems.java
@@ -5,6 +5,7 @@ import net.Indyuce.mmoitems.MMOItems;
 import net.Indyuce.mmoitems.api.ReforgeOptions;
 import net.Indyuce.mmoitems.api.event.MMOItemReforgeEvent;
 import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
+import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
 import net.Indyuce.mmoitems.stat.data.GemSocketsData;
 import net.Indyuce.mmoitems.stat.data.GemstoneData;
 import net.Indyuce.mmoitems.stat.data.type.Mergeable;
@@ -148,8 +149,10 @@ public class RFGKeepGems implements Listener {
 
                 // Get MMOItem
                 MMOItem restoredGem = event.getOldMMOItem().extractGemstone(lost);
+                if (restoredGem == null) { continue; }
 
                 // Success? Add that gem there
-                if (restoredGem != null) { event.getReforger().addReforgingOutput(restoredGem.newBuilder().build()); } } }
+                event.getReforger().addReforgingOutput(restoredGem.newBuilder().build());
+            } }
     }
 }
diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml
index 648971a7..5d3085f2 100644
--- a/src/main/resources/config.yml
+++ b/src/main/resources/config.yml
@@ -256,10 +256,13 @@ item-revision:
     # ´reroll-when-updated´ is set to true.
     default-item-level: -1
 
-    # Whether or not the current tier of the item should
-    # be carried over.
-    # Please note, that this value has no effect if
-    # ´reroll-when-updated´ is set to true.
+    # Unsocketing gems picks them up with the stats they had
+    # when first put into the item, disable this option to
+    # force them to be regenerated.
+    regenerate-gems-when-unsocketed: false
+
+    # Legacy option to carry tiers over, will take precedence
+    # If not specified next to the other keep- flags.
     keep-tiers: true
 
     # If an item is updated, and the new version does not
@@ -303,9 +306,12 @@ item-revision:
         # Modifiers of items ~ Sharp, Light, Heavy, Arcane
         modifications: true
 
-        # Third party plugin compatibility
+        # Skins applied by MMOItems
         skins: true
 
+        # Tier of the item
+        tier: true
+
         # Third party plugin compatibility
         advanced-enchantments: true
 
@@ -317,6 +323,7 @@ item-revision:
         upgrades: false
         lore: false
         exsh: false
+        tier: true
         skins: false
         reroll: true
         modifications: false